summaryrefslogtreecommitdiff
path: root/lib/repl.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/repl.js')
-rw-r--r--lib/repl.js59
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();