@grafema/core 0.1.1-alpha → 0.2.1-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/dist/Orchestrator.d.ts +7 -0
- package/dist/Orchestrator.d.ts.map +1 -1
- package/dist/Orchestrator.js +25 -3
- package/dist/config/ConfigLoader.d.ts +18 -0
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js +65 -3
- package/dist/core/FileExplainer.d.ts +101 -0
- package/dist/core/FileExplainer.d.ts.map +1 -0
- package/dist/core/FileExplainer.js +139 -0
- package/dist/core/NodeFactory.d.ts +44 -5
- package/dist/core/NodeFactory.d.ts.map +1 -1
- package/dist/core/NodeFactory.js +52 -7
- package/dist/core/nodes/ArrayLiteralNode.d.ts.map +1 -1
- package/dist/core/nodes/ArrayLiteralNode.js +4 -2
- package/dist/core/nodes/BranchNode.d.ts +41 -0
- package/dist/core/nodes/BranchNode.d.ts.map +1 -0
- package/dist/core/nodes/BranchNode.js +82 -0
- package/dist/core/nodes/CallSiteNode.d.ts +2 -2
- package/dist/core/nodes/CallSiteNode.d.ts.map +1 -1
- package/dist/core/nodes/CallSiteNode.js +9 -5
- package/dist/core/nodes/CaseNode.d.ts +43 -0
- package/dist/core/nodes/CaseNode.d.ts.map +1 -0
- package/dist/core/nodes/CaseNode.js +81 -0
- package/dist/core/nodes/ClassNode.d.ts +2 -2
- package/dist/core/nodes/ClassNode.d.ts.map +1 -1
- package/dist/core/nodes/ClassNode.js +8 -4
- package/dist/core/nodes/ConstantNode.d.ts +2 -2
- package/dist/core/nodes/ConstantNode.d.ts.map +1 -1
- package/dist/core/nodes/ConstantNode.js +6 -4
- package/dist/core/nodes/ConstructorCallNode.d.ts +51 -0
- package/dist/core/nodes/ConstructorCallNode.d.ts.map +1 -0
- package/dist/core/nodes/ConstructorCallNode.js +171 -0
- package/dist/core/nodes/DatabaseQueryNode.d.ts +3 -2
- package/dist/core/nodes/DatabaseQueryNode.d.ts.map +1 -1
- package/dist/core/nodes/DatabaseQueryNode.js +5 -2
- package/dist/core/nodes/DecoratorNode.d.ts +2 -2
- package/dist/core/nodes/DecoratorNode.d.ts.map +1 -1
- package/dist/core/nodes/DecoratorNode.js +5 -3
- package/dist/core/nodes/EnumNode.d.ts +2 -2
- package/dist/core/nodes/EnumNode.d.ts.map +1 -1
- package/dist/core/nodes/EnumNode.js +5 -3
- package/dist/core/nodes/EventListenerNode.d.ts +4 -4
- package/dist/core/nodes/EventListenerNode.d.ts.map +1 -1
- package/dist/core/nodes/EventListenerNode.js +7 -4
- package/dist/core/nodes/ExportNode.d.ts +2 -2
- package/dist/core/nodes/ExportNode.d.ts.map +1 -1
- package/dist/core/nodes/ExportNode.js +8 -4
- package/dist/core/nodes/ExpressionNode.d.ts +2 -2
- package/dist/core/nodes/ExpressionNode.d.ts.map +1 -1
- package/dist/core/nodes/ExpressionNode.js +6 -4
- package/dist/core/nodes/ExternalModuleNode.d.ts +4 -0
- package/dist/core/nodes/ExternalModuleNode.d.ts.map +1 -1
- package/dist/core/nodes/ExternalModuleNode.js +10 -2
- package/dist/core/nodes/HttpRequestNode.d.ts +4 -4
- package/dist/core/nodes/HttpRequestNode.d.ts.map +1 -1
- package/dist/core/nodes/HttpRequestNode.js +7 -4
- package/dist/core/nodes/ImportNode.d.ts +10 -2
- package/dist/core/nodes/ImportNode.d.ts.map +1 -1
- package/dist/core/nodes/ImportNode.js +21 -4
- package/dist/core/nodes/InterfaceNode.d.ts +2 -2
- package/dist/core/nodes/InterfaceNode.d.ts.map +1 -1
- package/dist/core/nodes/InterfaceNode.js +5 -3
- package/dist/core/nodes/LiteralNode.d.ts +2 -2
- package/dist/core/nodes/LiteralNode.d.ts.map +1 -1
- package/dist/core/nodes/LiteralNode.js +6 -4
- package/dist/core/nodes/MethodCallNode.d.ts +2 -2
- package/dist/core/nodes/MethodCallNode.d.ts.map +1 -1
- package/dist/core/nodes/MethodCallNode.js +9 -5
- package/dist/core/nodes/MethodNode.d.ts +2 -2
- package/dist/core/nodes/MethodNode.d.ts.map +1 -1
- package/dist/core/nodes/MethodNode.js +8 -4
- package/dist/core/nodes/ObjectLiteralNode.d.ts.map +1 -1
- package/dist/core/nodes/ObjectLiteralNode.js +4 -2
- package/dist/core/nodes/ParameterNode.d.ts +2 -2
- package/dist/core/nodes/ParameterNode.d.ts.map +1 -1
- package/dist/core/nodes/ParameterNode.js +5 -3
- package/dist/core/nodes/TypeNode.d.ts +2 -2
- package/dist/core/nodes/TypeNode.d.ts.map +1 -1
- package/dist/core/nodes/TypeNode.js +5 -3
- package/dist/core/nodes/VariableDeclarationNode.d.ts +2 -2
- package/dist/core/nodes/VariableDeclarationNode.d.ts.map +1 -1
- package/dist/core/nodes/VariableDeclarationNode.js +9 -5
- package/dist/core/nodes/index.d.ts +3 -0
- package/dist/core/nodes/index.d.ts.map +1 -1
- package/dist/core/nodes/index.js +3 -0
- package/dist/data/builtins/BuiltinRegistry.d.ts +78 -0
- package/dist/data/builtins/BuiltinRegistry.d.ts.map +1 -0
- package/dist/data/builtins/BuiltinRegistry.js +110 -0
- package/dist/data/builtins/definitions.d.ts +28 -0
- package/dist/data/builtins/definitions.d.ts.map +1 -0
- package/dist/data/builtins/definitions.js +250 -0
- package/dist/data/builtins/index.d.ts +10 -0
- package/dist/data/builtins/index.d.ts.map +1 -0
- package/dist/data/builtins/index.js +8 -0
- package/dist/data/builtins/jsGlobals.d.ts +18 -0
- package/dist/data/builtins/jsGlobals.d.ts.map +1 -0
- package/dist/data/builtins/jsGlobals.js +26 -0
- package/dist/data/builtins/types.d.ts +34 -0
- package/dist/data/builtins/types.d.ts.map +1 -0
- package/dist/data/builtins/types.js +7 -0
- package/dist/data/globals/definitions.d.ts +27 -0
- package/dist/data/globals/definitions.d.ts.map +1 -0
- package/dist/data/globals/definitions.js +117 -0
- package/dist/data/globals/index.d.ts +36 -0
- package/dist/data/globals/index.d.ts.map +1 -0
- package/dist/data/globals/index.js +52 -0
- package/dist/diagnostics/DiagnosticReporter.d.ts +23 -0
- package/dist/diagnostics/DiagnosticReporter.d.ts.map +1 -1
- package/dist/diagnostics/DiagnosticReporter.js +88 -0
- package/dist/diagnostics/index.d.ts +1 -1
- package/dist/diagnostics/index.d.ts.map +1 -1
- package/dist/errors/GrafemaError.d.ts +43 -0
- package/dist/errors/GrafemaError.d.ts.map +1 -1
- package/dist/errors/GrafemaError.js +50 -0
- package/dist/index.d.ts +17 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -1
- package/dist/plugins/analysis/DatabaseAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/DatabaseAnalyzer.js +3 -2
- package/dist/plugins/analysis/ExpressAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/ExpressAnalyzer.js +3 -1
- package/dist/plugins/analysis/ExpressResponseAnalyzer.d.ts +148 -0
- package/dist/plugins/analysis/ExpressResponseAnalyzer.d.ts.map +1 -0
- package/dist/plugins/analysis/ExpressResponseAnalyzer.js +495 -0
- package/dist/plugins/analysis/ExpressRouteAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/ExpressRouteAnalyzer.js +53 -18
- package/dist/plugins/analysis/FetchAnalyzer.d.ts +40 -0
- package/dist/plugins/analysis/FetchAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/FetchAnalyzer.js +163 -15
- package/dist/plugins/analysis/JSASTAnalyzer.d.ts +157 -26
- package/dist/plugins/analysis/JSASTAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/JSASTAnalyzer.js +2418 -191
- package/dist/plugins/analysis/RustAnalyzer.js +4 -4
- package/dist/plugins/analysis/SQLiteAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/SQLiteAnalyzer.js +4 -2
- package/dist/plugins/analysis/SocketIOAnalyzer.d.ts +9 -0
- package/dist/plugins/analysis/SocketIOAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/SocketIOAnalyzer.js +91 -7
- package/dist/plugins/analysis/ast/GraphBuilder.d.ts +173 -0
- package/dist/plugins/analysis/ast/GraphBuilder.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/GraphBuilder.js +1256 -65
- package/dist/plugins/analysis/ast/types.d.ts +294 -0
- package/dist/plugins/analysis/ast/types.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/ASTVisitor.d.ts +5 -1
- package/dist/plugins/analysis/ast/visitors/ASTVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts +1 -0
- package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.js +12 -1
- package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts +10 -0
- package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/FunctionVisitor.js +62 -0
- package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.d.ts +4 -0
- package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.js +101 -0
- package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts +16 -1
- package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/VariableVisitor.js +233 -39
- package/dist/plugins/discovery/WorkspaceDiscovery.d.ts.map +1 -1
- package/dist/plugins/discovery/WorkspaceDiscovery.js +9 -4
- package/dist/plugins/enrichment/AliasTracker.d.ts.map +1 -1
- package/dist/plugins/enrichment/AliasTracker.js +16 -1
- package/dist/plugins/enrichment/ArgumentParameterLinker.d.ts +32 -0
- package/dist/plugins/enrichment/ArgumentParameterLinker.d.ts.map +1 -0
- package/dist/plugins/enrichment/ArgumentParameterLinker.js +175 -0
- package/dist/plugins/enrichment/ClosureCaptureEnricher.d.ts +51 -0
- package/dist/plugins/enrichment/ClosureCaptureEnricher.d.ts.map +1 -0
- package/dist/plugins/enrichment/ClosureCaptureEnricher.js +205 -0
- package/dist/plugins/enrichment/ExternalCallResolver.d.ts +42 -0
- package/dist/plugins/enrichment/ExternalCallResolver.d.ts.map +1 -0
- package/dist/plugins/enrichment/ExternalCallResolver.js +213 -0
- package/dist/plugins/enrichment/FunctionCallResolver.d.ts +58 -0
- package/dist/plugins/enrichment/FunctionCallResolver.d.ts.map +1 -0
- package/dist/plugins/enrichment/FunctionCallResolver.js +340 -0
- package/dist/plugins/enrichment/HTTPConnectionEnricher.d.ts +16 -3
- package/dist/plugins/enrichment/HTTPConnectionEnricher.d.ts.map +1 -1
- package/dist/plugins/enrichment/HTTPConnectionEnricher.js +64 -20
- package/dist/plugins/enrichment/MethodCallResolver.d.ts.map +1 -1
- package/dist/plugins/enrichment/MethodCallResolver.js +15 -1
- package/dist/plugins/enrichment/MountPointResolver.d.ts +14 -12
- package/dist/plugins/enrichment/MountPointResolver.d.ts.map +1 -1
- package/dist/plugins/enrichment/MountPointResolver.js +172 -151
- package/dist/plugins/enrichment/NodejsBuiltinsResolver.d.ts +44 -0
- package/dist/plugins/enrichment/NodejsBuiltinsResolver.d.ts.map +1 -0
- package/dist/plugins/enrichment/NodejsBuiltinsResolver.js +271 -0
- package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts +5 -27
- package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts.map +1 -1
- package/dist/plugins/enrichment/ValueDomainAnalyzer.js +62 -139
- package/dist/plugins/indexing/JSModuleIndexer.d.ts +15 -0
- package/dist/plugins/indexing/JSModuleIndexer.d.ts.map +1 -1
- package/dist/plugins/indexing/JSModuleIndexer.js +58 -0
- package/dist/plugins/indexing/RustModuleIndexer.d.ts +1 -1
- package/dist/plugins/indexing/RustModuleIndexer.js +4 -4
- package/dist/plugins/validation/BrokenImportValidator.d.ts +31 -0
- package/dist/plugins/validation/BrokenImportValidator.d.ts.map +1 -0
- package/dist/plugins/validation/BrokenImportValidator.js +249 -0
- package/dist/plugins/validation/CallResolverValidator.d.ts +21 -10
- package/dist/plugins/validation/CallResolverValidator.d.ts.map +1 -1
- package/dist/plugins/validation/CallResolverValidator.js +101 -76
- package/dist/plugins/validation/DataFlowValidator.d.ts.map +1 -1
- package/dist/plugins/validation/DataFlowValidator.js +49 -41
- package/dist/plugins/validation/GraphConnectivityValidator.d.ts.map +1 -1
- package/dist/plugins/validation/GraphConnectivityValidator.js +25 -1
- package/dist/plugins/validation/SQLInjectionValidator.d.ts.map +1 -1
- package/dist/plugins/validation/SQLInjectionValidator.js +2 -3
- package/dist/queries/findCallsInFunction.d.ts +52 -0
- package/dist/queries/findCallsInFunction.d.ts.map +1 -0
- package/dist/queries/findCallsInFunction.js +135 -0
- package/dist/queries/findContainingFunction.d.ts +45 -0
- package/dist/queries/findContainingFunction.d.ts.map +1 -0
- package/dist/queries/findContainingFunction.js +54 -0
- package/dist/queries/index.d.ts +14 -0
- package/dist/queries/index.d.ts.map +1 -0
- package/dist/queries/index.js +11 -0
- package/dist/queries/traceValues.d.ts +70 -0
- package/dist/queries/traceValues.d.ts.map +1 -0
- package/dist/queries/traceValues.js +299 -0
- package/dist/queries/types.d.ts +163 -0
- package/dist/queries/types.d.ts.map +1 -0
- package/dist/queries/types.js +9 -0
- package/dist/schema/GraphSchemaExtractor.d.ts +53 -0
- package/dist/schema/GraphSchemaExtractor.d.ts.map +1 -0
- package/dist/schema/GraphSchemaExtractor.js +124 -0
- package/dist/schema/InterfaceSchemaExtractor.d.ts +73 -0
- package/dist/schema/InterfaceSchemaExtractor.d.ts.map +1 -0
- package/dist/schema/InterfaceSchemaExtractor.js +112 -0
- package/dist/schema/index.d.ts +5 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +2 -0
- package/dist/storage/backends/RFDBServerBackend.d.ts +13 -18
- package/dist/storage/backends/RFDBServerBackend.d.ts.map +1 -1
- package/dist/storage/backends/RFDBServerBackend.js +47 -51
- package/dist/storage/backends/typeValidation.d.ts.map +1 -1
- package/dist/storage/backends/typeValidation.js +1 -0
- package/package.json +3 -3
- package/src/Orchestrator.ts +35 -3
- package/src/config/ConfigLoader.ts +94 -3
- package/src/core/FileExplainer.ts +179 -0
- package/src/core/NodeFactory.ts +72 -8
- package/src/core/nodes/ArrayLiteralNode.ts +3 -2
- package/src/core/nodes/BranchNode.ts +113 -0
- package/src/core/nodes/CallSiteNode.ts +7 -5
- package/src/core/nodes/CaseNode.ts +123 -0
- package/src/core/nodes/ClassNode.ts +6 -4
- package/src/core/nodes/ConstantNode.ts +5 -4
- package/src/core/nodes/ConstructorCallNode.ts +217 -0
- package/src/core/nodes/DatabaseQueryNode.ts +5 -1
- package/src/core/nodes/DecoratorNode.ts +4 -3
- package/src/core/nodes/EnumNode.ts +4 -3
- package/src/core/nodes/EventListenerNode.ts +7 -4
- package/src/core/nodes/ExportNode.ts +6 -4
- package/src/core/nodes/ExpressionNode.ts +5 -4
- package/src/core/nodes/ExternalModuleNode.ts +11 -2
- package/src/core/nodes/HttpRequestNode.ts +7 -4
- package/src/core/nodes/ImportNode.ts +31 -4
- package/src/core/nodes/InterfaceNode.ts +4 -3
- package/src/core/nodes/LiteralNode.ts +5 -4
- package/src/core/nodes/MethodCallNode.ts +7 -5
- package/src/core/nodes/MethodNode.ts +6 -4
- package/src/core/nodes/ObjectLiteralNode.ts +3 -2
- package/src/core/nodes/ParameterNode.ts +4 -3
- package/src/core/nodes/TypeNode.ts +4 -3
- package/src/core/nodes/VariableDeclarationNode.ts +7 -5
- package/src/core/nodes/index.ts +3 -0
- package/src/data/builtins/BuiltinRegistry.ts +124 -0
- package/src/data/builtins/definitions.ts +267 -0
- package/src/data/builtins/index.ts +10 -0
- package/src/data/builtins/jsGlobals.ts +28 -0
- package/src/data/builtins/types.ts +36 -0
- package/src/data/globals/definitions.ts +156 -0
- package/src/data/globals/index.ts +66 -0
- package/src/diagnostics/DiagnosticReporter.ts +120 -0
- package/src/diagnostics/index.ts +1 -1
- package/src/errors/GrafemaError.ts +65 -0
- package/src/index.ts +45 -0
- package/src/plugins/analysis/DatabaseAnalyzer.ts +4 -2
- package/src/plugins/analysis/ExpressAnalyzer.ts +5 -1
- package/src/plugins/analysis/ExpressResponseAnalyzer.ts +636 -0
- package/src/plugins/analysis/ExpressRouteAnalyzer.ts +57 -18
- package/src/plugins/analysis/FetchAnalyzer.ts +204 -16
- package/src/plugins/analysis/JSASTAnalyzer.ts +2958 -260
- package/src/plugins/analysis/RustAnalyzer.ts +4 -4
- package/src/plugins/analysis/SQLiteAnalyzer.ts +5 -2
- package/src/plugins/analysis/SocketIOAnalyzer.ts +121 -7
- package/src/plugins/analysis/ast/GraphBuilder.ts +1578 -70
- package/src/plugins/analysis/ast/types.ts +387 -0
- package/src/plugins/analysis/ast/visitors/ASTVisitor.ts +8 -0
- package/src/plugins/analysis/ast/visitors/CallExpressionVisitor.ts +16 -1
- package/src/plugins/analysis/ast/visitors/FunctionVisitor.ts +77 -2
- package/src/plugins/analysis/ast/visitors/ImportExportVisitor.ts +112 -1
- package/src/plugins/analysis/ast/visitors/VariableVisitor.ts +272 -47
- package/src/plugins/discovery/WorkspaceDiscovery.ts +11 -4
- package/src/plugins/enrichment/AliasTracker.ts +22 -1
- package/src/plugins/enrichment/ArgumentParameterLinker.ts +240 -0
- package/src/plugins/enrichment/ClosureCaptureEnricher.ts +267 -0
- package/src/plugins/enrichment/ExternalCallResolver.ts +262 -0
- package/src/plugins/enrichment/FunctionCallResolver.ts +456 -0
- package/src/plugins/enrichment/HTTPConnectionEnricher.ts +70 -20
- package/src/plugins/enrichment/MethodCallResolver.ts +21 -1
- package/src/plugins/enrichment/MountPointResolver.ts +206 -198
- package/src/plugins/enrichment/NodejsBuiltinsResolver.ts +365 -0
- package/src/plugins/enrichment/ValueDomainAnalyzer.ts +67 -184
- package/src/plugins/indexing/JSModuleIndexer.ts +66 -0
- package/src/plugins/indexing/RustModuleIndexer.ts +4 -4
- package/src/plugins/validation/BrokenImportValidator.ts +325 -0
- package/src/plugins/validation/CallResolverValidator.ts +129 -109
- package/src/plugins/validation/DataFlowValidator.ts +75 -58
- package/src/plugins/validation/GraphConnectivityValidator.ts +39 -1
- package/src/plugins/validation/SQLInjectionValidator.ts +2 -5
- package/src/queries/README.md +46 -0
- package/src/queries/findCallsInFunction.ts +206 -0
- package/src/queries/findContainingFunction.ts +83 -0
- package/src/queries/index.ts +23 -0
- package/src/queries/traceValues.ts +398 -0
- package/src/queries/types.ts +187 -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 +64 -68
- package/src/storage/backends/typeValidation.ts +1 -0
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NodejsBuiltinsResolver - Creates EXTERNAL_FUNCTION nodes for Node.js builtin calls (REG-218)
|
|
3
|
+
*
|
|
4
|
+
* This ENRICHMENT plugin:
|
|
5
|
+
* 1. Queries all CALL nodes
|
|
6
|
+
* 2. For each call that targets a builtin function:
|
|
7
|
+
* - Checks if call's `object` matches a builtin module (fs, path, etc.)
|
|
8
|
+
* - Or traces via IMPORT node to find the module source
|
|
9
|
+
* 3. Creates EXTERNAL_FUNCTION node lazily (if not exists)
|
|
10
|
+
* 4. Creates CALLS edge from CALL to EXTERNAL_FUNCTION
|
|
11
|
+
*
|
|
12
|
+
* Architecture:
|
|
13
|
+
* - Nodes are created lazily - only when a call is detected
|
|
14
|
+
* - ID format: EXTERNAL_FUNCTION:fs.readFile
|
|
15
|
+
* - Metadata includes: isBuiltin:true, security?, pure?
|
|
16
|
+
*
|
|
17
|
+
* Also creates:
|
|
18
|
+
* - EXTERNAL_MODULE nodes for imported builtin modules
|
|
19
|
+
* - IMPORTS_FROM edges from IMPORT to EXTERNAL_MODULE
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { Plugin, createSuccessResult } from '../Plugin.js';
|
|
23
|
+
import type { PluginContext, PluginResult, PluginMetadata } from '../Plugin.js';
|
|
24
|
+
import type { BaseNodeRecord } from '@grafema/types';
|
|
25
|
+
import { BuiltinRegistry } from '../../data/builtins/BuiltinRegistry.js';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Call node with method properties
|
|
29
|
+
*/
|
|
30
|
+
interface CallNode extends BaseNodeRecord {
|
|
31
|
+
object?: string;
|
|
32
|
+
method?: string;
|
|
33
|
+
callee?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Import node with source info
|
|
38
|
+
*/
|
|
39
|
+
interface ImportNode extends BaseNodeRecord {
|
|
40
|
+
source?: string;
|
|
41
|
+
imported?: string;
|
|
42
|
+
importType?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class NodejsBuiltinsResolver extends Plugin {
|
|
46
|
+
private registry: BuiltinRegistry;
|
|
47
|
+
|
|
48
|
+
constructor(config: Record<string, unknown> = {}) {
|
|
49
|
+
super(config);
|
|
50
|
+
this.registry = new BuiltinRegistry();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get metadata(): PluginMetadata {
|
|
54
|
+
return {
|
|
55
|
+
name: 'NodejsBuiltinsResolver',
|
|
56
|
+
phase: 'ENRICHMENT',
|
|
57
|
+
priority: 45, // After ImportExportLinker (90), before/around MethodCallResolver (50)
|
|
58
|
+
creates: {
|
|
59
|
+
nodes: ['EXTERNAL_FUNCTION', 'EXTERNAL_MODULE'],
|
|
60
|
+
edges: ['CALLS', 'IMPORTS_FROM']
|
|
61
|
+
},
|
|
62
|
+
dependencies: ['JSASTAnalyzer', 'ImportExportLinker']
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async execute(context: PluginContext): Promise<PluginResult> {
|
|
67
|
+
const { graph, onProgress } = context;
|
|
68
|
+
const logger = this.log(context);
|
|
69
|
+
|
|
70
|
+
logger.info('Starting Node.js builtins resolution');
|
|
71
|
+
const startTime = Date.now();
|
|
72
|
+
|
|
73
|
+
// Track created nodes and edges to avoid duplicates
|
|
74
|
+
const createdExternalFunctions = new Set<string>();
|
|
75
|
+
const createdExternalModules = new Set<string>();
|
|
76
|
+
const createdCallsEdges = new Set<string>();
|
|
77
|
+
const createdImportsFromEdges = new Set<string>();
|
|
78
|
+
|
|
79
|
+
// Build import index: local name -> {source, imported}
|
|
80
|
+
// For tracking what module each imported function comes from
|
|
81
|
+
const importIndex = await this.buildImportIndex(graph);
|
|
82
|
+
logger.debug('Built import index', { entries: importIndex.size });
|
|
83
|
+
|
|
84
|
+
// Step 1: Create EXTERNAL_MODULE nodes for builtin imports
|
|
85
|
+
// and IMPORTS_FROM edges
|
|
86
|
+
let externalModulesCreated = 0;
|
|
87
|
+
let importsFromEdgesCreated = 0;
|
|
88
|
+
|
|
89
|
+
for (const [, importInfo] of importIndex) {
|
|
90
|
+
const { source, file, localName, importNodeId, importType } = importInfo;
|
|
91
|
+
const normalizedSource = this.registry.normalizeModule(source);
|
|
92
|
+
|
|
93
|
+
if (this.registry.isBuiltinModule(normalizedSource)) {
|
|
94
|
+
// Create EXTERNAL_MODULE node if not exists
|
|
95
|
+
if (!createdExternalModules.has(normalizedSource)) {
|
|
96
|
+
const moduleNodeId = `EXTERNAL_MODULE:${normalizedSource}`;
|
|
97
|
+
|
|
98
|
+
// Check if node already exists in graph
|
|
99
|
+
const existingNode = await graph.getNode(moduleNodeId);
|
|
100
|
+
if (!existingNode) {
|
|
101
|
+
await graph.addNode({
|
|
102
|
+
id: moduleNodeId,
|
|
103
|
+
type: 'EXTERNAL_MODULE',
|
|
104
|
+
name: normalizedSource,
|
|
105
|
+
file: '',
|
|
106
|
+
line: 0
|
|
107
|
+
});
|
|
108
|
+
externalModulesCreated++;
|
|
109
|
+
}
|
|
110
|
+
createdExternalModules.add(normalizedSource);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Create IMPORTS_FROM edge from IMPORT to EXTERNAL_MODULE
|
|
114
|
+
const moduleNodeId = `EXTERNAL_MODULE:${normalizedSource}`;
|
|
115
|
+
const edgeKey = `${importNodeId}:${moduleNodeId}`;
|
|
116
|
+
|
|
117
|
+
if (!createdImportsFromEdges.has(edgeKey) && importNodeId) {
|
|
118
|
+
// Check if edge already exists
|
|
119
|
+
const existingEdges = await graph.getOutgoingEdges(importNodeId, ['IMPORTS_FROM']);
|
|
120
|
+
const alreadyExists = existingEdges.some(e => e.dst === moduleNodeId);
|
|
121
|
+
|
|
122
|
+
if (!alreadyExists) {
|
|
123
|
+
await graph.addEdge({
|
|
124
|
+
type: 'IMPORTS_FROM',
|
|
125
|
+
src: importNodeId,
|
|
126
|
+
dst: moduleNodeId
|
|
127
|
+
});
|
|
128
|
+
importsFromEdgesCreated++;
|
|
129
|
+
}
|
|
130
|
+
createdImportsFromEdges.add(edgeKey);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
logger.debug('Created EXTERNAL_MODULE nodes', { count: externalModulesCreated });
|
|
136
|
+
logger.debug('Created IMPORTS_FROM edges', { count: importsFromEdgesCreated });
|
|
137
|
+
|
|
138
|
+
// Step 2: Process all CALL nodes
|
|
139
|
+
const allCalls: CallNode[] = [];
|
|
140
|
+
for await (const node of graph.queryNodes({ nodeType: 'CALL' })) {
|
|
141
|
+
allCalls.push(node as CallNode);
|
|
142
|
+
}
|
|
143
|
+
logger.info('Found CALL nodes to process', { count: allCalls.length });
|
|
144
|
+
|
|
145
|
+
let nodesCreated = 0;
|
|
146
|
+
let edgesCreated = 0;
|
|
147
|
+
let processed = 0;
|
|
148
|
+
|
|
149
|
+
for (const callNode of allCalls) {
|
|
150
|
+
processed++;
|
|
151
|
+
|
|
152
|
+
// Progress reporting
|
|
153
|
+
if (onProgress && processed % 100 === 0) {
|
|
154
|
+
onProgress({
|
|
155
|
+
phase: 'enrichment',
|
|
156
|
+
currentPlugin: 'NodejsBuiltinsResolver',
|
|
157
|
+
message: `Processing calls ${processed}/${allCalls.length}`,
|
|
158
|
+
totalFiles: allCalls.length,
|
|
159
|
+
processedFiles: processed
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Determine module and function name
|
|
164
|
+
const resolution = this.resolveBuiltinCall(callNode, importIndex);
|
|
165
|
+
if (!resolution) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const { moduleName, functionName } = resolution;
|
|
170
|
+
|
|
171
|
+
// Check if this is a known builtin function
|
|
172
|
+
const funcDef = this.registry.getFunction(moduleName, functionName);
|
|
173
|
+
if (!funcDef) {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Create EXTERNAL_FUNCTION node if not exists
|
|
178
|
+
const externalFuncId = this.registry.createNodeId(moduleName, functionName);
|
|
179
|
+
|
|
180
|
+
if (!createdExternalFunctions.has(externalFuncId)) {
|
|
181
|
+
// Check if node already exists in graph
|
|
182
|
+
const existingNode = await graph.getNode(externalFuncId);
|
|
183
|
+
if (!existingNode) {
|
|
184
|
+
await graph.addNode({
|
|
185
|
+
id: externalFuncId,
|
|
186
|
+
type: 'EXTERNAL_FUNCTION',
|
|
187
|
+
name: `${this.registry.normalizeModule(moduleName)}.${functionName}`,
|
|
188
|
+
file: '',
|
|
189
|
+
line: 0,
|
|
190
|
+
isBuiltin: true,
|
|
191
|
+
...(funcDef.security && { security: funcDef.security }),
|
|
192
|
+
...(funcDef.pure !== undefined && { pure: funcDef.pure })
|
|
193
|
+
});
|
|
194
|
+
nodesCreated++;
|
|
195
|
+
}
|
|
196
|
+
createdExternalFunctions.add(externalFuncId);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Create CALLS edge from CALL to EXTERNAL_FUNCTION
|
|
200
|
+
const edgeKey = `${callNode.id}:${externalFuncId}`;
|
|
201
|
+
if (!createdCallsEdges.has(edgeKey)) {
|
|
202
|
+
// Check if CALLS edge already exists
|
|
203
|
+
const existingEdges = await graph.getOutgoingEdges(callNode.id, ['CALLS']);
|
|
204
|
+
const alreadyExists = existingEdges.some(e => e.dst === externalFuncId);
|
|
205
|
+
|
|
206
|
+
if (!alreadyExists) {
|
|
207
|
+
await graph.addEdge({
|
|
208
|
+
type: 'CALLS',
|
|
209
|
+
src: callNode.id,
|
|
210
|
+
dst: externalFuncId
|
|
211
|
+
});
|
|
212
|
+
edgesCreated++;
|
|
213
|
+
}
|
|
214
|
+
createdCallsEdges.add(edgeKey);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const totalTime = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
219
|
+
const summary = {
|
|
220
|
+
callsProcessed: processed,
|
|
221
|
+
externalFunctionsCreated: nodesCreated,
|
|
222
|
+
externalModulesCreated,
|
|
223
|
+
callsEdgesCreated: edgesCreated,
|
|
224
|
+
importsFromEdgesCreated,
|
|
225
|
+
time: `${totalTime}s`
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
logger.info('Complete', summary);
|
|
229
|
+
|
|
230
|
+
return createSuccessResult(
|
|
231
|
+
{
|
|
232
|
+
nodes: nodesCreated + externalModulesCreated,
|
|
233
|
+
edges: edgesCreated + importsFromEdgesCreated
|
|
234
|
+
},
|
|
235
|
+
summary
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Build index of imports for tracking module sources.
|
|
241
|
+
*
|
|
242
|
+
* Maps: file:localName -> {source, imported, importNodeId, importType}
|
|
243
|
+
*/
|
|
244
|
+
private async buildImportIndex(
|
|
245
|
+
graph: PluginContext['graph']
|
|
246
|
+
): Promise<Map<string, {
|
|
247
|
+
source: string;
|
|
248
|
+
imported: string;
|
|
249
|
+
localName: string;
|
|
250
|
+
file: string;
|
|
251
|
+
importNodeId: string;
|
|
252
|
+
importType?: string;
|
|
253
|
+
}>> {
|
|
254
|
+
const index = new Map<string, {
|
|
255
|
+
source: string;
|
|
256
|
+
imported: string;
|
|
257
|
+
localName: string;
|
|
258
|
+
file: string;
|
|
259
|
+
importNodeId: string;
|
|
260
|
+
importType?: string;
|
|
261
|
+
}>();
|
|
262
|
+
|
|
263
|
+
for await (const node of graph.queryNodes({ nodeType: 'IMPORT' })) {
|
|
264
|
+
const importNode = node as ImportNode;
|
|
265
|
+
if (!importNode.source || !importNode.file) continue;
|
|
266
|
+
|
|
267
|
+
const localName = importNode.name as string;
|
|
268
|
+
const imported = importNode.imported || localName;
|
|
269
|
+
const importType = importNode.importType;
|
|
270
|
+
|
|
271
|
+
// Key: file:localName - for looking up what module a local name comes from
|
|
272
|
+
const key = `${importNode.file}:${localName}`;
|
|
273
|
+
|
|
274
|
+
index.set(key, {
|
|
275
|
+
source: importNode.source,
|
|
276
|
+
imported,
|
|
277
|
+
localName,
|
|
278
|
+
file: importNode.file,
|
|
279
|
+
importNodeId: importNode.id,
|
|
280
|
+
importType
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return index;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Resolve a CALL node to its builtin module and function.
|
|
289
|
+
*
|
|
290
|
+
* Handles:
|
|
291
|
+
* 1. Method calls: fs.readFile() -> {module: 'fs', function: 'readFile'}
|
|
292
|
+
* 2. Direct calls from imports: readFile() -> trace to import source
|
|
293
|
+
* 3. Aliased imports: rf() where rf = readFile from 'fs'
|
|
294
|
+
*/
|
|
295
|
+
private resolveBuiltinCall(
|
|
296
|
+
callNode: CallNode,
|
|
297
|
+
importIndex: Map<string, {
|
|
298
|
+
source: string;
|
|
299
|
+
imported: string;
|
|
300
|
+
localName: string;
|
|
301
|
+
file: string;
|
|
302
|
+
importNodeId: string;
|
|
303
|
+
importType?: string;
|
|
304
|
+
}>
|
|
305
|
+
): { moduleName: string; functionName: string } | null {
|
|
306
|
+
const file = callNode.file;
|
|
307
|
+
if (!file) return null;
|
|
308
|
+
|
|
309
|
+
// Case 1: Method call - obj.method()
|
|
310
|
+
if (callNode.object && callNode.method) {
|
|
311
|
+
const objectName = callNode.object;
|
|
312
|
+
const methodName = callNode.method;
|
|
313
|
+
|
|
314
|
+
// Check if objectName is a namespace import (import * as fs from 'fs')
|
|
315
|
+
const importKey = `${file}:${objectName}`;
|
|
316
|
+
const importInfo = importIndex.get(importKey);
|
|
317
|
+
|
|
318
|
+
if (importInfo) {
|
|
319
|
+
// Object is an imported namespace or module
|
|
320
|
+
const normalizedSource = this.registry.normalizeModule(importInfo.source);
|
|
321
|
+
|
|
322
|
+
if (this.registry.isBuiltinModule(normalizedSource)) {
|
|
323
|
+
return {
|
|
324
|
+
moduleName: normalizedSource,
|
|
325
|
+
functionName: methodName
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Check if objectName directly matches a builtin module
|
|
331
|
+
// (for cases like: const fs = require('fs'); fs.readFile())
|
|
332
|
+
if (this.registry.isBuiltinModule(objectName)) {
|
|
333
|
+
return {
|
|
334
|
+
moduleName: this.registry.normalizeModule(objectName),
|
|
335
|
+
functionName: methodName
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Case 2: Direct call - funcName()
|
|
343
|
+
const calleeName = callNode.name as string || callNode.callee;
|
|
344
|
+
if (!calleeName) return null;
|
|
345
|
+
|
|
346
|
+
// Look up in import index
|
|
347
|
+
const importKey = `${file}:${calleeName}`;
|
|
348
|
+
const importInfo = importIndex.get(importKey);
|
|
349
|
+
|
|
350
|
+
if (importInfo) {
|
|
351
|
+
const normalizedSource = this.registry.normalizeModule(importInfo.source);
|
|
352
|
+
|
|
353
|
+
if (this.registry.isBuiltinModule(normalizedSource)) {
|
|
354
|
+
// Use the original imported name, not the alias
|
|
355
|
+
const originalName = importInfo.imported || calleeName;
|
|
356
|
+
return {
|
|
357
|
+
moduleName: normalizedSource,
|
|
358
|
+
functionName: originalName
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
@@ -17,6 +17,15 @@ import { Plugin, createSuccessResult } from '../Plugin.js';
|
|
|
17
17
|
import type { PluginMetadata, PluginContext, PluginResult } from '../Plugin.js';
|
|
18
18
|
import type { NodeRecord } from '@grafema/types';
|
|
19
19
|
import type { EdgeRecord } from '@grafema/types';
|
|
20
|
+
import {
|
|
21
|
+
traceValues,
|
|
22
|
+
aggregateValues,
|
|
23
|
+
NONDETERMINISTIC_PATTERNS,
|
|
24
|
+
NONDETERMINISTIC_OBJECTS,
|
|
25
|
+
} from '../../queries/traceValues.js';
|
|
26
|
+
|
|
27
|
+
// Re-export for backward compatibility
|
|
28
|
+
export { NONDETERMINISTIC_PATTERNS, NONDETERMINISTIC_OBJECTS };
|
|
20
29
|
|
|
21
30
|
interface ComputedCallNode {
|
|
22
31
|
id: string;
|
|
@@ -42,22 +51,6 @@ interface VariableNode {
|
|
|
42
51
|
[key: string]: unknown;
|
|
43
52
|
}
|
|
44
53
|
|
|
45
|
-
interface ExpressionNode {
|
|
46
|
-
id: string;
|
|
47
|
-
type: string;
|
|
48
|
-
name?: string;
|
|
49
|
-
file?: string;
|
|
50
|
-
line?: number;
|
|
51
|
-
expressionType?: string;
|
|
52
|
-
object?: string;
|
|
53
|
-
property?: string;
|
|
54
|
-
attrs?: {
|
|
55
|
-
expressionType?: string;
|
|
56
|
-
object?: string;
|
|
57
|
-
property?: string;
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
54
|
interface ScopeNode {
|
|
62
55
|
id: string;
|
|
63
56
|
type: string;
|
|
@@ -89,11 +82,6 @@ interface ValueSetAtNodeResult extends ValueSetResult {
|
|
|
89
82
|
globalHasUnknown: boolean;
|
|
90
83
|
}
|
|
91
84
|
|
|
92
|
-
interface NondeterministicPattern {
|
|
93
|
-
object: string;
|
|
94
|
-
property: string;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
85
|
interface Graph {
|
|
98
86
|
queryNodes(filter: { nodeType: string }): AsyncIterable<NodeRecord>;
|
|
99
87
|
getNode(id: string): Promise<NodeRecord | null>;
|
|
@@ -116,37 +104,6 @@ interface ProgressCallback {
|
|
|
116
104
|
export class ValueDomainAnalyzer extends Plugin {
|
|
117
105
|
static MAX_DEPTH = 10; // Maximum depth for tracing
|
|
118
106
|
|
|
119
|
-
// Nondeterministic MemberExpression patterns
|
|
120
|
-
// object.property patterns that are external/user input
|
|
121
|
-
static NONDETERMINISTIC_PATTERNS: NondeterministicPattern[] = [
|
|
122
|
-
// Environment variables
|
|
123
|
-
{ object: 'process', property: 'env' },
|
|
124
|
-
// HTTP request data (Express.js patterns)
|
|
125
|
-
{ object: 'req', property: 'body' },
|
|
126
|
-
{ object: 'req', property: 'query' },
|
|
127
|
-
{ object: 'req', property: 'params' },
|
|
128
|
-
{ object: 'req', property: 'headers' },
|
|
129
|
-
{ object: 'req', property: 'cookies' },
|
|
130
|
-
{ object: 'request', property: 'body' },
|
|
131
|
-
{ object: 'request', property: 'query' },
|
|
132
|
-
{ object: 'request', property: 'params' },
|
|
133
|
-
// Context patterns (Koa, etc.)
|
|
134
|
-
{ object: 'ctx', property: 'request' },
|
|
135
|
-
{ object: 'ctx', property: 'body' },
|
|
136
|
-
{ object: 'ctx', property: 'query' },
|
|
137
|
-
{ object: 'ctx', property: 'params' },
|
|
138
|
-
];
|
|
139
|
-
|
|
140
|
-
// Nondeterministic object prefixes (any property access is nondeterministic)
|
|
141
|
-
static NONDETERMINISTIC_OBJECTS: string[] = [
|
|
142
|
-
'process.env', // process.env.ANY_VAR
|
|
143
|
-
'req.body', // req.body.userId
|
|
144
|
-
'req.query', // req.query.filter
|
|
145
|
-
'req.params', // req.params.id
|
|
146
|
-
'request.body',
|
|
147
|
-
'ctx.request',
|
|
148
|
-
];
|
|
149
|
-
|
|
150
107
|
get metadata(): PluginMetadata {
|
|
151
108
|
return {
|
|
152
109
|
name: 'ValueDomainAnalyzer',
|
|
@@ -508,135 +465,69 @@ export class ValueDomainAnalyzer extends Plugin {
|
|
|
508
465
|
}
|
|
509
466
|
|
|
510
467
|
/**
|
|
511
|
-
*
|
|
512
|
-
|
|
513
|
-
isNondeterministicExpression(node: ExpressionNode): boolean {
|
|
514
|
-
const expressionType = node.expressionType || node.attrs?.expressionType;
|
|
515
|
-
if (expressionType !== 'MemberExpression') {
|
|
516
|
-
return false;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
const object = node.object || node.attrs?.object;
|
|
520
|
-
const property = node.property || node.attrs?.property;
|
|
521
|
-
|
|
522
|
-
if (!object || !property) {
|
|
523
|
-
return false;
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
// Check exact patterns (object.property)
|
|
527
|
-
for (const pattern of ValueDomainAnalyzer.NONDETERMINISTIC_PATTERNS) {
|
|
528
|
-
if (object === pattern.object && property === pattern.property) {
|
|
529
|
-
return true;
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// Check if object is a known nondeterministic prefix
|
|
534
|
-
// e.g., process.env.VAR where object is 'process.env'
|
|
535
|
-
for (const prefix of ValueDomainAnalyzer.NONDETERMINISTIC_OBJECTS) {
|
|
536
|
-
if (object === prefix || object.startsWith(prefix + '.')) {
|
|
537
|
-
return true;
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
return false;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
/**
|
|
545
|
-
* Recursive value set tracing through ASSIGNED_FROM edges
|
|
468
|
+
* Recursive value set tracing through ASSIGNED_FROM edges.
|
|
469
|
+
* Delegates to shared traceValues utility (REG-244).
|
|
546
470
|
*/
|
|
547
471
|
async traceValueSet(
|
|
548
472
|
node: NodeRecord,
|
|
549
473
|
graph: Graph,
|
|
550
|
-
|
|
474
|
+
_visited: Set<string>,
|
|
551
475
|
depth: number
|
|
552
476
|
): Promise<ValueSetResult> {
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
}
|
|
477
|
+
// Create adapter from Graph interface to TraceValuesGraphBackend
|
|
478
|
+
const backend = {
|
|
479
|
+
getNode: async (id: string) => {
|
|
480
|
+
const n = await graph.getNode(id);
|
|
481
|
+
if (!n) return null;
|
|
482
|
+
return {
|
|
483
|
+
id: n.id,
|
|
484
|
+
type: (n as { type?: string }).type,
|
|
485
|
+
nodeType: (n as { nodeType?: string }).nodeType,
|
|
486
|
+
value: (n as { value?: unknown }).value,
|
|
487
|
+
file: (n as { file?: string }).file,
|
|
488
|
+
line: (n as { line?: number }).line,
|
|
489
|
+
expressionType: (n as { expressionType?: string }).expressionType,
|
|
490
|
+
object: (n as { object?: string }).object,
|
|
491
|
+
property: (n as { property?: string }).property,
|
|
492
|
+
};
|
|
493
|
+
},
|
|
494
|
+
getOutgoingEdges: async (nodeId: string, edgeTypes: string[] | null) => {
|
|
495
|
+
const edges = await graph.getOutgoingEdges(nodeId);
|
|
496
|
+
const filtered = edgeTypes === null
|
|
497
|
+
? edges
|
|
498
|
+
: edges.filter(e => edgeTypes.includes(e.type));
|
|
499
|
+
return filtered.map(e => ({
|
|
500
|
+
src: (e as { src?: string; source_id?: string }).src ||
|
|
501
|
+
(e as { source_id?: string }).source_id || '',
|
|
502
|
+
dst: (e as { dst?: string; target_id?: string }).dst ||
|
|
503
|
+
(e as { target_id?: string }).target_id || '',
|
|
504
|
+
type: e.type,
|
|
505
|
+
}));
|
|
506
|
+
},
|
|
507
|
+
// REG-334: getIncomingEdges required for Promise tracing
|
|
508
|
+
getIncomingEdges: async (nodeId: string, edgeTypes: string[] | null) => {
|
|
509
|
+
const edges = await graph.getIncomingEdges(nodeId);
|
|
510
|
+
const filtered = edgeTypes === null
|
|
511
|
+
? edges
|
|
512
|
+
: edges.filter(e => edgeTypes.includes(e.type));
|
|
513
|
+
return filtered.map(e => ({
|
|
514
|
+
src: (e as { src?: string; source_id?: string }).src ||
|
|
515
|
+
(e as { source_id?: string }).source_id || '',
|
|
516
|
+
dst: (e as { dst?: string; target_id?: string }).dst ||
|
|
517
|
+
(e as { target_id?: string }).target_id || '',
|
|
518
|
+
type: e.type,
|
|
519
|
+
}));
|
|
520
|
+
},
|
|
521
|
+
};
|
|
599
522
|
|
|
600
|
-
//
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
const edgeType = (e as { edgeType?: string; edge_type?: string }).edgeType ||
|
|
606
|
-
(e as { edge_type?: string }).edge_type;
|
|
607
|
-
return edgeType === 'ASSIGNED_FROM' || edgeType === 'DERIVES_FROM';
|
|
523
|
+
// Use shared utility
|
|
524
|
+
const traced = await traceValues(backend, node.id, {
|
|
525
|
+
maxDepth: ValueDomainAnalyzer.MAX_DEPTH - depth,
|
|
526
|
+
followDerivesFrom: true,
|
|
527
|
+
detectNondeterministic: true,
|
|
608
528
|
});
|
|
609
529
|
|
|
610
|
-
|
|
611
|
-
// No sources - unknown
|
|
612
|
-
result.hasUnknown = true;
|
|
613
|
-
return result;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
// Recursively trace each source
|
|
617
|
-
for (const edge of dataFlowEdges) {
|
|
618
|
-
// dst (from getOutgoingEdges) or target_id (from other APIs)
|
|
619
|
-
const targetId = (edge as { dst?: string; target_id?: string }).dst ||
|
|
620
|
-
(edge as { target_id?: string }).target_id;
|
|
621
|
-
if (!targetId) continue;
|
|
622
|
-
|
|
623
|
-
const sourceNode = await graph.getNode(targetId);
|
|
624
|
-
if (!sourceNode) continue;
|
|
625
|
-
|
|
626
|
-
const sourceResult = await this.traceValueSet(
|
|
627
|
-
sourceNode,
|
|
628
|
-
graph,
|
|
629
|
-
visited,
|
|
630
|
-
depth + 1
|
|
631
|
-
);
|
|
632
|
-
|
|
633
|
-
sourceResult.values.forEach(v => result.values.push(v));
|
|
634
|
-
if (sourceResult.hasUnknown) {
|
|
635
|
-
result.hasUnknown = true;
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
return result;
|
|
530
|
+
return aggregateValues(traced);
|
|
640
531
|
}
|
|
641
532
|
|
|
642
533
|
/**
|
|
@@ -655,11 +546,7 @@ export class ValueDomainAnalyzer extends Plugin {
|
|
|
655
546
|
// Check if this is a method of the right object
|
|
656
547
|
// Simplified: check via incoming CONTAINS edges from CLASS
|
|
657
548
|
const incoming = await graph.getIncomingEdges(node.id);
|
|
658
|
-
const containsEdges = incoming.filter(e =>
|
|
659
|
-
const edgeType = (e as { edgeType?: string; edge_type?: string }).edgeType ||
|
|
660
|
-
(e as { edge_type?: string }).edge_type;
|
|
661
|
-
return edgeType === 'CONTAINS';
|
|
662
|
-
});
|
|
549
|
+
const containsEdges = incoming.filter(e => e.type === 'CONTAINS');
|
|
663
550
|
|
|
664
551
|
for (const edge of containsEdges) {
|
|
665
552
|
const sourceId = (edge as { src?: string; source_id?: string }).src ||
|
|
@@ -714,18 +601,14 @@ export class ValueDomainAnalyzer extends Plugin {
|
|
|
714
601
|
const outgoing = await graph.getOutgoingEdges(node.id);
|
|
715
602
|
|
|
716
603
|
for (const edge of outgoing) {
|
|
717
|
-
|
|
718
|
-
(edge as { edge_type?: string }).edge_type ||
|
|
719
|
-
(edge as { type?: string }).type;
|
|
720
|
-
|
|
721
|
-
if (edgeType !== 'FLOWS_INTO') continue;
|
|
604
|
+
if (edge.type !== 'FLOWS_INTO') continue;
|
|
722
605
|
|
|
723
606
|
const edgeKey = `${edge.src}->${edge.dst}:FLOWS_INTO`;
|
|
724
607
|
if (processedEdges.has(edgeKey)) continue;
|
|
725
608
|
processedEdges.add(edgeKey);
|
|
726
609
|
|
|
727
|
-
const mutationType =
|
|
728
|
-
const computedPropertyVar =
|
|
610
|
+
const mutationType = edge.metadata?.mutationType as string | undefined;
|
|
611
|
+
const computedPropertyVar = edge.metadata?.computedPropertyVar as string | undefined;
|
|
729
612
|
|
|
730
613
|
if (mutationType !== 'computed' || !computedPropertyVar) continue;
|
|
731
614
|
|