refactor(javascript): own coverage facts and reuse block prefixes

Separate syntax, semantic uncertainty, examination limits and observed Electron applicability at the static producer, then preserve them through worker, graph and retained/inline summary views. Derive the established parse_status from the same facts and leave historical measurements unknown. Give semantic resource-limit classifications one schema owner.

Replace repeated block-prefix searches and copies with collector-scoped syntax indexes. Keep invocation environments separate, charge indexing/replay to the existing work budget and yield during prefix work. Remove the superseded synchronous collector entrypoint.

Validated producer, worker, CLI/MCP, historical and partial-coverage regressions, plus actual cancellation during indexing. Bounded authored 128/256-call controls preserved all prior facts while replacing repeated search/copy work with one index pass; this is not a throughput or agent-token benchmark.
This commit is contained in:
morluto committed 2026-10-25 09:49:26 +08:00
1 parent c8269ca497
commit f62a2baad8
21 files changed
+898 -125

No files matched your search

@@ -0,0 +1,78 @@
import * as t from "@babel/types";
import { expect, it } from "vitest";
import { ElectronCallPathBlockPrefixes } from "./electronCallPathBlockPrefixes.js";
import { parseJavaScriptSource } from "./javascriptSourceParser.js";
import { completeSemanticSteps } from "./javascriptSemanticTraversal.js";
it("indexes a real flat block once, retaining contextual guards in source order", () => {
const parsed = parseJavaScriptSource(`{
${"0;".repeat(2048)}
if (uncertain) ordinary();
if (flag) throw 0;
electron.send("tail");
}`);
const block = parsed?.program.body[0];
if (!t.isBlockStatement(block)) throw new Error("Expected parsed block");
const first = block.body[0];
const tail = block.body.at(-1);
if (first === undefined || tail === undefined)
throw new Error("Expected block statements");
let examined = 0;
const prefixes = new ElectronCallPathBlockPrefixes(() => {
examined += 1;
return true;
});
const steps = prefixes.before(block, tail);
expect(steps.next()).toEqual({ done: false, value: undefined });
expect(examined).toBe(1024);
const prefix = completeSemanticSteps(steps);
expect(examined).toBe(block.body.length);
expect(prefix).toMatchObject({
before: 2050,
entries: [
{
position: 2048,
fact: {
kind: "branch",
test: { type: "Identifier", name: "uncertain" },
consequentExits: false,
alternateExits: false,
},
},
{
position: 2049,
fact: {
kind: "branch",
test: { type: "Identifier", name: "flag" },
consequentExits: true,
alternateExits: false,
},
},
],
});
for (const statement of block.body) {
const earlier = completeSemanticSteps(prefixes.before(block, statement));
expect(earlier?.entries).toBe(prefix?.entries);
}
expect(examined).toBe(block.body.length);
expect(completeSemanticSteps(prefixes.before(block, first))?.before).toBe(0);
});
it("does not publish an incomplete block index when its work budget ends", () => {
const parsed = parseJavaScriptSource(
`{ 0; 1; if (stop) throw 0; send("tail"); }`,
);
const block = parsed?.program.body[0];
if (!t.isBlockStatement(block)) throw new Error("Expected parsed block");
const tail = block.body.at(-1);
if (tail === undefined) throw new Error("Expected terminal statement");
let remaining = 2;
const prefixes = new ElectronCallPathBlockPrefixes(() => --remaining >= 0);
expect(completeSemanticSteps(prefixes.before(block, tail))).toBeUndefined();
remaining = block.body.length;
expect(completeSemanticSteps(prefixes.before(block, tail))).toMatchObject({
before: 3,
entries: [{ position: 2, fact: { kind: "branch" } }],
});
expect(remaining).toBe(0);
});
@@ -0,0 +1,85 @@
import * as t from "@babel/types";
import { symbolicDefiniteExit } from "./javascriptSymbolicControlFlow.js";
/** Syntax alone can establish an exit, but never a branch's contextual truth. */
export type ElectronStatementFallthrough =
| { readonly kind: "exit" }
| {
readonly kind: "branch";
readonly test: t.Expression;
readonly consequentExits: boolean;
readonly alternateExits: boolean;
};
interface PrefixEntry {
readonly position: number;
readonly fact: ElectronStatementFallthrough;
}
interface BlockIndex {
readonly positions: WeakMap<t.Node, number>;
readonly entries: readonly PrefixEntry[];
}
/**
* One collector's immutable syntax facts. Positions replace repeated body
* searches; ordinary fallthrough statements need no replay. Conditional tests
* remain present even when neither branch exits, since evaluating them belongs
* to the invocation's symbolic environment and can establish unknown coverage.
*/
export class ElectronCallPathBlockPrefixes {
readonly #blocks = new WeakMap<t.BlockStatement, BlockIndex>();
readonly #facts = new WeakMap<
t.Statement,
ElectronStatementFallthrough | null
>();
constructor(private readonly admitVisit: () => boolean) {}
statement(statement: t.Statement): ElectronStatementFallthrough | null {
const cached = this.#facts.get(statement);
if (cached !== undefined) return cached;
const fact: ElectronStatementFallthrough | null = symbolicDefiniteExit(
statement,
)
? { kind: "exit" }
: t.isIfStatement(statement)
? {
kind: "branch",
test: statement.test,
consequentExits: symbolicDefiniteExit(statement.consequent),
alternateExits: symbolicDefiniteExit(statement.alternate),
}
: null;
this.#facts.set(statement, fact);
return fact;
}
*before(
block: t.BlockStatement,
child: t.Node,
): Generator<
void,
| { readonly entries: readonly PrefixEntry[]; readonly before: number }
| undefined
> {
let index = this.#blocks.get(block);
if (index === undefined) {
const positions = new WeakMap<t.Node, number>();
const entries: PrefixEntry[] = [];
for (const [position, statement] of block.body.entries()) {
if (!this.admitVisit()) return undefined;
positions.set(statement, position);
const fact = this.statement(statement);
if (fact !== null) entries.push({ position, fact });
if ((position + 1) % 1024 === 0) yield;
}
index = { positions, entries };
this.#blocks.set(block, index);
}
const before = index.positions.get(child);
return before === undefined
? undefined
: { entries: index.entries, before };
}
}
@@ -1,6 +1,100 @@
import { describe, expect, it } from "vitest";
import { analyzeJavaScriptStaticSource } from "./javascriptStaticAnalysis.js";
it("preserves every direct observation in a long flat sibling block", () => {
const channels = Array.from({ length: 256 }, (_, index) => `flat:${index}`);
const result = analyzeJavaScriptStaticSource(`const e=require("electron"); {
${channels.map((channel) => `e.ipcRenderer.send("${channel}");`).join("\n")}
}`);
expect(result.electron.ipc.map(({ channel }) => channel)).toEqual(channels);
expect(result.electron.call_paths ?? []).toEqual([]);
expect(result.parse_status).toBe("complete");
});
it("keeps sibling guards, definite exits and nested shadowing separate", () => {
const result = analyzeJavaScriptStaticSource(`const e=require("electron"); {
if (stop) throw new Error("stop");
e.ipcMain.on("guarded", event => event.sender.copy());
{
const e = {ipcMain: {on() {}}};
e.ipcMain.on("shadowed", event => event.sender.copy());
}
if (true) throw new Error("end");
e.ipcMain.on("unreachable", event => event.sender.copy());
}`);
expect(
result.electron.call_paths?.map(
({ entry, terminal, steps, conditions }) => ({
entry,
terminal,
terminalStart: steps.at(-1)?.location.start,
conditions: conditions.map(({ expression }) => expression),
}),
),
).toEqual([
{
entry: "guarded",
terminal: "electron.ipcMain.on",
terminalStart: { line: 3, column: 4 },
conditions: ["!(stop)"],
},
{
entry: "guarded",
terminal: "ipc-event.sender.copy",
terminalStart: { line: 3, column: 37 },
conditions: ["!(stop)"],
},
]);
// Raw syntax after a definite exit remains an observation, not a reachable
// callback path. The shadowed ordinary object provides no Electron identity.
expect(result.electron.ipc.map(({ channel }) => channel)).toEqual([
"guarded",
"unreachable",
]);
});
it("evaluates shared return syntax separately for each invocation environment", () => {
const result = analyzeJavaScriptStaticSource(`const e=require("electron");
function install(channel, enabled) {
if (!enabled) return;
e.ipcMain.on(channel, event => event.sender.copy());
}
install("enabled", true);
install("disabled", false);
install("uncertain", externalFlag);
`);
expect(
result.electron.call_paths?.map(
({ entry, terminal, steps, conditions }) => ({
entry,
terminal,
invocationStart: steps[0]?.location.start,
conditions: conditions.map(({ expression }) => expression),
}),
),
).toEqual([
{
entry: "enabled",
terminal: "ipc-event.sender.copy",
invocationStart: { line: 6, column: 4 },
conditions: [],
},
{
entry: "uncertain",
terminal: "electron.ipcMain.on",
invocationStart: { line: 8, column: 4 },
conditions: ["!(!enabled)"],
},
{
entry: "uncertain",
terminal: "ipc-event.sender.copy",
invocationStart: { line: 8, column: 4 },
conditions: ["!(!enabled)"],
},
]);
expect(result.parse_status).toBe("partial");
});
const bundle = (entry: string) => `(() => {
const modules = {
2(module) { module.exports = require("electron"); },
+117 -79
View File
@@ -33,17 +33,22 @@ import {
boundedExpression,
contextBridgeMemberPathDepth,
} from "./electronStaticAnalysisValues.js";
import { argumentNode } from "./javascriptStaticAnalysisHelpers.js";
import {
argumentNode,
range,
calleeName,
} from "./javascriptStaticAnalysisHelpers.js";
import {
childNodes,
traverseJavaScriptValueAst,
traverseJavaScriptValueAstSteps,
} from "./javascriptSemanticTraversal.js";
import { range, calleeName } from "./javascriptStaticAnalysisHelpers.js";
import { ipcDescriptor } from "./electronStaticAnalysisIpc.js";
import { symbolicLogicalRight } from "./javascriptSymbolicControlFlow.js";
import {
symbolicDefiniteExit,
symbolicLogicalRight,
} from "./javascriptSymbolicControlFlow.js";
ElectronCallPathBlockPrefixes,
type ElectronStatementFallthrough,
} from "./electronCallPathBlockPrefixes.js";
import { compareUnicodeCodePoints } from "../unicodeCodePointOrder.js";
const callLabel = (node: t.Node): string =>
@@ -227,16 +232,19 @@ interface PathContext {
}
/** Substitutes inert wrapper syntax; every emitted path remains a candidate. */
export const collectElectronWrappedCallPaths = (
export function* collectElectronWrappedCallPathsSteps(
program: t.Program,
state: JavaScriptSemanticAnalysisState,
source: string,
accumulator: JavaScriptAnalysisAccumulator,
identity: JavaScriptElectronIdentity,
): readonly ElectronCallPath[] => {
): Generator<void, readonly ElectronCallPath[]> {
// Bounds repeated interprocedural expansion independently of bundle bytes.
// Exhaustion is reported as unknown coverage, never as a negative finding.
let remainingVisits = 1_000_000;
const prefixes = new ElectronCallPathBlockPrefixes(
() => --remainingVisits >= 0,
);
const resolver = new JavaScriptSymbolicBindings(state, program, identity);
const paths: ElectronCallPath[] = [];
const seen = new Set<string>();
@@ -282,28 +290,26 @@ export const collectElectronWrappedCallPaths = (
};
};
const sequentialFallthrough = (
statement: t.Statement,
fact: ElectronStatementFallthrough | null,
env: SymbolicEnvironment,
context: PathContext,
): { readonly continues: boolean; readonly context: PathContext } => {
if (symbolicDefiniteExit(statement)) return { continues: false, context };
if (!t.isIfStatement(statement)) return { continues: true, context };
const truth = symbolicTruth(resolver.evaluate(statement.test, env));
if (fact === null) return { continues: true, context };
if (fact.kind === "exit") return { continues: false, context };
const truth = symbolicTruth(resolver.evaluate(fact.test, env));
if (truth !== undefined)
return symbolicDefiniteExit(
truth ? statement.consequent : statement.alternate,
)
return (truth ? fact.consequentExits : fact.alternateExits)
? { continues: false, context }
: { continues: true, context };
if (symbolicDefiniteExit(statement.consequent))
if (fact.consequentExits)
return {
continues: true,
context: condition(context, statement.test, false),
context: condition(context, fact.test, false),
};
if (symbolicDefiniteExit(statement.alternate))
if (fact.alternateExits)
return {
continues: true,
context: condition(context, statement.test),
context: condition(context, fact.test),
};
return { continues: true, context };
};
@@ -1148,7 +1154,11 @@ export const collectElectronWrappedCallPaths = (
let next = context;
for (const statement of node.body) {
walk(statement, env, next);
const fallthrough = sequentialFallthrough(statement, env, next);
const fallthrough = sequentialFallthrough(
prefixes.statement(statement),
env,
next,
);
if (!fallthrough.continues) break;
next = fallthrough.context;
}
@@ -1194,70 +1204,98 @@ export const collectElectronWrappedCallPaths = (
call(node, env, context);
for (const child of childNodes(node)) walk(child, env, context);
}
traverseJavaScriptValueAst(program, state.erasedSyntaxNodes, {
enter: (node) => {
if (!t.isCallExpression(node) && !t.isOptionalCallExpression(node))
return;
const isolatedSeed = t.isStringLiteral(node.arguments[0])
? undefined
: isolatedBridgeCall(node);
if (!t.isStringLiteral(node.arguments[0]) && isolatedSeed === undefined)
return;
const env = isolatedSeed?.env ?? resolver.environmentAt(node);
let context: PathContext = {
entryNode: node,
calls: [],
entry: "",
entryKind: null,
channel: null,
steps: [],
conditions: [],
active: new Set(),
};
for (
let child: t.Node = node, parent = state.parentsByNode.get(child);
parent && !t.isFunction(parent);
child = parent, parent = state.parentsByNode.get(child)
) {
if (t.isIfStatement(parent) || t.isConditionalExpression(parent)) {
if (child === parent.test) continue;
const truth = symbolicTruth(resolver.evaluate(parent.test, env));
const positive = child === parent.consequent;
if (truth !== undefined && truth !== positive) return;
if (truth === undefined)
context = condition(context, parent.test, positive);
} else if (t.isLogicalExpression(parent) && child === parent.right) {
const right = symbolicLogicalRight(
parent.operator,
resolver.evaluate(parent.left, env),
let prefixVisits = 0;
function* seed(
node: t.CallExpression | t.OptionalCallExpression,
): Generator<void, void> {
if (remainingVisits < 0) return;
const isolatedSeed = t.isStringLiteral(node.arguments[0])
? undefined
: isolatedBridgeCall(node);
if (!t.isStringLiteral(node.arguments[0]) && isolatedSeed === undefined)
return;
const env = isolatedSeed?.env ?? resolver.environmentAt(node);
let context: PathContext = {
entryNode: node,
calls: [],
entry: "",
entryKind: null,
channel: null,
steps: [],
conditions: [],
active: new Set(),
};
for (
let child: t.Node = node, parent = state.parentsByNode.get(child);
parent && !t.isFunction(parent);
child = parent, parent = state.parentsByNode.get(child)
) {
if (--remainingVisits < 0) return;
if (++prefixVisits % 1024 === 0) yield;
if (t.isIfStatement(parent) || t.isConditionalExpression(parent)) {
if (child === parent.test) continue;
const truth = symbolicTruth(resolver.evaluate(parent.test, env));
const positive = child === parent.consequent;
if (truth !== undefined && truth !== positive) return;
if (truth === undefined)
context = condition(context, parent.test, positive);
} else if (t.isLogicalExpression(parent) && child === parent.right) {
const right = symbolicLogicalRight(
parent.operator,
resolver.evaluate(parent.left, env),
);
if (right === false) return;
if (right === undefined)
context = condition(
context,
parent.left,
parent.operator === "??" ? "nullish" : parent.operator === "&&",
);
if (right === false) return;
if (right === undefined)
context = condition(
context,
parent.left,
parent.operator === "??" ? "nullish" : parent.operator === "&&",
);
} else if (t.isBlockStatement(parent)) {
const index = parent.body.findIndex(
(statement) => statement === child,
);
if (index >= 0) {
for (const statement of parent.body.slice(0, index)) {
const fallthrough = sequentialFallthrough(
statement,
env,
context,
);
if (!fallthrough.continues) return;
context = fallthrough.context;
}
} else if (t.isBlockStatement(parent)) {
const prefix = yield* prefixes.before(parent, child);
if (remainingVisits < 0) return;
if (prefix !== undefined) {
for (const entry of prefix.entries) {
if (entry.position >= prefix.before) break;
if (--remainingVisits < 0) return;
if (++prefixVisits % 1024 === 0) yield;
const fallthrough = sequentialFallthrough(entry.fact, env, context);
if (!fallthrough.continues) return;
context = fallthrough.context;
}
}
}
call(node, env, context, isolatedSeed?.callee);
}
call(node, env, context, isolatedSeed?.callee);
}
// The shared walker supplies one bounded batch at a time. Prefix work must
// run outside its synchronous callback so cancellation can interrupt a large
// block index or a genuinely long sequence of contextual branch facts.
const seeds: (t.CallExpression | t.OptionalCallExpression)[] = [];
const traversal = traverseJavaScriptValueAstSteps(
program,
state.erasedSyntaxNodes,
{
enter: (node) => {
if (t.isCallExpression(node) || t.isOptionalCallExpression(node))
seeds.push(node);
},
},
});
);
try {
for (;;) {
const batch = traversal.next();
for (const node of seeds) {
yield* seed(node);
if (remainingVisits < 0) break;
}
seeds.length = 0;
if (batch.done || remainingVisits < 0) break;
yield;
}
} finally {
traversal.return();
}
recordBridgeExposures();
if (remainingVisits < 0 || resolver.truncated) {
accumulator.unknownFindings += 1;
@@ -1265,4 +1303,4 @@ export const collectElectronWrappedCallPaths = (
}
if (resolver.unresolved) accumulator.unknownFindings += 1;
return paths;
};
}
@@ -21,6 +21,9 @@ it("preserves possible ambient effects and discloses projection widening in sour
expect(ir.limitations).toContain(RETURNED_REFERENCE_WIDENING_LIMITATION);
const facts = analyzeJavaScriptStaticSource(source);
expect(facts.limitations).toContain(RETURNED_REFERENCE_WIDENING_LIMITATION);
expect(facts.analysis_coverage?.semantics.uncertainty).toContain(
"returned-reference-widening",
);
expect(facts.endpoints).toEqual(
expect.arrayContaining([
expect.objectContaining({ value: "/preserved", mechanism: "call:fetch" }),
@@ -1,13 +1,21 @@
import { z } from "zod";
/** Primitive values admitted into the constant lattice. */
export type JavaScriptSemanticPrimitive = string | number | boolean | null;
/** Resource bound that prevented an exact semantic value. */
export type JavaScriptSemanticResourceLimit =
| "primitive-candidates"
| "primitive-bytes"
| "expression-depth"
| "getter-expansion"
| "alias-selections";
export const javaScriptSemanticResourceLimitSchema = z.enum([
"primitive-candidates",
"primitive-bytes",
"expression-depth",
"getter-expansion",
"alias-selections",
]);
/** Resource-limit classifications shared by static facts and semantic values. */
export type JavaScriptSemanticResourceLimit = z.infer<
typeof javaScriptSemanticResourceLimitSchema
>;
type JavaScriptSemanticObjectValue = {
readonly status: "object";
@@ -3,7 +3,7 @@ import * as t from "@babel/types";
import { JavaScriptRouteScan } from "./javascriptRouteScan.js";
import type { JavaScriptRouteSourceFacts } from "./javascriptRouteFacts.js";
import { RETURNED_REFERENCE_WIDENING_LIMITATION } from "./javascriptSemanticCoverage.js";
import { collectElectronWrappedCallPaths } from "./electronWrappedCallPaths.js";
import { collectElectronWrappedCallPathsSteps } from "./electronWrappedCallPaths.js";
import {
ELECTRON_IDENTITY_LIMITATION,
ELECTRON_MODULE,
@@ -76,6 +76,10 @@ import {
isTypeOnlyImportDeclaration,
semanticImportEqualsSpecifier,
} from "./javascriptModuleDeclaration.js";
import {
javaScriptStaticParseStatus,
type JavaScriptStaticCoverage,
} from "./javascriptStaticCoverage.js";
/** Parse one JavaScript artifact and recover static structure only. */
export const analyzeJavaScriptStaticSource = (
@@ -154,7 +158,7 @@ export function* analyzeParsedJavaScriptStaticSourceSteps(
finishPartialNetworkEndpoints(findings, bindings, index);
finishSqliteStorageCalls(findings, bindings, index);
}
accumulator.electronCallPaths = collectElectronWrappedCallPaths(
accumulator.electronCallPaths = yield* collectElectronWrappedCallPathsSteps(
file.program,
bindings,
source,
@@ -191,6 +195,43 @@ const finalizeStaticAnalysis = (
routes: JavaScriptRouteSourceFacts,
): JavaScriptStaticAnalysis => {
const parserErrors = file.errors.length;
const typeOnlySideEffect = hasUncertainTypeOnlyModuleSideEffect(file.program);
const electronObserved = accumulator.references.some(
({ value }) =>
value.specifier !== null && ELECTRON_MODULE.test(value.specifier),
);
const resourceLimits = [...bindings.valueResourceLimits].sort();
const coverage: JavaScriptStaticCoverage = {
syntax:
parserErrors === 0
? { status: "complete", error_count: 0 }
: { status: "recovered", error_count: parserErrors },
semantics: {
unknown_findings: accumulator.unknownFindings,
uncertainty: [
...(accumulator.unknownFindings > 0
? ["dynamic-findings" as const]
: []),
...(bindings.returnedReferenceWidenings.size > 0
? ["returned-reference-widening" as const]
: []),
...(typeOnlySideEffect
? ["type-only-module-side-effect" as const]
: []),
],
},
examination: {
status:
resourceLimits.length > 0 ||
accumulator.electronCallPathLimitReached === true
? "limited"
: "complete",
semantic_resource_limits: resourceLimits,
electron_call_paths_limited:
accumulator.electronCallPathLimitReached === true,
},
applicability: { electron: electronObserved ? "observed" : "unknown" },
};
const limitations = [
...(bindings.valueResourceLimits.has("alias-selections")
? [semanticResourceLimitReason("alias-selections")]
@@ -218,26 +259,17 @@ const finalizeStaticAnalysis = (
: [
"One or more static keys, expressions, or Electron boundary values were dynamic and remain unknown.",
]),
...(hasUncertainTypeOnlyModuleSideEffect(file.program)
...(typeOnlySideEffect
? [
"Compiler options are unavailable; inline type-only imports or re-exports may preserve a module side-effect dependency.",
]
: []),
...(accumulator.references.some(
({ value }) =>
value.specifier !== null && ELECTRON_MODULE.test(value.specifier),
)
? [ELECTRON_IDENTITY_LIMITATION]
: []),
...(electronObserved ? [ELECTRON_IDENTITY_LIMITATION] : []),
"JavaScript syntax was parsed as data and was never evaluated.",
];
return {
parse_status:
parserErrors > 0 ||
accumulator.unknownFindings > 0 ||
bindings.valueResourceLimits.has("alias-selections")
? "partial"
: "complete",
parse_status: javaScriptStaticParseStatus(coverage),
analysis_coverage: coverage,
parse_error_count: parserErrors,
visited_ast_nodes: accumulator.visitedNodes,
references: finalizeLocatedFindings(
@@ -23,10 +23,17 @@ import {
compareUnicodeCodePoints,
compositeKey,
} from "../unicodeCodePointOrder.js";
import { unexaminedJavaScriptStaticCoverage } from "./javascriptStaticCoverage.js";
/** Explicit result for source text that Babel cannot parse. */
export const failedJavaScriptStaticAnalysis = (): JavaScriptStaticAnalysis => ({
parse_status: "failed",
analysis_coverage: {
...unexaminedJavaScriptStaticCoverage(
"JavaScript source could not be parsed.",
),
syntax: { status: "failed", error_count: null },
},
parse_error_count: 1,
visited_ast_nodes: 0,
references: [],
@@ -1,5 +1,6 @@
import type { ElectronStaticFindings } from "./electronStaticAnalysisTypes.js";
import type { JavaScriptRouteSourceFacts } from "./javascriptRouteFacts.js";
import type { JavaScriptStaticCoverage } from "./javascriptStaticCoverage.js";
/** Token semantics shared by bundle producers and worker admission. */
export const JAVASCRIPT_AST_FINGERPRINT_ALGORITHM = "babel-ast-v3";
@@ -124,7 +125,10 @@ export interface JavaScriptRolePath {
/** Deterministic AST-only analysis of one JavaScript source file. */
export interface JavaScriptStaticAnalysis {
/** Established overall summary; syntax alone is reported in analysis_coverage. */
readonly parse_status: "complete" | "partial" | "failed";
/** Historical facts omit this measurement; consumers must not infer it. */
readonly analysis_coverage?: JavaScriptStaticCoverage;
readonly parse_error_count: number;
readonly visited_ast_nodes: number;
readonly references: readonly JavaScriptStaticReference[];
@@ -0,0 +1,106 @@
import { expect, it } from "vitest";
import { analyzeJavaScriptStaticSource } from "./javascriptStaticAnalysis.js";
import {
javaScriptStaticParseStatus,
unexaminedJavaScriptStaticCoverage,
} from "./javascriptStaticCoverage.js";
import { aliasSelectionBudgetSource } from "../../../tests/fixtures/javascriptAliasSelectionBudget.js";
it("separates dynamic semantic uncertainty from completed syntax and examination", () => {
const result = analyzeJavaScriptStaticSource(
"const {ipcMain}=require('electron'); ipcMain.on(channel, () => {});",
);
expect(result.parse_status).toBe("partial");
expect(result.analysis_coverage).toMatchObject({
syntax: { status: "complete", error_count: 0 },
semantics: { unknown_findings: 1, uncertainty: ["dynamic-findings"] },
examination: {
status: "complete",
semantic_resource_limits: [],
electron_call_paths_limited: false,
},
applicability: { electron: "observed" },
});
expect(result.electron.ipc).toMatchObject([
{ channel: null, channel_expression: "channel" },
]);
});
it("distinguishes recovered syntax from unparseable source without inventing an error total", () => {
const recovered = analyzeJavaScriptStaticSource("let value; let value;");
expect(recovered.parse_status).toBe("partial");
expect(recovered.analysis_coverage?.syntax).toEqual({
status: "recovered",
error_count: recovered.parse_error_count,
});
const failed = analyzeJavaScriptStaticSource("const value = ;");
expect(failed.parse_status).toBe("failed");
expect(failed.analysis_coverage).toMatchObject({
syntax: { status: "failed", error_count: null },
semantics: { unknown_findings: null },
examination: { status: "not-examined" },
});
});
it("keeps framework applicability unknown without positive Electron evidence", () => {
const ordinary = analyzeJavaScriptStaticSource("export const value = 1;");
expect(ordinary.parse_status).toBe("complete");
expect(ordinary.analysis_coverage?.applicability.electron).toBe("unknown");
const electron = analyzeJavaScriptStaticSource(
"const {ipcMain}=require('electron');",
);
expect(electron.analysis_coverage?.applicability.electron).toBe("observed");
});
it("reports compiler-dependent module side effects independently of complete syntax", () => {
const result = analyzeJavaScriptStaticSource(
"import { type Config } from './config';",
);
expect(result.analysis_coverage?.syntax).toEqual({
status: "complete",
error_count: 0,
});
expect(result.analysis_coverage?.semantics.uncertainty).toContain(
"type-only-module-side-effect",
);
});
it("retains typed examination limits alongside successfully parsed source", () => {
const result = analyzeJavaScriptStaticSource(aliasSelectionBudgetSource());
expect(result.parse_status).toBe("partial");
expect(result.analysis_coverage).toMatchObject({
syntax: { status: "complete", error_count: 0 },
examination: {
status: "limited",
semantic_resource_limits: ["alias-selections"],
},
});
});
it("preserves the legacy summary responsibility without relabeling independent limitations", () => {
const base = analyzeJavaScriptStaticSource(
"export const value = 1;",
).analysis_coverage!;
expect(
javaScriptStaticParseStatus({
...base,
semantics: {
unknown_findings: 0,
uncertainty: ["returned-reference-widening"],
},
examination: {
...base.examination,
status: "limited",
electron_call_paths_limited: true,
},
}),
).toBe("complete");
expect(
unexaminedJavaScriptStaticCoverage("Caller selected another source."),
).toMatchObject({
syntax: { status: "not-examined", error_count: null },
semantics: { unknown_findings: null },
examination: { status: "not-examined" },
unexamined_reason: "Caller selected another source.",
});
});
@@ -0,0 +1,72 @@
import { z } from "zod";
import { javaScriptSemanticResourceLimitSchema } from "./javascriptSemanticValueTypes.js";
/** Independent observations from one inert static pass; no runtime completeness claim. */
export const javaScriptStaticCoverageSchema = z.strictObject({
syntax: z.discriminatedUnion("status", [
z.strictObject({
status: z.literal("complete"),
error_count: z.literal(0),
}),
z.strictObject({
status: z.literal("recovered"),
error_count: z.int().positive(),
}),
z.strictObject({ status: z.literal("failed"), error_count: z.null() }),
z.strictObject({
status: z.literal("not-examined"),
error_count: z.null(),
}),
]),
semantics: z.strictObject({
unknown_findings: z.int().nonnegative().nullable(),
uncertainty: z.array(
z.enum([
"dynamic-findings",
"returned-reference-widening",
"type-only-module-side-effect",
]),
),
}),
examination: z.strictObject({
status: z.enum(["complete", "limited", "not-examined"]),
semantic_resource_limits: z.array(javaScriptSemanticResourceLimitSchema),
electron_call_paths_limited: z.boolean(),
}),
applicability: z.strictObject({ electron: z.enum(["observed", "unknown"]) }),
unexamined_reason: z.string().min(1).exactOptional(),
});
export type JavaScriptStaticCoverage = z.infer<
typeof javaScriptStaticCoverageSchema
>;
/** Preserve the established conservative summary, independently of finer facts. */
export const javaScriptStaticParseStatus = (
coverage: JavaScriptStaticCoverage,
): "complete" | "partial" | "failed" =>
coverage.syntax.status === "failed" ||
coverage.syntax.status === "not-examined"
? "failed"
: coverage.syntax.status === "recovered" ||
(coverage.semantics.unknown_findings ?? 0) > 0 ||
coverage.examination.semantic_resource_limits.includes(
"alias-selections",
)
? "partial"
: "complete";
/** Unperformed work has no measured syntax, finding count or framework applicability. */
export const unexaminedJavaScriptStaticCoverage = (
reason: string,
): JavaScriptStaticCoverage => ({
syntax: { status: "not-examined", error_count: null },
semantics: { unknown_findings: null, uncertainty: [] },
examination: {
status: "not-examined",
semantic_resource_limits: [],
electron_call_paths_limited: false,
},
applicability: { electron: "unknown" },
unexamined_reason: reason,
});