fix(javascript): complete large-ASAR analysis with file-local projection (#1055)

This commit is contained in:
Ysopwnable authored and GitHub committed 2026-10-08 16:15:35 +08:00
1 parent 7af7bc88ce
commit b9fb438835
27 files changed
+1231 -631

No files matched your search

@@ -4,6 +4,7 @@ import { javascriptDisplayText } from "../../domain/javascript/javascriptAstValu
import {
createJavaScriptSemanticGraphNode,
createJavaScriptSemanticGraphRelation,
javaScriptSemanticNodeId,
type JavaScriptSemanticGraphNode,
} from "../../domain/javascript/javascriptSemanticGraph.js";
import type { ApplicationGraphEvidence } from "../../domain/javascript/javascriptApplicationEvidenceSchemas.js";
@@ -80,6 +81,28 @@ export const createSemanticGraphProjectionState = (
};
};
/** Bind retained semantic identities after all application observations exist. */
export const bindSemanticGraphApplicationNodes = (
state: SemanticGraphProjectionState,
applicationGraph: Pick<JavaScriptApplicationGraph, "nodes">,
): void => {
const index = indexApplicationNodes(applicationGraph.nodes).identifiers;
for (const [identifier, node] of state.nodes) {
state.nodes.set(identifier, {
...node,
application_node_ids: [
...(index.get(
applicationLocationKey(
node.identity.artifact_sha256,
node.identity.module_path,
node.identity.source_range,
),
) ?? []),
],
});
}
};
/** Construct one canonical semantic node backed by an exact artifact file. */
export const constructSemanticGraphNode = (
file: JavaScriptArtifactFile,
@@ -101,6 +124,33 @@ export const constructSemanticGraphNode = (
evidence: observedSemanticEvidence(file, input.location),
});
/** Reuse retained identities and reject exhausted budgets before allocation. */
export const retainSemanticGraphNode = (
state: SemanticGraphProjectionState,
file: JavaScriptArtifactFile,
input: SemanticNodeConstructionInput,
): JavaScriptSemanticGraphNode | null => {
const identifier = javaScriptSemanticNodeId({
kind: input.kind,
identity: {
artifact_sha256: file.sha256,
module_path: file.path,
source_range: input.location,
role_key: input.roleKey,
},
});
const existing = state.nodes.get(identifier);
if (existing !== undefined) return existing;
if (typeof state.fileNodeBudget === "number" && state.fileNodeBudget <= 0) {
state.fileNodesDropped = true;
return null;
}
return addSemanticGraphNode(
state,
constructSemanticGraphNode(file, input, state),
);
};
/** Retain one canonical semantic node. */
export const addSemanticGraphNode = (
state: SemanticGraphProjectionState,