mirror of
https://github.com/morluto/rea
synced 2026-10-26 06:16:17 -04:00
f4322b15ed
Admit unknowns before canonical construction and provenance interning. Offer independent per-file and application capacities through CLI, Evidence and the owned analysis worker, and reject over-allocation during streamed decoding. Report examined omitted emission occurrences by family and reason without retaining discarded identities. Preserve omission-free graph identities and distinguish node truncation from overall partial coverage. Fixes #4797
73 lines
2.6 KiB
TypeScript
73 lines
2.6 KiB
TypeScript
import { expect, it } from "vitest";
|
|
import { analyzeJavaScriptStaticSource } from "../../domain/javascript/javascriptStaticAnalysis.js";
|
|
import { analyzeJavaScriptSemantics } from "../../domain/javascript/javascriptSemanticAnalysis.js";
|
|
import type { JavaScriptArtifactFile } from "../../domain/javascript/javascriptArtifactFiles.js";
|
|
import { projectJavaScriptSemanticFileSteps } from "./JavaScriptSemanticGraphBuilder.js";
|
|
|
|
const source = `${Array.from({ length: 40 }, (_, i) => `function library${String(i)}(){return ${String(i)}}`).join("\n")}
|
|
const e=require("electron");
|
|
function register(channel,callback){e.ipcMain.addListener(channel,event=>allowed(event)&&callback(event))}
|
|
register("test:copy",event=>event.sender.copy());`;
|
|
const file: JavaScriptArtifactFile = {
|
|
path: "main.js",
|
|
sha256: "a".repeat(64),
|
|
container_sha256: "b".repeat(64),
|
|
bytes: source.length,
|
|
inventory_artifact_id: `art_${"a".repeat(64)}`,
|
|
kind: "javascript",
|
|
unpacked: false,
|
|
text: { included: true, value: source },
|
|
};
|
|
const facts = analyzeJavaScriptStaticSource(source);
|
|
const ir = analyzeJavaScriptSemantics(source);
|
|
const project = (budget: number) => {
|
|
const steps = projectJavaScriptSemanticFileSteps(
|
|
file,
|
|
ir,
|
|
{ nodes: budget, unknowns: budget },
|
|
facts.electron.call_paths,
|
|
);
|
|
let result = steps.next();
|
|
while (!result.done) result = steps.next();
|
|
return result.value;
|
|
};
|
|
|
|
it("retains Electron calls before library definitions consume the node budget", () => {
|
|
const result = project(20);
|
|
expect(result.nodes).toHaveLength(20);
|
|
expect(result.nodesTruncated).toBe(true);
|
|
const terminal = result.nodes.find(
|
|
(node) => node.label === "ipc-event.sender.copy",
|
|
);
|
|
expect(terminal).toBeDefined();
|
|
expect(
|
|
result.relations.some(
|
|
(r) =>
|
|
r.target_node_id === terminal?.node_id && r.resolution === "candidate",
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
result.nodes.some(
|
|
(node) =>
|
|
node.properties.entry === "test:copy" &&
|
|
Array.isArray(node.properties.conditions) &&
|
|
node.properties.conditions.length === 1,
|
|
),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("reports truncation and keeps referential integrity even within a boundary path", () => {
|
|
const result = project(3);
|
|
expect(result.nodes).toHaveLength(3);
|
|
expect(result.nodesTruncated).toBe(true);
|
|
expect(
|
|
result.nodes.some((node) => node.label === "ipc-event.sender.copy"),
|
|
).toBe(false);
|
|
const retained = new Set(result.nodes.map((node) => node.node_id));
|
|
expect(
|
|
result.relations.every(
|
|
(r) => retained.has(r.source_node_id) && retained.has(r.target_node_id),
|
|
),
|
|
).toBe(true);
|
|
});
|