Files
rea/tests/boundary/cli/javascriptLogicalChainScaling.test.ts
Kaoru0822 81afb043f7 fix(javascript): evaluate each short-circuit left operand once (#7126)
Logical branch selection evaluated the left operand to decide which
branches stay reachable, and value evaluation then evaluated the selected
left branch again. In a left-nested `a || b || c ...` chain every level
repeated that, so semantic analysis doubled per operand and a 24-operand
chain exhausted the per-source deadline.

The selection now carries the left operand's value with the branch, and
value evaluation reuses it. Provenance still walks the branch nodes.
Results are unchanged.

Fixes #7115

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 05:25:54 -07:00

53 lines
1.8 KiB
TypeScript

import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect } from "vitest";
import { z } from "zod";
import { javascriptApplicationAnalysisResultSchema } from "../../../src/domain/javascript/javascriptApplicationAnalysis.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
// Hand-written tokenizers dispatch through long short-circuit chains; the
// CodeMirror 5 pug mode's `nextToken` has 38 operands. Work that doubled per
// operand could not finish such a chain within any per-source deadline.
const operands = 38;
cliTest(
"analyzes a long short-circuit dispatch chain within the source deadline",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-js-logical-chain-");
const chain = Array.from(
{ length: operands },
(unused, index) => `f${String(index)}(s)`,
).join(" || ");
await writeFile(
join(root, "index.js"),
`function next(s) {\n var tok = ${chain};\n return tok;\n}\nmodule.exports = next;\n`,
);
await writeFile(
join(root, "package.json"),
'{"name":"chain","version":"1.0.0","main":"index.js"}\n',
);
const output = await cli.run({
arguments: [
"analyze-javascript-application",
root,
"--analysis-timeout-ms",
"15000",
"--json",
],
});
expect(output.exitCode).toBe(0);
const result = z
.object({ normalized_result: javascriptApplicationAnalysisResultSchema })
.parse(output.json).normalized_result;
expect(result.statistics).toMatchObject({
parsed_javascript_files: 1,
parse_failures: 0,
});
expect(
result.semantic_graph.nodes.filter(({ kind }) => kind === "call-site"),
).toHaveLength(operands);
},
);