mirror of
https://github.com/morluto/rea.git
synced 2026-10-27 09:55:46 +00:00
112 lines
3.4 KiB
TypeScript
112 lines
3.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import { analyzeJavaScriptSemantics } from "./javascriptSemanticAnalysis.js";
|
|
import { onlyCallable } from "./javascriptSemanticAnalysis.fixture.js";
|
|
|
|
const returnedValue = (body: string, expression: string) =>
|
|
onlyCallable(
|
|
analyzeJavaScriptSemantics(
|
|
`export function result() { ${body} return ${expression}; }`,
|
|
),
|
|
"result",
|
|
).returnSites[0]?.value;
|
|
|
|
describe("member-path cycles and captured aliases", () => {
|
|
const branches = Array.from(
|
|
{ length: 16 },
|
|
(_, index) => `if (flag === ${index}) node = node.m${index};`,
|
|
).join(" else ");
|
|
|
|
it.each(["copy[key].value = 2;", "mutate(copy[key]);"])(
|
|
"retains shared-child effects through rest copies: %s",
|
|
(effect) => {
|
|
const body = `
|
|
const seed = { mode: "initial", m15: { m15: { child: { value: 1 } } } };
|
|
let node = seed.m15;
|
|
while (node) {
|
|
${branches}
|
|
const { ignore, ...copy } = node;
|
|
${effect}
|
|
}
|
|
`;
|
|
expect(returnedValue(body, "seed.m15.m15.child.value")?.status).toBe(
|
|
"unknown",
|
|
);
|
|
expect(returnedValue(body, "seed.mode")).toEqual({
|
|
status: "literal",
|
|
value: "initial",
|
|
});
|
|
},
|
|
);
|
|
|
|
it.each([
|
|
["while", (body: string) => `while (node) { ${body} }`],
|
|
["do/while", (body: string) => `do { ${body} } while (node);`],
|
|
["for", (body: string) => `for (; node; ) { ${body} }`],
|
|
["for/in", (body: string) => `for (const key in { a: 1 }) { ${body} }`],
|
|
["for/of", (body: string) => `for (const item of [1]) { ${body} }`],
|
|
] as const)(
|
|
"keeps a late child effect within its siblings in %s",
|
|
(_kind, loop) => {
|
|
const body = `
|
|
const seed = { mode: "initial", m15: { value: 1, keep: 3 } };
|
|
let node = seed;
|
|
${loop(`${branches} node.value = 2;`)}
|
|
`;
|
|
expect(returnedValue(body, "seed.m15.value")?.status).toBe("unknown");
|
|
expect(returnedValue(body, "seed.mode")).toEqual({
|
|
status: "literal",
|
|
value: "initial",
|
|
});
|
|
expect(returnedValue(body, "seed.m15.keep")).toEqual({
|
|
status: "literal",
|
|
value: 3,
|
|
});
|
|
},
|
|
);
|
|
|
|
it("keeps an acyclic chain of reassignments within its selected child", () => {
|
|
const body = `
|
|
const seed = { branch: { child: { value: 1 }, keep: 3 }, keep: 4 };
|
|
let node = seed;
|
|
node = node.branch;
|
|
node = node.child;
|
|
mutate(node);
|
|
`;
|
|
expect(returnedValue(body, "seed.branch.child.value")?.status).toBe(
|
|
"unknown",
|
|
);
|
|
expect(returnedValue(body, "seed.branch.keep")).toEqual({
|
|
status: "literal",
|
|
value: 3,
|
|
});
|
|
expect(returnedValue(body, "seed.keep")).toEqual({
|
|
status: "literal",
|
|
value: 4,
|
|
});
|
|
});
|
|
|
|
it("selects saved aliases at their capture, before or after a rebind", () => {
|
|
const body = `
|
|
const seed = { branch: { child: { value: 1 }, keep: 3 } };
|
|
let node = seed.branch;
|
|
const before = node;
|
|
node = node.child;
|
|
const after = node;
|
|
`;
|
|
expect(
|
|
returnedValue(`${body} mutate(after);`, "seed.branch.child.value")
|
|
?.status,
|
|
).toBe("unknown");
|
|
expect(returnedValue(`${body} mutate(after);`, "seed.branch.keep")).toEqual(
|
|
{
|
|
status: "literal",
|
|
value: 3,
|
|
},
|
|
);
|
|
expect(
|
|
returnedValue(`${body} mutate(before);`, "seed.branch.keep")?.status,
|
|
).toBe("unknown");
|
|
});
|
|
});
|