Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
liuxingbaoyu committed Dec 21, 2023
1 parent 3f9bb7b commit c4a52d2
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 40 deletions.
96 changes: 62 additions & 34 deletions packages/babel-core/src/errors/rewrite-stack-trace.ts
Expand Up @@ -96,7 +96,27 @@ export function beginHiddenCallStack<A extends unknown[], R>(
return Object.defineProperty(
function (...args: A) {
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") {
isAsync = true;

ret
// @ts-expect-error checked above
.catch(function (err) {
err.stack;
resetPrepareStackTrace();
});
}
return ret;
} catch (err) {
err.stack;
throw err;
} finally {
if (!isAsync) resetPrepareStackTrace();
}
},
"name",
{ value: STOP_HIDING },
Expand All @@ -117,12 +137,43 @@ export function endHiddenCallStack<A extends unknown[], R>(
);
}

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.
Expand All @@ -137,35 +188,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[]) {
Expand Down
39 changes: 33 additions & 6 deletions packages/babel-core/test/errors-stacks.js
Expand Up @@ -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 {
Expand All @@ -268,18 +271,18 @@ describe("@babel/core errors", function () {
}).toMatchTemplate`\
Error: Internal error! This is a fake bug :)
at Array.map (<CWD>/packages/babel-core/test/errors-stacks.js:_:_)
at ${/loadOneConfig|findRootConfig/} (<CWD>/packages/babel-core/src/config/files/configuration.ts:_:_)
at ${/loadOneConfig|findRootConfig/} (<CWD>/packages/babel-core/lib/config/files/configuration.js:_:_)
at loadOneConfig.next (<anonymous>)
at buildRootChain (<CWD>/packages/babel-core/src/config/config-chain.ts:_:_)
at buildRootChain (<CWD>/packages/babel-core/lib/config/config-chain.js:_:_)
at buildRootChain.next (<anonymous>)
at loadPrivatePartialConfig (<CWD>/packages/babel-core/src/config/partial.ts:_:_)
at loadPrivatePartialConfig (<CWD>/packages/babel-core/lib/config/partial.js:_:_)
at loadPrivatePartialConfig.next (<anonymous>)
at ${/loadFullConfig|loadConfig/} (<CWD>/packages/babel-core/src/config/full.ts:_:_)
at ${/loadFullConfig|loadConfig/} (<CWD>/packages/babel-core/lib/config/full.js:_:_)
at loadFullConfig.next (<anonymous>)
at parse (<CWD>/packages/babel-core/src/parse.ts:_:_)
at parse (<CWD>/packages/babel-core/lib/parse.js:_:_)
at parse.next (<anonymous>)
at evaluateSync (<CWD>/node_modules/gensync/index.js:_:_)
at fn (<CWD>/node_modules/gensync/index.js:_:_)
at sync (<CWD>/node_modules/gensync/index.js:_:_)
at stopHiding - secret - don't use this - v1 (<CWD>/packages/babel-core/src/errors/rewrite-stack-trace.ts:_:_)
at Module.parseSync (<CWD>/packages/babel-core/src/parse.ts:_:_)
at <CWD>/packages/babel-core/test/errors-stacks.js:_:_
Expand All @@ -288,6 +291,30 @@ 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"),
});
await babel.parseAsync("foo;", {
root: fixture("valid"),
});
try {
babel.parseSync("foo;", {
root: fixture("invalid-json"),
});
} catch {}
try {
await babel.parseAsync("foo;", {
root: fixture("invalid-json"),
});
} catch {}
expect(Error.prepareStackTrace).toBeNull();
Error.prepareStackTrace = prepareStackTrace;
});

nodeGte12("should not throw in `node --frozen-intrinsics`", function () {
Expand Down

0 comments on commit c4a52d2

Please sign in to comment.