mirror of
https://github.com/morluto/rea.git
synced 2026-10-31 20:06:14 +00:00
feat(javascript): link assignment right-hand sides to their writes (#6206)
* feat(javascript): link assignment right-hand sides to their writes A declaration carries its value forward, but a later assignment to a variable, a property or through a compound operator stopped the forward trace at the right-hand-side read. The semantic IR now records one syntactic assignment flow per simple assignment target (ranges, operator, owning callable), and the graph projection connects each retained read of the right-hand side to the write occurrence through a defines relation. Compound assignments also consume the previous value of the target; the written value itself stays unknown, keeping the boundary of #4342 intact. Fixes #6193 * fix(javascript): preserve computed key assignment ownership * test(javascript): retain nested callback assignment ownership * docs(javascript): record assignment influence verification * test(mcp): isolate mocks and acknowledge cancellation boundaries * test(javascript): retain CLI diagnostics and current-main verification --------- Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
This commit is contained in:
1 parent
2968d1e932
commit
9df94a62cd
17 files changed
+702
-35
No files matched your search
@@ -0,0 +1,87 @@
|
||||
import { mkdir, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { expect } from "vitest";
|
||||
import { z } from "zod";
|
||||
import { javaScriptSemanticTraceResultSchema } from "../../../src/domain/javascript/javascriptSemanticTraceSchemas.js";
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
import { cliTest } from "../../support/cli/cliFixture.js";
|
||||
|
||||
cliTest(
|
||||
"traces reassignment inputs through the public analysis and trace commands",
|
||||
async ({ cli }) => {
|
||||
const root = await createTestTempDirectory("rea-assignment-influence-");
|
||||
for (const [name, body, label] of [
|
||||
["declaration", "const next = accel; return next;", "next"],
|
||||
["variable", "speed = accel; return speed;", "speed"],
|
||||
["property", "state.speed = accel; return state.speed;", "speed"],
|
||||
["compound", "state.speed += accel; return state.speed;", "speed"],
|
||||
[
|
||||
"computed-key",
|
||||
"const obj = { [speed = accel]() {} }; return speed;",
|
||||
"speed",
|
||||
],
|
||||
] as const) {
|
||||
const directory = join(root, name);
|
||||
await mkdir(directory);
|
||||
await writeFile(
|
||||
join(directory, "main.js"),
|
||||
`const accel = 0.001; let speed = 6; const state = { speed: 6 }; export function update() { ${body} }`,
|
||||
);
|
||||
// The compiled CLI prepares Darwin ownership helpers; hosts that select
|
||||
// a matching SDK explicitly must pass that selection through, as the
|
||||
// other compiled-CLI lifecycle tests do.
|
||||
const environment: { readonly SDKROOT: string } | Record<string, never> =
|
||||
process.env.SDKROOT === undefined
|
||||
? {}
|
||||
: { SDKROOT: process.env.SDKROOT };
|
||||
const analyzed = await cli.run({
|
||||
arguments: ["analyze-javascript-application", directory, "--json"],
|
||||
environment,
|
||||
});
|
||||
expect(analyzed.exitCode, `${name} analyzed: ${analyzed.stderr}`).toBe(0);
|
||||
const queryFile = join(root, `${name}.json`);
|
||||
const query = {
|
||||
application: analyzed.json,
|
||||
query: {
|
||||
seed: { kind: "literal", value: 0.001 },
|
||||
direction: "forward-influence",
|
||||
},
|
||||
};
|
||||
await writeFile(queryFile, JSON.stringify(query));
|
||||
const traced = await cli.run({
|
||||
arguments: ["trace-javascript-semantics", queryFile, "--json"],
|
||||
});
|
||||
expect(traced.exitCode, `${name} traced: ${traced.stderr}`).toBe(0);
|
||||
const { normalized_result: result } = z
|
||||
.object({ normalized_result: javaScriptSemanticTraceResultSchema })
|
||||
.parse(traced.json);
|
||||
expect(
|
||||
result.nodes.some(
|
||||
(node) =>
|
||||
["binding", "property-slot"].includes(node.kind) &&
|
||||
node.label === label,
|
||||
),
|
||||
).toBe(true);
|
||||
// Later property reads remain uncertain after a mutable write. Follow
|
||||
// candidates explicitly rather than upgrading their pre-existing resolution.
|
||||
await writeFile(
|
||||
queryFile,
|
||||
JSON.stringify({
|
||||
...query,
|
||||
query: { ...query.query, include_ambiguous_dynamic_edges: true },
|
||||
}),
|
||||
);
|
||||
const expanded = await cli.run({
|
||||
arguments: ["trace-javascript-semantics", queryFile, "--json"],
|
||||
});
|
||||
expect(expanded.exitCode, `${name} expanded: ${expanded.stderr}`).toBe(0);
|
||||
const expandedResult = z
|
||||
.object({ normalized_result: javaScriptSemanticTraceResultSchema })
|
||||
.parse(expanded.json).normalized_result;
|
||||
expect(expandedResult.nodes.map((node) => node.label)).toContain(
|
||||
"return",
|
||||
);
|
||||
}
|
||||
},
|
||||
120_000,
|
||||
);
|
||||
Reference in new issue
Block a user