diff --git a/source-map-support.js b/source-map-support.js index b312e62..82259df 100644 --- a/source-map-support.js +++ b/source-map-support.js @@ -355,21 +355,35 @@ function getErrorSource(error) { return null; } -// Mimic node's stack trace printing when an exception escapes the process -function handleUncaughtExceptions(error) { - if (!error || !error.stack) { - console.error('Uncaught exception:', error); - } else { - var source = getErrorSource(error); - if (source !== null) { - console.error(); - console.error(source); - } - console.error(error.stack); +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; @@ -405,7 +419,7 @@ exports.install = function(options) { // generated JavaScript code will be shown above the stack trace instead of // the original source code. if (installHandler && !isInBrowser()) { - process.on('uncaughtException', handleUncaughtExceptions); + shimEmitUncaughtException(); } } }; diff --git a/test.js b/test.js index bd25f92..5d3f928 100644 --- a/test.js +++ b/test.js @@ -415,3 +415,25 @@ it('finds source maps with charset specified', function() { } 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(); + }); +});