From 2986982459a939531ea552660e0d729f0044c318 Mon Sep 17 00:00:00 2001 From: bcoe Date: Tue, 31 Dec 2019 09:24:43 -0800 Subject: [PATCH] errors: support prepareSourceMap with source-maps Adds support for Error.prepareStackTrace override, when --enable-source-maps is set. PR-URL: https://github.com/nodejs/node/pull/31143 Reviewed-By: Benjamin Gruenbaum Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Anna Henningsen --- lib/internal/errors.js | 32 ++++++++++++------- .../source_map/prepare_stack_trace.js | 10 +++++- .../test-error-prepare-stack-trace.js | 19 +++++++++++ 3 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 test/parallel/test-error-prepare-stack-trace.js diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 05b92ab9b082f9..2e851867c74a51 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -20,6 +20,7 @@ const { kMaxLength } = internalBinding('buffer'); const MainContextError = Error; const ErrorToString = Error.prototype.toString; const overrideStackTrace = new WeakMap(); +const kNoOverride = Symbol('kNoOverride'); const prepareStackTrace = (globalThis, error, trace) => { // API for node internals to override error stack formatting // without interfering with userland code. @@ -29,6 +30,23 @@ const prepareStackTrace = (globalThis, error, trace) => { return f(error, trace); } + const globalOverride = + maybeOverridePrepareStackTrace(globalThis, error, trace); + if (globalOverride !== kNoOverride) return globalOverride; + + // Normal error formatting: + // + // Error: Message + // at function (file) + // at file + const errorString = ErrorToString.call(error); + if (trace.length === 0) { + return errorString; + } + return `${errorString}\n at ${trace.join('\n at ')}`; +}; + +const maybeOverridePrepareStackTrace = (globalThis, error, trace) => { // Polyfill of V8's Error.prepareStackTrace API. // https://crbug.com/v8/7848 // `globalThis` is the global that contains the constructor which @@ -43,19 +61,9 @@ const prepareStackTrace = (globalThis, error, trace) => { return MainContextError.prepareStackTrace(error, trace); } - // Normal error formatting: - // - // Error: Message - // at function (file) - // at file - const errorString = ErrorToString.call(error); - if (trace.length === 0) { - return errorString; - } - return `${errorString}\n at ${trace.join('\n at ')}`; + return kNoOverride; }; - let excludedStackFn; // Lazily loaded @@ -683,7 +691,9 @@ module.exports = { SystemError, // This is exported only to facilitate testing. E, + kNoOverride, prepareStackTrace, + maybeOverridePrepareStackTrace, overrideStackTrace, kEnhanceStackBeforeInspector, fatalExceptionStackEnhancers diff --git a/lib/internal/source_map/prepare_stack_trace.js b/lib/internal/source_map/prepare_stack_trace.js index d6c5fce60a29e3..91bedcb266be70 100644 --- a/lib/internal/source_map/prepare_stack_trace.js +++ b/lib/internal/source_map/prepare_stack_trace.js @@ -2,7 +2,11 @@ const debug = require('internal/util/debuglog').debuglog('source_map'); const { findSourceMap } = require('internal/source_map/source_map_cache'); -const { overrideStackTrace } = require('internal/errors'); +const { + kNoOverride, + overrideStackTrace, + maybeOverridePrepareStackTrace +} = require('internal/errors'); // Create a prettified stacktrace, inserting context from source maps // if possible. @@ -17,6 +21,10 @@ const prepareStackTrace = (globalThis, error, trace) => { return f(error, trace); } + const globalOverride = + maybeOverridePrepareStackTrace(globalThis, error, trace); + if (globalOverride !== kNoOverride) return globalOverride; + const { SourceMap } = require('internal/source_map/source_map'); const errorString = ErrorToString.call(error); diff --git a/test/parallel/test-error-prepare-stack-trace.js b/test/parallel/test-error-prepare-stack-trace.js new file mode 100644 index 00000000000000..2ace9c8d71491d --- /dev/null +++ b/test/parallel/test-error-prepare-stack-trace.js @@ -0,0 +1,19 @@ +// Flags: --enable-source-maps +'use strict'; + +require('../common'); +const assert = require('assert'); + +// Error.prepareStackTrace() can be overridden with source maps enabled. +{ + let prepareCalled = false; + Error.prepareStackTrace = (_error, trace) => { + prepareCalled = true; + }; + try { + throw new Error('foo'); + } catch (err) { + err.stack; + } + assert(prepareCalled); +}