[Pkg-javascript-commits] [node-source-map-support] 01/03: New upstream version 0.4.3+ds

Julien Puydt julien.puydt at laposte.net
Tue Oct 4 16:50:03 UTC 2016


This is an automated email from the git hooks/post-receive script.

jpuydt-guest pushed a commit to branch master
in repository node-source-map-support.

commit 61a1df53ff4c3f1aed130454425483e35f44912f
Author: Julien Puydt <julien.puydt at laposte.net>
Date:   Tue Oct 4 18:32:28 2016 +0200

    New upstream version 0.4.3+ds
---
 .gitignore            |   9 +
 .npmignore            |   1 +
 .travis.yml           |   5 +
 LICENSE.md            |  21 ++
 README.md             | 240 +++++++++++++++++++++++
 build.js              |  73 +++++++
 package.json          |  28 +++
 register.js           |   1 +
 source-map-support.js | 486 +++++++++++++++++++++++++++++++++++++++++++++
 test.js               | 531 ++++++++++++++++++++++++++++++++++++++++++++++++++
 10 files changed, 1395 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..19c622f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+node_modules/
+amd-test/browser-source-map-support.js
+amd-test/script.js
+amd-test/script.map
+browserify-test/compiled.js
+browserify-test/script.js
+browserify-test/script.map
+header-test/script.js
+header-test/script.map
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..d91de11
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1 @@
+browserify-test/
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..2a2f1c6
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,5 @@
+language: node_js
+node_js:
+  - 'stable'
+  - '0.12'
+  - '0.10'
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..6247ca9
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Evan Wallace
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..57f4d1d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,240 @@
+# Source Map Support
+[![Build Status](https://travis-ci.org/evanw/node-source-map-support.svg?branch=master)](https://travis-ci.org/evanw/node-source-map-support)
+
+This module provides source map support for stack traces in node via the [V8 stack trace API](http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi). It uses the [source-map](https://github.com/mozilla/source-map) module to replace the paths and line numbers of source-mapped files with their original paths and line numbers. The output mimics node's stack trace format with the goal of making every compile-to-JS language more of a first-class citizen. Source maps are completely general  [...]
+
+## Installation and Usage
+
+#### Node support
+
+```
+$ npm install source-map-support
+```
+
+Source maps can be generated using libraries such as [source-map-index-generator](https://github.com/twolfson/source-map-index-generator). Once you have a valid source map, insert the following line at the top of your compiled code:
+
+```js
+require('source-map-support').install();
+```
+
+And place a source mapping comment somewhere in the file (usually done automatically or with an option by your transpiler):
+
+```
+//# sourceMappingURL=path/to/source.map
+```
+
+If multiple sourceMappingURL comments exist in one file, the last sourceMappingURL comment will be
+respected (e.g. if a file mentions the comment in code, or went through multiple transpilers).
+The path should either be absolute or relative to the compiled file.
+
+It is also possible to to install the source map support directly by
+requiring the `register` module which can be handy with ES6:
+
+```js
+import 'source-map-support/register'
+
+// Instead of:
+import sourceMapSupport from 'source-map-support'
+sourceMapSupport.install()
+```
+Note: if you're using babel-register, it includes source-map-support already.
+
+It is also very useful with Mocha:
+
+```
+$ mocha --require source-map-support/register tests/
+```
+
+#### Browser support
+
+This library also works in Chrome. While the DevTools console already supports source maps, the V8 engine doesn't and `Error.prototype.stack` will be incorrect without this library. Everything will just work if you deploy your source files using [browserify](http://browserify.org/). Just make sure to pass the `--debug` flag to the browserify command so your source maps are included in the bundled code.
+
+This library also works if you use another build process or just include the source files directly. In this case, include the file `browser-source-map-support.js` in your page and call `sourceMapSupport.install()`. It contains the whole library already bundled for the browser using browserify.
+
+```html
+<script src="browser-source-map-support.js"></script>
+<script>sourceMapSupport.install();</script>
+```
+
+This library also works if you use AMD (Asynchronous Module Definition), which is used in tools like [RequireJS](http://requirejs.org/). Just list `browser-source-map-support` as a dependency:
+
+```html
+<script>
+  define(['browser-source-map-support'], function(sourceMapSupport) {
+    sourceMapSupport.install();
+  });
+</script>
+```
+
+## Options
+
+This module installs two things: a change to the `stack` property on `Error` objects and a handler for uncaught exceptions that mimics node's default exception handler (the handler can be seen in the demos below). You may want to disable the handler if you have your own uncaught exception handler. This can be done by passing an argument to the installer:
+
+```js
+require('source-map-support').install({
+  handleUncaughtExceptions: false
+});
+```
+
+This module loads source maps from the filesystem by default. You can provide alternate loading behavior through a callback as shown below. For example, [Meteor](https://github.com/meteor) keeps all source maps cached in memory to avoid disk access.
+
+```js
+require('source-map-support').install({
+  retrieveSourceMap: function(source) {
+    if (source === 'compiled.js') {
+      return {
+        url: 'original.js',
+        map: fs.readFileSync('compiled.js.map', 'utf8')
+      };
+    }
+    return null;
+  }
+});
+```
+
+The module will by default assume a browser environment if XMLHttpRequest and window are defined. If either of these do not exist it will instead assume a node environment. 
+In some rare cases, e.g. when running a browser emulation and where both variables are also set, you can explictly specify the environment to be either 'browser' or 'node'. 
+
+```js
+require('source-map-support').install({
+  environment: 'node'
+});
+```
+
+## Demos
+
+#### Basic Demo
+
+original.js:
+
+```js
+throw new Error('test'); // This is the original code
+```
+
+compiled.js:
+
+```js
+require('source-map-support').install();
+
+throw new Error('test'); // This is the compiled code
+// The next line defines the sourceMapping.
+//# sourceMappingURL=compiled.js.map
+```
+
+compiled.js.map:
+
+```json
+{
+  "version": 3,
+  "file": "compiled.js",
+  "sources": ["original.js"],
+  "names": [],
+  "mappings": ";;;AAAA,MAAM,IAAI"
+}
+```
+
+Run compiled.js using node (notice how the stack trace uses original.js instead of compiled.js):
+
+```
+$ node compiled.js
+
+original.js:1
+throw new Error('test'); // This is the original code
+      ^
+Error: test
+    at Object.<anonymous> (original.js:1:7)
+    at Module._compile (module.js:456:26)
+    at Object.Module._extensions..js (module.js:474:10)
+    at Module.load (module.js:356:32)
+    at Function.Module._load (module.js:312:12)
+    at Function.Module.runMain (module.js:497:10)
+    at startup (node.js:119:16)
+    at node.js:901:3
+```
+
+#### TypeScript Demo
+
+demo.ts:
+
+```typescript
+declare function require(name: string);
+require('source-map-support').install();
+class Foo {
+  constructor() { this.bar(); }
+  bar() { throw new Error('this is a demo'); }
+}
+new Foo();
+```
+
+Compile and run the file using the TypeScript compiler from the terminal:
+
+```
+$ npm install source-map-support typescript
+$ node_modules/typescript/bin/tsc -sourcemap demo.ts
+$ node demo.js
+
+demo.ts:5
+  bar() { throw new Error('this is a demo'); }
+                ^
+Error: this is a demo
+    at Foo.bar (demo.ts:5:17)
+    at new Foo (demo.ts:4:24)
+    at Object.<anonymous> (demo.ts:7:1)
+    at Module._compile (module.js:456:26)
+    at Object.Module._extensions..js (module.js:474:10)
+    at Module.load (module.js:356:32)
+    at Function.Module._load (module.js:312:12)
+    at Function.Module.runMain (module.js:497:10)
+    at startup (node.js:119:16)
+    at node.js:901:3
+```
+    
+#### CoffeeScript Demo
+
+demo.coffee:
+
+```coffee
+require('source-map-support').install()
+foo = ->
+  bar = -> throw new Error 'this is a demo'
+  bar()
+foo()
+```
+
+Compile and run the file using the CoffeeScript compiler from the terminal:
+
+```sh
+$ npm install source-map-support coffee-script
+$ node_modules/coffee-script/bin/coffee --map --compile demo.coffee
+$ node demo.js
+
+demo.coffee:3
+  bar = -> throw new Error 'this is a demo'
+                     ^
+Error: this is a demo
+    at bar (demo.coffee:3:22)
+    at foo (demo.coffee:4:3)
+    at Object.<anonymous> (demo.coffee:5:1)
+    at Object.<anonymous> (demo.coffee:1:1)
+    at Module._compile (module.js:456:26)
+    at Object.Module._extensions..js (module.js:474:10)
+    at Module.load (module.js:356:32)
+    at Function.Module._load (module.js:312:12)
+    at Function.Module.runMain (module.js:497:10)
+    at startup (node.js:119:16)
+```
+
+## Tests
+
+This repo contains both automated tests for node and manual tests for the browser. The automated tests can be run using mocha (type `mocha` in the root directory). To run the manual tests:
+
+* Build the tests using `build.js`
+* Launch the HTTP server (`npm run serve-tests`) and visit
+  * http://127.0.0.1:1336/amd-test
+  * http://127.0.0.1:1336/browser-test
+  * http://127.0.0.1:1336/browserify-test - **Currently not working** due to a bug with browserify (see [pull request #66](https://github.com/evanw/node-source-map-support/pull/66) for details).
+* For `header-test`, run `server.js` inside that directory and visit http://127.0.0.1:1337/
+
+## License
+
+This code is available under the [MIT license](http://opensource.org/licenses/MIT).
diff --git a/build.js b/build.js
new file mode 100755
index 0000000..fdbf145
--- /dev/null
+++ b/build.js
@@ -0,0 +1,73 @@
+#!/usr/bin/env node
+
+var fs = require('fs');
+var path = require('path');
+var querystring = require('querystring');
+var child_process = require('child_process');
+
+var browserify = path.join('node_modules', '.bin', 'browserify');
+var coffee = path.join('node_modules', '.bin', 'coffee');
+
+function run(command, callback) {
+  console.log(command);
+  child_process.exec(command, callback);
+}
+
+// Use browserify to package up source-map-support.js
+fs.writeFileSync('.temp.js', 'sourceMapSupport = require("./source-map-support");');
+run(browserify + ' .temp.js', function(error, stdout) {
+  if (error) throw error;
+
+  // Wrap the code so it works both as a normal <script> module and as an AMD module
+  var header = [
+    '/*',
+    ' * Support for source maps in V8 stack traces',
+    ' * https://github.com/evanw/node-source-map-support',
+    ' */',
+  ].join('\n');
+  var code = [
+    '(this["define"] || function(name, callback) { this["sourceMapSupport"] = callback(); })("browser-source-map-support", function(sourceMapSupport) {',
+    stdout.replace(/\bbyte\b/g, 'bite').replace(new RegExp(__dirname + '/', 'g'), '').replace(/@license/g, 'license'),
+    'return sourceMapSupport});',
+  ].join('\n');
+
+  // Use the online Google Closure Compiler service for minification
+  fs.writeFileSync('.temp.js', querystring.stringify({
+    compilation_level: 'SIMPLE_OPTIMIZATIONS',
+    output_info: 'compiled_code',
+    output_format: 'text',
+    js_code: code
+  }));
+  run('curl -d @.temp.js "http://closure-compiler.appspot.com/compile"', function(error, stdout) {
+    if (error) throw error;
+    var code = header + '\n' + stdout;
+    fs.unlinkSync('.temp.js');
+    fs.writeFileSync('browser-source-map-support.js', code);
+    fs.writeFileSync('amd-test/browser-source-map-support.js', code);
+  });
+});
+
+// Build the AMD test
+run(coffee + ' --map --compile amd-test/script.coffee', function(error) {
+  if (error) throw error;
+});
+
+// Build the browserify test
+run(coffee + ' --map --compile browserify-test/script.coffee', function(error) {
+  if (error) throw error;
+  run(browserify + ' --debug browserify-test/script.js > browserify-test/compiled.js', function(error) {
+    if (error) throw error;
+  })
+});
+
+// Build the browser test
+run(coffee + ' --map --compile browser-test/script.coffee', function(error) {
+  if (error) throw error;
+});
+
+// Build the header test
+run(coffee + ' --map --compile header-test/script.coffee', function(error) {
+  if (error) throw error;
+  var contents = fs.readFileSync('header-test/script.js', 'utf8');
+  fs.writeFileSync('header-test/script.js', contents.replace(/\/\/# sourceMappingURL=.*/g, ''))
+});
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..7b36c19
--- /dev/null
+++ b/package.json
@@ -0,0 +1,28 @@
+{
+  "name": "source-map-support",
+  "description": "Fixes stack traces for files with source maps",
+  "version": "0.4.3",
+  "main": "./source-map-support.js",
+  "scripts": {
+    "build": "node build.js",
+    "serve-tests": "http-server -p 1336",
+    "test": "mocha"
+  },
+  "dependencies": {
+    "source-map": "^0.5.3"
+  },
+  "devDependencies": {
+    "browserify": "3.44.2",
+    "coffee-script": "1.7.1",
+    "http-server": "^0.8.5",
+    "mocha": "1.18.2"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/evanw/node-source-map-support"
+  },
+  "bugs": {
+    "url": "https://github.com/evanw/node-source-map-support/issues"
+  },
+  "license": "MIT"
+}
diff --git a/register.js b/register.js
new file mode 100644
index 0000000..4f68e67
--- /dev/null
+++ b/register.js
@@ -0,0 +1 @@
+require('./').install();
diff --git a/source-map-support.js b/source-map-support.js
new file mode 100644
index 0000000..0cfb14d
--- /dev/null
+++ b/source-map-support.js
@@ -0,0 +1,486 @@
+var SourceMapConsumer = require('source-map').SourceMapConsumer;
+var path = require('path');
+var fs = require('fs');
+
+// Only install once if called multiple times
+var errorFormatterInstalled = false;
+var uncaughtShimInstalled = false;
+
+// If true, the caches are reset before a stack trace formatting operation
+var emptyCacheBetweenOperations = false;
+
+// Supports {browser, node, auto}
+var environment = "auto";
+
+// Maps a file path to a string containing the file contents
+var fileContentsCache = {};
+
+// Maps a file path to a source map for that file
+var sourceMapCache = {};
+
+// Regex for detecting source maps
+var reSourceMap = /^data:application\/json[^,]+base64,/;
+
+// Priority list of retrieve handlers
+var retrieveFileHandlers = [];
+var retrieveMapHandlers = [];
+
+function isInBrowser() {
+  if (environment === "browser")
+    return true;
+  if (environment === "node")
+    return false;
+  return ((typeof window !== 'undefined') && (typeof XMLHttpRequest === 'function') && !(window.require && window.module && window.process && window.process.type === "renderer"));
+}
+
+function hasGlobalProcessEventEmitter() {
+  return ((typeof process === 'object') && (process !== null) && (typeof process.on === 'function'));
+}
+
+function handlerExec(list) {
+  return function(arg) {
+    for (var i = 0; i < list.length; i++) {
+      var ret = list[i](arg);
+      if (ret) {
+        return ret;
+      }
+    }
+    return null;
+  };
+}
+
+var retrieveFile = handlerExec(retrieveFileHandlers);
+
+retrieveFileHandlers.push(function(path) {
+  // Trim the path to make sure there is no extra whitespace.
+  path = path.trim();
+  if (path in fileContentsCache) {
+    return fileContentsCache[path];
+  }
+
+  try {
+    // Use SJAX if we are in the browser
+    if (isInBrowser()) {
+      var xhr = new XMLHttpRequest();
+      xhr.open('GET', path, false);
+      xhr.send(null);
+      var contents = null
+      if (xhr.readyState === 4 && xhr.status === 200) {
+        contents = xhr.responseText
+      }
+    }
+
+    // Otherwise, use the filesystem
+    else {
+      var contents = fs.readFileSync(path, 'utf8');
+    }
+  } catch (e) {
+    var contents = null;
+  }
+
+  return fileContentsCache[path] = contents;
+});
+
+// Support URLs relative to a directory, but be careful about a protocol prefix
+// in case we are in the browser (i.e. directories may start with "http://")
+function supportRelativeURL(file, url) {
+  if (!file) return url;
+  var dir = path.dirname(file);
+  var match = /^\w+:\/\/[^\/]*/.exec(dir);
+  var protocol = match ? match[0] : '';
+  return protocol + path.resolve(dir.slice(protocol.length), url);
+}
+
+function retrieveSourceMapURL(source) {
+  var fileData;
+
+  if (isInBrowser()) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', source, false);
+    xhr.send(null);
+    fileData = xhr.readyState === 4 ? xhr.responseText : null;
+
+    // Support providing a sourceMappingURL via the SourceMap header
+    var sourceMapHeader = xhr.getResponseHeader("SourceMap") ||
+                          xhr.getResponseHeader("X-SourceMap");
+    if (sourceMapHeader) {
+      return sourceMapHeader;
+    }
+  }
+
+  // Get the URL of the source map
+  fileData = retrieveFile(source);
+  //        //# sourceMappingURL=foo.js.map                       /*# sourceMappingURL=foo.js.map */
+  var re = /(?:\/\/[@#][ \t]+sourceMappingURL=([^\s'"]+?)[ \t]*$)|(?:\/\*[@#][ \t]+sourceMappingURL=([^\*]+?)[ \t]*(?:\*\/)[ \t]*$)/mg;
+  // Keep executing the search to find the *last* sourceMappingURL to avoid
+  // picking up sourceMappingURLs from comments, strings, etc.
+  var lastMatch, match;
+  while (match = re.exec(fileData)) lastMatch = match;
+  if (!lastMatch) return null;
+  return lastMatch[1];
+};
+
+// Can be overridden by the retrieveSourceMap option to install. Takes a
+// generated source filename; returns a {map, optional url} object, or null if
+// there is no source map.  The map field may be either a string or the parsed
+// JSON object (ie, it must be a valid argument to the SourceMapConsumer
+// constructor).
+var retrieveSourceMap = handlerExec(retrieveMapHandlers);
+retrieveMapHandlers.push(function(source) {
+  var sourceMappingURL = retrieveSourceMapURL(source);
+  if (!sourceMappingURL) return null;
+
+  // Read the contents of the source map
+  var sourceMapData;
+  if (reSourceMap.test(sourceMappingURL)) {
+    // Support source map URL as a data url
+    var rawData = sourceMappingURL.slice(sourceMappingURL.indexOf(',') + 1);
+    sourceMapData = new Buffer(rawData, "base64").toString();
+    sourceMappingURL = null;
+  } else {
+    // Support source map URLs relative to the source URL
+    sourceMappingURL = supportRelativeURL(source, sourceMappingURL);
+    sourceMapData = retrieveFile(sourceMappingURL);
+  }
+
+  if (!sourceMapData) {
+    return null;
+  }
+
+  return {
+    url: sourceMappingURL,
+    map: sourceMapData
+  };
+});
+
+function mapSourcePosition(position) {
+  var sourceMap = sourceMapCache[position.source];
+  if (!sourceMap) {
+    // Call the (overrideable) retrieveSourceMap function to get the source map.
+    var urlAndMap = retrieveSourceMap(position.source);
+    if (urlAndMap) {
+      sourceMap = sourceMapCache[position.source] = {
+        url: urlAndMap.url,
+        map: new SourceMapConsumer(urlAndMap.map)
+      };
+
+      // Load all sources stored inline with the source map into the file cache
+      // to pretend like they are already loaded. They may not exist on disk.
+      if (sourceMap.map.sourcesContent) {
+        sourceMap.map.sources.forEach(function(source, i) {
+          var contents = sourceMap.map.sourcesContent[i];
+          if (contents) {
+            var url = supportRelativeURL(sourceMap.url, source);
+            fileContentsCache[url] = contents;
+          }
+        });
+      }
+    } else {
+      sourceMap = sourceMapCache[position.source] = {
+        url: null,
+        map: null
+      };
+    }
+  }
+
+  // Resolve the source URL relative to the URL of the source map
+  if (sourceMap && sourceMap.map) {
+    var originalPosition = sourceMap.map.originalPositionFor(position);
+
+    // Only return the original position if a matching line was found. If no
+    // matching line is found then we return position instead, which will cause
+    // the stack trace to print the path and line for the compiled file. It is
+    // better to give a precise location in the compiled file than a vague
+    // location in the original file.
+    if (originalPosition.source !== null) {
+      originalPosition.source = supportRelativeURL(
+        sourceMap.url, originalPosition.source);
+      return originalPosition;
+    }
+  }
+
+  return position;
+}
+
+// Parses code generated by FormatEvalOrigin(), a function inside V8:
+// https://code.google.com/p/v8/source/browse/trunk/src/messages.js
+function mapEvalOrigin(origin) {
+  // Most eval() calls are in this format
+  var match = /^eval at ([^(]+) \((.+):(\d+):(\d+)\)$/.exec(origin);
+  if (match) {
+    var position = mapSourcePosition({
+      source: match[2],
+      line: +match[3],
+      column: match[4] - 1
+    });
+    return 'eval at ' + match[1] + ' (' + position.source + ':' +
+      position.line + ':' + (position.column + 1) + ')';
+  }
+
+  // Parse nested eval() calls using recursion
+  match = /^eval at ([^(]+) \((.+)\)$/.exec(origin);
+  if (match) {
+    return 'eval at ' + match[1] + ' (' + mapEvalOrigin(match[2]) + ')';
+  }
+
+  // Make sure we still return useful information if we didn't find anything
+  return origin;
+}
+
+// This is copied almost verbatim from the V8 source code at
+// https://code.google.com/p/v8/source/browse/trunk/src/messages.js. The
+// implementation of wrapCallSite() used to just forward to the actual source
+// code of CallSite.prototype.toString but unfortunately a new release of V8
+// did something to the prototype chain and broke the shim. The only fix I
+// could find was copy/paste.
+function CallSiteToString() {
+  var fileName;
+  var fileLocation = "";
+  if (this.isNative()) {
+    fileLocation = "native";
+  } else {
+    fileName = this.getScriptNameOrSourceURL();
+    if (!fileName && this.isEval()) {
+      fileLocation = this.getEvalOrigin();
+      fileLocation += ", ";  // Expecting source position to follow.
+    }
+
+    if (fileName) {
+      fileLocation += fileName;
+    } else {
+      // Source code does not originate from a file and is not native, but we
+      // can still get the source position inside the source string, e.g. in
+      // an eval string.
+      fileLocation += "<anonymous>";
+    }
+    var lineNumber = this.getLineNumber();
+    if (lineNumber != null) {
+      fileLocation += ":" + lineNumber;
+      var columnNumber = this.getColumnNumber();
+      if (columnNumber) {
+        fileLocation += ":" + columnNumber;
+      }
+    }
+  }
+
+  var line = "";
+  var functionName = this.getFunctionName();
+  var addSuffix = true;
+  var isConstructor = this.isConstructor();
+  var isMethodCall = !(this.isToplevel() || isConstructor);
+  if (isMethodCall) {
+    var typeName = this.getTypeName();
+    var methodName = this.getMethodName();
+    if (functionName) {
+      if (typeName && functionName.indexOf(typeName) != 0) {
+        line += typeName + ".";
+      }
+      line += functionName;
+      if (methodName && functionName.indexOf("." + methodName) != functionName.length - methodName.length - 1) {
+        line += " [as " + methodName + "]";
+      }
+    } else {
+      line += typeName + "." + (methodName || "<anonymous>");
+    }
+  } else if (isConstructor) {
+    line += "new " + (functionName || "<anonymous>");
+  } else if (functionName) {
+    line += functionName;
+  } else {
+    line += fileLocation;
+    addSuffix = false;
+  }
+  if (addSuffix) {
+    line += " (" + fileLocation + ")";
+  }
+  return line;
+}
+
+function cloneCallSite(frame) {
+  var object = {};
+  Object.getOwnPropertyNames(Object.getPrototypeOf(frame)).forEach(function(name) {
+    object[name] = /^(?:is|get)/.test(name) ? function() { return frame[name].call(frame); } : frame[name];
+  });
+  object.toString = CallSiteToString;
+  return object;
+}
+
+function wrapCallSite(frame) {
+  if(frame.isNative()) {
+    return frame;
+  }
+
+  // Most call sites will return the source file from getFileName(), but code
+  // passed to eval() ending in "//# sourceURL=..." will return the source file
+  // from getScriptNameOrSourceURL() instead
+  var source = frame.getFileName() || frame.getScriptNameOrSourceURL();
+  if (source) {
+    var line = frame.getLineNumber();
+    var column = frame.getColumnNumber() - 1;
+
+    // Fix position in Node where some (internal) code is prepended.
+    // See https://github.com/evanw/node-source-map-support/issues/36
+    if (line === 1 && !isInBrowser() && !frame.isEval()) {
+      column -= 62;
+    }
+
+    var position = mapSourcePosition({
+      source: source,
+      line: line,
+      column: column
+    });
+    frame = cloneCallSite(frame);
+    frame.getFileName = function() { return position.source; };
+    frame.getLineNumber = function() { return position.line; };
+    frame.getColumnNumber = function() { return position.column + 1; };
+    frame.getScriptNameOrSourceURL = function() { return position.source; };
+    return frame;
+  }
+
+  // Code called using eval() needs special handling
+  var origin = frame.isEval() && frame.getEvalOrigin();
+  if (origin) {
+    origin = mapEvalOrigin(origin);
+    frame = cloneCallSite(frame);
+    frame.getEvalOrigin = function() { return origin; };
+    return frame;
+  }
+
+  // If we get here then we were unable to change the source position
+  return frame;
+}
+
+// This function is part of the V8 stack trace API, for more info see:
+// http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
+function prepareStackTrace(error, stack) {
+  if (emptyCacheBetweenOperations) {
+    fileContentsCache = {};
+    sourceMapCache = {};
+  }
+
+  return error + stack.map(function(frame) {
+    return '\n    at ' + wrapCallSite(frame);
+  }).join('');
+}
+
+// Generate position and snippet of original source with pointer
+function getErrorSource(error) {
+  var match = /\n    at [^(]+ \((.*):(\d+):(\d+)\)/.exec(error.stack);
+  if (match) {
+    var source = match[1];
+    var line = +match[2];
+    var column = +match[3];
+
+    // Support the inline sourceContents inside the source map
+    var contents = fileContentsCache[source];
+
+    // Support files on disk
+    if (!contents && fs.existsSync(source)) {
+      contents = fs.readFileSync(source, 'utf8');
+    }
+
+    // Format the line from the original source code like node does
+    if (contents) {
+      var code = contents.split(/(?:\r\n|\r|\n)/)[line - 1];
+      if (code) {
+        return source + ':' + line + '\n' + code + '\n' +
+          new Array(column).join(' ') + '^';
+      }
+    }
+  }
+  return null;
+}
+
+function printErrorAndExit (error) {
+  var source = getErrorSource(error);
+
+  if (source) {
+    console.error();
+    console.error(source);
+  }
+
+  console.error(error.stack);
+  process.exit(1);
+}
+
+function shimEmitUncaughtException () {
+  var origEmit = process.emit;
+
+  process.emit = function (type) {
+    if (type === 'uncaughtException') {
+      var hasStack = (arguments[1] && arguments[1].stack);
+      var hasListeners = (this.listeners(type).length > 0);
+
+      if (hasStack && !hasListeners) {
+        return printErrorAndExit(arguments[1]);
+      }
+    }
+
+    return origEmit.apply(this, arguments);
+  };
+}
+
+exports.wrapCallSite = wrapCallSite;
+exports.getErrorSource = getErrorSource;
+exports.mapSourcePosition = mapSourcePosition;
+exports.retrieveSourceMap = retrieveSourceMap;
+
+exports.install = function(options) {
+  options = options || {};
+
+  if (options.environment) {
+    environment = options.environment;
+    if (["node", "browser", "auto"].indexOf(environment) === -1) {
+      throw new Error("environment " + environment + " was unknown. Available options are {auto, browser, node}")
+    }
+  }
+
+  // Allow sources to be found by methods other than reading the files
+  // directly from disk.
+  if (options.retrieveFile) {
+    if (options.overrideRetrieveFile) {
+      retrieveFileHandlers.length = 0;
+    }
+
+    retrieveFileHandlers.unshift(options.retrieveFile);
+  }
+
+  // Allow source maps to be found by methods other than reading the files
+  // directly from disk.
+  if (options.retrieveSourceMap) {
+    if (options.overrideRetrieveSourceMap) {
+      retrieveMapHandlers.length = 0;
+    }
+
+    retrieveMapHandlers.unshift(options.retrieveSourceMap);
+  }
+
+  // Configure options
+  if (!emptyCacheBetweenOperations) {
+    emptyCacheBetweenOperations = 'emptyCacheBetweenOperations' in options ?
+      options.emptyCacheBetweenOperations : false;
+  }
+
+  // Install the error reformatter
+  if (!errorFormatterInstalled) {
+    errorFormatterInstalled = true;
+    Error.prepareStackTrace = prepareStackTrace;
+  }
+
+  if (!uncaughtShimInstalled) {
+    var installHandler = 'handleUncaughtExceptions' in options ?
+      options.handleUncaughtExceptions : true;
+
+    // Provide the option to not install the uncaught exception handler. This is
+    // to support other uncaught exception handlers (in test frameworks, for
+    // example). If this handler is not installed and there are no other uncaught
+    // exception handlers, uncaught exceptions will be caught by node's built-in
+    // exception handler and the process will still be terminated. However, the
+    // generated JavaScript code will be shown above the stack trace instead of
+    // the original source code.
+    if (installHandler && hasGlobalProcessEventEmitter()) {
+      uncaughtShimInstalled = true;
+      shimEmitUncaughtException();
+    }
+  }
+};
diff --git a/test.js b/test.js
new file mode 100644
index 0000000..72245ec
--- /dev/null
+++ b/test.js
@@ -0,0 +1,531 @@
+require('./source-map-support').install({
+  emptyCacheBetweenOperations: true // Needed to be able to test for failure
+});
+
+var SourceMapGenerator = require('source-map').SourceMapGenerator;
+var child_process = require('child_process');
+var assert = require('assert');
+var fs = require('fs');
+
+function compareLines(actual, expected) {
+  assert(actual.length >= expected.length, 'got ' + actual.length + ' lines but expected at least ' + expected.length + ' lines');
+  for (var i = 0; i < expected.length; i++) {
+    // Some tests are regular expressions because the output format changed slightly between node v0.9.2 and v0.9.3
+    if (expected[i] instanceof RegExp) {
+      assert(expected[i].test(actual[i]), JSON.stringify(actual[i]) + ' does not match ' + expected[i]);
+    } else {
+      assert.equal(actual[i], expected[i]);
+    }
+  }
+}
+
+function createEmptySourceMap() {
+  return new SourceMapGenerator({
+    file: '.generated.js',
+    sourceRoot: '.'
+  });
+}
+
+function createSourceMapWithGap() {
+  var sourceMap = createEmptySourceMap();
+  sourceMap.addMapping({
+    generated: { line: 100, column: 0 },
+    original: { line: 100, column: 0 },
+    source: '.original.js'
+  });
+  return sourceMap;
+}
+
+function createSingleLineSourceMap() {
+  var sourceMap = createEmptySourceMap();
+  sourceMap.addMapping({
+    generated: { line: 1, column: 0 },
+    original: { line: 1, column: 0 },
+    source: '.original.js'
+  });
+  return sourceMap;
+}
+
+function createSecondLineSourceMap() {
+  var sourceMap = createEmptySourceMap();
+  sourceMap.addMapping({
+    generated: { line: 2, column: 0 },
+    original: { line: 1, column: 0 },
+    source: '.original.js'
+  });
+  return sourceMap;
+}
+
+function createMultiLineSourceMap() {
+  var sourceMap = createEmptySourceMap();
+  for (var i = 1; i <= 100; i++) {
+    sourceMap.addMapping({
+      generated: { line: i, column: 0 },
+      original: { line: 1000 + i, column: 99 + i },
+      source: 'line' + i + '.js'
+    });
+  }
+  return sourceMap;
+}
+
+function createMultiLineSourceMapWithSourcesContent() {
+  var sourceMap = createEmptySourceMap();
+  var original = new Array(1001).join('\n');
+  for (var i = 1; i <= 100; i++) {
+    sourceMap.addMapping({
+      generated: { line: i, column: 0 },
+      original: { line: 1000 + i, column: 4 },
+      source: 'original.js'
+    });
+    original += '    line ' + i + '\n';
+  }
+  sourceMap.setSourceContent('original.js', original);
+  return sourceMap;
+}
+
+function compareStackTrace(sourceMap, source, expected) {
+  // Check once with a separate source map
+  fs.writeFileSync('.generated.js.map', sourceMap);
+  fs.writeFileSync('.generated.js', 'exports.test = function() {' +
+    source.join('\n') + '};//@ sourceMappingURL=.generated.js.map');
+  try {
+    delete require.cache[require.resolve('./.generated')];
+    require('./.generated').test();
+  } catch (e) {
+    compareLines(e.stack.split('\n'), expected);
+  }
+  fs.unlinkSync('.generated.js');
+  fs.unlinkSync('.generated.js.map');
+
+  // Check again with an inline source map (in a data URL)
+  fs.writeFileSync('.generated.js', 'exports.test = function() {' +
+    source.join('\n') + '};//@ sourceMappingURL=data:application/json;base64,' +
+    new Buffer(sourceMap.toString()).toString('base64'));
+  try {
+    delete require.cache[require.resolve('./.generated')];
+    require('./.generated').test();
+  } catch (e) {
+    compareLines(e.stack.split('\n'), expected);
+  }
+  fs.unlinkSync('.generated.js');
+}
+
+function compareStdout(done, sourceMap, source, expected) {
+  fs.writeFileSync('.original.js', 'this is the original code');
+  fs.writeFileSync('.generated.js.map', sourceMap);
+  fs.writeFileSync('.generated.js', source.join('\n') +
+    '//@ sourceMappingURL=.generated.js.map');
+  child_process.exec('node ./.generated', function(error, stdout, stderr) {
+    try {
+      compareLines(
+        (stdout + stderr)
+          .trim()
+          .split('\n')
+          .filter(function (line) { return line !== '' }), // Empty lines are not relevant.
+        expected
+      );
+    } catch (e) {
+      return done(e);
+    }
+    fs.unlinkSync('.generated.js');
+    fs.unlinkSync('.generated.js.map');
+    fs.unlinkSync('.original.js');
+    done();
+  });
+}
+
+it('normal throw', function() {
+  compareStackTrace(createMultiLineSourceMap(), [
+    'throw new Error("test");'
+  ], [
+    'Error: test',
+    /^    at Object\.exports\.test \((?:.*\/)?line1\.js:1001:101\)$/
+  ]);
+});
+
+it('throw inside function', function() {
+  compareStackTrace(createMultiLineSourceMap(), [
+    'function foo() {',
+    '  throw new Error("test");',
+    '}',
+    'foo();'
+  ], [
+    'Error: test',
+    /^    at foo \((?:.*\/)?line2\.js:1002:102\)$/,
+    /^    at Object\.exports\.test \((?:.*\/)?line4\.js:1004:104\)$/
+  ]);
+});
+
+it('throw inside function inside function', function() {
+  compareStackTrace(createMultiLineSourceMap(), [
+    'function foo() {',
+    '  function bar() {',
+    '    throw new Error("test");',
+    '  }',
+    '  bar();',
+    '}',
+    'foo();'
+  ], [
+    'Error: test',
+    /^    at bar \((?:.*\/)?line3\.js:1003:103\)$/,
+    /^    at foo \((?:.*\/)?line5\.js:1005:105\)$/,
+    /^    at Object\.exports\.test \((?:.*\/)?line7\.js:1007:107\)$/
+  ]);
+});
+
+it('eval', function() {
+  compareStackTrace(createMultiLineSourceMap(), [
+    'eval("throw new Error(\'test\')");'
+  ], [
+    'Error: test',
+
+    // Before Node 4, `Object.eval`, after just `eval`.
+    /^    at (?:Object\.)?eval \(eval at <anonymous> \((?:.*\/)?line1\.js:1001:101\)/,
+
+    /^    at Object\.exports\.test \((?:.*\/)?line1\.js:1001:101\)$/
+  ]);
+});
+
+it('eval inside eval', function() {
+  compareStackTrace(createMultiLineSourceMap(), [
+    'eval("eval(\'throw new Error(\\"test\\")\')");'
+  ], [
+    'Error: test',
+    /^    at (?:Object\.)?eval \(eval at <anonymous> \(eval at <anonymous> \((?:.*\/)?line1\.js:1001:101\)/,
+    /^    at (?:Object\.)?eval \(eval at <anonymous> \((?:.*\/)?line1\.js:1001:101\)/,
+    /^    at Object\.exports\.test \((?:.*\/)?line1\.js:1001:101\)$/
+  ]);
+});
+
+it('eval inside function', function() {
+  compareStackTrace(createMultiLineSourceMap(), [
+    'function foo() {',
+    '  eval("throw new Error(\'test\')");',
+    '}',
+    'foo();'
+  ], [
+    'Error: test',
+    /^    at eval \(eval at foo \((?:.*\/)?line2\.js:1002:102\)/,
+    /^    at foo \((?:.*\/)?line2\.js:1002:102\)/,
+    /^    at Object\.exports\.test \((?:.*\/)?line4\.js:1004:104\)$/
+  ]);
+});
+
+it('eval with sourceURL', function() {
+  compareStackTrace(createMultiLineSourceMap(), [
+    'eval("throw new Error(\'test\')//@ sourceURL=sourceURL.js");'
+  ], [
+    'Error: test',
+    /^    at (?:Object\.)?eval \(sourceURL\.js:1:7\)$/,
+    /^    at Object\.exports\.test \((?:.*\/)?line1\.js:1001:101\)$/
+  ]);
+});
+
+it('eval with sourceURL inside eval', function() {
+  compareStackTrace(createMultiLineSourceMap(), [
+    'eval("eval(\'throw new Error(\\"test\\")//@ sourceURL=sourceURL.js\')");'
+  ], [
+    'Error: test',
+    /^    at (?:Object\.)?eval \(sourceURL\.js:1:7\)$/,
+    /^    at (?:Object\.)?eval \(eval at <anonymous> \((?:.*\/)?line1\.js:1001:101\)/,
+    /^    at Object\.exports\.test \((?:.*\/)?line1\.js:1001:101\)$/
+  ]);
+});
+
+it('native function', function() {
+  compareStackTrace(createSingleLineSourceMap(), [
+    '[1].map(function(x) { throw new Error(x); });'
+  ], [
+    'Error: 1',
+    /\/.original\.js/,
+    /at Array\.map \(native\)/
+  ]);
+});
+
+it('function constructor', function() {
+  compareStackTrace(createMultiLineSourceMap(), [
+    'throw new Function(")");'
+  ], [
+    'SyntaxError: Unexpected token )',
+    /^    at (?:Object\.)?Function \((?:unknown source|<anonymous>|native)\)$/,
+    /^    at Object\.exports\.test \((?:.*\/)?line1\.js:1001:101\)$/,
+  ]);
+});
+
+it('throw with empty source map', function() {
+  compareStackTrace(createEmptySourceMap(), [
+    'throw new Error("test");'
+  ], [
+    'Error: test',
+    /^    at Object\.exports\.test \((?:.*\/)?.generated.js:1:34\)$/
+  ]);
+});
+
+it('throw with source map with gap', function() {
+  compareStackTrace(createSourceMapWithGap(), [
+    'throw new Error("test");'
+  ], [
+    'Error: test',
+    /^    at Object\.exports\.test \((?:.*\/)?.generated.js:1:34\)$/
+  ]);
+});
+
+it('sourcesContent with data URL', function() {
+  compareStackTrace(createMultiLineSourceMapWithSourcesContent(), [
+    'throw new Error("test");'
+  ], [
+    'Error: test',
+    /^    at Object\.exports\.test \((?:.*\/)?original.js:1001:5\)$/
+  ]);
+});
+
+it('finds the last sourceMappingURL', function() {
+  compareStackTrace(createMultiLineSourceMapWithSourcesContent(), [
+    '//# sourceMappingURL=missing.map.js',  // NB: compareStackTrace adds another source mapping.
+    'throw new Error("test");'
+  ], [
+    'Error: test',
+    /^    at Object\.exports\.test \((?:.*\/)?original.js:1002:5\)$/
+  ]);
+});
+
+it('default options', function(done) {
+  compareStdout(done, createSecondLineSourceMap(), [
+    '',
+    'function foo() { throw new Error("this is the error"); }',
+    'require("./source-map-support").install();',
+    'process.nextTick(foo);',
+    'process.nextTick(function() { process.exit(1); });'
+  ], [
+    /\/.original\.js:1$/,
+    'this is the original code',
+    '^',
+    'Error: this is the error',
+    /^    at foo \((?:.*\/)?.original\.js:1:1\)$/
+  ]);
+});
+
+it('handleUncaughtExceptions is true', function(done) {
+  compareStdout(done, createSecondLineSourceMap(), [
+    '',
+    'function foo() { throw new Error("this is the error"); }',
+    'require("./source-map-support").install({ handleUncaughtExceptions: true });',
+    'process.nextTick(foo);'
+  ], [
+    /\/.original\.js:1$/,
+    'this is the original code',
+    '^',
+    'Error: this is the error',
+    /^    at foo \((?:.*\/)?.original\.js:1:1\)$/
+  ]);
+});
+
+it('handleUncaughtExceptions is false', function(done) {
+  compareStdout(done, createSecondLineSourceMap(), [
+    '',
+    'function foo() { throw new Error("this is the error"); }',
+    'require("./source-map-support").install({ handleUncaughtExceptions: false });',
+    'process.nextTick(foo);'
+  ], [
+    /\/.generated.js:2$/,
+    'function foo() { throw new Error("this is the error"); }',
+
+    // Before Node 4, the arrow points on the `new`, after on the
+    // `throw`.
+    /^                 (?:      )?\^$/,
+
+    'Error: this is the error',
+    /^    at foo \((?:.*\/)?.original\.js:1:1\)$/
+  ]);
+});
+
+it('default options with empty source map', function(done) {
+  compareStdout(done, createEmptySourceMap(), [
+    '',
+    'function foo() { throw new Error("this is the error"); }',
+    'require("./source-map-support").install();',
+    'process.nextTick(foo);'
+  ], [
+    /\/.generated.js:2$/,
+    'function foo() { throw new Error("this is the error"); }',
+    /^                 (?:      )?\^$/,
+    'Error: this is the error',
+    /^    at foo \((?:.*\/)?.generated.js:2:24\)$/
+  ]);
+});
+
+it('default options with source map with gap', function(done) {
+  compareStdout(done, createSourceMapWithGap(), [
+    '',
+    'function foo() { throw new Error("this is the error"); }',
+    'require("./source-map-support").install();',
+    'process.nextTick(foo);'
+  ], [
+    /\/.generated.js:2$/,
+    'function foo() { throw new Error("this is the error"); }',
+    /^                 (?:      )?\^$/,
+    'Error: this is the error',
+    /^    at foo \((?:.*\/)?.generated.js:2:24\)$/
+  ]);
+});
+
+it('specifically requested error source', function(done) {
+  compareStdout(done, createSecondLineSourceMap(), [
+    '',
+    'function foo() { throw new Error("this is the error"); }',
+    'var sms = require("./source-map-support");',
+    'sms.install({ handleUncaughtExceptions: false });',
+    'process.on("uncaughtException", function (e) { console.log("SRC:" + sms.getErrorSource(e)); });',
+    'process.nextTick(foo);'
+  ], [
+    /^SRC:.*\/.original.js:1$/,
+    'this is the original code',
+    '^'
+  ]);
+});
+
+it('sourcesContent', function(done) {
+  compareStdout(done, createMultiLineSourceMapWithSourcesContent(), [
+    '',
+    'function foo() { throw new Error("this is the error"); }',
+    'require("./source-map-support").install();',
+    'process.nextTick(foo);',
+    'process.nextTick(function() { process.exit(1); });'
+  ], [
+    /\/original\.js:1002$/,
+    '    line 2',
+    '    ^',
+    'Error: this is the error',
+    /^    at foo \((?:.*\/)?original\.js:1002:5\)$/
+  ]);
+});
+
+it('missing source maps should also be cached', function(done) {
+  compareStdout(done, createSingleLineSourceMap(), [
+    '',
+    'var count = 0;',
+    'function foo() {',
+    '  console.log(new Error("this is the error").stack.split("\\n").slice(0, 2).join("\\n"));',
+    '}',
+    'require("./source-map-support").install({',
+    '  overrideRetrieveSourceMap: true,',
+    '  retrieveSourceMap: function(name) {',
+    '    if (/\\.generated.js$/.test(name)) count++;',
+    '    return null;',
+    '  }',
+    '});',
+    'process.nextTick(foo);',
+    'process.nextTick(foo);',
+    'process.nextTick(function() { console.log(count); });',
+  ], [
+    'Error: this is the error',
+    /^    at foo \((?:.*\/)?.generated.js:4:15\)$/,
+    'Error: this is the error',
+    /^    at foo \((?:.*\/)?.generated.js:4:15\)$/,
+    '1', // The retrieval should only be attempted once
+  ]);
+});
+
+it('should consult all retrieve source map providers', function(done) {
+  compareStdout(done, createSingleLineSourceMap(), [
+    '',
+    'var count = 0;',
+    'function foo() {',
+    '  console.log(new Error("this is the error").stack.split("\\n").slice(0, 2).join("\\n"));',
+    '}',
+    'require("./source-map-support").install({',
+    '  retrieveSourceMap: function(name) {',
+    '    if (/\\.generated.js$/.test(name)) count++;',
+    '    return undefined;',
+    '  }',
+    '});',
+    'require("./source-map-support").install({',
+    '  retrieveSourceMap: function(name) {',
+    '    if (/\\.generated.js$/.test(name)) {',
+    '      count++;',
+    '      return ' + JSON.stringify({url: '.original.js', map: createMultiLineSourceMapWithSourcesContent().toJSON()}) + ';',
+    '    }',
+    '  }',
+    '});',
+    'process.nextTick(foo);',
+    'process.nextTick(foo);',
+    'process.nextTick(function() { console.log(count); });',
+  ], [
+    'Error: this is the error',
+    /^    at foo \((?:.*\/)?original.js:1004:5\)$/,
+    'Error: this is the error',
+    /^    at foo \((?:.*\/)?original.js:1004:5\)$/,
+    '1', // The retrieval should only be attempted once
+  ]);
+});
+
+/* The following test duplicates some of the code in
+ * `compareStackTrace` but appends a charset to the
+ * source mapping url.
+ */
+it('finds source maps with charset specified', function() {
+  var sourceMap = createMultiLineSourceMap()
+  var source = [ 'throw new Error("test");' ];
+  var expected = [
+    'Error: test',
+    /^    at Object\.exports\.test \((?:.*\/)?line1\.js:1001:101\)$/
+  ];
+
+  fs.writeFileSync('.generated.js', 'exports.test = function() {' +
+    source.join('\n') + '};//@ sourceMappingURL=data:application/json;charset=utf8;base64,' +
+    new Buffer(sourceMap.toString()).toString('base64'));
+  try {
+    delete require.cache[require.resolve('./.generated')];
+    require('./.generated').test();
+  } catch (e) {
+    compareLines(e.stack.split('\n'), expected);
+  }
+  fs.unlinkSync('.generated.js');
+});
+
+/* The following test duplicates some of the code in
+ * `compareStackTrace` but appends some code and a
+ * comment to the source mapping url.
+ */
+it('allows code/comments after sourceMappingURL', function() {
+  var sourceMap = createMultiLineSourceMap()
+  var source = [ 'throw new Error("test");' ];
+  var expected = [
+    'Error: test',
+    /^    at Object\.exports\.test \((?:.*\/)?line1\.js:1001:101\)$/
+  ];
+
+  fs.writeFileSync('.generated.js', 'exports.test = function() {' +
+    source.join('\n') + '};//# sourceMappingURL=data:application/json;base64,' +
+    new Buffer(sourceMap.toString()).toString('base64') +
+    '\n// Some comment below the sourceMappingURL\nvar foo = 0;');
+  try {
+    delete require.cache[require.resolve('./.generated')];
+    require('./.generated').test();
+  } catch (e) {
+    compareLines(e.stack.split('\n'), expected);
+  }
+  fs.unlinkSync('.generated.js');
+});
+
+it('handleUncaughtExceptions is true with existing listener', function(done) {
+  var source = [
+    'process.on("uncaughtException", function() { /* Silent */ });',
+    'function foo() { throw new Error("this is the error"); }',
+    'require("./source-map-support").install();',
+    'process.nextTick(foo);',
+    '//@ sourceMappingURL=.generated.js.map'
+  ];
+
+  fs.writeFileSync('.original.js', 'this is the original code');
+  fs.writeFileSync('.generated.js.map', createSingleLineSourceMap());
+  fs.writeFileSync('.generated.js', source.join('\n'));
+
+  child_process.exec('node ./.generated', function(error, stdout, stderr) {
+    fs.unlinkSync('.generated.js');
+    fs.unlinkSync('.generated.js.map');
+    fs.unlinkSync('.original.js');
+    assert.equal((stdout + stderr).trim(), '');
+    done();
+  });
+});

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-source-map-support.git



More information about the Pkg-javascript-commits mailing list