diff --git a/lib/repl.js b/lib/repl.js index 3029c94b1e1ac0..8b96a1f55652af 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -45,7 +45,7 @@ const { ArrayPrototypeAt, ArrayPrototypeFilter, - ArrayPrototypeFindIndex, + ArrayPrototypeFindLastIndex, ArrayPrototypeForEach, ArrayPrototypeIncludes, ArrayPrototypeJoin, @@ -53,15 +53,13 @@ const { ArrayPrototypePop, ArrayPrototypePush, ArrayPrototypePushApply, - ArrayPrototypeReverse, ArrayPrototypeShift, ArrayPrototypeSlice, ArrayPrototypeSome, ArrayPrototypeSort, - ArrayPrototypeSplice, ArrayPrototypeUnshift, Boolean, - Error, + Error: MainContextError, FunctionPrototypeBind, JSONStringify, MathMaxApply, @@ -630,10 +628,10 @@ function REPLServer(prompt, if (self.breakEvalOnSigint) { const interrupt = new Promise((resolve, reject) => { sigintListener = () => { - const tmp = Error.stackTraceLimit; - if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0; + const tmp = MainContextError.stackTraceLimit; + if (isErrorStackTraceLimitWritable()) MainContextError.stackTraceLimit = 0; const err = new ERR_SCRIPT_EXECUTION_INTERRUPTED(); - if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = tmp; + if (isErrorStackTraceLimitWritable()) MainContextError.stackTraceLimit = tmp; reject(err); }; prioritizedSigintQueue.add(sigintListener); @@ -679,23 +677,23 @@ function REPLServer(prompt, if (typeof stackFrames === 'object') { // Search from the bottom of the call stack to // find the first frame with a null function name - const idx = ArrayPrototypeFindIndex( - ArrayPrototypeReverse(stackFrames), + const idx = ArrayPrototypeFindLastIndex( + stackFrames, (frame) => frame.getFunctionName() === null, ); // If found, get rid of it and everything below it - frames = ArrayPrototypeSplice(stackFrames, idx + 1); + frames = ArrayPrototypeSlice(stackFrames, 0, idx); } else { frames = stackFrames; } // FIXME(devsnek): this is inconsistent with the checks // that the real prepareStackTrace dispatch uses in // lib/internal/errors.js. - if (typeof Error.prepareStackTrace === 'function') { - return Error.prepareStackTrace(error, frames); + if (typeof MainContextError.prepareStackTrace === 'function') { + return MainContextError.prepareStackTrace(error, frames); } - ArrayPrototypePush(frames, error); - return ArrayPrototypeJoin(ArrayPrototypeReverse(frames), '\n at '); + ArrayPrototypeUnshift(frames, error); + return ArrayPrototypeJoin(frames, '\n at '); }); decorateErrorStack(e); diff --git a/test/parallel/test-repl-pretty-custom-stack.js b/test/parallel/test-repl-pretty-custom-stack.js index a10cd032a688c4..f5697c2362e261 100644 --- a/test/parallel/test-repl-pretty-custom-stack.js +++ b/test/parallel/test-repl-pretty-custom-stack.js @@ -42,8 +42,9 @@ const origPrepareStackTrace = Error.prepareStackTrace; Error.prepareStackTrace = (err, stack) => { if (err instanceof SyntaxError) return err.toString(); - stack.push(err); - return stack.reverse().join('--->\n'); + // Insert the error at the beginning of the stack + stack.unshift(err); + return stack.join('--->\n'); }; process.on('uncaughtException', (e) => { @@ -78,3 +79,10 @@ const tests = [ ]; tests.forEach(run); + +// Verify that the stack can be generated when Error.prepareStackTrace is deleted. +delete Error.prepareStackTrace; +run({ + command: 'throw new TypeError(\'Whoops!\')', + expected: 'Uncaught TypeError: Whoops!\n' +});