test(javascript): consolidate source analysis and export regressions

This commit is contained in:
morluto committed 2026-10-08 04:03:23 +08:00
1 parent c93422a898
commit f517a5a1d7
18 files changed
+352 -851

No files matched your search

@@ -1,31 +0,0 @@
import { describe, expect, it } from "vitest";
import { ok } from "../domain/result.js";
import { traceLiteralFeature } from "./EnhancedLiteralTracing.js";
describe("literal feature tracing", () => {
it("returns matched procedure and string facts with references", async () => {
const result = await traceLiteralFeature(
async (name) => {
if (name === "search_strings")
return ok([{ address: "0x1000", value: "launch feature" }]);
if (name === "search_procedures")
return ok([{ address: "0x2000", value: "launchFeature" }]);
if (name === "xrefs") return ok([]);
if (name === "resolve_containing_procedure") return ok(null);
throw new Error(`Unexpected analysis call: ${name}`);
},
{ query: "launch feature", case_sensitive: false },
);
expect(result).toMatchObject({
ok: true,
value: {
matches: [
{ type: "string", address: "0x1000", value: "launch feature" },
{ type: "procedure", address: "0x2000", value: "launchFeature" },
],
references: [],
},
});
});
});
@@ -20,37 +20,46 @@ const filesFor = (paths: readonly string[]) =>
]),
);
const cases = ["#", "?"].flatMap((punctuation) =>
(["require", "import", undefined] as const).flatMap((moduleKind) =>
(["literal", "stripped", "both"] as const).map((layout) => ({
punctuation,
moduleKind,
layout,
})),
),
);
describe("module specifier punctuation", () => {
it.each(cases)(
"resolves $moduleKind with $punctuation and $layout files",
({ punctuation, moduleKind, layout }) => {
it.each(["#", "?"])(
"keeps CommonJS punctuation and strips URL suffixes for ESM (%s)",
(punctuation) => {
const literal = `app/dep.cjs${punctuation}literal.cjs`;
const stripped = "app/dep.cjs";
const files = filesFor([
...(layout !== "stripped" ? [literal] : []),
...(layout !== "literal" ? [stripped] : []),
]);
const expected = moduleKind === "require" ? literal : stripped;
const result = resolveArtifactPathByContext({
const commonJs = resolveArtifactPathByContext({
declaredPath: `./dep.cjs${punctuation}literal.cjs`,
sourcePath: "app/main.js",
context: "module-specifier",
files,
...(moduleKind === undefined ? {} : { moduleKind }),
files: filesFor([literal, stripped]),
moduleKind: "require",
});
expect(result).toMatchObject({
resolution_status: files.has(expected) ? "resolved" : "not-found",
resolved_path: files.has(expected) ? expected : null,
expect(commonJs).toMatchObject({
resolution_status: "resolved",
resolved_path: literal,
});
const esm = resolveArtifactPathByContext({
declaredPath: `./dep.cjs${punctuation}literal.cjs`,
sourcePath: "app/main.js",
context: "module-specifier",
files: filesFor([literal, stripped]),
moduleKind: "import",
});
expect(esm).toMatchObject({
resolution_status: "resolved",
resolved_path: stripped,
});
const noStrippedTarget = resolveArtifactPathByContext({
declaredPath: `./dep.cjs${punctuation}literal.cjs`,
sourcePath: "app/main.js",
context: "module-specifier",
files: filesFor([literal]),
moduleKind: "import",
});
expect(noStrippedTarget).toMatchObject({
resolution_status: "not-found",
resolved_path: null,
});
},
);
@@ -1,166 +0,0 @@
import { describe, expect, it } from "vitest";
import { analyzeJavaScriptSemantics } from "../../domain/javascript/javascriptSemanticAnalysis.js";
import { completeApplicationCoverage } from "../../domain/javascript/javascriptApplicationEvidenceSchemas.js";
import { projectJavaScriptExportReturnShapes } from "./JavaScriptReturnShapeProjection.js";
const projectReturns = (body: string) => {
const ir = analyzeJavaScriptSemantics(`export function result() { ${body} }`);
const link = ir.moduleLinks.find(
({ exportedName }) => exportedName === "result",
);
if (link === undefined) throw new Error("Expected the result export");
const projected = projectJavaScriptExportReturnShapes({
ir,
link,
modulePath: "fixture.js",
baseCoverage: completeApplicationCoverage(),
});
if (projected === null) throw new Error("Expected exported return shapes");
return projected;
};
const unknownBranchField = {
path: "",
state: "unknown",
value: null,
reason: "Branches have incompatible values.",
};
describe("exported primitive union return shapes", () => {
const conditionalCases = [
"missing",
"unsupported()",
'({ key: "value" })',
'["value"]',
'+"invalid"',
].flatMap((other) => [
`condition ? (choice ? "one" : "two") : ${other}`,
`condition ? ${other} : (choice ? "one" : "two")`,
]);
const logicalCases = [
{ operator: "||", known: '(choice ? "" : "one")' },
{ operator: "&&", known: '(choice ? 0 : "one")' },
{ operator: "??", known: '(choice ? null : "one")' },
].flatMap(({ operator, known }) => [
`${known} ${operator} missing`,
`missing ${operator} ${known}`,
]);
it.each([...conditionalCases, ...logicalCases])(
"projects an unknown field instead of a definite union for %s",
(expression) => {
const projected = projectReturns(`return ${expression};`);
expect(projected.properties.static_return_shapes).toEqual([
{
source_range: expect.any(Object),
value_status: "ambiguous",
fields: [unknownBranchField],
property_coverage: [],
},
]);
// Complete return-site collection does not make its values known.
expect(projected.properties.return_shape_coverage).toEqual({
status: "complete",
retained_return_sites: 1,
omitted_return_sites: 0,
omitted_fields: 0,
omitted_property_coverage: 0,
projection_complete: true,
});
expect(projected.coverage).toEqual(completeApplicationCoverage());
expect(projected.limitations).toContain(
"Return shapes are inferred from inert syntax and do not prove runtime behavior.",
);
},
);
it("keeps an incompatible object field unknown beside a known literal", () => {
const projected = projectReturns(`
return {
kind: "result",
value: condition ? (choice ? "one" : "two") : missing,
};
`);
expect(projected.properties.static_return_shapes).toEqual([
{
source_range: expect.any(Object),
value_status: "object",
fields: [
{ path: "/kind", state: "literal", value: "result", reason: null },
{ ...unknownBranchField, path: "/value" },
],
property_coverage: [{ path: "", status: "complete", omitted: 0 }],
},
]);
});
it("retains valid nested unions, duplicates, and null alternatives", () => {
const projected = projectReturns(`
return condition
? (choice ? "two" : "one")
: (other ? "one" : null);
`);
expect(projected.properties.static_return_shapes).toEqual([
{
source_range: expect.any(Object),
value_status: "union",
fields: [
{
path: "",
state: "union",
value: [null, "one", "two"],
reason: null,
},
],
property_coverage: [],
},
]);
});
it("preserves three independent direct returns without merging their values", () => {
const projected = projectReturns(`
if (condition) return choice ? "one" : "two";
if (other) return missing;
return { kind: "object" };
`);
expect(projected.properties.static_return_shapes).toEqual([
{
source_range: expect.any(Object),
value_status: "union",
fields: [
{ path: "", state: "union", value: ["one", "two"], reason: null },
],
property_coverage: [],
},
{
source_range: expect.any(Object),
value_status: "unknown",
fields: [
{
path: "",
state: "unknown",
value: null,
reason: "Unbound identifier missing.",
},
],
property_coverage: [],
},
{
source_range: expect.any(Object),
value_status: "object",
fields: [
{ path: "/kind", state: "literal", value: "object", reason: null },
],
property_coverage: [{ path: "", status: "complete", omitted: 0 }],
},
]);
expect(projected.properties.return_shape_coverage).toMatchObject({
status: "complete",
retained_return_sites: 3,
omitted_return_sites: 0,
projection_complete: true,
});
});
});
@@ -2,156 +2,46 @@ import { describe, expect, it } from "vitest";
import { analyzeJavaScriptStaticSource } from "./javascriptStaticAnalysis.js";
describe.each(["webPreferences", "serviceName"] as const)(
"Electron %s option lookup",
(name) => {
const value =
name === "webPreferences"
? '{ preload: "./kept.js", sandbox: true }'
: '"kept"';
const explicit = `${name}: ${value}`;
const method = `${name}() { return ${value}; }`;
const getter = `get ${name}() { return ${value}; }`;
const setter = `set ${name}(value) {}`;
describe("Electron option evidence", () => {
it("keeps the final explicit preload and service name with unrelated keys", () => {
const analysis = analyzeJavaScriptStaticSource(`
new BrowserWindow({ webPreferences: { preload: "./kept.js", sandbox: true }, title: "App" });
utilityProcess.fork("./worker.js", [], { serviceName: "kept", cwd: "/app" });
`);
const explicitCases = [
["plain key", explicit],
["quoted key", `"${name}": ${value}`],
["computed string key", `["${name}"]: ${value}`],
["duplicate key", `${name}: null, ${explicit}`],
["computed duplicate key", `${name}: null, ["${name}"]: ${value}`],
["earlier spread", `...options, ${explicit}`],
["earlier computed identifier", `[key]: null, ${explicit}`],
["earlier computed expression", `[getKey()]: null, ${explicit}`],
["earlier getter", `${getter}, ${explicit}`],
["earlier method", `${method}, ${explicit}`],
["unrelated later key", `${explicit}, title: "title"`],
["unrelated computed literal", `${explicit}, ["title"]: null`],
["unrelated numeric key", `${explicit}, [1]: null`],
["unrelated empty key", `${explicit}, [""]: null`],
["unrelated getter", `${explicit}, get title() { return "title"; }`],
];
it.each(explicitCases)(
"retains the explicit value with %s",
(_, members) => {
const analysis = analyzeOption(name, `{ ${members} }`);
expect(analysis.parse_status).toBe("complete");
if (name === "webPreferences") {
expect(analysis.electron.browser_windows).toEqual([
expect.objectContaining({
options_status: "object-literal",
web_preferences_status: "object-literal",
preload_path: "./kept.js",
preload_resolution_context: "module-specifier",
web_preferences: [
{ name: "preload", value: literal("./kept.js") },
{ name: "sandbox", value: literal(true) },
],
}),
]);
} else {
expect(analysis.electron.utility_processes).toEqual([
expect.objectContaining({ service_name: "kept" }),
]);
}
},
);
const dynamicCases = [
["same-spelled computed binding", `[${name}]: ${value}`],
["different computed binding", `[key]: ${value}`],
["computed expression", `[getKey()]: ${value}`],
["unevaluated template key", `[\`${name}\`]: ${value}`],
["spread only", "...options"],
["later spread", `${explicit}, ...options`],
["later computed binding", `${explicit}, [key]: null`],
["later computed expression", `${explicit}, [getKey()]: null`],
["exact getter", getter],
["exact setter", setter],
["exact method", method],
["computed string method", `["${name}"]() { return ${value}; }`],
["overriding getter", `${explicit}, ${getter}`],
["overriding setter", `${explicit}, ${setter}`],
["overriding method", `${explicit}, ${method}`],
["dynamic explicit value", `${name}: dynamicValue`],
["null explicit value", `${name}: null`],
["duplicate null value", `${explicit}, ${name}: null`],
];
it.each(dynamicCases)("preserves uncertainty for %s", (_, members) => {
expectUnknownOption(name, `{ ${members} }`, "object-literal");
});
it.each(["null", "options"])(
"preserves nonliteral options %s",
(options) => {
expectUnknownOption(name, options, "dynamic");
},
);
it.each(["", "{}", '{ title: "title", ["other"]: null }'])(
"reports an omitted option in %s without inventing a default",
(options) => {
const analysis = analyzeOption(name, options);
expect(analysis.parse_status).toBe("complete");
if (name === "webPreferences")
expect(analysis.electron.browser_windows[0]).toMatchObject({
options_status: options === "" ? "missing" : "object-literal",
web_preferences_status: "missing",
web_preferences: [],
preload_path: null,
preload_resolution_context: null,
});
else
expect(
analysis.electron.utility_processes[0]?.service_name,
).toBeNull();
},
);
},
);
type OptionName = "webPreferences" | "serviceName";
const analyzeOption = (name: OptionName, options: string) =>
analyzeJavaScriptStaticSource(`
const webPreferences = "title";
const serviceName = "env";
${
name === "webPreferences"
? `new BrowserWindow(${options});`
: `utilityProcess.fork("./worker.js", []${options === "" ? "" : `, ${options}`});`
}
`);
const literal = (value: string | boolean) => ({
status: "literal",
value,
expression: null,
});
const expectUnknownOption = (
name: OptionName,
options: string,
optionsStatus: "object-literal" | "dynamic",
): void => {
const analysis = analyzeOption(name, options);
expect(analysis.parse_status).toBe("partial");
expect(analysis.parse_error_count).toBe(0);
expect(analysis.limitations.join(" ")).toContain("remain unknown");
if (name === "webPreferences")
expect(analysis.parse_status).toBe("complete");
expect(analysis.electron.browser_windows[0]).toMatchObject({
options_status: optionsStatus,
preload_path: "./kept.js",
preload_resolution_context: "module-specifier",
web_preferences: [
{ name: "preload", value: { status: "literal", value: "./kept.js" } },
{ name: "sandbox", value: { status: "literal", value: true } },
],
});
expect(analysis.electron.utility_processes[0]).toMatchObject({
module_path: "./worker.js",
service_name: "kept",
});
});
it("keeps values unknown when a later computed key can override them", () => {
const analysis = analyzeJavaScriptStaticSource(`
new BrowserWindow({ webPreferences: { preload: "./maybe.js" }, [key]: null });
utilityProcess.fork("./worker.js", [], { serviceName: "maybe", [key]: null });
`);
expect(analysis.parse_status).toBe("partial");
expect(analysis.parse_error_count).toBe(0);
expect(analysis.limitations.join(" ")).toContain("remain unknown");
expect(analysis.electron.browser_windows[0]).toMatchObject({
preload_path: null,
preload_resolution_context: null,
web_preferences_status: "dynamic",
web_preferences: [],
preload_path: null,
preload_resolution_context: null,
});
else
expect(analysis.electron.utility_processes[0]).toMatchObject({
module_path: "./worker.js",
module_expression: null,
service_name: null,
});
};
});
});
@@ -1,9 +1,6 @@
import { expect, it } from "vitest";
import {
javaScriptExportShapeComparisonResultSchema,
projectedExportReturnShapesSchema,
} from "./javascriptExportShapeComparisonSchemas.js";
import { projectedExportReturnShapesSchema } from "./javascriptExportShapeComparisonSchemas.js";
const projectionWithField = (field: unknown) => ({
semantic_role: "export-return-shapes",
@@ -54,104 +51,3 @@ it("parses projected fields into literal, union, or unknown values", () => {
).success,
).toBe(true);
});
it("accepts every projected return site and field without presentation caps", () => {
const fields = Array.from({ length: 65 }, (_, index) => ({
path: `/field-${String(index)}`,
state: "literal",
value: index,
reason: null,
}));
const propertyCoverage = fields.map(({ path }) => ({
path,
status: "complete",
omitted: 0,
}));
const shapes = Array.from({ length: 33 }, () => ({
source_range: {
start: { line: 1, column: 0 },
end: { line: 1, column: 10 },
},
value_status: "object",
fields,
property_coverage: propertyCoverage,
}));
expect(
projectedExportReturnShapesSchema.parse({
...projectionWithField(fields[0]),
static_return_shapes: shapes,
return_shape_coverage: {
status: "complete",
retained_return_sites: shapes.length,
omitted_return_sites: 0,
omitted_fields: 0,
omitted_property_coverage: 0,
projection_complete: true,
},
}).static_return_shapes,
).toHaveLength(33);
});
it("accepts complete candidate and change inventories without page ceilings", () => {
const evidenceId = `ev_${"a".repeat(64)}`;
const graphId = `jag_${"b".repeat(64)}`;
const selector = {
evidence_id: evidenceId,
graph_id: graphId,
requested_module_path: "index.js",
requested_export_name: "render",
candidates: Array.from({ length: 1_001 }, (_, index) => ({
node_id: `jag_node_${index.toString(16).padStart(64, "0")}`,
module_path: "index.js",
export_name: "render",
matches_requested_module: true,
matches_requested_export: true,
})),
omitted_candidates: 0,
status: "missing",
selected_node_id: null,
};
const changes = Array.from({ length: 10_001 }, (_, index) => ({
change_id: `jesc_change_${index.toString(16).padStart(64, "0")}`,
status: "unknown",
path: `/field-${String(index)}`,
discriminant: null,
left: { availability: "absent" },
right: { availability: "absent" },
left_source_range: null,
right_source_range: null,
evidence_links: [evidenceId, `ev_${"c".repeat(64)}`],
limitations: [],
}));
expect(
javaScriptExportShapeComparisonResultSchema.parse({
comparison_id: `jesc_${"d".repeat(64)}`,
left: selector,
right: { ...selector, graph_id: `jag_${"e".repeat(64)}` },
summary: { added: 0, removed: 0, changed: 0, unknown: changes.length },
changes,
coverage: {
status: "complete-within-inputs",
left_graph_status: "complete",
right_graph_status: "complete",
paired_variants: 0,
unpaired_left_variants: 0,
unpaired_right_variants: 0,
omitted_left_variants: 0,
omitted_right_variants: 0,
left_source_omitted_variants: 0,
right_source_omitted_variants: 0,
left_omitted_fields: 0,
right_omitted_fields: 0,
left_omitted_property_coverage: 0,
right_omitted_property_coverage: 0,
omitted_candidates: 0,
omitted_changes: 0,
},
evidence_links: [evidenceId, `ev_${"c".repeat(64)}`],
limitations: [],
}).changes,
).toHaveLength(10_001);
});
@@ -253,56 +253,58 @@ describe("feature seed selection controls", () => {
});
describe("public feature trace from contextBridge source members", () => {
it.each(matchingModes)(
"traces $match / $value / case-sensitive $case_sensitive",
(mode) => {
const graph = contextBridgeGraph();
const before = structuredClone(graph);
const input = {
sourceEvidenceId,
graph,
nativeEvidence: [],
direction: "both" as const,
};
const generic = traceApplicationFeature({
...input,
seed: { kind: "string", ...mode },
});
const typed = traceApplicationFeature({
...input,
seed: { kind: "api", ...mode },
});
it("traces one exact member seed through the public feature workflow", () => {
const mode = {
value: "openProject",
match: "exact" as const,
case_sensitive: true,
};
const graph = contextBridgeGraph();
const before = structuredClone(graph);
const input = {
sourceEvidenceId,
graph,
nativeEvidence: [],
direction: "both" as const,
};
const generic = traceApplicationFeature({
...input,
seed: { kind: "string", ...mode },
});
const typed = traceApplicationFeature({
...input,
seed: { kind: "api", ...mode },
});
expect(typed.coverage).toEqual({
status: "complete-within-source",
source_graph_status: "complete",
total_seed_matches: 1,
});
expect(typed.seed_matches).toEqual(generic.seed_matches);
expect(typed.seed_matches).toEqual([
{
node_id: graph.nodes[0]?.node_id,
kind: "context-bridge-api",
basis: "property",
field: "observations[0].properties.members[1]",
},
]);
expect(typed.graph?.nodes).toEqual(graph.nodes);
expect(typed.graph?.edges).toEqual([]);
expect(typed.evidence_links).toEqual([sourceEvidenceId]);
expect(typed.summary).toMatchObject({
matched_seeds: 1,
traced_nodes: 1,
traced_edges: 0,
observed_facts: 1,
inferred_facts: 0,
unknown_facts: 0,
unavailable_facts: 0,
});
expect(typed.native_handoffs).toEqual([]);
expect(graph).toEqual(before);
},
);
expect(typed.coverage).toEqual({
status: "complete-within-source",
source_graph_status: "complete",
total_seed_matches: 1,
});
expect(typed.seed_matches).toEqual(generic.seed_matches);
expect(typed.seed_matches).toEqual([
{
node_id: graph.nodes[0]?.node_id,
kind: "context-bridge-api",
basis: "property",
field: "observations[0].properties.members[1]",
},
]);
expect(typed.graph?.nodes).toEqual(graph.nodes);
expect(typed.graph?.edges).toEqual([]);
expect(typed.evidence_links).toEqual([sourceEvidenceId]);
expect(typed.summary).toMatchObject({
matched_seeds: 1,
traced_nodes: 1,
traced_edges: 0,
observed_facts: 1,
inferred_facts: 0,
unknown_facts: 0,
unavailable_facts: 0,
});
expect(typed.native_handoffs).toEqual([]);
expect(graph).toEqual(before);
});
it("keeps a missing member explicit without changing source coverage", () => {
const graph = contextBridgeGraph();
@@ -2,19 +2,6 @@ import { describe, expect, it } from "vitest";
import { javascriptRecoveryInputSchema } from "./javascriptRecovery.js";
describe("JavaScript recovery requests", () => {
it("defaults omitted transform metadata without requiring engine confirmations", () => {
expect(
javascriptRecoveryInputSchema.parse({
path: "/tmp/bundle.js",
output_directory: "/tmp/recovered",
}),
).toEqual({
path: "/tmp/bundle.js",
output_directory: "/tmp/recovered",
extraction_mode: "structural",
rewrite_level: "standard",
});
});
it.each([
{ path: "", output_directory: "/tmp/recovered" },
{ path: "/tmp/bundle.js" },
@@ -1,39 +1,15 @@
import { expect, it } from "vitest";
import { analyzeJavaScriptSemantics } from "./javascriptSemanticAnalysis.js";
it.each(["namespace", "default", "named-default"])(
"retains Node built-in effects from %s imports",
(mode) => {
const imports = ["fs", "child_process", "timers", "http"]
.map((name, index) => {
const declaration =
mode === "namespace"
? `* as m${String(index)}`
: mode === "default"
? `m${String(index)}`
: `{default as m${String(index)}}`;
return `import ${declaration} from 'node:${name}';`;
})
.join("\n");
const ir = analyzeJavaScriptSemantics(`${imports}
const text = m0.readFileSync('config.json','utf8');
const stream = m0.createReadStream('config.json'); stream.destroy();
const child = m1.spawn('/usr/bin/tool', ['--version']);
const timer = m2.setTimeout(work,1000); m2.clearTimeout(timer);
const request = m3.get('http://localhost/');
it("does not assign built-in APIs to unrelated or shadowed bindings", () => {
const ir = analyzeJavaScriptSemantics(`
import fs from "./fs.js";
import { constants as constantsFs } from "node:fs";
fs.createReadStream("config.json");
constantsFs.createReadStream("config.json");
function run(fs) { fs.createReadStream("config.json"); }
`);
expect(ir.configurationOperations).toHaveLength(1);
expect(ir.resourceOperations).toHaveLength(2);
expect(ir.childProcessSpawns).toHaveLength(1);
expect(ir.timerOperations).toHaveLength(2);
expect(ir.requestOperations).toHaveLength(1);
},
);
it.each([
"import fs from './fs.js'; fs.createReadStream('config.json');",
"import {constants as fs} from 'node:fs'; fs.createReadStream('config.json');",
"function run(fs) { fs.createReadStream('config.json'); }",
])("does not invent a built-in namespace for %s", (source) => {
expect(analyzeJavaScriptSemantics(source).resourceOperations).toEqual([]);
expect(ir.resourceOperations).toEqual([]);
});
@@ -155,19 +155,6 @@ describe("JavaScript semantic analysis: calls 2", () => {
]);
});
it("retains every promise operation found in the finite source", () => {
const ir = analyzeJavaScriptSemantics(
`
Promise.resolve(1);
Promise.resolve(2);
Promise.resolve(3);
`,
);
expect(ir.promiseOperations).toHaveLength(3);
expect(ir.coverage.status).toBe("complete");
});
it("fingerprints formatting and local-name changes identically", () => {
const left = analyzeJavaScriptSemantics(`
function calculate(value) {
@@ -1,67 +1,43 @@
import * as t from "@babel/types";
import { expect, it } from "vitest";
import { analyzeJavaScriptSemantics } from "./javascriptSemanticAnalysis.js";
import {
analyzeJavaScriptSemantics,
analyzeParsedJavaScriptSemantics,
} from "./javascriptSemanticAnalysis.js";
import { onlyBinding, origin } from "./javascriptSemanticAnalysis.fixture.js";
import { parseJavaScriptSource } from "./javascriptSourceParser.js";
import { calleeName } from "./javascriptStaticAnalysisHelpers.js";
import { analyzeJavaScriptStaticSource } from "./javascriptStaticAnalysis.js";
import { analyzeParsedJavaScriptStaticSource } from "./javascriptStaticAnalysis.js";
const memberChain = ".next".repeat(12_000);
const ordinaryMemberChain = ".next".repeat(64);
it("retains native addon observations through a deep member initializer", () => {
const analysis = analyzeJavaScriptStaticSource(
`const value = require("./addon.node")${memberChain}.last[""];`,
it("preserves a 12,000-member native import through both analyzers", () => {
const parsed = parseJavaScriptSource(
`const value = require("./addon.node")${memberChain}.last; const ordinary = root.next.last;`,
);
expect(analysis.electron.native_addon_bindings).toEqual([
if (parsed === null) throw new Error("Expected valid JavaScript");
const staticAnalysis = analyzeParsedJavaScriptStaticSource("", parsed);
const ir = analyzeParsedJavaScriptSemantics(parsed);
expect(staticAnalysis.parse_status).toBe("complete");
expect(staticAnalysis.electron.native_addon_bindings).toEqual([
expect.objectContaining({ specifier: "./addon.node", members: ["last"] }),
]);
expect(analysis.parse_error_count).toBe(0);
});
it("keeps a deep non-native initializer outside native addon observations", () => {
const analysis = analyzeJavaScriptStaticSource(
`const value = root${memberChain}.last;`,
);
expect(analysis.electron.native_addon_bindings).toEqual([]);
expect(analysis.parse_status).toBe("complete");
});
it("retains unknown value diagnostics and references after a deep member initializer", () => {
const ir = analyzeJavaScriptSemantics(
`const value = root${memberChain}.last;`,
);
expect(ir.coverage).toEqual({ status: "complete", omittedCount: 0 });
expect(onlyBinding(ir, "value")).toMatchObject({
value: { status: "unknown", reason: "Cannot project last from unknown." },
provenance: { status: "unknown", reason: "Unbound identifier root." },
});
expect(ir.references.map(({ name, role }) => ({ name, role }))).toEqual([
{ name: "root", role: "read" },
]);
});
it.each([
`const value = require("./dependency.js")${memberChain}[""].last;`,
`const dependency = require("./dependency.js"); const value = dependency${memberChain}[""].last;`,
`const value = require("./dependency.js")?.next${memberChain}[""].last;`,
])("preserves the full literal module path (case %#)", (source) => {
const ir = analyzeJavaScriptSemantics(source);
const path = origin(onlyBinding(ir, "value"));
expect(path.specifier).toBe("./dependency.js");
expect(path.specifier).toBe("./addon.node");
expect(path.importedPath).toEqual([
...(source.includes("?.next") ? ["next"] : []),
...Array.from({ length: 12_000 }, () => "next"),
"",
"last",
]);
expect(ir.coverage.status).toBe("complete");
});
it("retains a deep CommonJS re-export path without inventing dynamic module links", () => {
const ir = analyzeJavaScriptSemantics(`
module.exports.result = require("./dependency.js")${memberChain}.last;
const dynamic = require("./other.js")${memberChain}[key].last;
module.exports.result = require("./dependency.js")${ordinaryMemberChain}.last;
const dynamic = require("./other.js")${ordinaryMemberChain}[key].last;
`);
expect(ir.moduleLinks).toEqual([
expect.objectContaining({
@@ -80,7 +56,7 @@ it("retains a deep CommonJS re-export path without inventing dynamic module link
it("invalidates a deep mutation while retaining unrelated literal properties", () => {
const ir = analyzeJavaScriptSemantics(`
const root = { untouched: "retained" };
root${memberChain}.last = 1;
root${ordinaryMemberChain}.last = 1;
const value = root.untouched;
`);
expect(onlyBinding(ir, "root").value).toEqual({
@@ -98,7 +74,7 @@ it("invalidates a deep mutation while retaining unrelated literal properties", (
});
it("retains the complete location and unresolved target of a deep call", () => {
const callee = `root${memberChain}.last`;
const callee = `root${ordinaryMemberChain}.last`;
const ir = analyzeJavaScriptSemantics(`${callee}();`);
expect(ir.callSites).toEqual([
expect.objectContaining({
@@ -115,7 +91,7 @@ it("retains the complete location and unresolved target of a deep call", () => {
it("retains deep default values without confusing their reads with parameter bindings", () => {
const ir = analyzeJavaScriptSemantics(
`export function inspect(value = root${memberChain}.last) { return value; }`,
`export function inspect(value = root${ordinaryMemberChain}.last) { return value; }`,
);
expect(ir.references.map(({ name, role }) => ({ name, role }))).toEqual([
{ name: "root", role: "read" },
@@ -126,7 +102,7 @@ it("retains deep default values without confusing their reads with parameter bin
it("keeps a shadowed require local through a deep member initializer", () => {
const ir = analyzeJavaScriptSemantics(
`function inspect(require) { const value = require("./dependency.js")${memberChain}.last; return value; }`,
`function inspect(require) { const value = require("./dependency.js")${ordinaryMemberChain}.last; return value; }`,
);
expect(ir.moduleLinks).toEqual([]);
expect(onlyBinding(ir, "value").provenance.origins).toEqual([]);
@@ -140,7 +116,7 @@ it.each([
["root[0].last()", "root.0.last"],
["root[key].last()", "root.[computed@5].last"],
["root?.first.last()", "root.first.last"],
[`root${memberChain}.last()`, `root${memberChain}.last`],
[`root${ordinaryMemberChain}.last()`, `root${ordinaryMemberChain}.last`],
])("preserves exact callee syntax (case %#)", (source, expected) => {
const file = parseJavaScriptSource(source);
const statement = file?.program.body[0];
@@ -18,6 +18,19 @@ const valueOf = (expression: string) =>
analyzeJavaScriptSemantics(`const answer = ${expression};`),
"answer",
).value;
const valuesOf = (expressions: readonly string[]) => {
const ir = analyzeJavaScriptSemantics(
expressions
.map(
(expression, index) =>
`const candidate${String(index)} = ${expression};`,
)
.join("\n"),
);
return expressions.map(
(_, index) => topLevelBinding(ir, `candidate${String(index)}`).value,
);
};
describe("conditional primitive unions", () => {
const cases = conditionalCandidates.flatMap((known) =>
@@ -35,11 +48,11 @@ describe("conditional primitive unions", () => {
]),
);
it.each(cases)("preserves incompatible alternatives in %s", (expression) => {
expect(valueOf(expression)).toEqual(incompatibleValue);
it("preserves incompatible alternatives across conditional expressions", () => {
expect(valuesOf(cases)).toEqual(cases.map(() => incompatibleValue));
});
it.each([
const exactCases = [
[
'condition ? (choice ? "two" : "one") : "three"',
{ status: "union", values: ["one", "three", "two"] },
@@ -69,8 +82,12 @@ describe("conditional primitive unions", () => {
{ status: "union", values: [null, "one", "two"] },
],
["condition ? null : null", { status: "literal", value: null }],
])("retains exact primitive candidates in %s", (expression, expected) => {
expect(valueOf(expression)).toEqual(expected);
] as const;
it("retains exact primitive candidates across conditional expressions", () => {
expect(valuesOf(exactCases.map(([expression]) => expression))).toEqual(
exactCases.map(([, expected]) => expected),
);
});
it("propagates an incompatible nested branch through an outer union", () => {
@@ -119,11 +136,11 @@ describe("logical primitive unions", () => {
),
);
it.each(cases)("preserves unresolved alternatives in %s", (expression) => {
expect(valueOf(expression)).toEqual(incompatibleValue);
it("preserves unresolved alternatives across logical expressions", () => {
expect(valuesOf(cases)).toEqual(cases.map(() => incompatibleValue));
});
it.each([
const exactCases = [
[
'(choice ? "" : "one") || "two"',
{ status: "union", values: ["", "one", "two"] },
@@ -138,19 +155,24 @@ describe("logical primitive unions", () => {
],
['"one" || "one"', { status: "literal", value: "one" }],
["null ?? null", { status: "literal", value: null }],
])(
"retains the conservative primitive union in %s",
(expression, expected) => {
expect(valueOf(expression)).toEqual(expected);
},
);
] as const;
it.each([
it("retains conservative primitive unions across logical expressions", () => {
expect(valuesOf(exactCases.map(([expression]) => expression))).toEqual(
exactCases.map(([, expected]) => expected),
);
});
const unevaluatedCases = [
'true ? "one" : missing',
'"one" || missing',
"false && missing",
'"one" ?? missing',
])("does not introduce short-circuit evaluation for %s", (expression) => {
expect(valueOf(expression)).toEqual(incompatibleValue);
];
it("does not introduce short-circuit evaluation", () => {
expect(valuesOf(unevaluatedCases)).toEqual(
unevaluatedCases.map(() => incompatibleValue),
);
});
});
@@ -1,28 +1,8 @@
import { expect, it } from "vitest";
import {
javaScriptSemanticQueryInputSchema,
javaScriptSemanticQueryResultSchema,
} from "./javascriptSemanticQuerySchemas.js";
import { javaScriptSemanticQueryInputSchema } from "./javascriptSemanticQuerySchemas.js";
it("accepts long selectors and complete relation and class selections", () => {
const longText = "x".repeat(16_385);
const result = javaScriptSemanticQueryInputSchema.parse({
seed: { kind: "endpoint", value: longText },
direction: "forward-influence",
allowed_relations: Array(2).fill("calls"),
expected: {
role: "sink",
classes: Array(25).fill("module"),
},
});
expect(result.seed).toEqual({ kind: "endpoint", value: longText });
expect(result.allowed_relations).toHaveLength(2);
expect(result.expected?.classes).toHaveLength(25);
});
it("rejects the inert source-map authority setting", () => {
it("rejects a source-map authority setting that the query does not consume", () => {
expect(
javaScriptSemanticQueryInputSchema.safeParse({
seed: { kind: "endpoint", value: "/api" },
@@ -31,36 +11,3 @@ it("rejects the inert source-map authority setting", () => {
}).success,
).toBe(false);
});
it("accepts every reported limitation without a count ceiling", () => {
const limitations = Array.from(
{ length: 1_001 },
(_, index) => `gap-${index}`,
);
const id = "a".repeat(64);
const result = javaScriptSemanticQueryResultSchema.parse({
query_id: `jsrq_${id}`,
source_graph_id: `jsrg_${id}`,
seed: { kind: "literal", value: null },
direction: "forward-influence",
status: "no-match",
seed_node_ids: [],
nodes: [],
relations: [],
unknowns: [],
expected_match_node_ids: [],
summary: {
total_seed_matches: 0,
traversed_nodes: 0,
traversed_relations: 0,
traversed_functions: 0,
traversed_modules: 0,
relevant_unknowns: 0,
},
coverage: { status: "complete" },
limitations,
});
expect(result.limitations).toHaveLength(1_001);
});
@@ -1,66 +0,0 @@
import * as t from "@babel/types";
import { expect, it } from "vitest";
import { parseJavaScriptSource } from "./javascriptSourceParser.js";
import { traverseJavaScriptAst } from "./javascriptSemanticTraversal.js";
it("preserves source-tree enter/exit order and detached ancestor snapshots", () => {
const parsed = parseJavaScriptSource("const answer = first + second;");
if (parsed === null)
throw new TypeError("Expected a parsed JavaScript fixture");
const visits: string[] = [];
const snapshots: (readonly t.Node[])[] = [];
traverseJavaScriptAst(parsed.program, {
enter: (node, parent, readAncestors) => {
visits.push(`enter:${node.type}`);
const ancestors = readAncestors();
expect(ancestors.at(-1) ?? null).toBe(parent);
if (t.isIdentifier(node)) snapshots.push(ancestors);
},
exit: (node) => visits.push(`exit:${node.type}`),
});
expect(visits).toEqual([
"enter:Program",
"enter:VariableDeclaration",
"enter:VariableDeclarator",
"enter:Identifier",
"exit:Identifier",
"enter:BinaryExpression",
"enter:Identifier",
"exit:Identifier",
"enter:Identifier",
"exit:Identifier",
"exit:BinaryExpression",
"exit:VariableDeclarator",
"exit:VariableDeclaration",
"exit:Program",
]);
expect(snapshots.map((nodes) => nodes.map(({ type }) => type))).toEqual([
["Program", "VariableDeclaration", "VariableDeclarator"],
[
"Program",
"VariableDeclaration",
"VariableDeclarator",
"BinaryExpression",
],
[
"Program",
"VariableDeclaration",
"VariableDeclarator",
"BinaryExpression",
],
]);
});
it("skips sparse child slots without disturbing sibling visit order", () => {
const parsed = parseJavaScriptSource("const values = [first, , second];");
if (parsed === null)
throw new TypeError("Expected a parsed JavaScript fixture");
const identifiers: string[] = [];
traverseJavaScriptAst(parsed.program, {
enter: (node) => {
if (t.isIdentifier(node)) identifiers.push(node.name);
},
});
expect(identifiers).toEqual(["values", "first", "second"]);
});
@@ -5,6 +5,7 @@ import { analyzeJavaScriptStaticSource } from "./javascriptStaticAnalysis.js";
import { parseJavaScriptSource } from "./javascriptSourceParser.js";
const memberChain = ".next".repeat(12_000);
const ordinaryMemberChain = ".next".repeat(64);
it("collects a 12,000-member CommonJS export path without recursion", () => {
const file = parseJavaScriptSource(`exports${memberChain}.last = 1;`);
@@ -48,8 +49,8 @@ it("keeps left-first and outer-member-first bundler runtime matches", () => {
).toBe("webpackChunkInner");
});
it("analyzes a 12,000-member bundler runtime chain without recursion", () => {
const source = `globalThis.webpackChunkApp${memberChain}.push([[1], { 1: function(module) { module.exports.ok = 42; } }]);`;
it("recognizes a bundler runtime through nested member names", () => {
const source = `globalThis.webpackChunkApp${ordinaryMemberChain}.push([[1], { 1: function(module) { module.exports.ok = 42; } }]);`;
const analysis = analyzeJavaScriptStaticSource(source);
expect(analysis.parse_status).toBe("complete");
expect(analysis.parse_error_count).toBe(0);
@@ -22,12 +22,6 @@ describe("source map directives", () => {
expect(sourceMapUrls(source)).toEqual([expected]);
});
it("keeps the comment terminator out of the declared url", () => {
expect(sourceMapUrls("/*# sourceMappingURL=app.js.map */")).toEqual([
"app.js.map",
]);
});
it("retains every directive in a source", () => {
expect(
sourceMapUrls(
@@ -84,30 +78,6 @@ describe("source map comment boundaries", () => {
});
describe("source map comment locations and recovery", () => {
it("keeps exact locations and the first occurrence of duplicate URLs", () => {
const line = "//# sourceMappingURL=first.map";
const block = "/*# sourceMappingURL=second.map";
const result = analyzeJavaScriptStaticSource(
['const marker = "😀";', line, `${block} */`, line].join("\r\n"),
);
expect(result.source_map_urls).toEqual([
{
declared_url: "first.map",
location: {
start: { line: 2, column: 0 },
end: { line: 2, column: line.length },
},
},
{
declared_url: "second.map",
location: {
start: { line: 3, column: 0 },
end: { line: 3, column: block.length },
},
},
]);
});
it("keeps real comments when the parser recovers and reports partial syntax", () => {
const result = analyzeJavaScriptStaticSource(
"let value; let value;\n//# sourceMappingURL=recovered.map",
@@ -1,9 +1,7 @@
import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
import type { Client } from "@modelcontextprotocol/client";
import { describe, expect, it } from "vitest";
import { createTestBinarySession } from "../../fixtures/binarySession.js";
import type { BinarySession } from "../../../src/application/binary/BinarySession.js";
import { createServer } from "../../../src/server/createServer.js";
import {
JAVASCRIPT_FEATURE_TRACE_FULL_EVIDENCE_EXAMPLE,
JAVASCRIPT_FEATURE_TRACE_EXAMPLE,
@@ -11,39 +9,10 @@ import {
SOURCE_TO_BUNDLE_COMPARISON_EXAMPLE,
} from "../../../src/contracts/javascript/javascriptApplicationWorkflowExamples.js";
import { createEvidence } from "../../../src/domain/evidence.js";
import { observed } from "../../fixtures/analysisExecution.js";
interface TestHarness {
readonly client: Client;
readonly session: BinarySession;
readonly close: () => Promise<void>;
}
async function createTestHarness(): Promise<TestHarness> {
const session = createTestBinarySession(() => ({
execute: () => Promise.resolve(observed(null)),
close: () => Promise.resolve(),
}));
const server = createServer(session, session);
const client = new Client({
name: "application-workflow-test",
version: "1",
});
const [clientTransport, serverTransport] =
InMemoryTransport.createLinkedPair();
await server.connect(serverTransport);
await client.connect(clientTransport);
return {
client,
session,
close: async () => {
await client.close();
await server.close();
await session.close();
},
};
}
import {
createApplicationMcpHarness,
type ApplicationMcpHarness,
} from "./mcpHarness.js";
async function runInlineEvidenceScenarios(
client: Client,
@@ -103,7 +72,9 @@ async function runInlineEvidenceScenarios(
expect(session.exportEvidenceBundle().records.length).toBeGreaterThan(2);
}
async function runInlineWorkflowScenarios(harness: TestHarness): Promise<void> {
async function runInlineWorkflowScenarios(
harness: ApplicationMcpHarness,
): Promise<void> {
const tracedInline = await harness.client.callTool({
name: "trace_application_feature",
arguments: {
@@ -250,7 +221,7 @@ async function assertRejectedInlineEvidence(client: Client): Promise<void> {
describe("application workflow MCP parity", () => {
it("traces and compares authenticated graph Evidence in the session", async () => {
const harness = await createTestHarness();
const harness = await createApplicationMcpHarness();
try {
await runInlineEvidenceScenarios(harness.client, harness.session);
await runInlineWorkflowScenarios(harness);
@@ -1,15 +1,14 @@
import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
import { describe, expect, it } from "vitest";
import { copyFile, mkdir, rm } from "node:fs/promises";
import { copyFile, mkdir, rm, writeFile } from "node:fs/promises";
import { join, relative, resolve } from "node:path";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { createTestBinarySession } from "../../fixtures/binarySession.js";
import { createServer } from "../../../src/server/createServer.js";
import { observed } from "../../fixtures/analysisExecution.js";
import { analyzeJavaScriptApplication } from "../../../src/application/javascript/JavaScriptApplicationService.js";
import { compareJavaScriptExportShapesEvidence } from "../../../src/application/javascript/JavaScriptApplicationWorkflowService.js";
import { javascriptApplicationAnalysisResultSchema } from "../../../src/domain/javascript/javascriptApplicationAnalysis.js";
import { javaScriptExportShapeComparisonResultSchema } from "../../../src/domain/javascript/javascriptExportShapeComparisonSchemas.js";
import { createApplicationMcpHarness } from "./mcpHarness.js";
describe("application workflow MCP parity", () => {
it("compares exact parser export shapes with inline Evidence", async () => {
@@ -40,14 +39,8 @@ describe("application workflow MCP parity", () => {
const leftAnalysis = javascriptApplicationAnalysisResultSchema.parse(
left.value.normalized_result,
);
const session = createTestBinarySession(() => ({
execute: () => Promise.resolve(observed(null)),
close: () => Promise.resolve(),
}));
const server = createServer(session, session);
const client = new Client({ name: "export-shape-test", version: "1" });
const [clientTransport, serverTransport] =
InMemoryTransport.createLinkedPair();
const harness = await createApplicationMcpHarness();
const { client, session } = harness;
const selectors = {
left_module_path: "parser.mjs",
left_export_name: "default",
@@ -55,8 +48,6 @@ describe("application workflow MCP parity", () => {
right_export_name: "default",
};
try {
await server.connect(serverTransport);
await client.connect(clientTransport);
const relativeApplication = await client.callTool({
name: "analyze_javascript_application",
arguments: { input_path: relative(process.cwd(), leftRoot) },
@@ -121,10 +112,110 @@ describe("application workflow MCP parity", () => {
},
});
} finally {
await client.close();
await server.close();
await session.close();
await harness.close();
await rm(root, { recursive: true, force: true });
}
});
});
describe("source-produced export comparison inventories", () => {
it("retains large source-produced export inventories through comparison schemas", async () => {
const fields = Array.from(
{ length: 64 },
(_, index) => `field${String(index)}: ${String(index)}`,
).join(", ");
const returnSites = Array.from(
{ length: 33 },
(_, index) =>
`if (value === ${String(index)}) return { type: "variant-${String(index)}", ${fields} };`,
).join("\n");
const extraExports = Array.from(
{ length: 1_000 },
(_, index) =>
`export const candidate${String(index)} = ${String(index)};`,
).join("\n");
const inventorySource = `export default function parse(value) {\n${returnSites}\n throw new Error("no match");\n}\n${extraExports}`;
const [inventoryLeft, inventoryRight] = await Promise.all([
analyzeSourceEvidence(inventorySource),
analyzeSourceEvidence(inventorySource),
]);
const variants = compareEvidence(inventoryLeft, inventoryRight);
expect(variants.left).toMatchObject({ status: "selected" });
expect(variants.coverage).toMatchObject({
paired_variants: 33,
unpaired_left_variants: 0,
unpaired_right_variants: 0,
left_source_omitted_variants: 0,
right_source_omitted_variants: 0,
left_omitted_fields: 0,
right_omitted_fields: 0,
});
const missing = compareEvidence(inventoryLeft, inventoryRight, {
leftExportName: "missing",
});
expect(missing.left).toMatchObject({
status: "missing",
omitted_candidates: 0,
});
expect(missing.left.candidates).toHaveLength(1_001);
const changedFieldsLeft = Array.from(
{ length: 10_001 },
(_, index) => `field${String(index)}: ${String(index)}`,
).join(", ");
const changedFieldsRight = Array.from(
{ length: 10_001 },
(_, index) => `field${String(index)}: ${String(index + 1)}`,
).join(", ");
const [changeLeft, changeRight] = await Promise.all([
analyzeSourceEvidence(
`export default () => ({ type: "record", ${changedFieldsLeft} });`,
),
analyzeSourceEvidence(
`export default () => ({ type: "record", ${changedFieldsRight} });`,
),
]);
const changes = compareEvidence(changeLeft, changeRight);
expect(changes.changes).toHaveLength(10_001);
expect(changes.summary).toEqual({
added: 0,
removed: 0,
changed: 10_001,
unknown: 0,
});
expect(changes.coverage).toMatchObject({
status: "complete-within-inputs",
omitted_changes: 0,
left_omitted_fields: 0,
right_omitted_fields: 0,
});
}, 30_000);
});
const analyzeSourceEvidence = async (source: string) => {
const root = await createTestTempDirectory("rea-export-shape-inventory-");
await writeFile(join(root, "parser.mjs"), source);
const analyzed = await analyzeJavaScriptApplication({ input_path: root });
if (!analyzed.ok) throw analyzed.error;
return analyzed.value;
};
const compareEvidence = (
left: Awaited<ReturnType<typeof analyzeSourceEvidence>>,
right: Awaited<ReturnType<typeof analyzeSourceEvidence>>,
selectors: { readonly leftExportName?: string } = {},
) => {
const compared = compareJavaScriptExportShapesEvidence({
left,
right,
left_module_path: "parser.mjs",
left_export_name: selectors.leftExportName ?? "default",
right_module_path: "parser.mjs",
right_export_name: "default",
});
if (!compared.ok) throw compared.error;
return javaScriptExportShapeComparisonResultSchema.parse(
compared.value.normalized_result,
);
};
@@ -0,0 +1,39 @@
import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
import { createTestBinarySession } from "../../fixtures/binarySession.js";
import type { BinarySession } from "../../../src/application/binary/BinarySession.js";
import { observed } from "../../fixtures/analysisExecution.js";
import { createServer } from "../../../src/server/createServer.js";
/** Owned MCP SDK session shared by application workflow scenarios. */
export interface ApplicationMcpHarness {
readonly client: Client;
readonly session: BinarySession;
readonly close: () => Promise<void>;
}
/** Connect application workflows through the production MCP registration. */
export async function createApplicationMcpHarness(): Promise<ApplicationMcpHarness> {
const session = createTestBinarySession(() => ({
execute: () => Promise.resolve(observed(null)),
close: () => Promise.resolve(),
}));
const server = createServer(session, session);
const client = new Client({
name: "application-workflow-test",
version: "1",
});
const [clientTransport, serverTransport] =
InMemoryTransport.createLinkedPair();
await server.connect(serverTransport);
await client.connect(clientTransport);
return {
client,
session,
close: async () => {
await Promise.all([client.close(), server.close(), session.close()]);
},
};
}