2026-10-24 10:08:56 +08:00
import { javaScriptSemanticQueryInputSchema } from "../../domain/javascript/javascriptSemanticQuerySchemas.js" ;
2026-10-24 02:52:47 +08:00
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 );
2026-10-24 10:08:56 +08:00
const trace = queryJavaScriptSemanticGraph (
graph ,
javaScriptSemanticQueryInputSchema . parse ({
seed : { kind : "property" , name : "speed" },
direction : "forward-influence" ,
}),
);
2026-10-24 02:52:47 +08:00
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 (
2026-10-24 10:08:56 +08:00
queryJavaScriptSemanticGraph (
graph ,
javaScriptSemanticQueryInputSchema . parse ({
seed : { kind : "property" , name : "absent" },
direction : "forward-influence" ,
}),
). seed_node_ids ,
2026-10-24 02:52:47 +08:00
). toEqual ([]);
},
);
it ( "keeps resolved property seeds on their slot without duplicating access occurrences" , () => {
const graph = graphForJavaScript (
"const state = { speed: 1 }; const result = state.speed;" ,
);
2026-10-24 10:08:56 +08:00
const trace = queryJavaScriptSemanticGraph (
graph ,
javaScriptSemanticQueryInputSchema . parse ({
seed : { kind : "property" , name : "speed" },
direction : "backward-provenance" ,
}),
);
2026-10-24 02:52:47 +08:00
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() {});' ,
);
2026-10-24 10:08:56 +08:00
const trace = queryJavaScriptSemanticGraph (
graph ,
javaScriptSemanticQueryInputSchema . parse ({
seed : { kind : "event" , name : "" },
direction : "forward-influence" ,
}),
);
2026-10-24 02:52:47 +08:00
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 );
});