72 lines
2.7 KiB
TypeScript
72 lines
2.7 KiB
TypeScript
import { expect, it } from "vitest";
|
|||
|
|
|
||
|
|
import { graphForJavaScript } from "../../../tests/fixtures/javascriptSemanticGraph.js";
|
||
|
|
import { queryJavaScriptSemanticGraph } from "../../domain/javascript/javascriptSemanticQuery.js";
|
||
|
|
|
||
|
|
it.each([
|
||
|
|
"function read() { return this.speed; }",
|
||
|
|
"class Game { read() { return this.config.speed; } }",
|
||
|
|
])(
|
||
|
|
"matches retained slotless property accesses and their unknowns: %s",
|
||
|
|
(source) => {
|
||
|
|
const graph = graphForJavaScript(source);
|
||
|
|
const accesses = graph.nodes.filter(
|
||
|
|
({ kind, properties }) =>
|
||
|
|
kind === "expression" &&
|
||
|
|
properties.property_slot_resolution === "unresolved" &&
|
||
|
|
Array.isArray(properties.property_path) &&
|
||
|
|
properties.property_path.at(-1) === "speed",
|
||
|
|
);
|
||
|
|
expect(accesses.length).toBeGreaterThan(0);
|
||
|
|
const trace = queryJavaScriptSemanticGraph(graph, {
|
||
|
|
seed: { kind: "property", name: "speed" },
|
||
|
|
direction: "forward-influence",
|
||
|
|
});
|
||
|
|
expect(trace.seed_node_ids).toEqual(
|
||
|
|
accesses.map(({ node_id }) => node_id).sort(),
|
||
|
|
);
|
||
|
|
const relevant = graph.unknowns.filter(({ node_id }) =>
|
||
|
|
accesses.some((node) => node.node_id === node_id),
|
||
|
|
);
|
||
|
|
expect(relevant.length).toBeGreaterThan(0);
|
||
|
|
expect(trace.unknowns.map(({ unknown_id }) => unknown_id)).toEqual(
|
||
|
|
expect.arrayContaining(relevant.map(({ unknown_id }) => unknown_id)),
|
||
|
|
);
|
||
|
|
expect(
|
||
|
|
queryJavaScriptSemanticGraph(graph, {
|
||
|
|
seed: { kind: "property", name: "absent" },
|
||
|
|
direction: "forward-influence",
|
||
|
|
}).seed_node_ids,
|
||
|
|
).toEqual([]);
|
||
|
|
},
|
||
|
|
);
|
||
|
|
|
||
|
|
it("keeps resolved property seeds on their slot without duplicating access occurrences", () => {
|
||
|
|
const graph = graphForJavaScript(
|
||
|
|
"const state = { speed: 1 }; const result = state.speed;",
|
||
|
|
);
|
||
|
|
const trace = queryJavaScriptSemanticGraph(graph, {
|
||
|
|
seed: { kind: "property", name: "speed" },
|
||
|
|
direction: "backward-provenance",
|
||
|
|
});
|
||
|
|
expect(trace.seed_node_ids).toHaveLength(1);
|
||
|
|
expect(
|
||
|
|
graph.nodes.find(({ node_id }) => node_id === trace.seed_node_ids[0])?.kind,
|
||
|
|
).toBe("property-slot");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("queries an empty event name as an exact retained event identity", () => {
|
||
|
|
const graph = graphForJavaScript(
|
||
|
|
'const { EventEmitter } = require("node:events"); const bus = new EventEmitter(); bus.on("", function emptyListener() {}); bus.on("data", function dataListener() {});',
|
||
|
|
);
|
||
|
|
const trace = queryJavaScriptSemanticGraph(graph, {
|
||
|
|
seed: { kind: "event", name: "" },
|
||
|
|
direction: "forward-influence",
|
||
|
|
});
|
||
|
|
expect(trace.seed_node_ids.length).toBeGreaterThan(0);
|
||
|
|
expect(
|
||
|
|
trace.nodes
|
||
|
|
.filter(({ node_id }) => trace.seed_node_ids.includes(node_id))
|
||
|
|
.every(({ properties }) => properties.event_name === ""),
|
||
|
|
).toBe(true);
|
||
|
|
});
|