2026-10-08 05:51:14 +08:00
import type { ArtifactInventorySnapshot } from "../../artifacts/inventory/ArtifactInventory.js" ;
2026-07-16 05:29:40 +08:00
import {
createJavaScriptApplicationGraph ,
2026-10-09 02:40:21 +08:00
createImmutableJavaScriptApplicationGraphSteps ,
2026-07-16 05:29:40 +08:00
type JavaScriptApplicationGraph ,
2026-10-07 17:16:58 +08:00
} from "../../domain/javascript/javascriptApplicationGraph.js" ;
2026-10-08 16:15:35 +08:00
import type { JavaScriptModuleArtifactAnalysis } from "./JavaScriptArtifactAnalysisTypes.js" ;
2026-10-07 17:57:33 +08:00
import type { JavaScriptArtifactFileSet } from "../../domain/javascript/javascriptArtifactFiles.js" ;
2026-07-16 05:29:40 +08:00
import { JavaScriptArtifactGraphAccumulator } from "./JavaScriptArtifactGraphAccumulator.js" ;
2026-09-29 14:53:50 +08:00
import type { JavaScriptArtifactGraphContext } from "./JavaScriptArtifactGraphContext.js" ;
2026-07-16 05:29:40 +08:00
import {
addJavaScriptHtmlRoles ,
addJavaScriptSourceMapOriginals ,
} from "./JavaScriptArtifactGraphDocuments.js" ;
import { addJavaScriptStaticFindings } from "./JavaScriptArtifactGraphFindings.js" ;
2026-07-17 23:57:23 +08:00
import {
addJavaScriptModuleRelationships ,
2026-10-09 01:10:38 +02:00
type JavaScriptModuleRelationshipOmissions ,
2026-07-17 23:57:23 +08:00
addJavaScriptSourceModules ,
} from "./JavaScriptModuleRelationships.js" ;
2026-07-16 05:29:40 +08:00
import {
2026-08-10 14:57:44 +08:00
completeApplicationCoverage ,
partialApplicationCoverage ,
2026-10-07 17:16:58 +08:00
} from "../../domain/javascript/javascriptApplicationEvidenceSchemas.js" ;
2026-10-09 00:20:48 +08:00
import type { JavaScriptSemanticResourceLimit } from "../../domain/javascript/javascriptSemanticValueTypes.js" ;
import { semanticCoverageResourceLimits } from "../../domain/javascript/javascriptSemanticCoverage.js" ;
import {
SEMANTIC_EXPRESSION_DEPTH_LIMIT ,
SEMANTIC_PRIMITIVE_CANDIDATE_LIMIT ,
2026-10-09 00:40:22 +08:00
SEMANTIC_PRIMITIVE_JSON_BYTES_LIMIT ,
2026-10-09 00:20:48 +08:00
semanticResourceLimitReason ,
} from "../../domain/javascript/javascriptSemanticResourceLimits.js" ;
2026-07-16 05:29:40 +08:00
import {
addJavaScriptArtifactContainers ,
addJavaScriptArtifactFiles ,
addJavaScriptBundlerNodes ,
addJavaScriptPackageNodes ,
createJavaScriptArtifactRootNode ,
} from "./JavaScriptArtifactGraphStructure.js" ;
2026-07-16 06:45:34 +08:00
import { addElectronBoundaries } from "./ElectronBoundaryGraph.js" ;
import {
classifyElectronIpcPairings ,
collectElectronIpcRecords ,
} from "./ElectronBoundaryAnalysis.js" ;
2026-07-16 05:29:40 +08:00
2026-09-29 14:53:50 +08:00
/** Project artifact and AST facts into JavaScript Application Graph. */
2026-07-16 05:29:40 +08:00
export const buildJavaScriptArtifactGraph = (
snapshot : ArtifactInventorySnapshot ,
fileSet : JavaScriptArtifactFileSet ,
2026-10-08 16:15:35 +08:00
analysis : JavaScriptModuleArtifactAnalysis ,
2026-10-09 02:40:21 +08:00
) : JavaScriptApplicationGraph =>
createJavaScriptApplicationGraph (
buildJavaScriptArtifactGraphInput ( snapshot , fileSet , analysis ),
);
/** Build a validated application graph with cooperative immutable ownership. */
export const buildImmutableJavaScriptArtifactGraphSteps = (
snapshot : ArtifactInventorySnapshot ,
fileSet : JavaScriptArtifactFileSet ,
analysis : JavaScriptModuleArtifactAnalysis ,
) : Generator < void , JavaScriptApplicationGraph > =>
createImmutableJavaScriptApplicationGraphSteps (
buildJavaScriptArtifactGraphInput ( snapshot , fileSet , analysis ),
);
const buildJavaScriptArtifactGraphInput = (
snapshot : ArtifactInventorySnapshot ,
fileSet : JavaScriptArtifactFileSet ,
analysis : JavaScriptModuleArtifactAnalysis ,
) : unknown => {
2026-07-16 05:29:40 +08:00
const accumulator = new JavaScriptArtifactGraphAccumulator ();
const root = createJavaScriptArtifactRootNode ( accumulator , snapshot );
const context : JavaScriptArtifactGraphContext = {
accumulator ,
snapshot ,
fileSet ,
analysis ,
root ,
filesByPath : new Map ( fileSet . files . map (( file ) => [ file . path , file ])),
fileNodes : new Map (),
assetNodes : new Map (),
2026-07-17 23:57:23 +08:00
sourceModuleNodes : new Map (),
2026-07-18 00:31:51 +08:00
chunkNodes : new Map (),
2026-07-16 05:29:40 +08:00
moduleNodes : new Map (),
containerNodes : new Map ([[ snapshot . manifest . root_sha256 , root ]]),
};
addJavaScriptArtifactContainers ( context );
addJavaScriptArtifactFiles ( context );
const packageRoots = addJavaScriptPackageNodes ( context );
2026-07-17 23:57:23 +08:00
addJavaScriptSourceModules ( context );
2026-10-09 09:37:37 +08:00
const bundlerLimitations = addJavaScriptBundlerNodes ( context );
2026-10-09 01:10:38 +02:00
const relationshipOmissions = addJavaScriptModuleRelationships ( context );
2026-07-16 05:29:40 +08:00
addJavaScriptStaticFindings ( context );
2026-07-16 06:45:34 +08:00
addElectronBoundaries ( context );
2026-07-16 05:29:40 +08:00
addJavaScriptHtmlRoles ( context );
addJavaScriptSourceMapOriginals ( context );
const coverage = graphCoverage ( context );
2026-10-09 02:40:21 +08:00
return {
2026-07-16 05:29:40 +08:00
schema : "JavaScriptApplicationGraph" ,
root_node_ids :
packageRoots.length === 0
? [ root . node_id ]
: packageRoots . map (({ node_id : id }) => id ),
nodes : accumulator.nodes (),
edges : accumulator.edges (),
coverage ,
2026-10-09 09:37:37 +08:00
limitations : [
... bundlerLimitations ,
... graphLimitations ( context , coverage . status , relationshipOmissions ),
],
2026-10-09 02:40:21 +08:00
};
2026-07-16 05:29:40 +08:00
};
const graphCoverage = ( context : JavaScriptArtifactGraphContext ) => {
2026-10-09 00:20:48 +08:00
const resourceLimits = semanticResourceLimits ( context );
2026-07-16 05:29:40 +08:00
const sourceMapPolicyGap = context . analysis . source_maps . some (
2026-09-29 07:08:46 +08:00
({ status }) => status === "invalid" ,
2026-07-16 05:29:40 +08:00
);
const malformedStructuredData =
context . analysis . packages . some (({ status }) => status !== "included" ) ||
2026-07-17 23:57:23 +08:00
context . analysis . json_modules . some (({ status }) => status !== "included" ) ||
2026-07-16 05:29:40 +08:00
context . analysis . source_maps . some (({ status }) => status === "invalid" );
2026-07-16 06:45:34 +08:00
const partialJavaScript = context . analysis . files . some (
({ javascript }) =>
javascript !== null && javascript . parse_status === "partial" ,
);
2026-07-16 05:29:40 +08:00
const unknownGap =
context . analysis . parse_failures > 0 ||
context . fileSet . invalid_utf8_files > 0 ||
sourceMapPolicyGap ||
2026-07-16 06:45:34 +08:00
malformedStructuredData ||
partialJavaScript ;
2026-07-16 05:29:40 +08:00
if ( context . analysis . truncated_scopes > 0 )
2026-09-29 14:53:50 +08:00
return partialApplicationCoverage ([], null );
2026-10-09 00:20:48 +08:00
if ( resourceLimits . length > 0 )
return partialApplicationCoverage (
resourceLimits . map ( applicationGraphResourceLimit ),
null ,
);
2026-09-29 14:53:50 +08:00
if ( unknownGap ) return partialApplicationCoverage ([], null );
return completeApplicationCoverage ();
2026-07-17 23:57:23 +08:00
};
2026-10-09 00:20:48 +08:00
const semanticResourceLimits = (
context : JavaScriptArtifactGraphContext ,
) : JavaScriptSemanticResourceLimit [] =>
[
... new Set (
context . analysis . files . flatMap (({ semantic }) =>
semantic === null
? []
: semanticCoverageResourceLimits ( semantic . ir . coverage ),
),
),
]. sort ();
const applicationGraphResourceLimit = (
resourceLimit : JavaScriptSemanticResourceLimit ,
) => ({
name : `javascript_semantic_ ${ resourceLimit . replaceAll ( "-" , "_" ) } ` ,
value :
resourceLimit === "primitive-candidates"
? SEMANTIC_PRIMITIVE_CANDIDATE_LIMIT
2026-10-09 00:40:22 +08:00
: resourceLimit === "primitive-bytes"
? SEMANTIC_PRIMITIVE_JSON_BYTES_LIMIT
: SEMANTIC_EXPRESSION_DEPTH_LIMIT ,
2026-10-09 00:20:48 +08:00
unit :
resourceLimit === "expression-depth"
? ( "depth" as const )
2026-10-09 00:40:22 +08:00
: resourceLimit === "primitive-bytes"
? ( "bytes" as const )
: ( "items" as const ),
2026-10-09 00:20:48 +08:00
});
2026-07-16 05:29:40 +08:00
const graphLimitations = (
context : JavaScriptArtifactGraphContext ,
coverage : "complete" | "partial" | "unknown" | "unavailable" ,
2026-10-09 01:10:38 +02:00
relationshipOmissions : JavaScriptModuleRelationshipOmissions ,
2026-07-16 06:45:34 +08:00
) : string [] => {
const ipc = collectElectronIpcRecords ( context . analysis );
const pairings = classifyElectronIpcPairings ( ipc );
const electronFindings = context . analysis . files . reduce (
( count , { javascript }) =>
count +
( javascript === null
? 0
: javascript.electron.browser_windows.length +
javascript . electron . context_bridge_apis . length +
javascript . electron . ipc . length +
javascript . electron . sender_validations . length +
javascript . electron . utility_processes . length +
javascript . electron . native_addon_bindings . length ),
0 ,
);
return [
... context . analysis . limitations ,
2026-10-09 01:10:38 +02:00
...( relationshipOmissions . selfImports > 0
? [
` ${ String ( relationshipOmissions . selfImports ) } import ${ relationshipOmissions . selfImports === 1 ? "specifier" : "specifiers" } resolved back to the importing module itself and ${ relationshipOmissions . selfImports === 1 ? "was" : "were" } omitted; application graph edges cannot be self-referential.` ,
]
: []),
2026-07-17 23:57:23 +08:00
"CommonJS and ESM binding relationships were recovered from inert syntax and resolved only within the inventoried artifact container." ,
2026-07-16 06:45:34 +08:00
"Webpack/Rspack factories were recovered from AST literals; REA did not invoke push handlers or bundle bootstrap code." ,
"Static imports, entrypoints, workers, endpoints, and storage relationships do not prove runtime execution." ,
...( electronFindings === 0
? []
: [
"Electron relationships are derived from inert syntax; runtime registration, reachability, defaults, and enforcement remain unproven." ,
]),
...( ipc . some (({ finding }) => finding . channel === null )
? [
"Dynamic IPC channel expressions remain unresolved and are never paired by textual similarity." ,
]
: []),
...( pairings . some (({ status }) => status === "ambiguous" )
? [
"Some literal IPC channels have multiple compatible main handlers; ambiguous calls are not paired to any handler." ,
]
: []),
...( context . analysis . files . some (
({ javascript }) =>
( javascript ? . electron . sender_validations . length ?? 0 ) > 0 ,
)
? [
"Sender, frame, URL, and origin checks are observations only; REA does not claim that they enforce a complete authorization policy." ,
]
: []),
2026-10-09 00:20:48 +08:00
... semanticResourceLimits ( context ). map ( semanticResourceLimitReason ),
2026-07-16 06:45:34 +08:00
...( context . analysis . files . some (
({ javascript }) =>
( javascript ? . electron . native_addon_bindings . length ?? 0 ) > 0 ,
)
? [
"Native member names are requested by JavaScript syntax and are not verified binary exports in this workflow." ,
]
: []),
...( coverage === "complete"
? []
: [
"Graph coverage is incomplete; unavailable facts remain explicit and must not be read as absence." ,
]),
];
};