fix(javascript): handle deep AST traversal and addition without stack overflow (#915)

* fix(javascript): avoid recursion and eager ancestry copies in deep ASTs

* fix(javascript): traverse static analysis and bundler ASTs iteratively
This commit is contained in:
morluto authored and GitHub committed 2026-10-07 17:40:05 +08:00
1 parent f6a58f1062
commit 62b37111e7
9 files changed
+203 -40

No files matched your search

@@ -268,12 +268,38 @@ const evaluateAddition = (
node: t.BinaryExpression,
context: EvaluationContext,
): JavaScriptSemanticValue => {
const left = primitiveCandidates(
evaluateExpression(node.left, nestedContext(context)),
);
const right = primitiveCandidates(
evaluateExpression(node.right, nestedContext(context)),
);
const pending: {
readonly node: t.BinaryExpression;
left: JavaScriptSemanticValue | undefined;
}[] = [];
let current: t.Node = node;
while (true) {
if (t.isBinaryExpression(current, { operator: "+" })) {
pending.push({ node: current, left: undefined });
current = current.left;
continue;
}
let value = evaluateExpression(current, nestedContext(context));
while (true) {
const parent = pending.at(-1);
if (parent === undefined) return value;
if (parent.left === undefined) {
parent.left = value;
current = parent.node.right;
break;
}
value = addPrimitiveValues(parent.left, value);
pending.pop();
}
}
};
const addPrimitiveValues = (
leftValue: JavaScriptSemanticValue,
rightValue: JavaScriptSemanticValue,
): JavaScriptSemanticValue => {
const left = primitiveCandidates(leftValue);
const right = primitiveCandidates(rightValue);
if (left === null || right === null)
return { status: "unknown", reason: "Non-primitive addition." };
const values = left.flatMap((leftValue) =>