mirror of
https://github.com/morluto/rea.git
synced 2026-11-11 01:13:39 +00:00
76 lines
2.4 KiB
TypeScript
76 lines
2.4 KiB
TypeScript
import * as t from "@babel/types";
|
|
import { expect, it } from "vitest";
|
|
|
|
import { semanticIdentifierRole } from "./javascriptSemanticProjection.js";
|
|
import { traverseJavaScriptAst } from "./javascriptSemanticTraversal.js";
|
|
import { parseJavaScriptSource } from "./javascriptSourceParser.js";
|
|
|
|
const rolesFor = (source: string) => {
|
|
const parsed = parseJavaScriptSource(source);
|
|
if (parsed === null) throw new Error("Expected parsed source");
|
|
const references: { name: string; role: string }[] = [];
|
|
let snapshots = 0;
|
|
traverseJavaScriptAst(parsed.program, {
|
|
enter(node, parent, readAncestors) {
|
|
if (!t.isIdentifier(node) || parent === null) return;
|
|
const role = semanticIdentifierRole(node, parent, () => {
|
|
snapshots++;
|
|
return readAncestors();
|
|
});
|
|
if (role !== null) references.push({ name: node.name, role });
|
|
},
|
|
});
|
|
return { references, snapshots };
|
|
};
|
|
|
|
it.each([256, 512])(
|
|
"classifies a %s-member chain without copying or scanning its ancestry",
|
|
(depth) => {
|
|
expect(rolesFor(`object${".property".repeat(depth)};`)).toEqual({
|
|
references: [{ name: "object", role: "read" }],
|
|
snapshots: 0,
|
|
});
|
|
},
|
|
);
|
|
|
|
it("retains optional and computed member reads without ancestor snapshots", () => {
|
|
expect(
|
|
rolesFor("object.property; object[key]; object?.property; object?.[key];"),
|
|
).toEqual({
|
|
references: [
|
|
{ name: "object", role: "read" },
|
|
{ name: "object", role: "read" },
|
|
{ name: "key", role: "read" },
|
|
{ name: "object", role: "read" },
|
|
{ name: "object", role: "read" },
|
|
{ name: "key", role: "read" },
|
|
],
|
|
snapshots: 0,
|
|
});
|
|
});
|
|
|
|
it("still reads ancestry to distinguish bound patterns from default-value reads", () => {
|
|
const result = rolesFor(
|
|
"const {key: value = compute()} = object; ({key: target} = source);",
|
|
);
|
|
expect(result.references).toEqual([
|
|
{ name: "compute", role: "read" },
|
|
{ name: "object", role: "read" },
|
|
{ name: "target", role: "write" },
|
|
{ name: "source", role: "read" },
|
|
]);
|
|
expect(result.snapshots).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("keeps member receivers and computed keys as reads in assignment patterns and updates", () => {
|
|
expect(
|
|
rolesFor("({field: object[key]} = source); object[key]++;").references,
|
|
).toEqual([
|
|
{ name: "object", role: "read" },
|
|
{ name: "key", role: "read" },
|
|
{ name: "source", role: "read" },
|
|
{ name: "object", role: "read" },
|
|
{ name: "key", role: "read" },
|
|
]);
|
|
});
|