@grafema/util 0.3.0-beta
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/LICENSE +190 -0
- package/dist/api/GraphAPI.d.ts +87 -0
- package/dist/api/GraphAPI.d.ts.map +1 -0
- package/dist/api/GraphAPI.js +212 -0
- package/dist/api/GraphAPI.js.map +1 -0
- package/dist/api/GuaranteeAPI.d.ts +147 -0
- package/dist/api/GuaranteeAPI.d.ts.map +1 -0
- package/dist/api/GuaranteeAPI.js +290 -0
- package/dist/api/GuaranteeAPI.js.map +1 -0
- package/dist/config/ConfigLoader.d.ts +214 -0
- package/dist/config/ConfigLoader.d.ts.map +1 -0
- package/dist/config/ConfigLoader.js +441 -0
- package/dist/config/ConfigLoader.js.map +1 -0
- package/dist/config/index.d.ts +6 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +5 -0
- package/dist/config/index.js.map +1 -0
- package/dist/core/CoverageAnalyzer.d.ts +65 -0
- package/dist/core/CoverageAnalyzer.d.ts.map +1 -0
- package/dist/core/CoverageAnalyzer.js +199 -0
- package/dist/core/CoverageAnalyzer.js.map +1 -0
- package/dist/core/FileExplainer.d.ts +101 -0
- package/dist/core/FileExplainer.d.ts.map +1 -0
- package/dist/core/FileExplainer.js +140 -0
- package/dist/core/FileExplainer.js.map +1 -0
- package/dist/core/FileOverview.d.ts +124 -0
- package/dist/core/FileOverview.d.ts.map +1 -0
- package/dist/core/FileOverview.js +279 -0
- package/dist/core/FileOverview.js.map +1 -0
- package/dist/core/GrafemaUri.d.ts +66 -0
- package/dist/core/GrafemaUri.d.ts.map +1 -0
- package/dist/core/GrafemaUri.js +191 -0
- package/dist/core/GrafemaUri.js.map +1 -0
- package/dist/core/GraphBackend.d.ts +158 -0
- package/dist/core/GraphBackend.d.ts.map +1 -0
- package/dist/core/GraphBackend.js +85 -0
- package/dist/core/GraphBackend.js.map +1 -0
- package/dist/core/GraphFreshnessChecker.d.ts +33 -0
- package/dist/core/GraphFreshnessChecker.d.ts.map +1 -0
- package/dist/core/GraphFreshnessChecker.js +104 -0
- package/dist/core/GraphFreshnessChecker.js.map +1 -0
- package/dist/core/GuaranteeManager.d.ts +254 -0
- package/dist/core/GuaranteeManager.d.ts.map +1 -0
- package/dist/core/GuaranteeManager.js +447 -0
- package/dist/core/GuaranteeManager.js.map +1 -0
- package/dist/core/HashUtils.d.ts +24 -0
- package/dist/core/HashUtils.d.ts.map +1 -0
- package/dist/core/HashUtils.js +46 -0
- package/dist/core/HashUtils.js.map +1 -0
- package/dist/core/IncrementalReanalyzer.d.ts +33 -0
- package/dist/core/IncrementalReanalyzer.d.ts.map +1 -0
- package/dist/core/IncrementalReanalyzer.js +67 -0
- package/dist/core/IncrementalReanalyzer.js.map +1 -0
- package/dist/core/ResourceRegistry.d.ts +17 -0
- package/dist/core/ResourceRegistry.d.ts.map +1 -0
- package/dist/core/ResourceRegistry.js +32 -0
- package/dist/core/ResourceRegistry.js.map +1 -0
- package/dist/core/SemanticId.d.ts +159 -0
- package/dist/core/SemanticId.d.ts.map +1 -0
- package/dist/core/SemanticId.js +291 -0
- package/dist/core/SemanticId.js.map +1 -0
- package/dist/core/VersionManager.d.ts +166 -0
- package/dist/core/VersionManager.d.ts.map +1 -0
- package/dist/core/VersionManager.js +239 -0
- package/dist/core/VersionManager.js.map +1 -0
- package/dist/core/brandNodeInternal.d.ts +14 -0
- package/dist/core/brandNodeInternal.d.ts.map +1 -0
- package/dist/core/brandNodeInternal.js +4 -0
- package/dist/core/brandNodeInternal.js.map +1 -0
- package/dist/core/nodes/GuaranteeNode.d.ts +76 -0
- package/dist/core/nodes/GuaranteeNode.d.ts.map +1 -0
- package/dist/core/nodes/GuaranteeNode.js +118 -0
- package/dist/core/nodes/GuaranteeNode.js.map +1 -0
- package/dist/core/nodes/IssueNode.d.ts +73 -0
- package/dist/core/nodes/IssueNode.d.ts.map +1 -0
- package/dist/core/nodes/IssueNode.js +130 -0
- package/dist/core/nodes/IssueNode.js.map +1 -0
- package/dist/core/nodes/NodeKind.d.ts +104 -0
- package/dist/core/nodes/NodeKind.d.ts.map +1 -0
- package/dist/core/nodes/NodeKind.js +166 -0
- package/dist/core/nodes/NodeKind.js.map +1 -0
- package/dist/diagnostics/DiagnosticCollector.d.ts +103 -0
- package/dist/diagnostics/DiagnosticCollector.d.ts.map +1 -0
- package/dist/diagnostics/DiagnosticCollector.js +133 -0
- package/dist/diagnostics/DiagnosticCollector.js.map +1 -0
- package/dist/diagnostics/DiagnosticReporter.d.ts +122 -0
- package/dist/diagnostics/DiagnosticReporter.d.ts.map +1 -0
- package/dist/diagnostics/DiagnosticReporter.js +300 -0
- package/dist/diagnostics/DiagnosticReporter.js.map +1 -0
- package/dist/diagnostics/DiagnosticWriter.d.ts +31 -0
- package/dist/diagnostics/DiagnosticWriter.d.ts.map +1 -0
- package/dist/diagnostics/DiagnosticWriter.js +44 -0
- package/dist/diagnostics/DiagnosticWriter.js.map +1 -0
- package/dist/diagnostics/categories.d.ts +57 -0
- package/dist/diagnostics/categories.d.ts.map +1 -0
- package/dist/diagnostics/categories.js +71 -0
- package/dist/diagnostics/categories.js.map +1 -0
- package/dist/diagnostics/index.d.ts +17 -0
- package/dist/diagnostics/index.d.ts.map +1 -0
- package/dist/diagnostics/index.js +15 -0
- package/dist/diagnostics/index.js.map +1 -0
- package/dist/errors/GrafemaError.d.ts +200 -0
- package/dist/errors/GrafemaError.d.ts.map +1 -0
- package/dist/errors/GrafemaError.js +209 -0
- package/dist/errors/GrafemaError.js.map +1 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/dist/instructions/index.d.ts +8 -0
- package/dist/instructions/index.d.ts.map +1 -0
- package/dist/instructions/index.js +20 -0
- package/dist/instructions/index.js.map +1 -0
- package/dist/instructions/onboarding.md +133 -0
- package/dist/knowledge/KnowledgeBase.d.ts +113 -0
- package/dist/knowledge/KnowledgeBase.d.ts.map +1 -0
- package/dist/knowledge/KnowledgeBase.js +420 -0
- package/dist/knowledge/KnowledgeBase.js.map +1 -0
- package/dist/knowledge/SemanticAddressResolver.d.ts +59 -0
- package/dist/knowledge/SemanticAddressResolver.d.ts.map +1 -0
- package/dist/knowledge/SemanticAddressResolver.js +160 -0
- package/dist/knowledge/SemanticAddressResolver.js.map +1 -0
- package/dist/knowledge/git-ingest.d.ts +58 -0
- package/dist/knowledge/git-ingest.d.ts.map +1 -0
- package/dist/knowledge/git-ingest.js +301 -0
- package/dist/knowledge/git-ingest.js.map +1 -0
- package/dist/knowledge/git-queries.d.ts +86 -0
- package/dist/knowledge/git-queries.d.ts.map +1 -0
- package/dist/knowledge/git-queries.js +177 -0
- package/dist/knowledge/git-queries.js.map +1 -0
- package/dist/knowledge/index.d.ts +14 -0
- package/dist/knowledge/index.d.ts.map +1 -0
- package/dist/knowledge/index.js +10 -0
- package/dist/knowledge/index.js.map +1 -0
- package/dist/knowledge/parser.d.ts +39 -0
- package/dist/knowledge/parser.d.ts.map +1 -0
- package/dist/knowledge/parser.js +292 -0
- package/dist/knowledge/parser.js.map +1 -0
- package/dist/knowledge/types.d.ts +133 -0
- package/dist/knowledge/types.d.ts.map +1 -0
- package/dist/knowledge/types.js +8 -0
- package/dist/knowledge/types.js.map +1 -0
- package/dist/logging/Logger.d.ts +98 -0
- package/dist/logging/Logger.d.ts.map +1 -0
- package/dist/logging/Logger.js +274 -0
- package/dist/logging/Logger.js.map +1 -0
- package/dist/notation/archetypes.d.ts +36 -0
- package/dist/notation/archetypes.d.ts.map +1 -0
- package/dist/notation/archetypes.js +173 -0
- package/dist/notation/archetypes.js.map +1 -0
- package/dist/notation/fold.d.ts +25 -0
- package/dist/notation/fold.d.ts.map +1 -0
- package/dist/notation/fold.js +598 -0
- package/dist/notation/fold.js.map +1 -0
- package/dist/notation/index.d.ts +18 -0
- package/dist/notation/index.d.ts.map +1 -0
- package/dist/notation/index.js +16 -0
- package/dist/notation/index.js.map +1 -0
- package/dist/notation/lodExtractor.d.ts +32 -0
- package/dist/notation/lodExtractor.d.ts.map +1 -0
- package/dist/notation/lodExtractor.js +149 -0
- package/dist/notation/lodExtractor.js.map +1 -0
- package/dist/notation/nameShortener.d.ts +22 -0
- package/dist/notation/nameShortener.d.ts.map +1 -0
- package/dist/notation/nameShortener.js +24 -0
- package/dist/notation/nameShortener.js.map +1 -0
- package/dist/notation/perspectives.d.ts +11 -0
- package/dist/notation/perspectives.d.ts.map +1 -0
- package/dist/notation/perspectives.js +16 -0
- package/dist/notation/perspectives.js.map +1 -0
- package/dist/notation/renderer.d.ts +31 -0
- package/dist/notation/renderer.d.ts.map +1 -0
- package/dist/notation/renderer.js +315 -0
- package/dist/notation/renderer.js.map +1 -0
- package/dist/notation/traceRenderer.d.ts +39 -0
- package/dist/notation/traceRenderer.d.ts.map +1 -0
- package/dist/notation/traceRenderer.js +358 -0
- package/dist/notation/traceRenderer.js.map +1 -0
- package/dist/notation/types.d.ts +66 -0
- package/dist/notation/types.d.ts.map +1 -0
- package/dist/notation/types.js +10 -0
- package/dist/notation/types.js.map +1 -0
- package/dist/queries/NodeContext.d.ts +81 -0
- package/dist/queries/NodeContext.d.ts.map +1 -0
- package/dist/queries/NodeContext.js +196 -0
- package/dist/queries/NodeContext.js.map +1 -0
- package/dist/queries/findCallsInFunction.d.ts +62 -0
- package/dist/queries/findCallsInFunction.d.ts.map +1 -0
- package/dist/queries/findCallsInFunction.js +169 -0
- package/dist/queries/findCallsInFunction.js.map +1 -0
- package/dist/queries/findContainingFunction.d.ts +57 -0
- package/dist/queries/findContainingFunction.d.ts.map +1 -0
- package/dist/queries/findContainingFunction.js +91 -0
- package/dist/queries/findContainingFunction.js.map +1 -0
- package/dist/queries/index.d.ts +18 -0
- package/dist/queries/index.d.ts.map +1 -0
- package/dist/queries/index.js +14 -0
- package/dist/queries/index.js.map +1 -0
- package/dist/queries/traceDataflow.d.ts +65 -0
- package/dist/queries/traceDataflow.d.ts.map +1 -0
- package/dist/queries/traceDataflow.js +754 -0
- package/dist/queries/traceDataflow.js.map +1 -0
- package/dist/queries/traceValues.d.ts +70 -0
- package/dist/queries/traceValues.d.ts.map +1 -0
- package/dist/queries/traceValues.js +373 -0
- package/dist/queries/traceValues.js.map +1 -0
- package/dist/queries/types.d.ts +166 -0
- package/dist/queries/types.d.ts.map +1 -0
- package/dist/queries/types.js +10 -0
- package/dist/queries/types.js.map +1 -0
- package/dist/schema/GraphSchemaExtractor.d.ts +53 -0
- package/dist/schema/GraphSchemaExtractor.d.ts.map +1 -0
- package/dist/schema/GraphSchemaExtractor.js +125 -0
- package/dist/schema/GraphSchemaExtractor.js.map +1 -0
- package/dist/schema/InterfaceSchemaExtractor.d.ts +73 -0
- package/dist/schema/InterfaceSchemaExtractor.d.ts.map +1 -0
- package/dist/schema/InterfaceSchemaExtractor.js +113 -0
- package/dist/schema/InterfaceSchemaExtractor.js.map +1 -0
- package/dist/schema/index.d.ts +5 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +3 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/storage/backends/RFDBServerBackend.d.ts +356 -0
- package/dist/storage/backends/RFDBServerBackend.d.ts.map +1 -0
- package/dist/storage/backends/RFDBServerBackend.js +748 -0
- package/dist/storage/backends/RFDBServerBackend.js.map +1 -0
- package/dist/storage/backends/typeValidation.d.ts +47 -0
- package/dist/storage/backends/typeValidation.d.ts.map +1 -0
- package/dist/storage/backends/typeValidation.js +141 -0
- package/dist/storage/backends/typeValidation.js.map +1 -0
- package/dist/utils/findRfdbBinary.d.ts +67 -0
- package/dist/utils/findRfdbBinary.d.ts.map +1 -0
- package/dist/utils/findRfdbBinary.js +261 -0
- package/dist/utils/findRfdbBinary.js.map +1 -0
- package/dist/utils/lazyDownload.d.ts +43 -0
- package/dist/utils/lazyDownload.d.ts.map +1 -0
- package/dist/utils/lazyDownload.js +175 -0
- package/dist/utils/lazyDownload.js.map +1 -0
- package/dist/utils/moduleResolution.d.ts +134 -0
- package/dist/utils/moduleResolution.d.ts.map +1 -0
- package/dist/utils/moduleResolution.js +189 -0
- package/dist/utils/moduleResolution.js.map +1 -0
- package/dist/utils/resolveNodeFile.d.ts +13 -0
- package/dist/utils/resolveNodeFile.d.ts.map +1 -0
- package/dist/utils/resolveNodeFile.js +18 -0
- package/dist/utils/resolveNodeFile.js.map +1 -0
- package/dist/utils/startRfdbServer.d.ts +63 -0
- package/dist/utils/startRfdbServer.d.ts.map +1 -0
- package/dist/utils/startRfdbServer.js +142 -0
- package/dist/utils/startRfdbServer.js.map +1 -0
- package/dist/validation/PathValidator.d.ts +80 -0
- package/dist/validation/PathValidator.d.ts.map +1 -0
- package/dist/validation/PathValidator.js +252 -0
- package/dist/validation/PathValidator.js.map +1 -0
- package/dist/version.d.ts +11 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +26 -0
- package/dist/version.js.map +1 -0
- package/package.json +50 -0
- package/src/api/GraphAPI.ts +307 -0
- package/src/api/GuaranteeAPI.ts +402 -0
- package/src/config/ConfigLoader.ts +653 -0
- package/src/config/index.ts +13 -0
- package/src/core/CoverageAnalyzer.ts +243 -0
- package/src/core/FileExplainer.ts +179 -0
- package/src/core/FileOverview.ts +397 -0
- package/src/core/GrafemaUri.ts +216 -0
- package/src/core/GraphBackend.ts +266 -0
- package/src/core/GraphFreshnessChecker.ts +145 -0
- package/src/core/GuaranteeManager.ts +684 -0
- package/src/core/HashUtils.ts +48 -0
- package/src/core/IncrementalReanalyzer.ts +106 -0
- package/src/core/ResourceRegistry.ts +39 -0
- package/src/core/SemanticId.ts +423 -0
- package/src/core/VersionManager.ts +405 -0
- package/src/core/brandNodeInternal.ts +16 -0
- package/src/core/nodes/GuaranteeNode.ts +162 -0
- package/src/core/nodes/IssueNode.ts +177 -0
- package/src/core/nodes/NodeKind.ts +192 -0
- package/src/diagnostics/DiagnosticCollector.ts +170 -0
- package/src/diagnostics/DiagnosticReporter.ts +395 -0
- package/src/diagnostics/DiagnosticWriter.ts +50 -0
- package/src/diagnostics/categories.ts +104 -0
- package/src/diagnostics/index.ts +30 -0
- package/src/errors/GrafemaError.ts +297 -0
- package/src/index.ts +261 -0
- package/src/instructions/index.ts +21 -0
- package/src/instructions/onboarding.md +133 -0
- package/src/knowledge/KnowledgeBase.ts +486 -0
- package/src/knowledge/SemanticAddressResolver.ts +191 -0
- package/src/knowledge/git-ingest.ts +402 -0
- package/src/knowledge/git-queries.ts +269 -0
- package/src/knowledge/index.ts +29 -0
- package/src/knowledge/parser.ts +294 -0
- package/src/knowledge/types.ts +146 -0
- package/src/logging/Logger.ts +303 -0
- package/src/notation/archetypes.ts +189 -0
- package/src/notation/fold.ts +696 -0
- package/src/notation/index.ts +27 -0
- package/src/notation/lodExtractor.ts +177 -0
- package/src/notation/nameShortener.ts +24 -0
- package/src/notation/perspectives.ts +18 -0
- package/src/notation/renderer.ts +394 -0
- package/src/notation/traceRenderer.ts +458 -0
- package/src/notation/types.ts +79 -0
- package/src/queries/NodeContext.ts +280 -0
- package/src/queries/findCallsInFunction.ts +249 -0
- package/src/queries/findContainingFunction.ts +124 -0
- package/src/queries/index.ts +44 -0
- package/src/queries/traceDataflow.ts +838 -0
- package/src/queries/traceValues.ts +531 -0
- package/src/queries/types.ts +191 -0
- package/src/schema/GraphSchemaExtractor.ts +177 -0
- package/src/schema/InterfaceSchemaExtractor.ts +173 -0
- package/src/schema/index.ts +5 -0
- package/src/storage/backends/RFDBServerBackend.ts +895 -0
- package/src/storage/backends/typeValidation.ts +154 -0
- package/src/utils/findRfdbBinary.ts +288 -0
- package/src/utils/lazyDownload.ts +206 -0
- package/src/utils/moduleResolution.ts +271 -0
- package/src/utils/resolveNodeFile.ts +18 -0
- package/src/utils/startRfdbServer.ts +197 -0
- package/src/validation/PathValidator.ts +334 -0
- package/src/version.ts +28 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node Context — shared data logic for building node neighborhood context
|
|
3
|
+
*
|
|
4
|
+
* Extracts source code preview and all incoming/outgoing edges
|
|
5
|
+
* for a given node, grouped by edge type.
|
|
6
|
+
*
|
|
7
|
+
* Used by CLI (grafema context) and MCP (get_context tool).
|
|
8
|
+
* Consumers handle their own formatting; this module provides data only.
|
|
9
|
+
*
|
|
10
|
+
* @module queries/NodeContext
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readFileSync } from 'fs';
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Constants
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
/**
|
|
17
|
+
* Edge types that are structural/containment — shown in compact form.
|
|
18
|
+
* These describe HOW code is nested, not WHAT it does.
|
|
19
|
+
*/
|
|
20
|
+
export const STRUCTURAL_EDGE_TYPES = new Set([
|
|
21
|
+
'CONTAINS',
|
|
22
|
+
'HAS_SCOPE',
|
|
23
|
+
'DECLARES',
|
|
24
|
+
'DEFINES',
|
|
25
|
+
'HAS_CONDITION',
|
|
26
|
+
'HAS_CASE',
|
|
27
|
+
'HAS_DEFAULT',
|
|
28
|
+
'HAS_CONSEQUENT',
|
|
29
|
+
'HAS_ALTERNATE',
|
|
30
|
+
'HAS_BODY',
|
|
31
|
+
'HAS_INIT',
|
|
32
|
+
'HAS_UPDATE',
|
|
33
|
+
'HAS_CATCH',
|
|
34
|
+
'HAS_FINALLY',
|
|
35
|
+
'HAS_PARAMETER',
|
|
36
|
+
'HAS_PROPERTY',
|
|
37
|
+
'HAS_ELEMENT',
|
|
38
|
+
'USES',
|
|
39
|
+
'GOVERNS',
|
|
40
|
+
'VIOLATES',
|
|
41
|
+
'AFFECTS',
|
|
42
|
+
'UNKNOWN',
|
|
43
|
+
]);
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Default file reader
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
function defaultReadFileContent(filePath) {
|
|
48
|
+
if (!existsSync(filePath))
|
|
49
|
+
return null;
|
|
50
|
+
try {
|
|
51
|
+
return readFileSync(filePath, 'utf-8');
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// Core function
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
/**
|
|
61
|
+
* Build full node context: source preview + all edges with connected nodes.
|
|
62
|
+
*
|
|
63
|
+
* @param backend - Graph backend for queries
|
|
64
|
+
* @param node - The node to build context for (already looked up by caller)
|
|
65
|
+
* @param options - Context options
|
|
66
|
+
* @returns NodeContext with source preview and grouped edges
|
|
67
|
+
*/
|
|
68
|
+
export async function buildNodeContext(backend, node, options = {}) {
|
|
69
|
+
const { contextLines = 3, edgeTypeFilter = null, readFileContent = defaultReadFileContent, } = options;
|
|
70
|
+
// Source code preview
|
|
71
|
+
let source = null;
|
|
72
|
+
if (node.file && node.line) {
|
|
73
|
+
const content = readFileContent(node.file);
|
|
74
|
+
if (content) {
|
|
75
|
+
const allLines = content.split('\n');
|
|
76
|
+
const line = node.line;
|
|
77
|
+
const startLine = Math.max(1, line - contextLines);
|
|
78
|
+
const endLine = Math.min(allLines.length, line + contextLines + 12);
|
|
79
|
+
source = {
|
|
80
|
+
file: node.file,
|
|
81
|
+
startLine,
|
|
82
|
+
endLine,
|
|
83
|
+
lines: allLines.slice(startLine - 1, endLine),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Outgoing edges
|
|
88
|
+
const rawOutgoing = await backend.getOutgoingEdges(node.id);
|
|
89
|
+
const outgoing = await groupEdges(backend, rawOutgoing, 'dst', edgeTypeFilter);
|
|
90
|
+
// Incoming edges
|
|
91
|
+
const rawIncoming = await backend.getIncomingEdges(node.id);
|
|
92
|
+
const incoming = await groupEdges(backend, rawIncoming, 'src', edgeTypeFilter);
|
|
93
|
+
return { node, source, outgoing, incoming };
|
|
94
|
+
}
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
// Edge grouping
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
/**
|
|
99
|
+
* Group edges by type and resolve connected nodes.
|
|
100
|
+
*
|
|
101
|
+
* Sort order: non-structural edges first (alphabetical),
|
|
102
|
+
* then structural edges (alphabetical).
|
|
103
|
+
*/
|
|
104
|
+
async function groupEdges(backend, edges, nodeField, edgeTypeFilter) {
|
|
105
|
+
const groups = new Map();
|
|
106
|
+
for (const edge of edges) {
|
|
107
|
+
const edgeType = edge.type || 'UNKNOWN';
|
|
108
|
+
// Apply edge type filter
|
|
109
|
+
if (edgeTypeFilter && !edgeTypeFilter.has(edgeType))
|
|
110
|
+
continue;
|
|
111
|
+
const connectedId = edge[nodeField];
|
|
112
|
+
const connectedNode = await backend.getNode(connectedId);
|
|
113
|
+
if (!groups.has(edgeType)) {
|
|
114
|
+
groups.set(edgeType, []);
|
|
115
|
+
}
|
|
116
|
+
groups.get(edgeType).push({ edge, node: connectedNode });
|
|
117
|
+
}
|
|
118
|
+
// Sort groups: primary edges first, then structural
|
|
119
|
+
return Array.from(groups.entries())
|
|
120
|
+
.sort(([a], [b]) => {
|
|
121
|
+
const aStructural = STRUCTURAL_EDGE_TYPES.has(a);
|
|
122
|
+
const bStructural = STRUCTURAL_EDGE_TYPES.has(b);
|
|
123
|
+
if (aStructural !== bStructural)
|
|
124
|
+
return aStructural ? 1 : -1;
|
|
125
|
+
return a.localeCompare(b);
|
|
126
|
+
})
|
|
127
|
+
.map(([edgeType, edgeList]) => ({ edgeType, edges: edgeList }));
|
|
128
|
+
}
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Display helpers
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
/**
|
|
133
|
+
* Get display name for a node based on its type.
|
|
134
|
+
*
|
|
135
|
+
* Special cases:
|
|
136
|
+
* - HTTP routes: "METHOD /path"
|
|
137
|
+
* - HTTP requests: "METHOD url"
|
|
138
|
+
* - Socket.IO: event name
|
|
139
|
+
* - Default: node.name or node.id
|
|
140
|
+
*/
|
|
141
|
+
export function getNodeDisplayName(node) {
|
|
142
|
+
// HTTP nodes: method + path/url
|
|
143
|
+
if (node.type === 'http:route') {
|
|
144
|
+
const method = node.method;
|
|
145
|
+
const path = node.path;
|
|
146
|
+
if (method && path)
|
|
147
|
+
return `${method} ${path}`;
|
|
148
|
+
}
|
|
149
|
+
if (node.type === 'http:request') {
|
|
150
|
+
const method = node.method;
|
|
151
|
+
const url = node.url;
|
|
152
|
+
if (method && url)
|
|
153
|
+
return `${method} ${url}`;
|
|
154
|
+
}
|
|
155
|
+
// Socket.IO: event name
|
|
156
|
+
if (node.type === 'socketio:emit' || node.type === 'socketio:on') {
|
|
157
|
+
const event = node.event;
|
|
158
|
+
if (event)
|
|
159
|
+
return event;
|
|
160
|
+
}
|
|
161
|
+
// Anonymous arrows/expressions → λ
|
|
162
|
+
if (node.name === '<arrow>' || node.name === '<expression>')
|
|
163
|
+
return 'λ';
|
|
164
|
+
// Default: name or ID fallback
|
|
165
|
+
if (node.name && !node.name.startsWith('{'))
|
|
166
|
+
return node.name;
|
|
167
|
+
return node.id;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Format edge metadata for inline display (only meaningful fields).
|
|
171
|
+
*
|
|
172
|
+
* Returns a string like " [arg0]" or "" if no relevant metadata.
|
|
173
|
+
*/
|
|
174
|
+
export function formatEdgeMetadata(edge) {
|
|
175
|
+
const parts = [];
|
|
176
|
+
const meta = edge.metadata || {};
|
|
177
|
+
if (edge.type === 'PASSES_ARGUMENT' || edge.type === 'RECEIVES_ARGUMENT') {
|
|
178
|
+
if ('argIndex' in meta) {
|
|
179
|
+
parts.push(`arg${meta.argIndex}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (edge.type === 'FLOWS_INTO') {
|
|
183
|
+
if ('mutationMethod' in meta)
|
|
184
|
+
parts.push(`via ${meta.mutationMethod}`);
|
|
185
|
+
}
|
|
186
|
+
if (edge.type === 'HAS_PROPERTY') {
|
|
187
|
+
if ('propertyName' in meta)
|
|
188
|
+
parts.push(`key: ${meta.propertyName}`);
|
|
189
|
+
}
|
|
190
|
+
if (edge.type === 'ITERATES_OVER') {
|
|
191
|
+
if ('iterates' in meta)
|
|
192
|
+
parts.push(`${meta.iterates}`);
|
|
193
|
+
}
|
|
194
|
+
return parts.length > 0 ? ` [${parts.join(', ')}]` : '';
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=NodeContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NodeContext.js","sourceRoot":"","sources":["../../src/queries/NodeContext.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find all CALL and METHOD_CALL nodes inside a function.
|
|
3
|
+
*
|
|
4
|
+
* Supports two graph layouts:
|
|
5
|
+
*
|
|
6
|
+
* Layout A (scope chain — legacy JS analyzer):
|
|
7
|
+
* ```
|
|
8
|
+
* FUNCTION -[HAS_SCOPE]-> SCOPE -[CONTAINS]-> CALL
|
|
9
|
+
* SCOPE -[CONTAINS]-> METHOD_CALL
|
|
10
|
+
* SCOPE -[CONTAINS]-> SCOPE (nested blocks)
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Layout B (direct edges — Rust orchestrator):
|
|
14
|
+
* ```
|
|
15
|
+
* FUNCTION -[AWAITS|RETURNS|THROWS|...]--> CALL / METHOD_CALL
|
|
16
|
+
* ```
|
|
17
|
+
* The orchestrator links functions directly to their call nodes via
|
|
18
|
+
* semantic edge types (AWAITS for async calls, RETURNS for return
|
|
19
|
+
* expressions, THROWS for throw expressions, etc.).
|
|
20
|
+
*
|
|
21
|
+
* Algorithm:
|
|
22
|
+
* 1. Try HAS_SCOPE path first (Layout A)
|
|
23
|
+
* 2. If no HAS_SCOPE edges, fall back to direct edges (Layout B):
|
|
24
|
+
* collect all outgoing edges, keep those targeting CALL/METHOD_CALL nodes
|
|
25
|
+
* 3. For each call, check CALLS edge to determine if resolved
|
|
26
|
+
* 4. If transitive=true, recursively follow resolved CALLS edges
|
|
27
|
+
*
|
|
28
|
+
* Performance: O(S + C) where S = scopes, C = calls
|
|
29
|
+
* For functions with 100 calls, expect ~200 DB operations.
|
|
30
|
+
*
|
|
31
|
+
* @module queries/findCallsInFunction
|
|
32
|
+
*/
|
|
33
|
+
import type { CallInfo, FindCallsOptions } from './types.js';
|
|
34
|
+
/**
|
|
35
|
+
* Graph backend interface (minimal surface)
|
|
36
|
+
*/
|
|
37
|
+
interface GraphBackend {
|
|
38
|
+
getNode(id: string): Promise<{
|
|
39
|
+
id: string;
|
|
40
|
+
type: string;
|
|
41
|
+
name?: string;
|
|
42
|
+
file?: string;
|
|
43
|
+
line?: number;
|
|
44
|
+
object?: string;
|
|
45
|
+
} | null>;
|
|
46
|
+
getOutgoingEdges(nodeId: string, edgeTypes: string[] | null): Promise<Array<{
|
|
47
|
+
src: string;
|
|
48
|
+
dst: string;
|
|
49
|
+
type: string;
|
|
50
|
+
}>>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Find all CALL and METHOD_CALL nodes inside a function.
|
|
54
|
+
*
|
|
55
|
+
* @param backend - Graph backend for queries
|
|
56
|
+
* @param functionId - ID of the FUNCTION node
|
|
57
|
+
* @param options - Options for traversal
|
|
58
|
+
* @returns Array of CallInfo objects
|
|
59
|
+
*/
|
|
60
|
+
export declare function findCallsInFunction(backend: GraphBackend, functionId: string, options?: FindCallsOptions): Promise<CallInfo[]>;
|
|
61
|
+
export {};
|
|
62
|
+
//# sourceMappingURL=findCallsInFunction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findCallsInFunction.d.ts","sourceRoot":"","sources":["../../src/queries/findCallsInFunction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE7D;;GAEG;AACH,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;QAC3B,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,IAAI,CAAC,CAAC;IACV,gBAAgB,CACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,GACzB,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;CAC/D;AAWD;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,YAAY,EACrB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,QAAQ,EAAE,CAAC,CA0FrB"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find all CALL and METHOD_CALL nodes inside a function.
|
|
3
|
+
*
|
|
4
|
+
* Supports two graph layouts:
|
|
5
|
+
*
|
|
6
|
+
* Layout A (scope chain — legacy JS analyzer):
|
|
7
|
+
* ```
|
|
8
|
+
* FUNCTION -[HAS_SCOPE]-> SCOPE -[CONTAINS]-> CALL
|
|
9
|
+
* SCOPE -[CONTAINS]-> METHOD_CALL
|
|
10
|
+
* SCOPE -[CONTAINS]-> SCOPE (nested blocks)
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Layout B (direct edges — Rust orchestrator):
|
|
14
|
+
* ```
|
|
15
|
+
* FUNCTION -[AWAITS|RETURNS|THROWS|...]--> CALL / METHOD_CALL
|
|
16
|
+
* ```
|
|
17
|
+
* The orchestrator links functions directly to their call nodes via
|
|
18
|
+
* semantic edge types (AWAITS for async calls, RETURNS for return
|
|
19
|
+
* expressions, THROWS for throw expressions, etc.).
|
|
20
|
+
*
|
|
21
|
+
* Algorithm:
|
|
22
|
+
* 1. Try HAS_SCOPE path first (Layout A)
|
|
23
|
+
* 2. If no HAS_SCOPE edges, fall back to direct edges (Layout B):
|
|
24
|
+
* collect all outgoing edges, keep those targeting CALL/METHOD_CALL nodes
|
|
25
|
+
* 3. For each call, check CALLS edge to determine if resolved
|
|
26
|
+
* 4. If transitive=true, recursively follow resolved CALLS edges
|
|
27
|
+
*
|
|
28
|
+
* Performance: O(S + C) where S = scopes, C = calls
|
|
29
|
+
* For functions with 100 calls, expect ~200 DB operations.
|
|
30
|
+
*
|
|
31
|
+
* @module queries/findCallsInFunction
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Maximum BFS depth for downward scope traversal.
|
|
35
|
+
*
|
|
36
|
+
* Each depth level = one CONTAINS hop through nested scopes.
|
|
37
|
+
* Typical function bodies: 2-5 scope levels (if → loop → try → ...).
|
|
38
|
+
* Set to 10 to cover deep nesting while bounding traversal in malformed graphs.
|
|
39
|
+
*/
|
|
40
|
+
const DEFAULT_MAX_SCOPE_DEPTH = 10;
|
|
41
|
+
/**
|
|
42
|
+
* Find all CALL and METHOD_CALL nodes inside a function.
|
|
43
|
+
*
|
|
44
|
+
* @param backend - Graph backend for queries
|
|
45
|
+
* @param functionId - ID of the FUNCTION node
|
|
46
|
+
* @param options - Options for traversal
|
|
47
|
+
* @returns Array of CallInfo objects
|
|
48
|
+
*/
|
|
49
|
+
export async function findCallsInFunction(backend, functionId, options = {}) {
|
|
50
|
+
const { maxDepth = DEFAULT_MAX_SCOPE_DEPTH, transitive = false, transitiveDepth = 5, } = options;
|
|
51
|
+
const calls = [];
|
|
52
|
+
const visited = new Set();
|
|
53
|
+
const seenTargets = new Set(); // For deduplication in transitive mode
|
|
54
|
+
// Add the starting function to seenTargets to prevent cycles back to it
|
|
55
|
+
if (transitive) {
|
|
56
|
+
seenTargets.add(functionId);
|
|
57
|
+
}
|
|
58
|
+
// Step 1: Try HAS_SCOPE path (Layout A — scope chain)
|
|
59
|
+
const hasScopeEdges = await backend.getOutgoingEdges(functionId, ['HAS_SCOPE']);
|
|
60
|
+
if (hasScopeEdges.length > 0) {
|
|
61
|
+
// Layout A: BFS through scope chain
|
|
62
|
+
const queue = [];
|
|
63
|
+
for (const edge of hasScopeEdges) {
|
|
64
|
+
queue.push({ id: edge.dst, depth: 0 });
|
|
65
|
+
}
|
|
66
|
+
while (queue.length > 0) {
|
|
67
|
+
const { id, depth } = queue.shift();
|
|
68
|
+
if (visited.has(id) || depth > maxDepth)
|
|
69
|
+
continue;
|
|
70
|
+
visited.add(id);
|
|
71
|
+
const containsEdges = await backend.getOutgoingEdges(id, ['CONTAINS']);
|
|
72
|
+
for (const edge of containsEdges) {
|
|
73
|
+
const child = await backend.getNode(edge.dst);
|
|
74
|
+
if (!child)
|
|
75
|
+
continue;
|
|
76
|
+
if (child.type === 'CALL' || child.type === 'METHOD_CALL') {
|
|
77
|
+
const callInfo = await buildCallInfo(backend, child, 0);
|
|
78
|
+
calls.push(callInfo);
|
|
79
|
+
if (transitive && callInfo.resolved && callInfo.target) {
|
|
80
|
+
await collectTransitiveCalls(backend, callInfo.target.id, 1, transitiveDepth, calls, seenTargets);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Continue into nested scopes, but NOT into nested functions/classes
|
|
84
|
+
if (child.type === 'SCOPE') {
|
|
85
|
+
queue.push({ id: child.id, depth: depth + 1 });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// Layout B: Direct edges from FUNCTION to CALL/METHOD_CALL nodes
|
|
92
|
+
// The Rust orchestrator links functions to calls via semantic edge types
|
|
93
|
+
// (AWAITS, RETURNS, THROWS, etc.) instead of HAS_SCOPE -> CONTAINS.
|
|
94
|
+
const allOutgoing = await backend.getOutgoingEdges(functionId, null);
|
|
95
|
+
for (const edge of allOutgoing) {
|
|
96
|
+
const child = await backend.getNode(edge.dst);
|
|
97
|
+
if (!child)
|
|
98
|
+
continue;
|
|
99
|
+
if (child.type === 'CALL' || child.type === 'METHOD_CALL') {
|
|
100
|
+
const callInfo = await buildCallInfo(backend, child, 0);
|
|
101
|
+
calls.push(callInfo);
|
|
102
|
+
if (transitive && callInfo.resolved && callInfo.target) {
|
|
103
|
+
await collectTransitiveCalls(backend, callInfo.target.id, 1, transitiveDepth, calls, seenTargets);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return calls;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Build CallInfo from a call node
|
|
112
|
+
*/
|
|
113
|
+
async function buildCallInfo(backend, callNode, depth) {
|
|
114
|
+
// Check for CALLS edge (resolved target)
|
|
115
|
+
const callsEdges = await backend.getOutgoingEdges(callNode.id, ['CALLS']);
|
|
116
|
+
const isResolved = callsEdges.length > 0;
|
|
117
|
+
let target = undefined;
|
|
118
|
+
if (isResolved) {
|
|
119
|
+
const targetNode = await backend.getNode(callsEdges[0].dst);
|
|
120
|
+
if (targetNode) {
|
|
121
|
+
target = {
|
|
122
|
+
id: targetNode.id,
|
|
123
|
+
name: targetNode.name ?? '<anonymous>',
|
|
124
|
+
file: targetNode.file,
|
|
125
|
+
line: targetNode.line,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
id: callNode.id,
|
|
131
|
+
name: callNode.name ?? '<unknown>',
|
|
132
|
+
type: callNode.type,
|
|
133
|
+
object: callNode.object,
|
|
134
|
+
resolved: isResolved,
|
|
135
|
+
target,
|
|
136
|
+
file: callNode.file,
|
|
137
|
+
line: callNode.line,
|
|
138
|
+
depth,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Recursively collect transitive calls
|
|
143
|
+
*
|
|
144
|
+
* Infinite loop prevention:
|
|
145
|
+
* - Track seen function IDs in seenTargets
|
|
146
|
+
* - Stop when we've seen a function before (handles recursion)
|
|
147
|
+
* - Stop at transitiveDepth limit
|
|
148
|
+
*/
|
|
149
|
+
async function collectTransitiveCalls(backend, functionId, currentDepth, maxTransitiveDepth, calls, seenTargets) {
|
|
150
|
+
// Prevent infinite loops and limit depth
|
|
151
|
+
if (seenTargets.has(functionId) || currentDepth > maxTransitiveDepth) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
seenTargets.add(functionId);
|
|
155
|
+
// Find calls in this function (non-transitive to avoid recursion)
|
|
156
|
+
const innerCalls = await findCallsInFunction(backend, functionId, {
|
|
157
|
+
maxDepth: DEFAULT_MAX_SCOPE_DEPTH,
|
|
158
|
+
transitive: false,
|
|
159
|
+
});
|
|
160
|
+
for (const call of innerCalls) {
|
|
161
|
+
// Add with updated depth
|
|
162
|
+
calls.push({ ...call, depth: currentDepth });
|
|
163
|
+
// Continue transitively if resolved
|
|
164
|
+
if (call.resolved && call.target) {
|
|
165
|
+
await collectTransitiveCalls(backend, call.target.id, currentDepth + 1, maxTransitiveDepth, calls, seenTargets);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=findCallsInFunction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findCallsInFunction.js","sourceRoot":"","sources":["../../src/queries/findCallsInFunction.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find the FUNCTION, CLASS, or MODULE that contains a node.
|
|
3
|
+
*
|
|
4
|
+
* Supports two graph layouts:
|
|
5
|
+
*
|
|
6
|
+
* Layout A (scope chain — legacy JS analyzer):
|
|
7
|
+
* ```
|
|
8
|
+
* CALL <- CONTAINS <- SCOPE <- ... <- SCOPE <- HAS_SCOPE <- FUNCTION
|
|
9
|
+
* VARIABLE <- DECLARES <- SCOPE <- ... <- SCOPE <- HAS_SCOPE <- FUNCTION
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* Layout B (direct edges — Rust orchestrator):
|
|
13
|
+
* ```
|
|
14
|
+
* CALL <- AWAITS|RETURNS|THROWS <- FUNCTION
|
|
15
|
+
* ```
|
|
16
|
+
* The orchestrator links functions directly to their call nodes via
|
|
17
|
+
* semantic edge types. These incoming edges on a CALL node point
|
|
18
|
+
* directly back to the containing FUNCTION.
|
|
19
|
+
*
|
|
20
|
+
* Algorithm:
|
|
21
|
+
* 1. BFS up via CONTAINS, HAS_SCOPE, DECLARES (Layout A)
|
|
22
|
+
* 2. Also follow AWAITS, RETURNS, THROWS incoming edges (Layout B)
|
|
23
|
+
* 3. Stop when we find FUNCTION, CLASS, or MODULE
|
|
24
|
+
* 4. Prefer FUNCTION over MODULE (FUNCTION is more specific)
|
|
25
|
+
*
|
|
26
|
+
* @module queries/findContainingFunction
|
|
27
|
+
*/
|
|
28
|
+
import type { CallerInfo } from './types.js';
|
|
29
|
+
/**
|
|
30
|
+
* Graph backend interface (minimal surface)
|
|
31
|
+
*/
|
|
32
|
+
interface GraphBackend {
|
|
33
|
+
getNode(id: string): Promise<{
|
|
34
|
+
id: string;
|
|
35
|
+
type: string;
|
|
36
|
+
name?: string;
|
|
37
|
+
file?: string;
|
|
38
|
+
line?: number;
|
|
39
|
+
} | null>;
|
|
40
|
+
getIncomingEdges(nodeId: string, edgeTypes: string[] | null): Promise<Array<{
|
|
41
|
+
src: string;
|
|
42
|
+
dst: string;
|
|
43
|
+
type: string;
|
|
44
|
+
}>>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Find the FUNCTION, CLASS, or MODULE that contains a node.
|
|
48
|
+
*
|
|
49
|
+
* @param backend - Graph backend for queries
|
|
50
|
+
* @param nodeId - ID of the node to find container for
|
|
51
|
+
* @param maxDepth - Maximum traversal depth (default: {@link DEFAULT_MAX_DEPTH}).
|
|
52
|
+
* Traversal visits depths 0 through maxDepth inclusive.
|
|
53
|
+
* @returns CallerInfo or null if no container found within maxDepth hops
|
|
54
|
+
*/
|
|
55
|
+
export declare function findContainingFunction(backend: GraphBackend, nodeId: string, maxDepth?: number): Promise<CallerInfo | null>;
|
|
56
|
+
export {};
|
|
57
|
+
//# sourceMappingURL=findContainingFunction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findContainingFunction.d.ts","sourceRoot":"","sources":["../../src/queries/findContainingFunction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;GAEG;AACH,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;QAC3B,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GAAG,IAAI,CAAC,CAAC;IACV,gBAAgB,CACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,GACzB,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;CAC/D;AAYD;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,MAA0B,GACnC,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAqD5B"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find the FUNCTION, CLASS, or MODULE that contains a node.
|
|
3
|
+
*
|
|
4
|
+
* Supports two graph layouts:
|
|
5
|
+
*
|
|
6
|
+
* Layout A (scope chain — legacy JS analyzer):
|
|
7
|
+
* ```
|
|
8
|
+
* CALL <- CONTAINS <- SCOPE <- ... <- SCOPE <- HAS_SCOPE <- FUNCTION
|
|
9
|
+
* VARIABLE <- DECLARES <- SCOPE <- ... <- SCOPE <- HAS_SCOPE <- FUNCTION
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* Layout B (direct edges — Rust orchestrator):
|
|
13
|
+
* ```
|
|
14
|
+
* CALL <- AWAITS|RETURNS|THROWS <- FUNCTION
|
|
15
|
+
* ```
|
|
16
|
+
* The orchestrator links functions directly to their call nodes via
|
|
17
|
+
* semantic edge types. These incoming edges on a CALL node point
|
|
18
|
+
* directly back to the containing FUNCTION.
|
|
19
|
+
*
|
|
20
|
+
* Algorithm:
|
|
21
|
+
* 1. BFS up via CONTAINS, HAS_SCOPE, DECLARES (Layout A)
|
|
22
|
+
* 2. Also follow AWAITS, RETURNS, THROWS incoming edges (Layout B)
|
|
23
|
+
* 3. Stop when we find FUNCTION, CLASS, or MODULE
|
|
24
|
+
* 4. Prefer FUNCTION over MODULE (FUNCTION is more specific)
|
|
25
|
+
*
|
|
26
|
+
* @module queries/findContainingFunction
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Maximum BFS depth for upward containment traversal.
|
|
30
|
+
*
|
|
31
|
+
* Each depth level = one CONTAINS/HAS_SCOPE/DECLARES hop.
|
|
32
|
+
* Typical real-world nesting: 3-7 levels (function body → if → loop → try → ...).
|
|
33
|
+
* Set to 15 to handle pathological cases (deeply nested callbacks, complex control flow)
|
|
34
|
+
* while still bounding traversal in malformed graphs.
|
|
35
|
+
*/
|
|
36
|
+
const DEFAULT_MAX_DEPTH = 15;
|
|
37
|
+
/**
|
|
38
|
+
* Find the FUNCTION, CLASS, or MODULE that contains a node.
|
|
39
|
+
*
|
|
40
|
+
* @param backend - Graph backend for queries
|
|
41
|
+
* @param nodeId - ID of the node to find container for
|
|
42
|
+
* @param maxDepth - Maximum traversal depth (default: {@link DEFAULT_MAX_DEPTH}).
|
|
43
|
+
* Traversal visits depths 0 through maxDepth inclusive.
|
|
44
|
+
* @returns CallerInfo or null if no container found within maxDepth hops
|
|
45
|
+
*/
|
|
46
|
+
export async function findContainingFunction(backend, nodeId, maxDepth = DEFAULT_MAX_DEPTH) {
|
|
47
|
+
const visited = new Set();
|
|
48
|
+
const queue = [{ id: nodeId, depth: 0 }];
|
|
49
|
+
// Collect all candidates so we can prefer FUNCTION over MODULE
|
|
50
|
+
let bestCandidate = null;
|
|
51
|
+
while (queue.length > 0) {
|
|
52
|
+
const { id, depth } = queue.shift();
|
|
53
|
+
if (visited.has(id) || depth > maxDepth)
|
|
54
|
+
continue;
|
|
55
|
+
visited.add(id);
|
|
56
|
+
// Layout A edges: CONTAINS, HAS_SCOPE, DECLARES (scope chain traversal)
|
|
57
|
+
// Layout B edges: AWAITS, RETURNS, THROWS (direct function-to-call edges)
|
|
58
|
+
const edges = await backend.getIncomingEdges(id, [
|
|
59
|
+
'CONTAINS', 'HAS_SCOPE', 'DECLARES',
|
|
60
|
+
'AWAITS', 'RETURNS', 'THROWS',
|
|
61
|
+
]);
|
|
62
|
+
for (const edge of edges) {
|
|
63
|
+
const parentNode = await backend.getNode(edge.src);
|
|
64
|
+
if (!parentNode || visited.has(parentNode.id))
|
|
65
|
+
continue;
|
|
66
|
+
// Found container!
|
|
67
|
+
if (parentNode.type === 'FUNCTION' || parentNode.type === 'CLASS' || parentNode.type === 'MODULE') {
|
|
68
|
+
const candidate = {
|
|
69
|
+
id: parentNode.id,
|
|
70
|
+
name: parentNode.name || '<anonymous>',
|
|
71
|
+
type: parentNode.type,
|
|
72
|
+
file: parentNode.file,
|
|
73
|
+
line: parentNode.line,
|
|
74
|
+
};
|
|
75
|
+
// FUNCTION/CLASS is most specific — return immediately
|
|
76
|
+
if (parentNode.type === 'FUNCTION' || parentNode.type === 'CLASS') {
|
|
77
|
+
return candidate;
|
|
78
|
+
}
|
|
79
|
+
// MODULE is less specific — keep as fallback, continue searching
|
|
80
|
+
if (!bestCandidate) {
|
|
81
|
+
bestCandidate = candidate;
|
|
82
|
+
}
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
// Continue searching
|
|
86
|
+
queue.push({ id: parentNode.id, depth: depth + 1 });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return bestCandidate;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=findContainingFunction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findContainingFunction.js","sourceRoot":"","sources":["../../src/queries/findContainingFunction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAqBH;;;;;;;GAOG;AACH,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAE7B;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,OAAqB,EACrB,MAAc,EACd,WAAmB,iBAAiB;IAEpC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,KAAK,GAAyC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IAE/E,+DAA+D;IAC/D,IAAI,aAAa,GAAsB,IAAI,CAAC;IAE5C,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,KAAK,EAAG,CAAC;QAErC,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,KAAK,GAAG,QAAQ;YAAE,SAAS;QAClD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEhB,wEAAwE;QACxE,0EAA0E;QAC1E,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,gBAAgB,CAAC,EAAE,EAAE;YAC/C,UAAU,EAAE,WAAW,EAAE,UAAU;YACnC,QAAQ,EAAE,SAAS,EAAE,QAAQ;SAC9B,CAAC,CAAC;QAEH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACnD,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;gBAAE,SAAS;YAExD,mBAAmB;YACnB,IAAI,UAAU,CAAC,IAAI,KAAK,UAAU,IAAI,UAAU,CAAC,IAAI,KAAK,OAAO,IAAI,UAAU,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAClG,MAAM,SAAS,GAAe;oBAC5B,EAAE,EAAE,UAAU,CAAC,EAAE;oBACjB,IAAI,EAAE,UAAU,CAAC,IAAI,IAAI,aAAa;oBACtC,IAAI,EAAE,UAAU,CAAC,IAAI;oBACrB,IAAI,EAAE,UAAU,CAAC,IAAI;oBACrB,IAAI,EAAE,UAAU,CAAC,IAAI;iBACtB,CAAC;gBAEF,uDAAuD;gBACvD,IAAI,UAAU,CAAC,IAAI,KAAK,UAAU,IAAI,UAAU,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAClE,OAAO,SAAS,CAAC;gBACnB,CAAC;gBAED,iEAAiE;gBACjE,IAAI,CAAC,aAAa,EAAE,CAAC;oBACnB,aAAa,GAAG,SAAS,CAAC;gBAC5B,CAAC;gBAED,SAAS;YACX,CAAC;YAED,qBAAqB;YACrB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED,OAAO,aAAa,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph Query Utilities
|
|
3
|
+
*
|
|
4
|
+
* Shared utilities for querying the code graph.
|
|
5
|
+
* Used by MCP, CLI, and other tools.
|
|
6
|
+
*
|
|
7
|
+
* @module queries
|
|
8
|
+
*/
|
|
9
|
+
export { findCallsInFunction } from './findCallsInFunction.js';
|
|
10
|
+
export { findContainingFunction } from './findContainingFunction.js';
|
|
11
|
+
export { traceValues, aggregateValues, NONDETERMINISTIC_PATTERNS, NONDETERMINISTIC_OBJECTS } from './traceValues.js';
|
|
12
|
+
export { traceDataflow, traceForwardBFS, traceBackwardBFS } from './traceDataflow.js';
|
|
13
|
+
export { buildNodeContext, getNodeDisplayName, formatEdgeMetadata, STRUCTURAL_EDGE_TYPES, } from './NodeContext.js';
|
|
14
|
+
export type { CallInfo, CallerInfo, FindCallsOptions } from './types.js';
|
|
15
|
+
export type { EdgeWithNode, EdgeGroup, SourcePreview, NodeContext, BuildNodeContextOptions, } from './NodeContext.js';
|
|
16
|
+
export type { TracedValue, ValueSource, UnknownReason, TraceValuesOptions, ValueSetResult, TraceValuesGraphBackend, NondeterministicPattern, } from './types.js';
|
|
17
|
+
export type { DataflowNode, DataflowEdge, DataflowBackend, TraceDataflowOptions, TraceDataflowResult, } from './traceDataflow.js';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/queries/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AACrH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtF,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACzE,YAAY,EACV,YAAY,EACZ,SAAS,EACT,aAAa,EACb,WAAW,EACX,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,WAAW,EACX,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph Query Utilities
|
|
3
|
+
*
|
|
4
|
+
* Shared utilities for querying the code graph.
|
|
5
|
+
* Used by MCP, CLI, and other tools.
|
|
6
|
+
*
|
|
7
|
+
* @module queries
|
|
8
|
+
*/
|
|
9
|
+
export { findCallsInFunction } from './findCallsInFunction.js';
|
|
10
|
+
export { findContainingFunction } from './findContainingFunction.js';
|
|
11
|
+
export { traceValues, aggregateValues, NONDETERMINISTIC_PATTERNS, NONDETERMINISTIC_OBJECTS } from './traceValues.js';
|
|
12
|
+
export { traceDataflow, traceForwardBFS, traceBackwardBFS } from './traceDataflow.js';
|
|
13
|
+
export { buildNodeContext, getNodeDisplayName, formatEdgeMetadata, STRUCTURAL_EDGE_TYPES, } from './NodeContext.js';
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/queries/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AACrH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtF,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,kBAAkB,CAAC"}
|