mirror of
https://github.com/morluto/rea.git
synced 2026-11-06 14:56:32 +00:00
Track module writes and escapes at their owner, preserve capture and reassignment ordering, and share CommonJS/default namespace identity without erasing parent-slot changes. Carry write sites into ambient alias resolution and use parsed write targets across consumers. Deduplicate returned-reference work with cycle context; retain unchanged temporal selection identity so provenance memoization stays effective. Reviewed fixes include #2041, #2465, #2830, #2881, and #2948. Remove superseded mutation representations and the ineffective per-markValue dedup layer. Validation: 380 focused JavaScript tests passed under a 384 MiB heap cap, including the previously aborting 30-level/128-call alias regression. Six public CLI/MCP builtin tests passed. Exact pdf.js completed-workflow performance remains unmeasured.
65 lines
2.5 KiB
TypeScript
65 lines
2.5 KiB
TypeScript
import * as t from "@babel/types";
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
import { semanticMutationInitializers } from "./javascriptSemanticMutationInitializers.js";
|
|
import type { JavaScriptSemanticBindingState } from "./javascriptSemanticState.js";
|
|
import { traverseJavaScriptAst } from "./javascriptSemanticTraversal.js";
|
|
import { parseJavaScriptSource } from "./javascriptSourceParser.js";
|
|
|
|
describe("parameter references copied into function body bindings", () => {
|
|
it.each([
|
|
["var arg = []; mutate(arg);", false],
|
|
["mutate(arg); var arg = [];", true],
|
|
["if (flag) { var arg = []; } mutate(arg);", true],
|
|
])(
|
|
"retains the entry reference only when still reachable: %s",
|
|
(body, retained) => {
|
|
const program = parseJavaScriptSource(
|
|
`function result(arg = source) { ${body} }`,
|
|
)?.program;
|
|
const callable = program?.body[0];
|
|
if (program === undefined || !t.isFunctionDeclaration(callable))
|
|
throw new Error("Expected a parsed function declaration");
|
|
const parameter = callable.params[0];
|
|
if (!t.isAssignmentPattern(parameter) || !t.isIdentifier(parameter.left))
|
|
throw new Error("Expected the source parameter binding");
|
|
const parents = new WeakMap<t.Node, t.Node>();
|
|
let replacement: t.Node | undefined;
|
|
let mutation: t.Node | undefined;
|
|
traverseJavaScriptAst(program, {
|
|
enter: (node, parent) => {
|
|
if (parent !== null) parents.set(node, parent);
|
|
if (t.isVariableDeclarator(node) && node.init !== null)
|
|
replacement = node.init;
|
|
if (t.isCallExpression(node)) mutation = node;
|
|
},
|
|
});
|
|
if (replacement === undefined || mutation === undefined)
|
|
throw new Error("Expected a body initializer and subsequent effect");
|
|
const entry = {
|
|
node: parameter.left,
|
|
projection: [],
|
|
entryBody: callable.body,
|
|
};
|
|
const assigned = { node: replacement, projection: [] };
|
|
const binding: JavaScriptSemanticBindingState = {
|
|
bindingId: "body:arg",
|
|
scopeId: "body",
|
|
name: "arg",
|
|
kind: "variable",
|
|
mutable: true,
|
|
memberWrites: [],
|
|
escapedPaths: [],
|
|
definitions: [],
|
|
initializers: [entry, assigned],
|
|
referenceInitializers: [],
|
|
directOrigins: [],
|
|
runtimeImport: false,
|
|
};
|
|
const origins = semanticMutationInitializers(binding, mutation, parents);
|
|
expect(origins.initializers.includes(entry)).toBe(retained);
|
|
expect(origins.initializers).toContain(assigned);
|
|
},
|
|
);
|
|
});
|