From 3b986daed3f5d91162477bda616b4df1fe86c9c8 Mon Sep 17 00:00:00 2001 From: Babel Bot <30521560+liuxingbaoyu@users.noreply.github.com> Date: Thu, 21 Dec 2023 21:58:23 +0800 Subject: [PATCH 1/2] fix --- .../src/errors/rewrite-stack-trace.ts | 103 ++++++++++++------ packages/babel-core/test/errors-stacks.js | 54 ++++++++- 2 files changed, 116 insertions(+), 41 deletions(-) diff --git a/packages/babel-core/src/errors/rewrite-stack-trace.ts b/packages/babel-core/src/errors/rewrite-stack-trace.ts index 20388e9103ce..01b9a588a1dd 100644 --- a/packages/babel-core/src/errors/rewrite-stack-trace.ts +++ b/packages/babel-core/src/errors/rewrite-stack-trace.ts @@ -94,9 +94,34 @@ export function beginHiddenCallStack( if (!SUPPORTED) return fn; return Object.defineProperty( - function (...args: A) { + function (...args: A): R { setupPrepareStackTrace(); - return fn(...args); + let isAsync = false; + try { + const ret = fn(...args); + // @ts-expect-error check if it's a promise + if (typeof ret?.then !== "function") return ret; + + isAsync = true; + return ( + ret + // @ts-expect-error checked above + .catch(function (err) { + err.stack; + resetPrepareStackTrace(); + throw err; + }) + .then(function (val: unknown) { + resetPrepareStackTrace(); + return val; + }) + ); + } catch (err) { + err.stack; + throw err; + } finally { + if (!isAsync) resetPrepareStackTrace(); + } }, "name", { value: STOP_HIDING }, @@ -117,12 +142,43 @@ export function endHiddenCallStack( ); } -function setupPrepareStackTrace() { - // @ts-expect-error This function is a singleton - // eslint-disable-next-line no-func-assign - setupPrepareStackTrace = () => {}; +let originalPrepareStackTrace: (err: Error, trace: CallSite[]) => string; +let originalMaxStackTraceLimit: number; + +function stackTraceRewriter(err: Error, trace: CallSite[]) { + let newTrace = []; + + const isExpected = expectedErrors.has(err); + let status: "showing" | "hiding" | "unknown" = isExpected + ? "hiding" + : "unknown"; + for (let i = 0; i < trace.length; i++) { + const name = trace[i].getFunctionName(); + if (name === START_HIDING) { + status = "hiding"; + } else if (name === STOP_HIDING) { + if (status === "hiding") { + status = "showing"; + if (virtualFrames.has(err)) { + newTrace.unshift(...virtualFrames.get(err)); + } + } else if (status === "unknown") { + // Unexpected internal error, show the full stack trace + newTrace = trace; + break; + } + } else if (status !== "hiding") { + newTrace.push(trace[i]); + } + } - const { prepareStackTrace = defaultPrepareStackTrace } = Error; + return (originalPrepareStackTrace || defaultPrepareStackTrace)(err, newTrace); +} + +function setupPrepareStackTrace() { + if (Error.prepareStackTrace === stackTraceRewriter) return; + originalPrepareStackTrace = Error.prepareStackTrace; + originalMaxStackTraceLimit = Error.stackTraceLimit; // We add some extra frames to Error.stackTraceLimit, so that we can // always show some useful frames even after deleting ours. @@ -137,35 +193,12 @@ function setupPrepareStackTrace() { MIN_STACK_TRACE_LIMIT, ); - Error.prepareStackTrace = function stackTraceRewriter(err, trace) { - let newTrace = []; - - const isExpected = expectedErrors.has(err); - let status: "showing" | "hiding" | "unknown" = isExpected - ? "hiding" - : "unknown"; - for (let i = 0; i < trace.length; i++) { - const name = trace[i].getFunctionName(); - if (name === START_HIDING) { - status = "hiding"; - } else if (name === STOP_HIDING) { - if (status === "hiding") { - status = "showing"; - if (virtualFrames.has(err)) { - newTrace.unshift(...virtualFrames.get(err)); - } - } else if (status === "unknown") { - // Unexpected internal error, show the full stack trace - newTrace = trace; - break; - } - } else if (status !== "hiding") { - newTrace.push(trace[i]); - } - } + Error.prepareStackTrace = stackTraceRewriter; +} - return prepareStackTrace(err, newTrace); - }; +function resetPrepareStackTrace() { + Error.prepareStackTrace = originalPrepareStackTrace; + Error.stackTraceLimit = originalMaxStackTraceLimit; } function defaultPrepareStackTrace(err: Error, trace: CallSite[]) { diff --git a/packages/babel-core/test/errors-stacks.js b/packages/babel-core/test/errors-stacks.js index 6332b3cdf119..360d9ac229d1 100644 --- a/packages/babel-core/test/errors-stacks.js +++ b/packages/babel-core/test/errors-stacks.js @@ -253,6 +253,9 @@ describe("@babel/core errors", function () { }); it("internal errors have the full stack trace", function () { + // Remove `Error.prepareStackTrace` because `source-map-support` used `Array.prototype.map` + const { prepareStackTrace } = Error; + Error.prepareStackTrace = null; expectError(() => { const { map } = Array.prototype; try { @@ -268,18 +271,18 @@ describe("@babel/core errors", function () { }).toMatchTemplate`\ Error: Internal error! This is a fake bug :) at Array.map (/packages/babel-core/test/errors-stacks.js:_:_) - at ${/loadOneConfig|findRootConfig/} (/packages/babel-core/src/config/files/configuration.ts:_:_) + at ${/loadOneConfig|findRootConfig/} (/packages/babel-core/lib/config/files/configuration.js:_:_) at loadOneConfig.next () - at buildRootChain (/packages/babel-core/src/config/config-chain.ts:_:_) + at buildRootChain (/packages/babel-core/lib/config/config-chain.js:_:_) at buildRootChain.next () - at loadPrivatePartialConfig (/packages/babel-core/src/config/partial.ts:_:_) + at loadPrivatePartialConfig (/packages/babel-core/lib/config/partial.js:_:_) at loadPrivatePartialConfig.next () - at ${/loadFullConfig|loadConfig/} (/packages/babel-core/src/config/full.ts:_:_) + at ${/loadFullConfig|loadConfig/} (/packages/babel-core/lib/config/full.js:_:_) at loadFullConfig.next () - at parse (/packages/babel-core/src/parse.ts:_:_) + at parse (/packages/babel-core/lib/parse.js:_:_) at parse.next () at evaluateSync (/node_modules/gensync/index.js:_:_) - at fn (/node_modules/gensync/index.js:_:_) + at sync (/node_modules/gensync/index.js:_:_) at stopHiding - secret - don't use this - v1 (/packages/babel-core/src/errors/rewrite-stack-trace.ts:_:_) at Module.parseSync (/packages/babel-core/src/parse.ts:_:_) at /packages/babel-core/test/errors-stacks.js:_:_ @@ -288,6 +291,45 @@ Error: Internal error! This is a fake bug :) at ... internal jest frames ...\ `; // TODO(Babel 8): We do not need regexps anymore in the matcher above + Error.prepareStackTrace = prepareStackTrace; + }); + + it("should reset `Error.prepareStackTrace`", async function () { + const { prepareStackTrace } = Error; + Error.prepareStackTrace = null; + babel.parseSync("foo;", { + root: fixture("valid"), + }); + expect(Error.prepareStackTrace).toBeNull(); + + await babel.parseAsync("foo;", { + root: fixture("valid"), + }); + expect(Error.prepareStackTrace).toBeNull(); + + const errors = []; + + try { + babel.parseSync("foo;", { + root: fixture("invalid-json"), + }); + } catch (e) { + errors.push(e); + } + expect(Error.prepareStackTrace).toBeNull(); + + try { + await babel.parseAsync("foo;", { + root: fixture("invalid-json"), + }); + } catch (e) { + errors.push(e); + } + expect(Error.prepareStackTrace).toBeNull(); + + expect(errors).toHaveLength(2); + + Error.prepareStackTrace = prepareStackTrace; }); nodeGte12("should not throw in `node --frozen-intrinsics`", function () { From 950fb085f5023fb33dfab2e6e7a528b0e5705f88 Mon Sep 17 00:00:00 2001 From: Babel Bot <30521560+liuxingbaoyu@users.noreply.github.com> Date: Fri, 22 Dec 2023 12:22:16 +0800 Subject: [PATCH 2/2] types --- .../src/errors/rewrite-stack-trace.ts | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/packages/babel-core/src/errors/rewrite-stack-trace.ts b/packages/babel-core/src/errors/rewrite-stack-trace.ts index 01b9a588a1dd..f839daee0f51 100644 --- a/packages/babel-core/src/errors/rewrite-stack-trace.ts +++ b/packages/babel-core/src/errors/rewrite-stack-trace.ts @@ -94,28 +94,24 @@ export function beginHiddenCallStack( if (!SUPPORTED) return fn; return Object.defineProperty( - function (...args: A): R { + function (...args: A) { setupPrepareStackTrace(); let isAsync = false; try { const ret = fn(...args); - // @ts-expect-error check if it's a promise - if (typeof ret?.then !== "function") return ret; + if (typeof (ret as any)?.then !== "function") return ret; isAsync = true; - return ( - ret - // @ts-expect-error checked above - .catch(function (err) { - err.stack; - resetPrepareStackTrace(); - throw err; - }) - .then(function (val: unknown) { - resetPrepareStackTrace(); - return val; - }) - ); + return (ret as Promise) + .catch(function (err) { + err.stack; + resetPrepareStackTrace(); + throw err; + }) + .then(function (val: unknown) { + resetPrepareStackTrace(); + return val; + }) as R; } catch (err) { err.stack; throw err;