@grafema/core 0.1.0-alpha.1
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/README.md +76 -0
- package/dist/Orchestrator.d.ts +142 -0
- package/dist/Orchestrator.d.ts.map +1 -0
- package/dist/Orchestrator.js +481 -0
- package/dist/api/GraphAPI.d.ts +87 -0
- package/dist/api/GraphAPI.d.ts.map +1 -0
- package/dist/api/GraphAPI.js +210 -0
- package/dist/api/GuaranteeAPI.d.ts +147 -0
- package/dist/api/GuaranteeAPI.d.ts.map +1 -0
- package/dist/api/GuaranteeAPI.js +288 -0
- package/dist/core/ASTWorker.d.ts +133 -0
- package/dist/core/ASTWorker.d.ts.map +1 -0
- package/dist/core/ASTWorker.js +352 -0
- package/dist/core/ASTWorkerPool.d.ts +85 -0
- package/dist/core/ASTWorkerPool.d.ts.map +1 -0
- package/dist/core/ASTWorkerPool.js +207 -0
- package/dist/core/AnalysisQueue.d.ts +104 -0
- package/dist/core/AnalysisQueue.d.ts.map +1 -0
- package/dist/core/AnalysisQueue.js +299 -0
- package/dist/core/AnalysisWorker.d.ts +14 -0
- package/dist/core/AnalysisWorker.d.ts.map +1 -0
- package/dist/core/AnalysisWorker.js +307 -0
- package/dist/core/GraphBackend.d.ts +156 -0
- package/dist/core/GraphBackend.d.ts.map +1 -0
- package/dist/core/GraphBackend.js +85 -0
- package/dist/core/GuaranteeManager.d.ts +230 -0
- package/dist/core/GuaranteeManager.d.ts.map +1 -0
- package/dist/core/GuaranteeManager.js +352 -0
- package/dist/core/ManifestStore.d.ts +71 -0
- package/dist/core/ManifestStore.d.ts.map +1 -0
- package/dist/core/ManifestStore.js +146 -0
- package/dist/core/NodeFactory.d.ts +160 -0
- package/dist/core/NodeFactory.d.ts.map +1 -0
- package/dist/core/NodeFactory.js +137 -0
- package/dist/core/NodeId.d.ts +88 -0
- package/dist/core/NodeId.d.ts.map +1 -0
- package/dist/core/NodeId.js +170 -0
- package/dist/core/ParallelAnalyzer.d.ts +120 -0
- package/dist/core/ParallelAnalyzer.d.ts.map +1 -0
- package/dist/core/ParallelAnalyzer.js +331 -0
- package/dist/core/PriorityQueue.d.ts +106 -0
- package/dist/core/PriorityQueue.d.ts.map +1 -0
- package/dist/core/PriorityQueue.js +168 -0
- package/dist/core/Profiler.d.ts +75 -0
- package/dist/core/Profiler.d.ts.map +1 -0
- package/dist/core/Profiler.js +149 -0
- package/dist/core/QueueWorker.d.ts +12 -0
- package/dist/core/QueueWorker.d.ts.map +1 -0
- package/dist/core/QueueWorker.js +567 -0
- package/dist/core/RFDBClient.d.ts +179 -0
- package/dist/core/RFDBClient.d.ts.map +1 -0
- package/dist/core/RFDBClient.js +429 -0
- package/dist/core/Task.d.ts +56 -0
- package/dist/core/Task.d.ts.map +1 -0
- package/dist/core/Task.js +85 -0
- package/dist/core/TaskTypes.d.ts +20 -0
- package/dist/core/TaskTypes.d.ts.map +1 -0
- package/dist/core/TaskTypes.js +10 -0
- package/dist/core/VersionManager.d.ts +166 -0
- package/dist/core/VersionManager.d.ts.map +1 -0
- package/dist/core/VersionManager.js +237 -0
- package/dist/core/WorkerPool.d.ts +82 -0
- package/dist/core/WorkerPool.d.ts.map +1 -0
- package/dist/core/WorkerPool.js +109 -0
- package/dist/core/nodes/CallSiteNode.d.ts +26 -0
- package/dist/core/nodes/CallSiteNode.d.ts.map +1 -0
- package/dist/core/nodes/CallSiteNode.js +44 -0
- package/dist/core/nodes/ClassNode.d.ts +25 -0
- package/dist/core/nodes/ClassNode.d.ts.map +1 -0
- package/dist/core/nodes/ClassNode.js +40 -0
- package/dist/core/nodes/ConstantNode.d.ts +24 -0
- package/dist/core/nodes/ConstantNode.d.ts.map +1 -0
- package/dist/core/nodes/ConstantNode.js +39 -0
- package/dist/core/nodes/DatabaseQueryNode.d.ts +22 -0
- package/dist/core/nodes/DatabaseQueryNode.d.ts.map +1 -0
- package/dist/core/nodes/DatabaseQueryNode.js +37 -0
- package/dist/core/nodes/EntrypointNode.d.ts +102 -0
- package/dist/core/nodes/EntrypointNode.d.ts.map +1 -0
- package/dist/core/nodes/EntrypointNode.js +119 -0
- package/dist/core/nodes/EventListenerNode.d.ts +25 -0
- package/dist/core/nodes/EventListenerNode.d.ts.map +1 -0
- package/dist/core/nodes/EventListenerNode.js +39 -0
- package/dist/core/nodes/ExportNode.d.ts +26 -0
- package/dist/core/nodes/ExportNode.d.ts.map +1 -0
- package/dist/core/nodes/ExportNode.js +40 -0
- package/dist/core/nodes/ExternalStdioNode.d.ts +17 -0
- package/dist/core/nodes/ExternalStdioNode.d.ts.map +1 -0
- package/dist/core/nodes/ExternalStdioNode.js +26 -0
- package/dist/core/nodes/FunctionNode.d.ts +27 -0
- package/dist/core/nodes/FunctionNode.d.ts.map +1 -0
- package/dist/core/nodes/FunctionNode.js +53 -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 +117 -0
- package/dist/core/nodes/HttpRequestNode.d.ts +24 -0
- package/dist/core/nodes/HttpRequestNode.d.ts.map +1 -0
- package/dist/core/nodes/HttpRequestNode.js +38 -0
- package/dist/core/nodes/ImportNode.d.ts +27 -0
- package/dist/core/nodes/ImportNode.d.ts.map +1 -0
- package/dist/core/nodes/ImportNode.js +43 -0
- package/dist/core/nodes/LiteralNode.d.ts +26 -0
- package/dist/core/nodes/LiteralNode.d.ts.map +1 -0
- package/dist/core/nodes/LiteralNode.js +40 -0
- package/dist/core/nodes/MethodCallNode.d.ts +29 -0
- package/dist/core/nodes/MethodCallNode.d.ts.map +1 -0
- package/dist/core/nodes/MethodCallNode.js +47 -0
- package/dist/core/nodes/MethodNode.d.ts +29 -0
- package/dist/core/nodes/MethodNode.d.ts.map +1 -0
- package/dist/core/nodes/MethodNode.js +44 -0
- package/dist/core/nodes/ModuleNode.d.ts +29 -0
- package/dist/core/nodes/ModuleNode.d.ts.map +1 -0
- package/dist/core/nodes/ModuleNode.js +49 -0
- package/dist/core/nodes/NodeKind.d.ts +91 -0
- package/dist/core/nodes/NodeKind.d.ts.map +1 -0
- package/dist/core/nodes/NodeKind.js +146 -0
- package/dist/core/nodes/ParameterNode.d.ts +26 -0
- package/dist/core/nodes/ParameterNode.d.ts.map +1 -0
- package/dist/core/nodes/ParameterNode.js +43 -0
- package/dist/core/nodes/ScopeNode.d.ts +32 -0
- package/dist/core/nodes/ScopeNode.d.ts.map +1 -0
- package/dist/core/nodes/ScopeNode.js +47 -0
- package/dist/core/nodes/ServiceNode.d.ts +44 -0
- package/dist/core/nodes/ServiceNode.d.ts.map +1 -0
- package/dist/core/nodes/ServiceNode.js +49 -0
- package/dist/core/nodes/VariableDeclarationNode.d.ts +22 -0
- package/dist/core/nodes/VariableDeclarationNode.d.ts.map +1 -0
- package/dist/core/nodes/VariableDeclarationNode.js +38 -0
- package/dist/core/nodes/index.d.ts +25 -0
- package/dist/core/nodes/index.d.ts.map +1 -0
- package/dist/core/nodes/index.js +30 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +63 -0
- package/dist/plugins/Plugin.d.ts +44 -0
- package/dist/plugins/Plugin.d.ts.map +1 -0
- package/dist/plugins/Plugin.js +46 -0
- package/dist/plugins/analysis/DatabaseAnalyzer.d.ts +23 -0
- package/dist/plugins/analysis/DatabaseAnalyzer.d.ts.map +1 -0
- package/dist/plugins/analysis/DatabaseAnalyzer.js +260 -0
- package/dist/plugins/analysis/ExpressAnalyzer.d.ts +19 -0
- package/dist/plugins/analysis/ExpressAnalyzer.d.ts.map +1 -0
- package/dist/plugins/analysis/ExpressAnalyzer.js +306 -0
- package/dist/plugins/analysis/ExpressRouteAnalyzer.d.ts +17 -0
- package/dist/plugins/analysis/ExpressRouteAnalyzer.d.ts.map +1 -0
- package/dist/plugins/analysis/ExpressRouteAnalyzer.js +308 -0
- package/dist/plugins/analysis/FetchAnalyzer.d.ts +38 -0
- package/dist/plugins/analysis/FetchAnalyzer.d.ts.map +1 -0
- package/dist/plugins/analysis/FetchAnalyzer.js +344 -0
- package/dist/plugins/analysis/IncrementalAnalysisPlugin.d.ts +65 -0
- package/dist/plugins/analysis/IncrementalAnalysisPlugin.d.ts.map +1 -0
- package/dist/plugins/analysis/IncrementalAnalysisPlugin.js +472 -0
- package/dist/plugins/analysis/JSASTAnalyzer.d.ts +84 -0
- package/dist/plugins/analysis/JSASTAnalyzer.d.ts.map +1 -0
- package/dist/plugins/analysis/JSASTAnalyzer.js +1378 -0
- package/dist/plugins/analysis/ReactAnalyzer.d.ts +90 -0
- package/dist/plugins/analysis/ReactAnalyzer.d.ts.map +1 -0
- package/dist/plugins/analysis/ReactAnalyzer.js +1153 -0
- package/dist/plugins/analysis/RustAnalyzer.d.ts +13 -0
- package/dist/plugins/analysis/RustAnalyzer.d.ts.map +1 -0
- package/dist/plugins/analysis/RustAnalyzer.js +259 -0
- package/dist/plugins/analysis/SQLiteAnalyzer.d.ts +21 -0
- package/dist/plugins/analysis/SQLiteAnalyzer.d.ts.map +1 -0
- package/dist/plugins/analysis/SQLiteAnalyzer.js +317 -0
- package/dist/plugins/analysis/ServiceLayerAnalyzer.d.ts +35 -0
- package/dist/plugins/analysis/ServiceLayerAnalyzer.d.ts.map +1 -0
- package/dist/plugins/analysis/ServiceLayerAnalyzer.js +303 -0
- package/dist/plugins/analysis/SocketIOAnalyzer.d.ts +33 -0
- package/dist/plugins/analysis/SocketIOAnalyzer.d.ts.map +1 -0
- package/dist/plugins/analysis/SocketIOAnalyzer.js +283 -0
- package/dist/plugins/analysis/SystemDbAnalyzer.d.ts +27 -0
- package/dist/plugins/analysis/SystemDbAnalyzer.d.ts.map +1 -0
- package/dist/plugins/analysis/SystemDbAnalyzer.js +211 -0
- package/dist/plugins/analysis/ast/ConditionParser.d.ts +85 -0
- package/dist/plugins/analysis/ast/ConditionParser.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/ConditionParser.js +277 -0
- package/dist/plugins/analysis/ast/ExpressionEvaluator.d.ts +15 -0
- package/dist/plugins/analysis/ast/ExpressionEvaluator.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/ExpressionEvaluator.js +91 -0
- package/dist/plugins/analysis/ast/GraphBuilder.d.ts +77 -0
- package/dist/plugins/analysis/ast/GraphBuilder.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/GraphBuilder.js +1077 -0
- package/dist/plugins/analysis/ast/OxcAdapter.d.ts +41 -0
- package/dist/plugins/analysis/ast/OxcAdapter.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/OxcAdapter.js +40 -0
- package/dist/plugins/analysis/ast/types.d.ts +346 -0
- package/dist/plugins/analysis/ast/types.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/types.js +4 -0
- package/dist/plugins/analysis/ast/visitors/ASTVisitor.d.ts +93 -0
- package/dist/plugins/analysis/ast/visitors/ASTVisitor.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/visitors/ASTVisitor.js +24 -0
- package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts +77 -0
- package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.js +377 -0
- package/dist/plugins/analysis/ast/visitors/ClassVisitor.d.ts +27 -0
- package/dist/plugins/analysis/ast/visitors/ClassVisitor.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/visitors/ClassVisitor.js +232 -0
- package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts +25 -0
- package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/visitors/FunctionVisitor.js +172 -0
- package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.d.ts +29 -0
- package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.js +180 -0
- package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.d.ts +14 -0
- package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.js +200 -0
- package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts +45 -0
- package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/visitors/VariableVisitor.js +150 -0
- package/dist/plugins/analysis/ast/visitors/index.d.ts +17 -0
- package/dist/plugins/analysis/ast/visitors/index.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/visitors/index.js +13 -0
- package/dist/plugins/discovery/DiscoveryPlugin.d.ts +34 -0
- package/dist/plugins/discovery/DiscoveryPlugin.d.ts.map +1 -0
- package/dist/plugins/discovery/DiscoveryPlugin.js +26 -0
- package/dist/plugins/discovery/MonorepoServiceDiscovery.d.ts +26 -0
- package/dist/plugins/discovery/MonorepoServiceDiscovery.d.ts.map +1 -0
- package/dist/plugins/discovery/MonorepoServiceDiscovery.js +79 -0
- package/dist/plugins/discovery/SimpleProjectDiscovery.d.ts +14 -0
- package/dist/plugins/discovery/SimpleProjectDiscovery.d.ts.map +1 -0
- package/dist/plugins/discovery/SimpleProjectDiscovery.js +65 -0
- package/dist/plugins/discovery/ZonServiceDiscovery.d.ts +19 -0
- package/dist/plugins/discovery/ZonServiceDiscovery.d.ts.map +1 -0
- package/dist/plugins/discovery/ZonServiceDiscovery.js +204 -0
- package/dist/plugins/enrichment/AliasTracker.d.ts +40 -0
- package/dist/plugins/enrichment/AliasTracker.d.ts.map +1 -0
- package/dist/plugins/enrichment/AliasTracker.js +290 -0
- package/dist/plugins/enrichment/HTTPConnectionEnricher.d.ts +30 -0
- package/dist/plugins/enrichment/HTTPConnectionEnricher.d.ts.map +1 -0
- package/dist/plugins/enrichment/HTTPConnectionEnricher.js +135 -0
- package/dist/plugins/enrichment/ImportExportLinker.d.ts +30 -0
- package/dist/plugins/enrichment/ImportExportLinker.d.ts.map +1 -0
- package/dist/plugins/enrichment/ImportExportLinker.js +176 -0
- package/dist/plugins/enrichment/InstanceOfResolver.d.ts +21 -0
- package/dist/plugins/enrichment/InstanceOfResolver.d.ts.map +1 -0
- package/dist/plugins/enrichment/InstanceOfResolver.js +117 -0
- package/dist/plugins/enrichment/MethodCallResolver.d.ts +41 -0
- package/dist/plugins/enrichment/MethodCallResolver.d.ts.map +1 -0
- package/dist/plugins/enrichment/MethodCallResolver.js +252 -0
- package/dist/plugins/enrichment/MountPointResolver.d.ts +26 -0
- package/dist/plugins/enrichment/MountPointResolver.d.ts.map +1 -0
- package/dist/plugins/enrichment/MountPointResolver.js +189 -0
- package/dist/plugins/enrichment/PrefixEvaluator.d.ts +89 -0
- package/dist/plugins/enrichment/PrefixEvaluator.d.ts.map +1 -0
- package/dist/plugins/enrichment/PrefixEvaluator.js +415 -0
- package/dist/plugins/enrichment/RustFFIEnricher.d.ts +25 -0
- package/dist/plugins/enrichment/RustFFIEnricher.d.ts.map +1 -0
- package/dist/plugins/enrichment/RustFFIEnricher.js +170 -0
- package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts +114 -0
- package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts.map +1 -0
- package/dist/plugins/enrichment/ValueDomainAnalyzer.js +464 -0
- package/dist/plugins/indexing/IncrementalModuleIndexer.d.ts +27 -0
- package/dist/plugins/indexing/IncrementalModuleIndexer.d.ts.map +1 -0
- package/dist/plugins/indexing/IncrementalModuleIndexer.js +238 -0
- package/dist/plugins/indexing/JSModuleIndexer.d.ts +33 -0
- package/dist/plugins/indexing/JSModuleIndexer.d.ts.map +1 -0
- package/dist/plugins/indexing/JSModuleIndexer.js +299 -0
- package/dist/plugins/indexing/RustModuleIndexer.d.ts +28 -0
- package/dist/plugins/indexing/RustModuleIndexer.d.ts.map +1 -0
- package/dist/plugins/indexing/RustModuleIndexer.js +140 -0
- package/dist/plugins/indexing/ServiceDetector.d.ts +46 -0
- package/dist/plugins/indexing/ServiceDetector.d.ts.map +1 -0
- package/dist/plugins/indexing/ServiceDetector.js +164 -0
- package/dist/plugins/validation/CallResolverValidator.d.ts +23 -0
- package/dist/plugins/validation/CallResolverValidator.d.ts.map +1 -0
- package/dist/plugins/validation/CallResolverValidator.js +108 -0
- package/dist/plugins/validation/DataFlowValidator.d.ts +24 -0
- package/dist/plugins/validation/DataFlowValidator.d.ts.map +1 -0
- package/dist/plugins/validation/DataFlowValidator.js +148 -0
- package/dist/plugins/validation/EvalBanValidator.d.ts +25 -0
- package/dist/plugins/validation/EvalBanValidator.d.ts.map +1 -0
- package/dist/plugins/validation/EvalBanValidator.js +123 -0
- package/dist/plugins/validation/GraphConnectivityValidator.d.ts +11 -0
- package/dist/plugins/validation/GraphConnectivityValidator.d.ts.map +1 -0
- package/dist/plugins/validation/GraphConnectivityValidator.js +135 -0
- package/dist/plugins/validation/SQLInjectionValidator.d.ts +43 -0
- package/dist/plugins/validation/SQLInjectionValidator.d.ts.map +1 -0
- package/dist/plugins/validation/SQLInjectionValidator.js +251 -0
- package/dist/plugins/validation/ShadowingDetector.d.ts +26 -0
- package/dist/plugins/validation/ShadowingDetector.d.ts.map +1 -0
- package/dist/plugins/validation/ShadowingDetector.js +119 -0
- package/dist/plugins/validation/TypeScriptDeadCodeValidator.d.ts +21 -0
- package/dist/plugins/validation/TypeScriptDeadCodeValidator.d.ts.map +1 -0
- package/dist/plugins/validation/TypeScriptDeadCodeValidator.js +151 -0
- package/dist/plugins/vcs/GitPlugin.d.ts +84 -0
- package/dist/plugins/vcs/GitPlugin.d.ts.map +1 -0
- package/dist/plugins/vcs/GitPlugin.js +295 -0
- package/dist/plugins/vcs/VCSPlugin.d.ts +133 -0
- package/dist/plugins/vcs/VCSPlugin.d.ts.map +1 -0
- package/dist/plugins/vcs/VCSPlugin.js +82 -0
- package/dist/plugins/vcs/index.d.ts +10 -0
- package/dist/plugins/vcs/index.d.ts.map +1 -0
- package/dist/plugins/vcs/index.js +18 -0
- package/dist/storage/backends/RFDBServerBackend.d.ts +258 -0
- package/dist/storage/backends/RFDBServerBackend.d.ts.map +1 -0
- package/dist/storage/backends/RFDBServerBackend.js +565 -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 +137 -0
- package/dist/validation/PathValidator.d.ts +81 -0
- package/dist/validation/PathValidator.d.ts.map +1 -0
- package/dist/validation/PathValidator.js +251 -0
- package/package.json +57 -0
- package/src/.rfguard/current-session.txt +1 -0
- package/src/Orchestrator.ts +673 -0
- package/src/api/GraphAPI.ts +305 -0
- package/src/api/GuaranteeAPI.ts +401 -0
- package/src/core/ASTWorker.ts +567 -0
- package/src/core/ASTWorkerPool.ts +299 -0
- package/src/core/AnalysisQueue.ts +447 -0
- package/src/core/AnalysisWorker.ts +410 -0
- package/src/core/GraphBackend.ts +265 -0
- package/src/core/GuaranteeManager.ts +581 -0
- package/src/core/ManifestStore.ts +196 -0
- package/src/core/NodeFactory.ts +274 -0
- package/src/core/NodeId.ts +257 -0
- package/src/core/ParallelAnalyzer.ts +476 -0
- package/src/core/PriorityQueue.ts +227 -0
- package/src/core/Profiler.ts +188 -0
- package/src/core/QueueWorker.ts +780 -0
- package/src/core/Task.ts +107 -0
- package/src/core/TaskTypes.ts +40 -0
- package/src/core/VersionManager.ts +404 -0
- package/src/core/WorkerPool.ts +180 -0
- package/src/core/nodes/CallSiteNode.ts +72 -0
- package/src/core/nodes/ClassNode.ts +69 -0
- package/src/core/nodes/ConstantNode.ts +63 -0
- package/src/core/nodes/DatabaseQueryNode.ts +60 -0
- package/src/core/nodes/EntrypointNode.ts +164 -0
- package/src/core/nodes/EventListenerNode.ts +64 -0
- package/src/core/nodes/ExportNode.ts +71 -0
- package/src/core/nodes/ExternalStdioNode.ts +36 -0
- package/src/core/nodes/FunctionNode.ts +78 -0
- package/src/core/nodes/GuaranteeNode.ts +162 -0
- package/src/core/nodes/HttpRequestNode.ts +63 -0
- package/src/core/nodes/ImportNode.ts +75 -0
- package/src/core/nodes/LiteralNode.ts +67 -0
- package/src/core/nodes/MethodCallNode.ts +79 -0
- package/src/core/nodes/MethodNode.ts +78 -0
- package/src/core/nodes/ModuleNode.ts +74 -0
- package/src/core/nodes/NodeKind.ts +171 -0
- package/src/core/nodes/ParameterNode.ts +73 -0
- package/src/core/nodes/ScopeNode.ts +80 -0
- package/src/core/nodes/ServiceNode.ts +86 -0
- package/src/core/nodes/VariableDeclarationNode.ts +60 -0
- package/src/core/nodes/index.ts +49 -0
- package/src/index.ts +93 -0
- package/src/plugins/Plugin.ts +74 -0
- package/src/plugins/analysis/DatabaseAnalyzer.ts +322 -0
- package/src/plugins/analysis/ExpressAnalyzer.ts +401 -0
- package/src/plugins/analysis/ExpressRouteAnalyzer.ts +414 -0
- package/src/plugins/analysis/FetchAnalyzer.ts +441 -0
- package/src/plugins/analysis/IncrementalAnalysisPlugin.ts +686 -0
- package/src/plugins/analysis/JSASTAnalyzer.ts +1680 -0
- package/src/plugins/analysis/ReactAnalyzer.ts +1368 -0
- package/src/plugins/analysis/RustAnalyzer.ts +438 -0
- package/src/plugins/analysis/SQLiteAnalyzer.ts +388 -0
- package/src/plugins/analysis/ServiceLayerAnalyzer.ts +429 -0
- package/src/plugins/analysis/SocketIOAnalyzer.ts +395 -0
- package/src/plugins/analysis/SystemDbAnalyzer.ts +284 -0
- package/src/plugins/analysis/ast/ConditionParser.ts +333 -0
- package/src/plugins/analysis/ast/ExpressionEvaluator.ts +117 -0
- package/src/plugins/analysis/ast/GraphBuilder.ts +1371 -0
- package/src/plugins/analysis/ast/OxcAdapter.ts +63 -0
- package/src/plugins/analysis/ast/types.ts +400 -0
- package/src/plugins/analysis/ast/visitors/ASTVisitor.ts +137 -0
- package/src/plugins/analysis/ast/visitors/CallExpressionVisitor.ts +528 -0
- package/src/plugins/analysis/ast/visitors/ClassVisitor.ts +339 -0
- package/src/plugins/analysis/ast/visitors/FunctionVisitor.ts +273 -0
- package/src/plugins/analysis/ast/visitors/ImportExportVisitor.ts +259 -0
- package/src/plugins/analysis/ast/visitors/TypeScriptVisitor.ts +235 -0
- package/src/plugins/analysis/ast/visitors/VariableVisitor.ts +268 -0
- package/src/plugins/analysis/ast/visitors/index.ts +36 -0
- package/src/plugins/discovery/DiscoveryPlugin.ts +50 -0
- package/src/plugins/discovery/MonorepoServiceDiscovery.ts +117 -0
- package/src/plugins/discovery/SimpleProjectDiscovery.ts +102 -0
- package/src/plugins/enrichment/AliasTracker.ts +399 -0
- package/src/plugins/enrichment/HTTPConnectionEnricher.ts +192 -0
- package/src/plugins/enrichment/ImportExportLinker.ts +221 -0
- package/src/plugins/enrichment/InstanceOfResolver.ts +165 -0
- package/src/plugins/enrichment/MethodCallResolver.ts +333 -0
- package/src/plugins/enrichment/MountPointResolver.ts +264 -0
- package/src/plugins/enrichment/PrefixEvaluator.ts +527 -0
- package/src/plugins/enrichment/RustFFIEnricher.ts +218 -0
- package/src/plugins/enrichment/ValueDomainAnalyzer.ts +682 -0
- package/src/plugins/indexing/IncrementalModuleIndexer.ts +287 -0
- package/src/plugins/indexing/JSModuleIndexer.ts +374 -0
- package/src/plugins/indexing/RustModuleIndexer.ts +160 -0
- package/src/plugins/indexing/ServiceDetector.ts +230 -0
- package/src/plugins/validation/CallResolverValidator.ts +170 -0
- package/src/plugins/validation/DataFlowValidator.ts +233 -0
- package/src/plugins/validation/EvalBanValidator.ts +175 -0
- package/src/plugins/validation/GraphConnectivityValidator.ts +201 -0
- package/src/plugins/validation/SQLInjectionValidator.ts +363 -0
- package/src/plugins/validation/ShadowingDetector.ts +173 -0
- package/src/plugins/validation/TypeScriptDeadCodeValidator.ts +203 -0
- package/src/plugins/vcs/GitPlugin.ts +344 -0
- package/src/plugins/vcs/VCSPlugin.ts +190 -0
- package/src/plugins/vcs/index.ts +32 -0
- package/src/storage/backends/RFDBServerBackend.ts +687 -0
- package/src/storage/backends/typeValidation.ts +151 -0
- package/src/validation/PathValidator.ts +342 -0
|
@@ -0,0 +1,1077 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphBuilder - создание узлов и рёбер графа из собранных AST данных
|
|
3
|
+
* OPTIMIZED: Uses batched writes to reduce FFI overhead
|
|
4
|
+
*/
|
|
5
|
+
import { dirname, resolve } from 'path';
|
|
6
|
+
export class GraphBuilder {
|
|
7
|
+
// Track singleton nodes to avoid duplicates (net:stdio, net:request, etc.)
|
|
8
|
+
_createdSingletons = new Set();
|
|
9
|
+
// Batching buffers for optimized writes
|
|
10
|
+
_nodeBuffer = [];
|
|
11
|
+
_edgeBuffer = [];
|
|
12
|
+
/**
|
|
13
|
+
* Buffer a node for batched writing
|
|
14
|
+
*/
|
|
15
|
+
_bufferNode(node) {
|
|
16
|
+
this._nodeBuffer.push(node);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Buffer an edge for batched writing
|
|
20
|
+
*/
|
|
21
|
+
_bufferEdge(edge) {
|
|
22
|
+
this._edgeBuffer.push(edge);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Flush all buffered nodes to the graph
|
|
26
|
+
*/
|
|
27
|
+
async _flushNodes(graph) {
|
|
28
|
+
if (this._nodeBuffer.length > 0) {
|
|
29
|
+
// Cast to unknown first since GraphNode is more permissive than NodeRecord
|
|
30
|
+
await graph.addNodes(this._nodeBuffer);
|
|
31
|
+
const count = this._nodeBuffer.length;
|
|
32
|
+
this._nodeBuffer = [];
|
|
33
|
+
return count;
|
|
34
|
+
}
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Flush all buffered edges to the graph
|
|
39
|
+
* Note: skip_validation=true because nodes were just flushed
|
|
40
|
+
*/
|
|
41
|
+
async _flushEdges(graph) {
|
|
42
|
+
if (this._edgeBuffer.length > 0) {
|
|
43
|
+
await graph.addEdges(this._edgeBuffer, true /* skip_validation */);
|
|
44
|
+
const count = this._edgeBuffer.length;
|
|
45
|
+
this._edgeBuffer = [];
|
|
46
|
+
return count;
|
|
47
|
+
}
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Создаёт ноды и рёбра в графе (BATCHED VERSION)
|
|
52
|
+
*/
|
|
53
|
+
async build(module, graph, projectPath, data) {
|
|
54
|
+
const { functions, parameters = [], scopes, variableDeclarations, callSites, methodCalls = [], eventListeners = [], classInstantiations = [], classDeclarations = [], methodCallbacks = [], callArguments = [], imports = [], exports = [], httpRequests = [], literals = [], variableAssignments = [],
|
|
55
|
+
// TypeScript-specific collections
|
|
56
|
+
interfaces = [], typeAliases = [], enums = [], decorators = [] } = data;
|
|
57
|
+
// Reset buffers for this build
|
|
58
|
+
this._nodeBuffer = [];
|
|
59
|
+
this._edgeBuffer = [];
|
|
60
|
+
// 1. Buffer all functions (without edges)
|
|
61
|
+
for (const func of functions) {
|
|
62
|
+
const { parentScopeId, ...funcData } = func;
|
|
63
|
+
this._bufferNode(funcData);
|
|
64
|
+
}
|
|
65
|
+
// 2. Buffer all SCOPE (without edges)
|
|
66
|
+
for (const scope of scopes) {
|
|
67
|
+
const { parentFunctionId, parentScopeId, capturesFrom, modifies, ...scopeData } = scope;
|
|
68
|
+
this._bufferNode(scopeData);
|
|
69
|
+
}
|
|
70
|
+
// 3. Buffer variables
|
|
71
|
+
for (const varDecl of variableDeclarations) {
|
|
72
|
+
const { parentScopeId, ...varData } = varDecl;
|
|
73
|
+
this._bufferNode(varData);
|
|
74
|
+
}
|
|
75
|
+
// 3.5. Buffer PARAMETER nodes and HAS_PARAMETER edges
|
|
76
|
+
for (const param of parameters) {
|
|
77
|
+
const { functionId, ...paramData } = param;
|
|
78
|
+
// Keep parentFunctionId on the node for queries
|
|
79
|
+
this._bufferNode(paramData);
|
|
80
|
+
if (param.parentFunctionId) {
|
|
81
|
+
this._bufferEdge({
|
|
82
|
+
type: 'HAS_PARAMETER',
|
|
83
|
+
src: param.parentFunctionId,
|
|
84
|
+
dst: param.id,
|
|
85
|
+
index: param.index
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// 4. Buffer CALL_SITE
|
|
90
|
+
for (const callSite of callSites) {
|
|
91
|
+
const { parentScopeId, targetFunctionName, ...callData } = callSite;
|
|
92
|
+
this._bufferNode(callData);
|
|
93
|
+
}
|
|
94
|
+
// 5. Buffer edges for functions
|
|
95
|
+
this.bufferFunctionEdges(module, functions);
|
|
96
|
+
// 6. Buffer edges for SCOPE
|
|
97
|
+
this.bufferScopeEdges(scopes, variableDeclarations);
|
|
98
|
+
// 7. Buffer edges for variables
|
|
99
|
+
this.bufferVariableEdges(variableDeclarations);
|
|
100
|
+
// 8. Buffer edges for CALL_SITE
|
|
101
|
+
this.bufferCallSiteEdges(callSites, functions);
|
|
102
|
+
// 9. Buffer METHOD_CALL nodes and CONTAINS edges
|
|
103
|
+
this.bufferMethodCalls(methodCalls);
|
|
104
|
+
// 10. Buffer net:stdio and WRITES_TO edges for console.log/error
|
|
105
|
+
this.bufferStdioNodes(methodCalls);
|
|
106
|
+
// 11. Buffer CLASS nodes for class declarations and CONTAINS edges
|
|
107
|
+
this.bufferClassDeclarationNodes(classDeclarations);
|
|
108
|
+
// 12. Buffer CLASS nodes and INSTANCE_OF edges for NewExpression
|
|
109
|
+
this.bufferClassNodes(module, classInstantiations, classDeclarations);
|
|
110
|
+
// 13. Buffer PASSES_ARGUMENT edges (METHOD_CALL -> FUNCTION)
|
|
111
|
+
this.bufferCallbackEdges(methodCallbacks, functions);
|
|
112
|
+
// 14. Buffer IMPORT nodes
|
|
113
|
+
this.bufferImportNodes(module, imports);
|
|
114
|
+
// 15. Buffer EXPORT nodes
|
|
115
|
+
this.bufferExportNodes(module, exports);
|
|
116
|
+
// 16. Buffer EVENT_LISTENER nodes and HANDLED_BY edges
|
|
117
|
+
this.bufferEventListeners(eventListeners, functions);
|
|
118
|
+
// 17. Buffer HTTP requests
|
|
119
|
+
this.bufferHttpRequests(httpRequests, functions);
|
|
120
|
+
// 18. Buffer LITERAL nodes
|
|
121
|
+
this.bufferLiterals(literals);
|
|
122
|
+
// 19. Buffer ASSIGNED_FROM edges for data flow (some need to create EXPRESSION nodes)
|
|
123
|
+
this.bufferAssignmentEdges(variableAssignments, variableDeclarations, callSites, methodCalls, functions, classInstantiations, parameters);
|
|
124
|
+
// 20. Buffer PASSES_ARGUMENT edges (CALL -> argument)
|
|
125
|
+
this.bufferArgumentEdges(callArguments, variableDeclarations, functions, callSites, methodCalls);
|
|
126
|
+
// 21. Buffer INTERFACE nodes and EXTENDS edges
|
|
127
|
+
this.bufferInterfaceNodes(module, interfaces);
|
|
128
|
+
// 22. Buffer TYPE nodes
|
|
129
|
+
this.bufferTypeAliasNodes(module, typeAliases);
|
|
130
|
+
// 23. Buffer ENUM nodes
|
|
131
|
+
this.bufferEnumNodes(module, enums);
|
|
132
|
+
// 24. Buffer DECORATOR nodes and DECORATED_BY edges
|
|
133
|
+
this.bufferDecoratorNodes(decorators);
|
|
134
|
+
// 25. Buffer IMPLEMENTS edges (CLASS -> INTERFACE)
|
|
135
|
+
this.bufferImplementsEdges(classDeclarations, interfaces);
|
|
136
|
+
// FLUSH: Write all nodes first, then edges in single batch calls
|
|
137
|
+
const nodesCreated = await this._flushNodes(graph);
|
|
138
|
+
const edgesCreated = await this._flushEdges(graph);
|
|
139
|
+
// Handle async operations that need graph queries (IMPORTS_FROM edges)
|
|
140
|
+
const importExportEdges = await this.createImportExportEdges(module, imports, exports, graph, projectPath);
|
|
141
|
+
// Handle async operations for ASSIGNED_FROM with CLASS lookups
|
|
142
|
+
const classAssignmentEdges = await this.createClassAssignmentEdges(variableAssignments, graph);
|
|
143
|
+
return { nodes: nodesCreated, edges: edgesCreated + importExportEdges + classAssignmentEdges };
|
|
144
|
+
}
|
|
145
|
+
// ============= BUFFERED METHODS (synchronous, no awaits) =============
|
|
146
|
+
bufferFunctionEdges(module, functions) {
|
|
147
|
+
for (const func of functions) {
|
|
148
|
+
const { parentScopeId, ...funcData } = func;
|
|
149
|
+
// MODULE -> CONTAINS -> FUNCTION (для функций верхнего уровня)
|
|
150
|
+
// или SCOPE -> CONTAINS -> FUNCTION (для вложенных функций)
|
|
151
|
+
if (parentScopeId) {
|
|
152
|
+
this._bufferEdge({
|
|
153
|
+
type: 'CONTAINS',
|
|
154
|
+
src: parentScopeId,
|
|
155
|
+
dst: funcData.id
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
this._bufferEdge({
|
|
160
|
+
type: 'CONTAINS',
|
|
161
|
+
src: module.id,
|
|
162
|
+
dst: funcData.id
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
bufferScopeEdges(scopes, variableDeclarations) {
|
|
168
|
+
for (const scope of scopes) {
|
|
169
|
+
const { parentFunctionId, parentScopeId, capturesFrom, modifies, ...scopeData } = scope;
|
|
170
|
+
// FUNCTION -> HAS_SCOPE -> SCOPE (для function_body)
|
|
171
|
+
if (parentFunctionId) {
|
|
172
|
+
this._bufferEdge({
|
|
173
|
+
type: 'HAS_SCOPE',
|
|
174
|
+
src: parentFunctionId,
|
|
175
|
+
dst: scopeData.id
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
// SCOPE -> CONTAINS -> SCOPE (для вложенных scope, типа if внутри function)
|
|
179
|
+
if (parentScopeId) {
|
|
180
|
+
this._bufferEdge({
|
|
181
|
+
type: 'CONTAINS',
|
|
182
|
+
src: parentScopeId,
|
|
183
|
+
dst: scopeData.id
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
// CAPTURES - замыкания захватывают переменные из родительского scope
|
|
187
|
+
if (capturesFrom && scopeData.scopeType === 'closure') {
|
|
188
|
+
const parentVars = variableDeclarations.filter(v => v.parentScopeId === capturesFrom);
|
|
189
|
+
for (const parentVar of parentVars) {
|
|
190
|
+
this._bufferEdge({
|
|
191
|
+
type: 'CAPTURES',
|
|
192
|
+
src: scopeData.id,
|
|
193
|
+
dst: parentVar.id
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// MODIFIES - scope модифицирует переменные (count++)
|
|
198
|
+
if (modifies && modifies.length > 0) {
|
|
199
|
+
for (const mod of modifies) {
|
|
200
|
+
this._bufferEdge({
|
|
201
|
+
type: 'MODIFIES',
|
|
202
|
+
src: scopeData.id,
|
|
203
|
+
dst: mod.variableId
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
bufferVariableEdges(variableDeclarations) {
|
|
210
|
+
for (const varDecl of variableDeclarations) {
|
|
211
|
+
const { parentScopeId, ...varData } = varDecl;
|
|
212
|
+
// SCOPE -> DECLARES -> VARIABLE
|
|
213
|
+
this._bufferEdge({
|
|
214
|
+
type: 'DECLARES',
|
|
215
|
+
src: parentScopeId,
|
|
216
|
+
dst: varData.id
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
bufferCallSiteEdges(callSites, functions) {
|
|
221
|
+
for (const callSite of callSites) {
|
|
222
|
+
const { parentScopeId, targetFunctionName, ...callData } = callSite;
|
|
223
|
+
// SCOPE -> CONTAINS -> CALL_SITE
|
|
224
|
+
this._bufferEdge({
|
|
225
|
+
type: 'CONTAINS',
|
|
226
|
+
src: parentScopeId,
|
|
227
|
+
dst: callData.id
|
|
228
|
+
});
|
|
229
|
+
// CALL_SITE -> CALLS -> FUNCTION
|
|
230
|
+
const targetFunction = functions.find(f => f.name === targetFunctionName);
|
|
231
|
+
if (targetFunction) {
|
|
232
|
+
this._bufferEdge({
|
|
233
|
+
type: 'CALLS',
|
|
234
|
+
src: callData.id,
|
|
235
|
+
dst: targetFunction.id
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
bufferMethodCalls(methodCalls) {
|
|
241
|
+
for (const methodCall of methodCalls) {
|
|
242
|
+
const { parentScopeId, ...methodData } = methodCall;
|
|
243
|
+
// Buffer METHOD_CALL node
|
|
244
|
+
this._bufferNode(methodData);
|
|
245
|
+
// SCOPE -> CONTAINS -> METHOD_CALL
|
|
246
|
+
this._bufferEdge({
|
|
247
|
+
type: 'CONTAINS',
|
|
248
|
+
src: parentScopeId,
|
|
249
|
+
dst: methodData.id
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
bufferStdioNodes(methodCalls) {
|
|
254
|
+
const consoleIOMethods = methodCalls.filter(mc => (mc.object === 'console' && (mc.method === 'log' || mc.method === 'error')));
|
|
255
|
+
if (consoleIOMethods.length > 0) {
|
|
256
|
+
const stdioId = 'net:stdio#__stdio__';
|
|
257
|
+
// Buffer net:stdio node only once (singleton)
|
|
258
|
+
if (!this._createdSingletons.has(stdioId)) {
|
|
259
|
+
this._bufferNode({
|
|
260
|
+
id: stdioId,
|
|
261
|
+
type: 'net:stdio',
|
|
262
|
+
name: '__stdio__',
|
|
263
|
+
description: 'Standard input/output stream'
|
|
264
|
+
});
|
|
265
|
+
this._createdSingletons.add(stdioId);
|
|
266
|
+
}
|
|
267
|
+
// Buffer WRITES_TO edges for console.log/error
|
|
268
|
+
for (const methodCall of consoleIOMethods) {
|
|
269
|
+
this._bufferEdge({
|
|
270
|
+
type: 'WRITES_TO',
|
|
271
|
+
src: methodCall.id,
|
|
272
|
+
dst: stdioId
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
bufferClassDeclarationNodes(classDeclarations) {
|
|
278
|
+
for (const classDecl of classDeclarations) {
|
|
279
|
+
const { id, type, name, file, line, column, superClass, methods } = classDecl;
|
|
280
|
+
// Buffer CLASS node
|
|
281
|
+
this._bufferNode({
|
|
282
|
+
id,
|
|
283
|
+
type,
|
|
284
|
+
name,
|
|
285
|
+
file,
|
|
286
|
+
line,
|
|
287
|
+
column,
|
|
288
|
+
superClass
|
|
289
|
+
});
|
|
290
|
+
// Buffer CONTAINS edges: CLASS -> METHOD
|
|
291
|
+
for (const methodId of methods) {
|
|
292
|
+
this._bufferEdge({
|
|
293
|
+
type: 'CONTAINS',
|
|
294
|
+
src: id,
|
|
295
|
+
dst: methodId
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
// If superClass, buffer DERIVES_FROM edge
|
|
299
|
+
if (superClass) {
|
|
300
|
+
const superClassId = `CLASS#${superClass}#${file}`;
|
|
301
|
+
this._bufferEdge({
|
|
302
|
+
type: 'DERIVES_FROM',
|
|
303
|
+
src: id,
|
|
304
|
+
dst: superClassId
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
bufferClassNodes(module, classInstantiations, classDeclarations) {
|
|
310
|
+
// Create lookup map: className → declaration ID
|
|
311
|
+
const declarationMap = new Map();
|
|
312
|
+
for (const decl of classDeclarations) {
|
|
313
|
+
if (decl.file === module.file) {
|
|
314
|
+
declarationMap.set(decl.name, decl.id);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
for (const instantiation of classInstantiations) {
|
|
318
|
+
const { variableId, className, line } = instantiation;
|
|
319
|
+
let classId = declarationMap.get(className);
|
|
320
|
+
if (!classId) {
|
|
321
|
+
// External class - buffer CLASS node
|
|
322
|
+
classId = `${module.file}:CLASS:${className}:${line}`;
|
|
323
|
+
this._bufferNode({
|
|
324
|
+
id: classId,
|
|
325
|
+
type: 'CLASS',
|
|
326
|
+
name: className,
|
|
327
|
+
file: module.file,
|
|
328
|
+
line,
|
|
329
|
+
isInstantiationRef: true
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
// Buffer INSTANCE_OF edge
|
|
333
|
+
this._bufferEdge({
|
|
334
|
+
type: 'INSTANCE_OF',
|
|
335
|
+
src: variableId,
|
|
336
|
+
dst: classId
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
bufferCallbackEdges(methodCallbacks, functions) {
|
|
341
|
+
for (const callback of methodCallbacks) {
|
|
342
|
+
const { methodCallId, callbackLine, callbackColumn } = callback;
|
|
343
|
+
const callbackFunction = functions.find(f => f.line === callbackLine && f.column === callbackColumn);
|
|
344
|
+
if (callbackFunction) {
|
|
345
|
+
this._bufferEdge({
|
|
346
|
+
type: 'HAS_CALLBACK',
|
|
347
|
+
src: methodCallId,
|
|
348
|
+
dst: callbackFunction.id
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
bufferImportNodes(module, imports) {
|
|
354
|
+
for (const imp of imports) {
|
|
355
|
+
const { source, specifiers, line } = imp;
|
|
356
|
+
for (const spec of specifiers) {
|
|
357
|
+
const importType = spec.imported === 'default' ? 'default' :
|
|
358
|
+
spec.imported === '*' ? 'namespace' : 'named';
|
|
359
|
+
const importId = `${module.file}:IMPORT:${source}:${spec.local}:${line}`;
|
|
360
|
+
this._bufferNode({
|
|
361
|
+
id: importId,
|
|
362
|
+
type: 'IMPORT',
|
|
363
|
+
source: source,
|
|
364
|
+
importType: importType,
|
|
365
|
+
imported: spec.imported,
|
|
366
|
+
local: spec.local,
|
|
367
|
+
file: module.file,
|
|
368
|
+
line: line
|
|
369
|
+
});
|
|
370
|
+
// MODULE -> CONTAINS -> IMPORT
|
|
371
|
+
this._bufferEdge({
|
|
372
|
+
type: 'CONTAINS',
|
|
373
|
+
src: module.id,
|
|
374
|
+
dst: importId
|
|
375
|
+
});
|
|
376
|
+
// Create EXTERNAL_MODULE node for external modules
|
|
377
|
+
const isRelative = source.startsWith('./') || source.startsWith('../');
|
|
378
|
+
if (!isRelative) {
|
|
379
|
+
const externalModuleId = `EXTERNAL_MODULE:${source}`;
|
|
380
|
+
this._bufferNode({
|
|
381
|
+
id: externalModuleId,
|
|
382
|
+
type: 'EXTERNAL_MODULE',
|
|
383
|
+
name: source,
|
|
384
|
+
file: module.file,
|
|
385
|
+
line: line
|
|
386
|
+
});
|
|
387
|
+
this._bufferEdge({
|
|
388
|
+
type: 'IMPORTS',
|
|
389
|
+
src: module.id,
|
|
390
|
+
dst: externalModuleId
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
bufferExportNodes(module, exports) {
|
|
397
|
+
for (const exp of exports) {
|
|
398
|
+
const { type, line, name, specifiers, source } = exp;
|
|
399
|
+
if (type === 'default') {
|
|
400
|
+
const exportId = `${module.file}:EXPORT:default:${line}`;
|
|
401
|
+
this._bufferNode({
|
|
402
|
+
id: exportId,
|
|
403
|
+
type: 'EXPORT',
|
|
404
|
+
exportType: 'default',
|
|
405
|
+
name: 'default',
|
|
406
|
+
file: module.file,
|
|
407
|
+
line: line
|
|
408
|
+
});
|
|
409
|
+
this._bufferEdge({
|
|
410
|
+
type: 'CONTAINS',
|
|
411
|
+
src: module.id,
|
|
412
|
+
dst: exportId
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
else if (type === 'named') {
|
|
416
|
+
if (specifiers) {
|
|
417
|
+
for (const spec of specifiers) {
|
|
418
|
+
const exportId = `${module.file}:EXPORT:${spec.exported}:${line}`;
|
|
419
|
+
this._bufferNode({
|
|
420
|
+
id: exportId,
|
|
421
|
+
type: 'EXPORT',
|
|
422
|
+
exportType: 'named',
|
|
423
|
+
name: spec.exported,
|
|
424
|
+
local: spec.local,
|
|
425
|
+
file: module.file,
|
|
426
|
+
line: line,
|
|
427
|
+
source: source
|
|
428
|
+
});
|
|
429
|
+
this._bufferEdge({
|
|
430
|
+
type: 'CONTAINS',
|
|
431
|
+
src: module.id,
|
|
432
|
+
dst: exportId
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
else if (name) {
|
|
437
|
+
const exportId = `${module.file}:EXPORT:${name}:${line}`;
|
|
438
|
+
this._bufferNode({
|
|
439
|
+
id: exportId,
|
|
440
|
+
type: 'EXPORT',
|
|
441
|
+
exportType: 'named',
|
|
442
|
+
name: name,
|
|
443
|
+
file: module.file,
|
|
444
|
+
line: line
|
|
445
|
+
});
|
|
446
|
+
this._bufferEdge({
|
|
447
|
+
type: 'CONTAINS',
|
|
448
|
+
src: module.id,
|
|
449
|
+
dst: exportId
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
else if (type === 'all') {
|
|
454
|
+
const exportId = `${module.file}:EXPORT:*:${line}`;
|
|
455
|
+
this._bufferNode({
|
|
456
|
+
id: exportId,
|
|
457
|
+
type: 'EXPORT',
|
|
458
|
+
exportType: 'all',
|
|
459
|
+
name: '*',
|
|
460
|
+
file: module.file,
|
|
461
|
+
line: line,
|
|
462
|
+
source: source
|
|
463
|
+
});
|
|
464
|
+
this._bufferEdge({
|
|
465
|
+
type: 'CONTAINS',
|
|
466
|
+
src: module.id,
|
|
467
|
+
dst: exportId
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
bufferEventListeners(eventListeners, functions) {
|
|
473
|
+
for (const eventListener of eventListeners) {
|
|
474
|
+
const { parentScopeId, callbackArg, ...listenerData } = eventListener;
|
|
475
|
+
this._bufferNode(listenerData);
|
|
476
|
+
this._bufferEdge({
|
|
477
|
+
type: 'CONTAINS',
|
|
478
|
+
src: parentScopeId,
|
|
479
|
+
dst: listenerData.id
|
|
480
|
+
});
|
|
481
|
+
if (callbackArg && callbackArg.type === 'ArrowFunctionExpression') {
|
|
482
|
+
const callbackLine = callbackArg.loc.start.line;
|
|
483
|
+
const callbackFunction = functions.find(f => f.line === callbackLine && f.arrowFunction);
|
|
484
|
+
if (callbackFunction) {
|
|
485
|
+
this._bufferEdge({
|
|
486
|
+
type: 'HANDLED_BY',
|
|
487
|
+
src: listenerData.id,
|
|
488
|
+
dst: callbackFunction.id
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
bufferHttpRequests(httpRequests, functions) {
|
|
495
|
+
if (httpRequests.length > 0) {
|
|
496
|
+
const networkId = 'net:request#__network__';
|
|
497
|
+
if (!this._createdSingletons.has(networkId)) {
|
|
498
|
+
this._bufferNode({
|
|
499
|
+
id: networkId,
|
|
500
|
+
type: 'net:request',
|
|
501
|
+
name: '__network__'
|
|
502
|
+
});
|
|
503
|
+
this._createdSingletons.add(networkId);
|
|
504
|
+
}
|
|
505
|
+
for (const request of httpRequests) {
|
|
506
|
+
const { parentScopeId, ...requestData } = request;
|
|
507
|
+
this._bufferNode(requestData);
|
|
508
|
+
this._bufferEdge({
|
|
509
|
+
type: 'CALLS',
|
|
510
|
+
src: request.id,
|
|
511
|
+
dst: networkId
|
|
512
|
+
});
|
|
513
|
+
if (parentScopeId) {
|
|
514
|
+
const scopeParts = parentScopeId.split(':');
|
|
515
|
+
if (scopeParts.length >= 3 && scopeParts[1] === 'SCOPE') {
|
|
516
|
+
const functionName = scopeParts[2];
|
|
517
|
+
const file = scopeParts[0];
|
|
518
|
+
const parentFunction = functions.find(f => f.file === file && f.name === functionName);
|
|
519
|
+
if (parentFunction) {
|
|
520
|
+
this._bufferEdge({
|
|
521
|
+
type: 'MAKES_REQUEST',
|
|
522
|
+
src: parentFunction.id,
|
|
523
|
+
dst: request.id
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
bufferLiterals(literals) {
|
|
532
|
+
for (const literal of literals) {
|
|
533
|
+
const { parentCallId, argIndex, ...literalData } = literal;
|
|
534
|
+
this._bufferNode(literalData);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
bufferAssignmentEdges(variableAssignments, variableDeclarations, callSites, methodCalls, functions, classInstantiations, parameters) {
|
|
538
|
+
for (const assignment of variableAssignments) {
|
|
539
|
+
const { variableId, sourceId, sourceType, sourceName, sourceLine, sourceColumn, sourceFile, functionName, line, className } = assignment;
|
|
540
|
+
// Skip CLASS sourceType - handled async in createClassAssignmentEdges
|
|
541
|
+
if (sourceType === 'CLASS') {
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
// Direct LITERAL assignment
|
|
545
|
+
if (sourceId && sourceType !== 'EXPRESSION') {
|
|
546
|
+
this._bufferEdge({
|
|
547
|
+
type: 'ASSIGNED_FROM',
|
|
548
|
+
src: variableId,
|
|
549
|
+
dst: sourceId
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
// METHOD_CALL by coordinates
|
|
553
|
+
else if (sourceType === 'METHOD_CALL' && sourceLine && sourceColumn) {
|
|
554
|
+
const methodCall = methodCalls.find(mc => mc.line === sourceLine &&
|
|
555
|
+
mc.column === sourceColumn &&
|
|
556
|
+
mc.file === sourceFile);
|
|
557
|
+
if (methodCall) {
|
|
558
|
+
this._bufferEdge({
|
|
559
|
+
type: 'ASSIGNED_FROM',
|
|
560
|
+
src: variableId,
|
|
561
|
+
dst: methodCall.id
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
// CALL_SITE by coordinates
|
|
566
|
+
else if (sourceType === 'CALL_SITE') {
|
|
567
|
+
const searchLine = sourceLine || assignment.callLine;
|
|
568
|
+
const searchColumn = sourceColumn || assignment.callColumn;
|
|
569
|
+
const searchName = assignment.callName;
|
|
570
|
+
if (searchLine && searchColumn) {
|
|
571
|
+
const callSite = callSites.find(cs => cs.line === searchLine &&
|
|
572
|
+
cs.column === searchColumn &&
|
|
573
|
+
(searchName ? cs.name === searchName : true));
|
|
574
|
+
if (callSite) {
|
|
575
|
+
this._bufferEdge({
|
|
576
|
+
type: 'ASSIGNED_FROM',
|
|
577
|
+
src: variableId,
|
|
578
|
+
dst: callSite.id
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
// VARIABLE by name
|
|
584
|
+
else if (sourceType === 'VARIABLE' && sourceName) {
|
|
585
|
+
const varIdParts = variableId.split('#');
|
|
586
|
+
const varFile = varIdParts.length >= 3 ? varIdParts[2] : null;
|
|
587
|
+
const sourceVariable = variableDeclarations.find(v => v.name === sourceName && v.file === varFile);
|
|
588
|
+
if (sourceVariable) {
|
|
589
|
+
this._bufferEdge({
|
|
590
|
+
type: 'ASSIGNED_FROM',
|
|
591
|
+
src: variableId,
|
|
592
|
+
dst: sourceVariable.id
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
const sourceParam = parameters.find(p => p.name === sourceName && p.file === varFile);
|
|
597
|
+
if (sourceParam) {
|
|
598
|
+
this._bufferEdge({
|
|
599
|
+
type: 'DERIVES_FROM',
|
|
600
|
+
src: variableId,
|
|
601
|
+
dst: sourceParam.id
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
// FUNCTION (arrow function assigned to variable)
|
|
607
|
+
else if (sourceType === 'FUNCTION' && functionName && line) {
|
|
608
|
+
const sourceFunction = functions.find(f => f.name === functionName && f.line === line);
|
|
609
|
+
if (sourceFunction) {
|
|
610
|
+
this._bufferEdge({
|
|
611
|
+
type: 'ASSIGNED_FROM',
|
|
612
|
+
src: variableId,
|
|
613
|
+
dst: sourceFunction.id
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
// EXPRESSION node creation
|
|
618
|
+
else if (sourceType === 'EXPRESSION' && sourceId) {
|
|
619
|
+
const { expressionType, object, property, computed, computedPropertyVar, operator, objectSourceName, leftSourceName, rightSourceName, consequentSourceName, alternateSourceName, file: exprFile, line: exprLine } = assignment;
|
|
620
|
+
const expressionNode = {
|
|
621
|
+
id: sourceId,
|
|
622
|
+
type: 'EXPRESSION',
|
|
623
|
+
expressionType,
|
|
624
|
+
file: exprFile,
|
|
625
|
+
line: exprLine
|
|
626
|
+
};
|
|
627
|
+
if (expressionType === 'MemberExpression') {
|
|
628
|
+
expressionNode.object = object;
|
|
629
|
+
expressionNode.property = property;
|
|
630
|
+
expressionNode.computed = computed;
|
|
631
|
+
if (computedPropertyVar) {
|
|
632
|
+
expressionNode.computedPropertyVar = computedPropertyVar;
|
|
633
|
+
}
|
|
634
|
+
expressionNode.name = `${object}.${property}`;
|
|
635
|
+
}
|
|
636
|
+
else if (expressionType === 'BinaryExpression' || expressionType === 'LogicalExpression') {
|
|
637
|
+
expressionNode.operator = operator;
|
|
638
|
+
expressionNode.name = `<${expressionType}>`;
|
|
639
|
+
}
|
|
640
|
+
else if (expressionType === 'ConditionalExpression') {
|
|
641
|
+
expressionNode.name = '<ternary>';
|
|
642
|
+
}
|
|
643
|
+
else if (expressionType === 'TemplateLiteral') {
|
|
644
|
+
expressionNode.name = '<template>';
|
|
645
|
+
}
|
|
646
|
+
this._bufferNode(expressionNode);
|
|
647
|
+
this._bufferEdge({
|
|
648
|
+
type: 'ASSIGNED_FROM',
|
|
649
|
+
src: variableId,
|
|
650
|
+
dst: sourceId
|
|
651
|
+
});
|
|
652
|
+
// Buffer DERIVES_FROM edges
|
|
653
|
+
const varParts = variableId.split('#');
|
|
654
|
+
const varFile = varParts.length >= 3 ? varParts[2] : null;
|
|
655
|
+
if (expressionType === 'MemberExpression' && objectSourceName) {
|
|
656
|
+
const objectVar = variableDeclarations.find(v => v.name === objectSourceName && (!varFile || v.file === varFile));
|
|
657
|
+
if (objectVar) {
|
|
658
|
+
this._bufferEdge({
|
|
659
|
+
type: 'DERIVES_FROM',
|
|
660
|
+
src: sourceId,
|
|
661
|
+
dst: objectVar.id
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
if ((expressionType === 'BinaryExpression' || expressionType === 'LogicalExpression')) {
|
|
666
|
+
if (leftSourceName) {
|
|
667
|
+
const leftVar = variableDeclarations.find(v => v.name === leftSourceName && (!varFile || v.file === varFile));
|
|
668
|
+
if (leftVar) {
|
|
669
|
+
this._bufferEdge({
|
|
670
|
+
type: 'DERIVES_FROM',
|
|
671
|
+
src: sourceId,
|
|
672
|
+
dst: leftVar.id
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
if (rightSourceName) {
|
|
677
|
+
const rightVar = variableDeclarations.find(v => v.name === rightSourceName && (!varFile || v.file === varFile));
|
|
678
|
+
if (rightVar) {
|
|
679
|
+
this._bufferEdge({
|
|
680
|
+
type: 'DERIVES_FROM',
|
|
681
|
+
src: sourceId,
|
|
682
|
+
dst: rightVar.id
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
if (expressionType === 'ConditionalExpression') {
|
|
688
|
+
if (consequentSourceName) {
|
|
689
|
+
const consequentVar = variableDeclarations.find(v => v.name === consequentSourceName && (!varFile || v.file === varFile));
|
|
690
|
+
if (consequentVar) {
|
|
691
|
+
this._bufferEdge({
|
|
692
|
+
type: 'DERIVES_FROM',
|
|
693
|
+
src: sourceId,
|
|
694
|
+
dst: consequentVar.id
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
if (alternateSourceName) {
|
|
699
|
+
const alternateVar = variableDeclarations.find(v => v.name === alternateSourceName && (!varFile || v.file === varFile));
|
|
700
|
+
if (alternateVar) {
|
|
701
|
+
this._bufferEdge({
|
|
702
|
+
type: 'DERIVES_FROM',
|
|
703
|
+
src: sourceId,
|
|
704
|
+
dst: alternateVar.id
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
if (expressionType === 'TemplateLiteral') {
|
|
710
|
+
const { expressionSourceNames } = assignment;
|
|
711
|
+
if (expressionSourceNames && expressionSourceNames.length > 0) {
|
|
712
|
+
for (const exprSourceName of expressionSourceNames) {
|
|
713
|
+
const sourceVar = variableDeclarations.find(v => v.name === exprSourceName && (!varFile || v.file === varFile));
|
|
714
|
+
if (sourceVar) {
|
|
715
|
+
this._bufferEdge({
|
|
716
|
+
type: 'DERIVES_FROM',
|
|
717
|
+
src: sourceId,
|
|
718
|
+
dst: sourceVar.id
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
// DERIVES_FROM_VARIABLE
|
|
726
|
+
else if (sourceType === 'DERIVES_FROM_VARIABLE' && sourceName) {
|
|
727
|
+
const expressionId = variableId;
|
|
728
|
+
const exprParts = expressionId.split('#');
|
|
729
|
+
const exprFile = exprParts.length >= 3 ? exprParts[2] : assignment.file;
|
|
730
|
+
const sourceVariable = variableDeclarations.find(v => v.name === sourceName && v.file === exprFile);
|
|
731
|
+
if (sourceVariable) {
|
|
732
|
+
this._bufferEdge({
|
|
733
|
+
type: 'DERIVES_FROM',
|
|
734
|
+
src: expressionId,
|
|
735
|
+
dst: sourceVariable.id
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
else {
|
|
739
|
+
const sourceParam = parameters.find(p => p.name === sourceName && p.file === exprFile);
|
|
740
|
+
if (sourceParam) {
|
|
741
|
+
this._bufferEdge({
|
|
742
|
+
type: 'DERIVES_FROM',
|
|
743
|
+
src: expressionId,
|
|
744
|
+
dst: sourceParam.id
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
bufferArgumentEdges(callArguments, variableDeclarations, functions, callSites, methodCalls) {
|
|
752
|
+
for (const arg of callArguments) {
|
|
753
|
+
const { callId, argIndex, targetType, targetId, targetName, file, isSpread, functionLine, functionColumn, nestedCallLine, nestedCallColumn } = arg;
|
|
754
|
+
let targetNodeId = targetId;
|
|
755
|
+
if (targetType === 'VARIABLE' && targetName) {
|
|
756
|
+
const varNode = variableDeclarations.find(v => v.name === targetName && v.file === file);
|
|
757
|
+
if (varNode) {
|
|
758
|
+
targetNodeId = varNode.id;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
else if (targetType === 'FUNCTION' && functionLine && functionColumn) {
|
|
762
|
+
const funcNode = functions.find(f => f.file === file && f.line === functionLine && f.column === functionColumn);
|
|
763
|
+
if (funcNode) {
|
|
764
|
+
targetNodeId = funcNode.id;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
else if (targetType === 'CALL' && nestedCallLine && nestedCallColumn) {
|
|
768
|
+
const nestedCall = callSites.find(c => c.file === file && c.line === nestedCallLine && c.column === nestedCallColumn) || methodCalls.find(c => c.file === file && c.line === nestedCallLine && c.column === nestedCallColumn);
|
|
769
|
+
if (nestedCall) {
|
|
770
|
+
targetNodeId = nestedCall.id;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
if (targetNodeId) {
|
|
774
|
+
const edgeData = {
|
|
775
|
+
type: 'PASSES_ARGUMENT',
|
|
776
|
+
src: callId,
|
|
777
|
+
dst: targetNodeId,
|
|
778
|
+
metadata: { argIndex }
|
|
779
|
+
};
|
|
780
|
+
if (isSpread) {
|
|
781
|
+
edgeData.metadata = { ...edgeData.metadata, isSpread: true };
|
|
782
|
+
}
|
|
783
|
+
this._bufferEdge(edgeData);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
// ============= TypeScript-specific buffer methods =============
|
|
788
|
+
/**
|
|
789
|
+
* Buffer INTERFACE nodes and EXTENDS edges
|
|
790
|
+
*/
|
|
791
|
+
bufferInterfaceNodes(module, interfaces) {
|
|
792
|
+
for (const iface of interfaces) {
|
|
793
|
+
// Buffer INTERFACE node
|
|
794
|
+
this._bufferNode({
|
|
795
|
+
id: iface.id,
|
|
796
|
+
type: 'INTERFACE',
|
|
797
|
+
name: iface.name,
|
|
798
|
+
file: iface.file,
|
|
799
|
+
line: iface.line,
|
|
800
|
+
column: iface.column,
|
|
801
|
+
properties: iface.properties,
|
|
802
|
+
extends: iface.extends
|
|
803
|
+
});
|
|
804
|
+
// MODULE -> CONTAINS -> INTERFACE
|
|
805
|
+
this._bufferEdge({
|
|
806
|
+
type: 'CONTAINS',
|
|
807
|
+
src: module.id,
|
|
808
|
+
dst: iface.id
|
|
809
|
+
});
|
|
810
|
+
// INTERFACE -> EXTENDS -> INTERFACE (for each parent interface)
|
|
811
|
+
if (iface.extends && iface.extends.length > 0) {
|
|
812
|
+
for (const parentName of iface.extends) {
|
|
813
|
+
// Try to find the parent interface in the same file
|
|
814
|
+
const parentInterface = interfaces.find(i => i.name === parentName);
|
|
815
|
+
if (parentInterface) {
|
|
816
|
+
this._bufferEdge({
|
|
817
|
+
type: 'EXTENDS',
|
|
818
|
+
src: iface.id,
|
|
819
|
+
dst: parentInterface.id
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
else {
|
|
823
|
+
// External interface - create a reference node
|
|
824
|
+
const externalId = `INTERFACE#${parentName}#${iface.file}#external`;
|
|
825
|
+
this._bufferNode({
|
|
826
|
+
id: externalId,
|
|
827
|
+
type: 'INTERFACE',
|
|
828
|
+
name: parentName,
|
|
829
|
+
file: iface.file,
|
|
830
|
+
line: iface.line,
|
|
831
|
+
isExternal: true
|
|
832
|
+
});
|
|
833
|
+
this._bufferEdge({
|
|
834
|
+
type: 'EXTENDS',
|
|
835
|
+
src: iface.id,
|
|
836
|
+
dst: externalId
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Buffer TYPE alias nodes
|
|
845
|
+
*/
|
|
846
|
+
bufferTypeAliasNodes(module, typeAliases) {
|
|
847
|
+
for (const typeAlias of typeAliases) {
|
|
848
|
+
// Buffer TYPE node
|
|
849
|
+
this._bufferNode({
|
|
850
|
+
id: typeAlias.id,
|
|
851
|
+
type: 'TYPE',
|
|
852
|
+
name: typeAlias.name,
|
|
853
|
+
file: typeAlias.file,
|
|
854
|
+
line: typeAlias.line,
|
|
855
|
+
column: typeAlias.column,
|
|
856
|
+
aliasOf: typeAlias.aliasOf
|
|
857
|
+
});
|
|
858
|
+
// MODULE -> CONTAINS -> TYPE
|
|
859
|
+
this._bufferEdge({
|
|
860
|
+
type: 'CONTAINS',
|
|
861
|
+
src: module.id,
|
|
862
|
+
dst: typeAlias.id
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Buffer ENUM nodes
|
|
868
|
+
*/
|
|
869
|
+
bufferEnumNodes(module, enums) {
|
|
870
|
+
for (const enumDecl of enums) {
|
|
871
|
+
// Buffer ENUM node
|
|
872
|
+
this._bufferNode({
|
|
873
|
+
id: enumDecl.id,
|
|
874
|
+
type: 'ENUM',
|
|
875
|
+
name: enumDecl.name,
|
|
876
|
+
file: enumDecl.file,
|
|
877
|
+
line: enumDecl.line,
|
|
878
|
+
column: enumDecl.column,
|
|
879
|
+
isConst: enumDecl.isConst,
|
|
880
|
+
members: enumDecl.members
|
|
881
|
+
});
|
|
882
|
+
// MODULE -> CONTAINS -> ENUM
|
|
883
|
+
this._bufferEdge({
|
|
884
|
+
type: 'CONTAINS',
|
|
885
|
+
src: module.id,
|
|
886
|
+
dst: enumDecl.id
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* Buffer DECORATOR nodes and DECORATED_BY edges
|
|
892
|
+
*/
|
|
893
|
+
bufferDecoratorNodes(decorators) {
|
|
894
|
+
for (const decorator of decorators) {
|
|
895
|
+
// Buffer DECORATOR node
|
|
896
|
+
this._bufferNode({
|
|
897
|
+
id: decorator.id,
|
|
898
|
+
type: 'DECORATOR',
|
|
899
|
+
name: decorator.name,
|
|
900
|
+
file: decorator.file,
|
|
901
|
+
line: decorator.line,
|
|
902
|
+
column: decorator.column,
|
|
903
|
+
arguments: decorator.arguments,
|
|
904
|
+
targetType: decorator.targetType
|
|
905
|
+
});
|
|
906
|
+
// TARGET -> DECORATED_BY -> DECORATOR
|
|
907
|
+
this._bufferEdge({
|
|
908
|
+
type: 'DECORATED_BY',
|
|
909
|
+
src: decorator.targetId,
|
|
910
|
+
dst: decorator.id
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
/**
|
|
915
|
+
* Buffer IMPLEMENTS edges (CLASS -> INTERFACE)
|
|
916
|
+
*/
|
|
917
|
+
bufferImplementsEdges(classDeclarations, interfaces) {
|
|
918
|
+
for (const classDecl of classDeclarations) {
|
|
919
|
+
if (classDecl.implements && classDecl.implements.length > 0) {
|
|
920
|
+
for (const ifaceName of classDecl.implements) {
|
|
921
|
+
// Try to find the interface in the same file
|
|
922
|
+
const iface = interfaces.find(i => i.name === ifaceName);
|
|
923
|
+
if (iface) {
|
|
924
|
+
this._bufferEdge({
|
|
925
|
+
type: 'IMPLEMENTS',
|
|
926
|
+
src: classDecl.id,
|
|
927
|
+
dst: iface.id
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
else {
|
|
931
|
+
// External interface - create a reference node
|
|
932
|
+
const externalId = `INTERFACE#${ifaceName}#${classDecl.file}#external`;
|
|
933
|
+
this._bufferNode({
|
|
934
|
+
id: externalId,
|
|
935
|
+
type: 'INTERFACE',
|
|
936
|
+
name: ifaceName,
|
|
937
|
+
file: classDecl.file,
|
|
938
|
+
line: classDecl.line,
|
|
939
|
+
isExternal: true
|
|
940
|
+
});
|
|
941
|
+
this._bufferEdge({
|
|
942
|
+
type: 'IMPLEMENTS',
|
|
943
|
+
src: classDecl.id,
|
|
944
|
+
dst: externalId
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Handle CLASS ASSIGNED_FROM edges asynchronously (needs graph queries)
|
|
953
|
+
*/
|
|
954
|
+
async createClassAssignmentEdges(variableAssignments, graph) {
|
|
955
|
+
let edgesCreated = 0;
|
|
956
|
+
for (const assignment of variableAssignments) {
|
|
957
|
+
const { variableId, sourceType, className } = assignment;
|
|
958
|
+
if (sourceType === 'CLASS' && className) {
|
|
959
|
+
const parts = variableId.split('#');
|
|
960
|
+
const file = parts.length >= 3 ? parts[2] : null;
|
|
961
|
+
let classNode = null;
|
|
962
|
+
for await (const node of graph.queryNodes({ type: 'CLASS' })) {
|
|
963
|
+
if (node.name === className && (!file || node.file === file)) {
|
|
964
|
+
classNode = node;
|
|
965
|
+
break;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
if (classNode) {
|
|
969
|
+
await graph.addEdge({
|
|
970
|
+
type: 'ASSIGNED_FROM',
|
|
971
|
+
src: variableId,
|
|
972
|
+
dst: classNode.id
|
|
973
|
+
});
|
|
974
|
+
edgesCreated++;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
return edgesCreated;
|
|
979
|
+
}
|
|
980
|
+
/**
|
|
981
|
+
* Create IMPORTS_FROM edges linking imports to their target exports
|
|
982
|
+
*/
|
|
983
|
+
async createImportExportEdges(module, imports, _exports, graph, _projectPath) {
|
|
984
|
+
let edgesCreated = 0;
|
|
985
|
+
for (const imp of imports) {
|
|
986
|
+
const { source, specifiers, line } = imp;
|
|
987
|
+
// Только для относительных импортов
|
|
988
|
+
const isRelative = source.startsWith('./') || source.startsWith('../');
|
|
989
|
+
if (!isRelative) {
|
|
990
|
+
continue;
|
|
991
|
+
}
|
|
992
|
+
// Резолвим целевой модуль
|
|
993
|
+
const currentDir = dirname(module.file);
|
|
994
|
+
let targetPath = resolve(currentDir, source);
|
|
995
|
+
// Пытаемся найти файл с расширениями .js, .ts, .jsx, .tsx
|
|
996
|
+
const extensions = ['', '.js', '.ts', '.jsx', '.tsx', '/index.js', '/index.ts'];
|
|
997
|
+
let targetModule = null;
|
|
998
|
+
// Ищем MODULE ноду по file атрибуту (не по ID, т.к. формат ID изменился)
|
|
999
|
+
for (const ext of extensions) {
|
|
1000
|
+
const testPath = targetPath + ext;
|
|
1001
|
+
// Ищем MODULE с этим file path
|
|
1002
|
+
for await (const node of graph.queryNodes({ type: 'MODULE' })) {
|
|
1003
|
+
if (node.file === testPath) {
|
|
1004
|
+
targetModule = node;
|
|
1005
|
+
targetPath = testPath;
|
|
1006
|
+
break;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
if (targetModule)
|
|
1010
|
+
break;
|
|
1011
|
+
}
|
|
1012
|
+
if (!targetModule) {
|
|
1013
|
+
// Целевой модуль не найден в графе
|
|
1014
|
+
continue;
|
|
1015
|
+
}
|
|
1016
|
+
// Создаём IMPORTS edge от MODULE к MODULE (для совместимости с тестами)
|
|
1017
|
+
await graph.addEdge({
|
|
1018
|
+
type: 'IMPORTS',
|
|
1019
|
+
src: module.id,
|
|
1020
|
+
dst: targetModule.id
|
|
1021
|
+
});
|
|
1022
|
+
edgesCreated++;
|
|
1023
|
+
// Для каждого импортированного идентификатора создаём ребро к соответствующему EXPORT
|
|
1024
|
+
for (const spec of specifiers) {
|
|
1025
|
+
const importId = `${module.file}:IMPORT:${source}:${spec.local}:${line}`;
|
|
1026
|
+
const importType = spec.imported === 'default' ? 'default' :
|
|
1027
|
+
spec.imported === '*' ? 'namespace' : 'named';
|
|
1028
|
+
if (importType === 'namespace') {
|
|
1029
|
+
// import * as foo - связываем со всем модулем
|
|
1030
|
+
await graph.addEdge({
|
|
1031
|
+
type: 'IMPORTS_FROM',
|
|
1032
|
+
src: importId,
|
|
1033
|
+
dst: targetModule.id
|
|
1034
|
+
});
|
|
1035
|
+
edgesCreated++;
|
|
1036
|
+
}
|
|
1037
|
+
else if (importType === 'default') {
|
|
1038
|
+
// Находим EXPORT default в целевом модуле
|
|
1039
|
+
const targetExports = [];
|
|
1040
|
+
for await (const node of graph.queryNodes({ type: 'EXPORT' })) {
|
|
1041
|
+
const exportNode = node;
|
|
1042
|
+
if (exportNode.file === targetPath && exportNode.exportType === 'default') {
|
|
1043
|
+
targetExports.push(exportNode);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
if (targetExports.length > 0) {
|
|
1047
|
+
await graph.addEdge({
|
|
1048
|
+
type: 'IMPORTS_FROM',
|
|
1049
|
+
src: importId,
|
|
1050
|
+
dst: targetExports[0].id
|
|
1051
|
+
});
|
|
1052
|
+
edgesCreated++;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
else {
|
|
1056
|
+
// Named import - находим соответствующий named export
|
|
1057
|
+
const targetExports = [];
|
|
1058
|
+
for await (const node of graph.queryNodes({ type: 'EXPORT' })) {
|
|
1059
|
+
const exportNode = node;
|
|
1060
|
+
if (exportNode.file === targetPath && exportNode.exportType === 'named' && exportNode.name === spec.imported) {
|
|
1061
|
+
targetExports.push(exportNode);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
if (targetExports.length > 0) {
|
|
1065
|
+
await graph.addEdge({
|
|
1066
|
+
type: 'IMPORTS_FROM',
|
|
1067
|
+
src: importId,
|
|
1068
|
+
dst: targetExports[0].id
|
|
1069
|
+
});
|
|
1070
|
+
edgesCreated++;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
return edgesCreated;
|
|
1076
|
+
}
|
|
1077
|
+
}
|