diff options
Diffstat (limited to 'lib/repl.js')
-rw-r--r-- | lib/repl.js | 59 |
1 files changed, 47 insertions, 12 deletions
diff --git a/lib/repl.js b/lib/repl.js index d439d205a4..e4a366664c 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -72,6 +72,7 @@ const { ERR_CANNOT_WATCH_SIGINT, ERR_INVALID_ARG_TYPE, ERR_INVALID_REPL_EVAL_CONFIG, + ERR_INVALID_REPL_INPUT, ERR_SCRIPT_EXECUTION_INTERRUPTED } = require('internal/errors').codes; const { sendInspectorCommand } = require('internal/util/inspector'); @@ -101,10 +102,13 @@ let processTopLevelAwait; const parentModule = module; const replMap = new WeakMap(); +const domainSet = new WeakSet(); const kBufferedCommandSymbol = Symbol('bufferedCommand'); const kContextId = Symbol('contextId'); +let addedNewListener = false; + try { // Hack for require.resolve("./relative") to work properly. module.filename = path.resolve('repl'); @@ -204,6 +208,28 @@ function REPLServer(prompt, throw new ERR_INVALID_REPL_EVAL_CONFIG(); } + // Add this listener only once and use a WeakSet that contains the REPLs + // domains. Otherwise we'd have to add a single listener to each REPL instance + // and that could trigger the `MaxListenersExceededWarning`. + if (!options[kStandaloneREPL] && !addedNewListener) { + process.prependListener('newListener', (event, listener) => { + if (event === 'uncaughtException' && + process.domain && + listener.name !== 'domainUncaughtExceptionClear' && + domainSet.has(process.domain)) { + // Throw an error so that the event will not be added and the current + // domain takes over. That way the user is notified about the error + // and the current code evaluation is stopped, just as any other code + // that contains an error. + throw new ERR_INVALID_REPL_INPUT( + 'Listeners for `uncaughtException` cannot be used in the REPL'); + } + }); + addedNewListener = true; + } + + domainSet.add(this._domain); + let rli = this; Object.defineProperty(this, 'rli', { get: deprecate(() => rli, @@ -264,7 +290,7 @@ function REPLServer(prompt, // statement rather than an object literal. So, we first try // to wrap it in parentheses, so that it will be interpreted as // an expression. Note that if the above condition changes, - // lib/internal/repl/recoverable.js needs to be changed to match. + // lib/internal/repl/utils.js needs to be changed to match. code = `(${code.trim()})\n`; wrappedCmd = true; } @@ -461,22 +487,31 @@ function REPLServer(prompt, } } - if (errStack === '') { - errStack = `Thrown: ${self.writer(e)}\n`; - } else { - const ln = errStack.endsWith('\n') ? '' : '\n'; - errStack = `Thrown:\n${errStack}${ln}`; - } - if (!self.underscoreErrAssigned) { self.lastError = e; } const top = replMap.get(self); - top.outputStream.write(errStack); - top.clearBufferedCommand(); - top.lines.level = []; - top.displayPrompt(); + if (options[kStandaloneREPL] && + process.listenerCount('uncaughtException') !== 0) { + process.nextTick(() => { + process.emit('uncaughtException', e); + top.clearBufferedCommand(); + top.lines.level = []; + top.displayPrompt(); + }); + } else { + if (errStack === '') { + errStack = `Thrown: ${self.writer(e)}\n`; + } else { + const ln = errStack.endsWith('\n') ? '' : '\n'; + errStack = `Thrown:\n${errStack}${ln}`; + } + top.outputStream.write(errStack); + top.clearBufferedCommand(); + top.lines.level = []; + top.displayPrompt(); + } }); self.resetContext(); |