rea-agents 2.1.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -18
- package/dist/application/AndroidApplicationService.js +17 -0
- package/dist/application/AppleApplicationService.js +17 -0
- package/dist/application/ApplicationWorkflowEvidenceResolver.js +162 -0
- package/dist/application/BinarySession.js +9 -2
- package/dist/application/BinarySessionStatus.js +39 -1
- package/dist/application/CapabilityInventory.js +15 -0
- package/dist/application/ClientRegistrationStatus.js +11 -4
- package/dist/application/CommandShimReplay.js +6 -3
- package/dist/application/CompositeProvider.js +5 -2
- package/dist/application/DirectAnalysis.js +1 -20
- package/dist/application/DirectAnalysisStatus.js +83 -0
- package/dist/application/Doctor.js +34 -25
- package/dist/application/DoctorDiagnostics.js +1 -4
- package/dist/application/DoctorProjection.js +43 -0
- package/dist/application/DoctorScope.js +102 -0
- package/dist/application/EvidenceReferenceResolver.js +26 -0
- package/dist/application/InventoryProjectionEvidence.js +41 -0
- package/dist/application/InvestigationProviders.js +12 -0
- package/dist/application/JavaScriptApplicationEvidence.js +1 -1
- package/dist/application/JavaScriptApplicationEvidenceGraph.js +10 -1
- package/dist/application/JavaScriptApplicationService.js +3 -2
- package/dist/application/JavaScriptApplicationWorkflowEvidence.js +26 -0
- package/dist/application/JavaScriptApplicationWorkflowService.js +49 -1
- package/dist/application/JavaScriptArtifactReconstruction.js +7 -0
- package/dist/application/JavaScriptModuleRelationships.js +25 -1
- package/dist/application/JavaScriptReturnShapeProjection.js +111 -0
- package/dist/application/JavaScriptSemanticGraphBuilder.js +294 -0
- package/dist/application/JavaScriptSemanticGraphConstruction.js +144 -0
- package/dist/application/JavaScriptSemanticGraphEvidence.js +86 -0
- package/dist/application/JavaScriptSemanticGraphFlowProjection.js +72 -0
- package/dist/application/JavaScriptSemanticGraphProjection.js +33 -0
- package/dist/application/JavaScriptSemanticTraceService.js +45 -0
- package/dist/application/LoopbackReplay.js +277 -133
- package/dist/application/LoopbackReplayRecorder.js +101 -0
- package/dist/application/PermissionAuthority.js +7 -3
- package/dist/application/ProcessCaptureJournal.js +95 -0
- package/dist/application/ProcessCaptureLifecycle.js +24 -13
- package/dist/application/ProcessCheckpoints.js +30 -4
- package/dist/application/ProcessCli.js +26 -4
- package/dist/application/ProcessHarness.js +20 -50
- package/dist/application/ProcessNormalization.js +3 -2
- package/dist/application/ProcessPairedExperiment.js +72 -0
- package/dist/application/ProcessReactiveCoordinator.js +218 -0
- package/dist/application/ProcessReactiveEffects.js +133 -0
- package/dist/application/ProcessReactiveObservations.js +20 -0
- package/dist/application/ProcessSampling.js +2 -0
- package/dist/application/SessionProviderRouter.js +7 -6
- package/dist/application/Setup.js +14 -13
- package/dist/application/SetupClientConfiguration.js +10 -6
- package/dist/application/SetupPlan.js +4 -3
- package/dist/application/SetupRegistrationEnvironment.js +12 -0
- package/dist/application/SetupSkill.js +44 -40
- package/dist/application/TerminalRenderer.js +3 -1
- package/dist/application/Uninstall.js +7 -1
- package/dist/application/Upgrade.js +16 -1
- package/dist/browser/CdpEndpoint.js +37 -4
- package/dist/catalogIdentity.js +16 -7
- package/dist/cli/coreAnalysisCommands.js +34 -2
- package/dist/cli/javascriptApplicationAnalysis.js +19 -0
- package/dist/cli/setupCommands.js +84 -30
- package/dist/cli/utilityCommands.js +10 -2
- package/dist/cliApplicationCommands.js +79 -16
- package/dist/cliCommandNames.js +3 -0
- package/dist/cliElectronCommands.js +23 -33
- package/dist/cliObservationOptions.js +1 -1
- package/dist/cliOutput.js +56 -0
- package/dist/cliProcessCommands.js +32 -1
- package/dist/cliSetup.js +55 -29
- package/dist/contracts/applicationToolContracts.js +54 -7
- package/dist/contracts/applicationWorkflowInputContracts.js +119 -0
- package/dist/contracts/electronToolContracts.js +73 -4
- package/dist/contracts/javascriptApplicationWorkflowExamples.js +32 -9
- package/dist/contracts/managedToolContracts.js +7 -2
- package/dist/contracts/processCaptureExample.js +1 -0
- package/dist/contracts/replayMachineExample.js +37 -0
- package/dist/contracts/sessionStatusContract.js +26 -0
- package/dist/contracts/toolContractExamples.js +2 -0
- package/dist/contracts/toolContractTypes.js +12 -1
- package/dist/contracts/toolContracts.js +8 -11
- package/dist/contracts/toolEffects.js +3 -0
- package/dist/contracts/toolOutputSchemaGroups.js +53 -9
- package/dist/contracts/toolOutputSchemaPrimitives.js +73 -32
- package/dist/doctorRuntime.js +41 -0
- package/dist/domain/analysisErrorPresentation.js +5 -3
- package/dist/domain/analysisErrorProjection.js +7 -1
- package/dist/domain/androidApplication.js +206 -0
- package/dist/domain/appleApplication.js +221 -0
- package/dist/domain/boundedCartesianProjection.js +15 -0
- package/dist/domain/changedBehavior.js +5 -4
- package/dist/domain/completionLedgerGeneration.js +190 -0
- package/dist/domain/errors.js +4 -2
- package/dist/domain/evidenceCompletionLedger.js +113 -0
- package/dist/domain/hopperStartupFailure.js +9 -0
- package/dist/domain/javascriptApplicationAnalysis.js +44 -2
- package/dist/domain/javascriptExportShapeComparison.js +145 -0
- package/dist/domain/javascriptExportShapeComparisonIdentity.js +11 -0
- package/dist/domain/javascriptExportShapeComparisonSchemas.js +277 -0
- package/dist/domain/javascriptExportShapeSelection.js +132 -0
- package/dist/domain/javascriptExportShapeVariants.js +272 -0
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +2 -2
- package/dist/domain/javascriptSemanticAnalysis.js +17 -36
- package/dist/domain/javascriptSemanticCallResolution.js +129 -0
- package/dist/domain/javascriptSemanticCalls.js +269 -0
- package/dist/domain/javascriptSemanticGraph.js +356 -0
- package/dist/domain/javascriptSemanticGraphSchemas.js +329 -0
- package/dist/domain/javascriptSemanticGraphSerialization.js +23 -0
- package/dist/domain/javascriptSemanticIr.js +14 -1
- package/dist/domain/javascriptSemanticPrimitives.js +36 -0
- package/dist/domain/javascriptSemanticProjection.js +36 -4
- package/dist/domain/javascriptSemanticProvenance.js +29 -0
- package/dist/domain/javascriptSemanticQuery.js +294 -0
- package/dist/domain/javascriptSemanticQueryAssessment.js +74 -0
- package/dist/domain/javascriptSemanticQueryIdentity.js +86 -0
- package/dist/domain/javascriptSemanticQueryRelations.js +15 -0
- package/dist/domain/javascriptSemanticQuerySchemas.js +188 -0
- package/dist/domain/javascriptSemanticReturns.js +187 -0
- package/dist/domain/javascriptSemanticState.js +32 -0
- package/dist/domain/javascriptSemanticTraceSchemas.js +14 -0
- package/dist/domain/javascriptSemanticValues.js +54 -70
- package/dist/domain/processCapture.js +36 -0
- package/dist/domain/processCaptureValidation.js +101 -12
- package/dist/domain/processComparison.js +96 -24
- package/dist/domain/processObservation.js +153 -0
- package/dist/domain/processPairedExperiment.js +128 -0
- package/dist/domain/processReactiveCheckpointDataflow.js +32 -0
- package/dist/domain/processReactiveMatching.js +210 -0
- package/dist/domain/processReactiveRuntime.js +109 -0
- package/dist/domain/processReactiveScenario.js +361 -0
- package/dist/domain/processReactiveScenarioPreflight.js +120 -0
- package/dist/domain/processReactiveTransition.js +159 -0
- package/dist/domain/processScenario.js +12 -0
- package/dist/domain/processTraceComparison.js +43 -0
- package/dist/domain/processTraceDimensionProjection.js +50 -0
- package/dist/domain/processTraceEvaluation.js +312 -0
- package/dist/domain/processTraceSpecification.js +373 -0
- package/dist/domain/reconstructionVerification.js +5 -4
- package/dist/domain/replayMachine.js +332 -0
- package/dist/domain/replayMachineRun.js +216 -0
- package/dist/domain/replayMachineRuntime.js +294 -0
- package/dist/domain/runtimeIdentification.js +210 -0
- package/dist/domain/staticRuntimeCorrelation.js +4 -2
- package/dist/evaluation/CodexAgentEval.js +156 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraClient.js +13 -2
- package/dist/ghidra/GhidraDiagnostics.js +1 -0
- package/dist/ghidra/GhidraLauncher.js +7 -3
- package/dist/ghidra/GhidraProvider.js +8 -1
- package/dist/hopper/BridgeLauncher.js +56 -14
- package/dist/hopper/HopperClient.js +23 -10
- package/dist/hopper/HopperDiagnostics.js +14 -0
- package/dist/hopper/HopperProcessDiagnostic.js +14 -0
- package/dist/hopper/HopperProvider.js +8 -1
- package/dist/hopper/LinuxPrivateDisplayDiagnostic.js +72 -0
- package/dist/hopper/LinuxPrivateDisplayProbe.js +217 -0
- package/dist/identity.js +2 -1
- package/dist/main/transport.js +2 -0
- package/dist/mcpDoctor.js +310 -0
- package/dist/process/ProcessOwnership.js +200 -53
- package/dist/process/ProviderRunLineage.js +21 -0
- package/dist/server/createServer.js +8 -2
- package/dist/server/javascriptApplicationResult.js +106 -0
- package/dist/server/registerApplicationTools/characterization.js +3 -3
- package/dist/server/registerApplicationTools/compareExportShapes.js +37 -0
- package/dist/server/registerApplicationTools/compareVersions.js +12 -6
- package/dist/server/registerApplicationTools/controlledReplay.js +2 -2
- package/dist/server/registerApplicationTools/coverage.js +3 -3
- package/dist/server/registerApplicationTools/helpers.js +37 -25
- package/dist/server/registerApplicationTools/traceFeature.js +9 -5
- package/dist/server/registerApplicationTools/traceSemantics.js +30 -0
- package/dist/server/registerApplicationTools.js +4 -0
- package/dist/server/registerElectronTools.js +19 -5
- package/dist/server/registerEvidenceResources.js +7 -1
- package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
- package/dist/server/registerManagedTools.js +18 -1
- package/dist/server/registerProcessComparisonTool.js +17 -7
- package/dist/server/registerReplayMachineTool.js +20 -0
- package/dist/server/registerSessionStatusTool.js +95 -25
- package/dist/server/registerSessionTools.js +12 -7
- package/dist/server/sessionAvailabilityPolicy.js +2 -1
- package/dist/server/toolResult.js +10 -4
- package/dist/serverIdentity.js +19 -0
- package/package.json +62 -29
- package/scripts/hopper-demo-x11.py +459 -61
- package/scripts/prepack.mjs +55 -0
- package/scripts/prepare.mjs +28 -0
- package/scripts/rea.mjs +26 -5
- package/skills/reverse-engineer-anything/SKILL.md +69 -228
- package/skills/reverse-engineer-anything/references/controlled-replay.md +12 -0
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +33 -0
- package/skills/reverse-engineer-anything/references/javascript-applications.md +35 -0
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
- package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
|
@@ -9,6 +9,7 @@ import { buildJavaScriptArtifactGraph } from "./JavaScriptArtifactGraphBuilder.j
|
|
|
9
9
|
import { artifactLimitsForReconstruction, javascriptArtifactReconstructionInputSchema, } from "./JavaScriptArtifactReconstructionInput.js";
|
|
10
10
|
import { scanCanonicalArtifactInventory } from "./ArtifactInventory.js";
|
|
11
11
|
import { summarizeElectronBoundaries } from "./ElectronBoundaryAnalysis.js";
|
|
12
|
+
import { buildJavaScriptSemanticGraph } from "./JavaScriptSemanticGraphBuilder.js";
|
|
12
13
|
/** Reconstruct one local ASAR or extracted directory without executing code. */
|
|
13
14
|
export const reconstructJavaScriptArtifact = async (rawInput, signal) => {
|
|
14
15
|
const input = javascriptArtifactReconstructionInputSchema.parse(rawInput);
|
|
@@ -24,6 +25,11 @@ export const reconstructJavaScriptArtifact = async (rawInput, signal) => {
|
|
|
24
25
|
const analysis = analyzeJavaScriptArtifactFiles(files, input, () => performance.now());
|
|
25
26
|
abortIfNeeded(signal);
|
|
26
27
|
const graph = buildJavaScriptArtifactGraph(snapshot, files, analysis, input);
|
|
28
|
+
const semanticGraph = buildJavaScriptSemanticGraph({
|
|
29
|
+
rootArtifactSha256: snapshot.manifest.root_sha256,
|
|
30
|
+
applicationGraph: graph,
|
|
31
|
+
analysis,
|
|
32
|
+
});
|
|
27
33
|
return {
|
|
28
34
|
input_path: path,
|
|
29
35
|
format,
|
|
@@ -31,6 +37,7 @@ export const reconstructJavaScriptArtifact = async (rawInput, signal) => {
|
|
|
31
37
|
inventory_manifest_id: snapshot.manifest.manifest_id,
|
|
32
38
|
inventory_graph_sha256: snapshot.manifest.graph_sha256,
|
|
33
39
|
graph,
|
|
40
|
+
semantic_graph: semanticGraph,
|
|
34
41
|
electron_summary: summarizeElectronBoundaries(analysis),
|
|
35
42
|
statistics: {
|
|
36
43
|
relevant_files: files.files.length,
|
|
@@ -2,6 +2,7 @@ import { posix } from "node:path";
|
|
|
2
2
|
import { addAstContainsEdge, artifactLocalIdentity, } from "./JavaScriptArtifactGraphContext.js";
|
|
3
3
|
import { astObservationEvidence, completeReconstructionCoverage, partialReconstructionCoverage, staticInferenceEvidence, } from "./JavaScriptArtifactGraphEvidence.js";
|
|
4
4
|
import { resolveArtifactPathByContext } from "./JavaScriptArtifactPathResolution.js";
|
|
5
|
+
import { projectJavaScriptExportReturnShapes } from "./JavaScriptReturnShapeProjection.js";
|
|
5
6
|
/** Create one path-scoped source-module identity for every analyzed source file. */
|
|
6
7
|
export const addJavaScriptSourceModules = (context) => {
|
|
7
8
|
for (const analyzed of context.analysis.files) {
|
|
@@ -76,6 +77,13 @@ const addExportRelationship = (input) => {
|
|
|
76
77
|
const { context, file, semantic, source, link } = input;
|
|
77
78
|
if (link.exportedName === null)
|
|
78
79
|
return;
|
|
80
|
+
const baseCoverage = semanticCoverage(semantic);
|
|
81
|
+
const returnShapes = projectJavaScriptExportReturnShapes({
|
|
82
|
+
ir: semantic.ir,
|
|
83
|
+
link,
|
|
84
|
+
modulePath: file.path,
|
|
85
|
+
baseCoverage,
|
|
86
|
+
});
|
|
79
87
|
const exported = context.accumulator.addNode({
|
|
80
88
|
kind: "javascript-module",
|
|
81
89
|
identity: artifactLocalIdentity(file.sha256, "module-export", `${file.container_sha256}:${file.path}:${link.exportedName}`),
|
|
@@ -96,10 +104,26 @@ const addExportRelationship = (input) => {
|
|
|
96
104
|
path: file.path,
|
|
97
105
|
range: link.location,
|
|
98
106
|
operation: "recover-module-export",
|
|
99
|
-
coverage:
|
|
107
|
+
coverage: baseCoverage,
|
|
100
108
|
limitations: semantic.ir.limitations,
|
|
101
109
|
}),
|
|
102
110
|
},
|
|
111
|
+
...(returnShapes === null
|
|
112
|
+
? []
|
|
113
|
+
: [
|
|
114
|
+
{
|
|
115
|
+
label: `${file.path}:${link.exportedName}:return-shapes`,
|
|
116
|
+
properties: returnShapes.properties,
|
|
117
|
+
evidence: staticInferenceEvidence({
|
|
118
|
+
sha256: file.sha256,
|
|
119
|
+
path: file.path,
|
|
120
|
+
range: returnShapes.range,
|
|
121
|
+
operation: "recover-export-return-shapes",
|
|
122
|
+
coverage: returnShapes.coverage,
|
|
123
|
+
limitations: returnShapes.limitations,
|
|
124
|
+
}),
|
|
125
|
+
},
|
|
126
|
+
]),
|
|
103
127
|
],
|
|
104
128
|
});
|
|
105
129
|
context.accumulator.addEdge({
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { jsonObjectSchema, jsonValueSchema } from "../domain/jsonValue.js";
|
|
2
|
+
import { flattenSemanticReturnValue } from "../domain/javascriptSemanticReturns.js";
|
|
3
|
+
import { partialReconstructionCoverage } from "./JavaScriptArtifactGraphEvidence.js";
|
|
4
|
+
const MAX_PROJECTED_RETURN_SHAPES = 32;
|
|
5
|
+
const MAX_PROJECTED_RETURN_FIELDS = 64;
|
|
6
|
+
const MAX_PROJECTED_PROPERTY_COVERAGE = 64;
|
|
7
|
+
/** Project one exact export/callable link into shallow bounded graph values. */
|
|
8
|
+
export const projectJavaScriptExportReturnShapes = (input) => {
|
|
9
|
+
if (input.link.callableId === null || input.link.exportedName === null)
|
|
10
|
+
return null;
|
|
11
|
+
const callable = input.ir.callables.find(({ callableId }) => callableId === input.link.callableId);
|
|
12
|
+
if (callable === undefined)
|
|
13
|
+
return null;
|
|
14
|
+
const projection = projectReturnSites(callable);
|
|
15
|
+
const projectionOmitted = projection.omittedSites +
|
|
16
|
+
projection.omittedFields +
|
|
17
|
+
projection.omittedCoverage;
|
|
18
|
+
const semanticOmitted = callable.returnCoverage.omittedCount;
|
|
19
|
+
const complete = input.baseCoverage.status === "complete" &&
|
|
20
|
+
callable.returnCoverage.status === "complete" &&
|
|
21
|
+
projectionOmitted === 0;
|
|
22
|
+
const coverage = complete
|
|
23
|
+
? input.baseCoverage
|
|
24
|
+
: partialReconstructionCoverage([
|
|
25
|
+
...input.baseCoverage.limits,
|
|
26
|
+
{
|
|
27
|
+
name: "return-shape-sites",
|
|
28
|
+
value: MAX_PROJECTED_RETURN_SHAPES,
|
|
29
|
+
unit: "items",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: "return-shape-fields",
|
|
33
|
+
value: MAX_PROJECTED_RETURN_FIELDS,
|
|
34
|
+
unit: "items",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "return-shape-property-coverage",
|
|
38
|
+
value: MAX_PROJECTED_PROPERTY_COVERAGE,
|
|
39
|
+
unit: "items",
|
|
40
|
+
},
|
|
41
|
+
], semanticOmitted === null ? null : semanticOmitted + projectionOmitted, callable.returnCoverage.status === "truncated" || projectionOmitted > 0);
|
|
42
|
+
const limitations = [
|
|
43
|
+
...input.ir.limitations,
|
|
44
|
+
"Return shapes are inferred from inert syntax and do not prove runtime behavior.",
|
|
45
|
+
...(callable.returnSites.length === 0
|
|
46
|
+
? [
|
|
47
|
+
"No direct return value was retained; runtime return behavior remains unknown.",
|
|
48
|
+
]
|
|
49
|
+
: []),
|
|
50
|
+
...(projectionOmitted > 0
|
|
51
|
+
? ["Return-shape graph projection reached explicit retention limits."]
|
|
52
|
+
: []),
|
|
53
|
+
];
|
|
54
|
+
return {
|
|
55
|
+
properties: jsonObjectSchema.parse({
|
|
56
|
+
semantic_role: "export-return-shapes",
|
|
57
|
+
module_path: input.modulePath,
|
|
58
|
+
exported_name: input.link.exportedName,
|
|
59
|
+
callable_id: callable.callableId,
|
|
60
|
+
callable_kind: callable.kind,
|
|
61
|
+
static_return_shapes: projection.shapes,
|
|
62
|
+
return_shape_coverage: {
|
|
63
|
+
status: callable.returnCoverage.status,
|
|
64
|
+
retained_return_sites: projection.shapes.length,
|
|
65
|
+
omitted_return_sites: semanticOmitted === null
|
|
66
|
+
? null
|
|
67
|
+
: semanticOmitted + projection.omittedSites,
|
|
68
|
+
omitted_fields: projection.omittedFields,
|
|
69
|
+
omitted_property_coverage: projection.omittedCoverage,
|
|
70
|
+
projection_complete: projectionOmitted === 0,
|
|
71
|
+
},
|
|
72
|
+
}),
|
|
73
|
+
range: callable.location,
|
|
74
|
+
coverage,
|
|
75
|
+
limitations,
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
const projectReturnSites = (callable) => {
|
|
79
|
+
let retainedFields = 0;
|
|
80
|
+
let retainedCoverage = 0;
|
|
81
|
+
let omittedFields = 0;
|
|
82
|
+
let omittedCoverage = 0;
|
|
83
|
+
const retainedSites = callable.returnSites.slice(0, MAX_PROJECTED_RETURN_SHAPES);
|
|
84
|
+
const shapes = retainedSites.map((site) => {
|
|
85
|
+
const flattened = flattenSemanticReturnValue(site.value);
|
|
86
|
+
const remainingFields = Math.max(0, MAX_PROJECTED_RETURN_FIELDS - retainedFields);
|
|
87
|
+
const fields = flattened.fields.slice(0, remainingFields).map((field) => ({
|
|
88
|
+
...field,
|
|
89
|
+
value: jsonValueSchema.parse(field.value),
|
|
90
|
+
}));
|
|
91
|
+
retainedFields += fields.length;
|
|
92
|
+
omittedFields += flattened.fields.length - fields.length;
|
|
93
|
+
const remainingCoverage = Math.max(0, MAX_PROJECTED_PROPERTY_COVERAGE - retainedCoverage);
|
|
94
|
+
const propertyCoverage = flattened.propertyCoverage.slice(0, remainingCoverage);
|
|
95
|
+
retainedCoverage += propertyCoverage.length;
|
|
96
|
+
omittedCoverage +=
|
|
97
|
+
flattened.propertyCoverage.length - propertyCoverage.length;
|
|
98
|
+
return {
|
|
99
|
+
source_range: site.location,
|
|
100
|
+
value_status: site.value.status,
|
|
101
|
+
fields,
|
|
102
|
+
property_coverage: propertyCoverage,
|
|
103
|
+
};
|
|
104
|
+
});
|
|
105
|
+
return {
|
|
106
|
+
shapes,
|
|
107
|
+
omittedSites: callable.returnSites.length - retainedSites.length,
|
|
108
|
+
omittedFields,
|
|
109
|
+
omittedCoverage,
|
|
110
|
+
};
|
|
111
|
+
};
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { createJavaScriptSemanticGraph, } from "../domain/javascriptSemanticGraph.js";
|
|
2
|
+
import { JAVASCRIPT_SEMANTIC_RELATION_FAMILIES, JAVASCRIPT_SEMANTIC_RELATION_FAMILY, } from "../domain/javascriptSemanticGraphSchemas.js";
|
|
3
|
+
import { inferredSemanticEvidenceAt } from "./JavaScriptSemanticGraphEvidence.js";
|
|
4
|
+
import { projectSemanticClosureCaptures, projectSemanticFrontiers, projectSemanticReturnValues, semanticRecoveryLimits, } from "./JavaScriptSemanticGraphFlowProjection.js";
|
|
5
|
+
import { owningSemanticCallableNode, semanticFamilyStatus, semanticNodesWithinRange, semanticRangesEqual as rangesEqual, } from "./JavaScriptSemanticGraphProjection.js";
|
|
6
|
+
import { addSemanticFallbackRoot as addFallbackRoot, addSemanticGraphNode as addNode, addSemanticGraphRelation as addRelation, constructSemanticGraphNode as semanticNode, createSemanticGraphProjectionState as emptyState, MAX_APPLICATION_NODE_IDS_PER_SEMANTIC_NODE, MAX_SEMANTIC_GRAPH_NODES, MAX_SEMANTIC_GRAPH_RELATIONS, MAX_SEMANTIC_GRAPH_UNKNOWNS, } from "./JavaScriptSemanticGraphConstruction.js";
|
|
7
|
+
/** Project bounded per-file semantic IR into an artifact-bound companion graph. */
|
|
8
|
+
export const buildJavaScriptSemanticGraph = ({ rootArtifactSha256, applicationGraph, analysis, }) => {
|
|
9
|
+
const state = emptyState(applicationGraph);
|
|
10
|
+
for (const analyzed of analysis.files) {
|
|
11
|
+
if (analyzed.semantic === null)
|
|
12
|
+
continue;
|
|
13
|
+
projectFile(analyzed.file, analyzed.semantic.ir, state);
|
|
14
|
+
}
|
|
15
|
+
if (state.roots.size === 0)
|
|
16
|
+
addFallbackRoot(rootArtifactSha256, state);
|
|
17
|
+
const semanticTruncated = analysis.files.some(({ semantic }) => semantic?.ir.coverage.status === "truncated");
|
|
18
|
+
const truncated = state.limitsReached.size > 0 || semanticTruncated;
|
|
19
|
+
const unknowns = [...state.unknowns.values()];
|
|
20
|
+
return createJavaScriptSemanticGraph({
|
|
21
|
+
schema: "JavaScriptSemanticRelationGraph",
|
|
22
|
+
schema_version: 1,
|
|
23
|
+
root_artifact_sha256: rootArtifactSha256,
|
|
24
|
+
application_graph_id: applicationGraph.graph_id,
|
|
25
|
+
root_node_ids: [...state.roots],
|
|
26
|
+
nodes: [...state.nodes.values()],
|
|
27
|
+
relations: [...state.relations.values()],
|
|
28
|
+
fingerprints: [],
|
|
29
|
+
unknowns,
|
|
30
|
+
coverage: {
|
|
31
|
+
status: truncated ? "partial" : "unknown",
|
|
32
|
+
truncated,
|
|
33
|
+
omitted_nodes: truncated ? null : 0,
|
|
34
|
+
omitted_relations: truncated ? null : 0,
|
|
35
|
+
limits: [
|
|
36
|
+
{
|
|
37
|
+
name: "max_nodes",
|
|
38
|
+
value: MAX_SEMANTIC_GRAPH_NODES,
|
|
39
|
+
unit: "items",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "max_relations",
|
|
43
|
+
value: MAX_SEMANTIC_GRAPH_RELATIONS,
|
|
44
|
+
unit: "items",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "max_unknowns",
|
|
48
|
+
value: MAX_SEMANTIC_GRAPH_UNKNOWNS,
|
|
49
|
+
unit: "items",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "max_application_node_ids_per_semantic_node",
|
|
53
|
+
value: MAX_APPLICATION_NODE_IDS_PER_SEMANTIC_NODE,
|
|
54
|
+
unit: "items",
|
|
55
|
+
},
|
|
56
|
+
...semanticRecoveryLimits(analysis),
|
|
57
|
+
],
|
|
58
|
+
families: JAVASCRIPT_SEMANTIC_RELATION_FAMILIES.map((family) => ({
|
|
59
|
+
family,
|
|
60
|
+
status: semanticFamilyStatus(family, analysis, truncated),
|
|
61
|
+
retained_relations: [...state.relations.values()].filter((relation) => JAVASCRIPT_SEMANTIC_RELATION_FAMILY[relation.relation] === family).length,
|
|
62
|
+
omitted_relations: truncated ? null : 0,
|
|
63
|
+
unknown_ids: unknowns
|
|
64
|
+
.filter((unknown) => unknown.family === family)
|
|
65
|
+
.map(({ unknown_id: identifier }) => identifier),
|
|
66
|
+
})),
|
|
67
|
+
},
|
|
68
|
+
limitations: [
|
|
69
|
+
"The semantic graph contains static syntax observations and conservative relationship candidates; it does not claim runtime execution.",
|
|
70
|
+
"Local data flow does not claim control-flow-sensitive reaching definitions or arbitrary dynamic property resolution.",
|
|
71
|
+
"Function fingerprints and promise, event, process, request, boundary, timer, configuration, and resource extraction are not available in this graph version's current extractor coverage.",
|
|
72
|
+
...(truncated
|
|
73
|
+
? [
|
|
74
|
+
"Semantic graph projection reached one or more explicit hard limits.",
|
|
75
|
+
]
|
|
76
|
+
: []),
|
|
77
|
+
],
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
const projectFile = (file, ir, state) => {
|
|
81
|
+
const moduleNode = addNode(state, semanticNode(file, {
|
|
82
|
+
kind: "module",
|
|
83
|
+
roleKey: "module",
|
|
84
|
+
location: null,
|
|
85
|
+
label: file.path,
|
|
86
|
+
functionNodeId: null,
|
|
87
|
+
}, state));
|
|
88
|
+
if (moduleNode === null)
|
|
89
|
+
return;
|
|
90
|
+
state.roots.add(moduleNode.node_id);
|
|
91
|
+
const callableNodes = new Map(ir.callables.flatMap((callable) => {
|
|
92
|
+
const node = addNode(state, semanticNode(file, {
|
|
93
|
+
kind: "function",
|
|
94
|
+
roleKey: `callable:${callable.callableId}`,
|
|
95
|
+
location: callable.location,
|
|
96
|
+
label: callable.name,
|
|
97
|
+
functionNodeId: null,
|
|
98
|
+
}, state));
|
|
99
|
+
return node === null ? [] : [[callable.callableId, node]];
|
|
100
|
+
}));
|
|
101
|
+
const bindingNodes = new Map(ir.bindings.flatMap((binding) => {
|
|
102
|
+
const location = binding.definitions[0]?.location ?? null;
|
|
103
|
+
const kind = binding.kind === "parameter" ? "parameter" : "binding";
|
|
104
|
+
const owner = owningSemanticCallableNode(location, ir, callableNodes);
|
|
105
|
+
const node = addNode(state, semanticNode(file, {
|
|
106
|
+
kind,
|
|
107
|
+
roleKey: `binding:${binding.bindingId}`,
|
|
108
|
+
location,
|
|
109
|
+
label: binding.name,
|
|
110
|
+
functionNodeId: owner?.node_id ?? null,
|
|
111
|
+
}, state));
|
|
112
|
+
return node === null ? [] : [[binding.bindingId, node]];
|
|
113
|
+
}));
|
|
114
|
+
const returnSiteNodes = createReturnSiteNodes(file, ir, callableNodes, state);
|
|
115
|
+
const callSiteNodes = createCallSiteNodes(file, ir, callableNodes, state);
|
|
116
|
+
const context = {
|
|
117
|
+
file,
|
|
118
|
+
ir,
|
|
119
|
+
state,
|
|
120
|
+
moduleNode,
|
|
121
|
+
bindingNodes,
|
|
122
|
+
callableNodes,
|
|
123
|
+
callSiteNodes,
|
|
124
|
+
returnSiteNodes,
|
|
125
|
+
argumentNodes: new Map(),
|
|
126
|
+
referenceNodes: [],
|
|
127
|
+
callResolutions: new Map(ir.callSites.map((call) => [
|
|
128
|
+
call.callSiteId,
|
|
129
|
+
call.resolution === "exact" ? "resolved" : "candidate",
|
|
130
|
+
])),
|
|
131
|
+
};
|
|
132
|
+
projectDefinitionsAndReferences(context);
|
|
133
|
+
projectCalls(context);
|
|
134
|
+
projectSemanticClosureCaptures(context);
|
|
135
|
+
projectSemanticFrontiers(context);
|
|
136
|
+
};
|
|
137
|
+
const createReturnSiteNodes = (file, ir, callables, state) => {
|
|
138
|
+
const result = new Map();
|
|
139
|
+
for (const callable of ir.callables) {
|
|
140
|
+
const owner = callables.get(callable.callableId);
|
|
141
|
+
if (owner === undefined)
|
|
142
|
+
continue;
|
|
143
|
+
for (const site of callable.returnSites) {
|
|
144
|
+
const identifier = site.returnSiteId;
|
|
145
|
+
const node = addNode(state, semanticNode(file, {
|
|
146
|
+
kind: "return-site",
|
|
147
|
+
roleKey: identifier,
|
|
148
|
+
location: site.location,
|
|
149
|
+
label: "return",
|
|
150
|
+
functionNodeId: owner.node_id,
|
|
151
|
+
}, state));
|
|
152
|
+
if (node !== null)
|
|
153
|
+
result.set(identifier, node);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return result;
|
|
157
|
+
};
|
|
158
|
+
const createCallSiteNodes = (file, ir, callables, state) => {
|
|
159
|
+
const result = new Map();
|
|
160
|
+
for (const call of ir.callSites) {
|
|
161
|
+
const owner = call.callerCallableId === null
|
|
162
|
+
? null
|
|
163
|
+
: (callables.get(call.callerCallableId)?.node_id ?? null);
|
|
164
|
+
const node = addNode(state, semanticNode(file, {
|
|
165
|
+
kind: "call-site",
|
|
166
|
+
roleKey: `call:${call.callSiteId}`,
|
|
167
|
+
location: call.location,
|
|
168
|
+
label: call.kind,
|
|
169
|
+
functionNodeId: owner,
|
|
170
|
+
}, state));
|
|
171
|
+
if (node !== null)
|
|
172
|
+
result.set(call.callSiteId, node);
|
|
173
|
+
}
|
|
174
|
+
return result;
|
|
175
|
+
};
|
|
176
|
+
const projectDefinitionsAndReferences = (context) => {
|
|
177
|
+
for (const binding of context.ir.bindings) {
|
|
178
|
+
const bindingNode = context.bindingNodes.get(binding.bindingId);
|
|
179
|
+
if (bindingNode === undefined)
|
|
180
|
+
continue;
|
|
181
|
+
for (const [index, definition] of binding.definitions.entries()) {
|
|
182
|
+
const definitionNode = addNode(context.state, semanticNode(context.file, {
|
|
183
|
+
kind: "expression",
|
|
184
|
+
roleKey: `definition:${binding.bindingId}:${String(index)}`,
|
|
185
|
+
location: definition.location,
|
|
186
|
+
label: definition.kind,
|
|
187
|
+
functionNodeId: bindingNode.function_node_id,
|
|
188
|
+
}, context.state));
|
|
189
|
+
addRelation(context.state, {
|
|
190
|
+
source: definitionNode,
|
|
191
|
+
target: bindingNode,
|
|
192
|
+
relation: "defines",
|
|
193
|
+
resolution: "resolved",
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
for (const [index, reference] of context.ir.references.entries()) {
|
|
198
|
+
const expression = addNode(context.state, semanticNode(context.file, {
|
|
199
|
+
kind: "expression",
|
|
200
|
+
roleKey: `reference:${String(index)}:${reference.role}:${reference.name}`,
|
|
201
|
+
location: reference.location,
|
|
202
|
+
label: reference.name,
|
|
203
|
+
functionNodeId: owningSemanticCallableNode(reference.location, context.ir, context.callableNodes)?.node_id ?? null,
|
|
204
|
+
}, context.state));
|
|
205
|
+
const binding = reference.bindingId === null
|
|
206
|
+
? undefined
|
|
207
|
+
: context.bindingNodes.get(reference.bindingId);
|
|
208
|
+
if (expression !== null)
|
|
209
|
+
context.referenceNodes.push(expression);
|
|
210
|
+
if (binding === undefined || expression === null)
|
|
211
|
+
continue;
|
|
212
|
+
if (reference.role === "read")
|
|
213
|
+
addRelation(context.state, {
|
|
214
|
+
source: binding,
|
|
215
|
+
target: expression,
|
|
216
|
+
relation: "reads",
|
|
217
|
+
resolution: "resolved",
|
|
218
|
+
evidence: inferredSemanticEvidenceAt(context.file, reference.location),
|
|
219
|
+
});
|
|
220
|
+
else
|
|
221
|
+
addRelation(context.state, {
|
|
222
|
+
source: expression,
|
|
223
|
+
target: binding,
|
|
224
|
+
relation: "writes",
|
|
225
|
+
resolution: "resolved",
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
const projectCalls = (context) => {
|
|
230
|
+
for (const call of context.ir.callSites) {
|
|
231
|
+
const callNode = context.callSiteNodes.get(call.callSiteId);
|
|
232
|
+
if (callNode === undefined)
|
|
233
|
+
continue;
|
|
234
|
+
for (const callableId of call.calleeCallableIds) {
|
|
235
|
+
const callable = context.callableNodes.get(callableId);
|
|
236
|
+
addRelation(context.state, {
|
|
237
|
+
source: callNode,
|
|
238
|
+
target: callable,
|
|
239
|
+
relation: "calls",
|
|
240
|
+
resolution: call.resolution === "exact" ? "resolved" : "candidate",
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
for (const argument of call.arguments) {
|
|
244
|
+
const argumentNode = createArgumentNode(context, callNode, call.callSiteId, argument);
|
|
245
|
+
if (argumentNode !== null)
|
|
246
|
+
context.argumentNodes.set(`${call.callSiteId}\u0000${String(argument.index)}`, argumentNode);
|
|
247
|
+
const references = semanticNodesWithinRange(context.referenceNodes, argument.location);
|
|
248
|
+
for (const reference of references)
|
|
249
|
+
addRelation(context.state, {
|
|
250
|
+
source: reference,
|
|
251
|
+
target: argumentNode,
|
|
252
|
+
relation: "aliases",
|
|
253
|
+
resolution: references.length === 1 &&
|
|
254
|
+
rangesEqual(reference.identity.source_range, argument.location)
|
|
255
|
+
? "resolved"
|
|
256
|
+
: "candidate",
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
for (const flow of context.ir.argumentFlows) {
|
|
261
|
+
const argument = context.argumentNodes.get(`${flow.callSiteId}\u0000${String(flow.argumentIndex)}`);
|
|
262
|
+
const parameter = context.bindingNodes.get(flow.parameterBindingId);
|
|
263
|
+
addRelation(context.state, {
|
|
264
|
+
source: argument,
|
|
265
|
+
target: parameter,
|
|
266
|
+
relation: "argument-to-parameter",
|
|
267
|
+
resolution: context.callResolutions.get(flow.callSiteId) ?? "candidate",
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
for (const flow of context.ir.callReturnFlows)
|
|
271
|
+
addRelation(context.state, {
|
|
272
|
+
source: context.returnSiteNodes.get(flow.returnSiteId),
|
|
273
|
+
target: context.callSiteNodes.get(flow.callSiteId),
|
|
274
|
+
relation: "returns-to-call",
|
|
275
|
+
resolution: context.callResolutions.get(flow.callSiteId) ?? "candidate",
|
|
276
|
+
});
|
|
277
|
+
for (const flow of context.ir.callResultFlows)
|
|
278
|
+
addRelation(context.state, {
|
|
279
|
+
source: context.callSiteNodes.get(flow.callSiteId),
|
|
280
|
+
target: context.bindingNodes.get(flow.bindingId),
|
|
281
|
+
relation: "aliases",
|
|
282
|
+
resolution: context.callResolutions.get(flow.callSiteId) ?? "candidate",
|
|
283
|
+
});
|
|
284
|
+
projectSemanticReturnValues(context);
|
|
285
|
+
};
|
|
286
|
+
const createArgumentNode = (context, callNode, callSiteId, argument) => addNode(context.state, semanticNode(context.file, {
|
|
287
|
+
kind: "expression",
|
|
288
|
+
roleKey: `argument:${callSiteId}:${String(argument.index)}`,
|
|
289
|
+
location: argument.location,
|
|
290
|
+
label: argument.spread
|
|
291
|
+
? "spread argument"
|
|
292
|
+
: `argument ${String(argument.index)}`,
|
|
293
|
+
functionNodeId: callNode.function_node_id,
|
|
294
|
+
}, context.state));
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { createJavaScriptSemanticGraphNode, createJavaScriptSemanticGraphRelation, } from "../domain/javascriptSemanticGraph.js";
|
|
2
|
+
import { inferredSemanticEvidence, observedSemanticEvidence, unavailableSemanticRootEvidence, } from "./JavaScriptSemanticGraphEvidence.js";
|
|
3
|
+
/** Hard semantic graph node bound enforced during artifact projection. */
|
|
4
|
+
export const MAX_SEMANTIC_GRAPH_NODES = 100_000;
|
|
5
|
+
/** Hard semantic graph relation bound enforced during artifact projection. */
|
|
6
|
+
export const MAX_SEMANTIC_GRAPH_RELATIONS = 200_000;
|
|
7
|
+
/** Hard unresolved-frontier bound enforced across all analyzed files. */
|
|
8
|
+
export const MAX_SEMANTIC_GRAPH_UNKNOWNS = 100_000;
|
|
9
|
+
/** Maximum structural nodes linked to one exact semantic location. */
|
|
10
|
+
export const MAX_APPLICATION_NODE_IDS_PER_SEMANTIC_NODE = 64;
|
|
11
|
+
/** Create empty projection state with structural application-node mappings. */
|
|
12
|
+
export const createSemanticGraphProjectionState = (applicationGraph) => {
|
|
13
|
+
const index = indexApplicationNodes(applicationGraph.nodes);
|
|
14
|
+
return {
|
|
15
|
+
nodes: new Map(),
|
|
16
|
+
relations: new Map(),
|
|
17
|
+
unknowns: new Map(),
|
|
18
|
+
roots: new Set(),
|
|
19
|
+
limitsReached: new Set(index.truncated ? ["max_application_node_ids_per_semantic_node"] : []),
|
|
20
|
+
applicationNodeIdsByLocation: index.identifiers,
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
/** Construct one canonical semantic node backed by an exact artifact file. */
|
|
24
|
+
export const constructSemanticGraphNode = (file, input, state) => createJavaScriptSemanticGraphNode({
|
|
25
|
+
kind: input.kind,
|
|
26
|
+
identity: {
|
|
27
|
+
artifact_sha256: file.sha256,
|
|
28
|
+
module_path: file.path,
|
|
29
|
+
source_range: input.location,
|
|
30
|
+
role_key: input.roleKey,
|
|
31
|
+
},
|
|
32
|
+
function_node_id: input.functionNodeId,
|
|
33
|
+
application_node_ids: matchingApplicationNodeIds(file, input, state),
|
|
34
|
+
label: input.label,
|
|
35
|
+
properties: {},
|
|
36
|
+
evidence: observedSemanticEvidence(file, input.location),
|
|
37
|
+
});
|
|
38
|
+
/** Retain one canonical node unless the hard graph bound was reached. */
|
|
39
|
+
export const addSemanticGraphNode = (state, node) => {
|
|
40
|
+
const existing = state.nodes.get(node.node_id);
|
|
41
|
+
if (existing !== undefined)
|
|
42
|
+
return existing;
|
|
43
|
+
if (state.nodes.size >= MAX_SEMANTIC_GRAPH_NODES) {
|
|
44
|
+
state.limitsReached.add("max_nodes");
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
state.nodes.set(node.node_id, node);
|
|
48
|
+
return node;
|
|
49
|
+
};
|
|
50
|
+
/** Retain one non-self semantic relationship unless its hard bound was reached. */
|
|
51
|
+
export const addSemanticGraphRelation = (state, input) => {
|
|
52
|
+
if (input.source === undefined ||
|
|
53
|
+
input.source === null ||
|
|
54
|
+
input.target === undefined ||
|
|
55
|
+
input.target === null ||
|
|
56
|
+
input.source.node_id === input.target.node_id)
|
|
57
|
+
return;
|
|
58
|
+
const value = createJavaScriptSemanticGraphRelation({
|
|
59
|
+
source_node_id: input.source.node_id,
|
|
60
|
+
target_node_id: input.target.node_id,
|
|
61
|
+
relation: input.relation,
|
|
62
|
+
resolution: input.resolution ?? "candidate",
|
|
63
|
+
properties: {},
|
|
64
|
+
evidence: input.evidence ?? inferredSemanticEvidence(input.source),
|
|
65
|
+
});
|
|
66
|
+
if (state.relations.has(value.relation_id))
|
|
67
|
+
return;
|
|
68
|
+
if (state.relations.size >= MAX_SEMANTIC_GRAPH_RELATIONS) {
|
|
69
|
+
state.limitsReached.add("max_relations");
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
state.relations.set(value.relation_id, value);
|
|
73
|
+
};
|
|
74
|
+
/** Retain one unresolved frontier unless the global graph bound was reached. */
|
|
75
|
+
export const addSemanticGraphUnknown = (state, unknown) => {
|
|
76
|
+
if (state.unknowns.has(unknown.unknown_id))
|
|
77
|
+
return;
|
|
78
|
+
if (state.unknowns.size >= MAX_SEMANTIC_GRAPH_UNKNOWNS) {
|
|
79
|
+
state.limitsReached.add("max_unknowns");
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
state.unknowns.set(unknown.unknown_id, unknown);
|
|
83
|
+
};
|
|
84
|
+
/** Add a truthful root when no source file could produce semantic IR. */
|
|
85
|
+
export const addSemanticFallbackRoot = (rootArtifactSha256, state) => {
|
|
86
|
+
const node = addSemanticGraphNode(state, createJavaScriptSemanticGraphNode({
|
|
87
|
+
kind: "module",
|
|
88
|
+
identity: {
|
|
89
|
+
artifact_sha256: rootArtifactSha256,
|
|
90
|
+
module_path: "unknown-semantic-root",
|
|
91
|
+
source_range: null,
|
|
92
|
+
role_key: "artifact-root",
|
|
93
|
+
},
|
|
94
|
+
function_node_id: null,
|
|
95
|
+
application_node_ids: [],
|
|
96
|
+
label: "unavailable semantic root",
|
|
97
|
+
properties: {},
|
|
98
|
+
evidence: unavailableSemanticRootEvidence(rootArtifactSha256),
|
|
99
|
+
}));
|
|
100
|
+
if (node !== null)
|
|
101
|
+
state.roots.add(node.node_id);
|
|
102
|
+
};
|
|
103
|
+
const indexApplicationNodes = (nodes) => {
|
|
104
|
+
const identifiers = new Map();
|
|
105
|
+
for (const node of nodes) {
|
|
106
|
+
for (const observation of node.observations) {
|
|
107
|
+
const { artifact, location } = observation.evidence;
|
|
108
|
+
if (!artifact.available || !location.available)
|
|
109
|
+
continue;
|
|
110
|
+
if (location.value.kind === "artifact-path") {
|
|
111
|
+
addApplicationNodeIdentifier(identifiers, applicationLocationKey(artifact.sha256, location.value.path, null), node.node_id);
|
|
112
|
+
}
|
|
113
|
+
if (location.value.kind === "source-range") {
|
|
114
|
+
addApplicationNodeIdentifier(identifiers, applicationLocationKey(artifact.sha256, location.value.source, {
|
|
115
|
+
start: location.value.start,
|
|
116
|
+
end: location.value.end,
|
|
117
|
+
}), node.node_id);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
let truncated = false;
|
|
122
|
+
const indexed = new Map([...identifiers].map(([key, values]) => {
|
|
123
|
+
const sorted = [...values].sort();
|
|
124
|
+
if (sorted.length > MAX_APPLICATION_NODE_IDS_PER_SEMANTIC_NODE)
|
|
125
|
+
truncated = true;
|
|
126
|
+
return [key, sorted.slice(0, MAX_APPLICATION_NODE_IDS_PER_SEMANTIC_NODE)];
|
|
127
|
+
}));
|
|
128
|
+
return { identifiers: indexed, truncated };
|
|
129
|
+
};
|
|
130
|
+
const matchingApplicationNodeIds = (file, input, state) => [
|
|
131
|
+
...(state.applicationNodeIdsByLocation.get(applicationLocationKey(file.sha256, file.path, input.location)) ?? []),
|
|
132
|
+
];
|
|
133
|
+
const addApplicationNodeIdentifier = (identifiers, key, nodeId) => {
|
|
134
|
+
const values = identifiers.get(key) ?? new Set();
|
|
135
|
+
values.add(nodeId);
|
|
136
|
+
identifiers.set(key, values);
|
|
137
|
+
};
|
|
138
|
+
const applicationLocationKey = (artifactSha256, path, range) => [
|
|
139
|
+
artifactSha256,
|
|
140
|
+
path,
|
|
141
|
+
range === null
|
|
142
|
+
? "artifact-path"
|
|
143
|
+
: `${range.start.line}:${range.start.column}-${range.end.line}:${range.end.column}`,
|
|
144
|
+
].join("\u0000");
|