mirror of
https://github.com/morluto/rea
synced 2026-10-27 14:42:18 -04:00
dea770d5d9
* fix(javascript): retain getter receivers through local aliases * fix(javascript): resolve projected private getter receivers --------- Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
86 lines
3.0 KiB
TypeScript
86 lines
3.0 KiB
TypeScript
import { writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { expect } from "vitest";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
import { cliTest } from "../../support/cli/cliFixture.js";
|
|
import { analyzeJavaScriptDirectory } from "../../support/cli/javascriptApplication.js";
|
|
|
|
cliTest.for(["CLI", "stdio MCP"] as const)(
|
|
"retains getter-local alias mutations in exported Evidence through %s",
|
|
async (surface, { cli }) => {
|
|
const root = await createTestTempDirectory("rea-getter-local-aliases-");
|
|
const cases = [
|
|
["initialized", "const self = this; return self.s;", true],
|
|
["assigned", "let self; self = this; return self.s;", true],
|
|
["destructured", "const { s: value } = this; return value;", true],
|
|
["readOnly", "const self = this; return self.s;", false],
|
|
[
|
|
"cyclic",
|
|
"let self = this.start; while (flag) self = self.child; return self;",
|
|
true,
|
|
"start: { child: { child: shared } }",
|
|
],
|
|
] as const;
|
|
const privateCases = [
|
|
["privateProjection", "shared", true, "unknown"],
|
|
["privateUnrelated", "{ peer: shared }", true, "literal"],
|
|
["privateReadOnly", "shared", false, "literal"],
|
|
] as const;
|
|
await writeFile(
|
|
join(root, "app.mjs"),
|
|
cases
|
|
.map(
|
|
([
|
|
name,
|
|
getter,
|
|
write,
|
|
members = "s: shared",
|
|
]) => `export function ${name}() {
|
|
const shared = { x: 1 };
|
|
const box = { ${members}, get v() { ${getter} } };
|
|
${write ? "box.v.x = 2;" : "const saved = box.v;"}
|
|
return shared.x;
|
|
}`,
|
|
)
|
|
.join("\n") +
|
|
privateCases
|
|
.map(
|
|
([name, value, write]) => `export function ${name}() {
|
|
const shared = { x: 1 };
|
|
class Box {
|
|
#s = ${value};
|
|
peer = this;
|
|
get v() { const { peer: self } = this; return self.#s; }
|
|
}
|
|
const box = new Box();
|
|
${write ? "box.v.x = 2;" : "const saved = box.v;"}
|
|
return shared.x;
|
|
}`,
|
|
)
|
|
.join("\n"),
|
|
);
|
|
const { graph } = await analyzeJavaScriptDirectory(surface, cli, root);
|
|
for (const [name, status] of [
|
|
...cases.map(([name, , write]) => [name, write ? "unknown" : "literal"]),
|
|
...privateCases.map(([name, , , status]) => [name, status]),
|
|
]) {
|
|
const observation = graph.nodes
|
|
.flatMap(({ observations }) => observations)
|
|
.find(
|
|
({ properties }) =>
|
|
properties.semantic_role === "export-return-shapes" &&
|
|
properties.exported_name === name,
|
|
);
|
|
expect(observation, name).toBeDefined();
|
|
expect(observation?.properties.static_return_shapes).toMatchObject([
|
|
{
|
|
value_status: status,
|
|
fields: [
|
|
{ path: "", state: status, value: status === "unknown" ? null : 1 },
|
|
],
|
|
},
|
|
]);
|
|
}
|
|
},
|
|
);
|