@grafema/core 0.1.0-alpha.5 → 0.1.1-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/dist/Orchestrator.d.ts +24 -2
- package/dist/Orchestrator.d.ts.map +1 -1
- package/dist/Orchestrator.js +197 -24
- package/dist/config/ConfigLoader.d.ts +72 -0
- package/dist/config/ConfigLoader.d.ts.map +1 -0
- package/dist/config/ConfigLoader.js +187 -0
- package/dist/config/index.d.ts +6 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +4 -0
- package/dist/core/ASTWorker.d.ts +11 -36
- package/dist/core/ASTWorker.d.ts.map +1 -1
- package/dist/core/ASTWorker.js +93 -99
- package/dist/core/CoverageAnalyzer.d.ts +65 -0
- package/dist/core/CoverageAnalyzer.d.ts.map +1 -0
- package/dist/core/CoverageAnalyzer.js +198 -0
- package/dist/core/FileNodeManager.d.ts +40 -0
- package/dist/core/FileNodeManager.d.ts.map +1 -0
- package/dist/core/FileNodeManager.js +84 -0
- package/dist/core/GraphFreshnessChecker.d.ts +33 -0
- package/dist/core/GraphFreshnessChecker.d.ts.map +1 -0
- package/dist/core/GraphFreshnessChecker.js +101 -0
- package/dist/core/HashUtils.d.ts +24 -0
- package/dist/core/HashUtils.d.ts.map +1 -0
- package/dist/core/HashUtils.js +45 -0
- package/dist/core/IncrementalReanalyzer.d.ts +36 -0
- package/dist/core/IncrementalReanalyzer.d.ts.map +1 -0
- package/dist/core/IncrementalReanalyzer.js +132 -0
- package/dist/core/NodeFactory.d.ts +225 -17
- package/dist/core/NodeFactory.d.ts.map +1 -1
- package/dist/core/NodeFactory.js +208 -18
- package/dist/core/ScopeTracker.d.ts +84 -0
- package/dist/core/ScopeTracker.d.ts.map +1 -0
- package/dist/core/ScopeTracker.js +116 -0
- package/dist/core/SemanticId.d.ts +90 -0
- package/dist/core/SemanticId.d.ts.map +1 -0
- package/dist/core/SemanticId.js +115 -0
- package/dist/core/VersionManager.d.ts.map +1 -1
- package/dist/core/VersionManager.js +3 -2
- package/dist/core/nodes/ArgumentExpressionNode.d.ts +43 -0
- package/dist/core/nodes/ArgumentExpressionNode.d.ts.map +1 -0
- package/dist/core/nodes/ArgumentExpressionNode.js +60 -0
- package/dist/core/nodes/ArrayLiteralNode.d.ts +27 -0
- package/dist/core/nodes/ArrayLiteralNode.d.ts.map +1 -0
- package/dist/core/nodes/ArrayLiteralNode.js +41 -0
- package/dist/core/nodes/CallSiteNode.d.ts +28 -0
- package/dist/core/nodes/CallSiteNode.d.ts.map +1 -1
- package/dist/core/nodes/CallSiteNode.js +46 -0
- package/dist/core/nodes/ClassNode.d.ts +33 -1
- package/dist/core/nodes/ClassNode.d.ts.map +1 -1
- package/dist/core/nodes/ClassNode.js +46 -2
- package/dist/core/nodes/DecoratorNode.d.ts +42 -0
- package/dist/core/nodes/DecoratorNode.d.ts.map +1 -0
- package/dist/core/nodes/DecoratorNode.js +62 -0
- package/dist/core/nodes/EnumNode.d.ts +42 -0
- package/dist/core/nodes/EnumNode.d.ts.map +1 -0
- package/dist/core/nodes/EnumNode.js +54 -0
- package/dist/core/nodes/ExportNode.d.ts +37 -1
- package/dist/core/nodes/ExportNode.d.ts.map +1 -1
- package/dist/core/nodes/ExportNode.js +48 -2
- package/dist/core/nodes/ExpressionNode.d.ts +97 -0
- package/dist/core/nodes/ExpressionNode.d.ts.map +1 -0
- package/dist/core/nodes/ExpressionNode.js +178 -0
- package/dist/core/nodes/ExternalModuleNode.d.ts +28 -0
- package/dist/core/nodes/ExternalModuleNode.d.ts.map +1 -0
- package/dist/core/nodes/ExternalModuleNode.js +41 -0
- package/dist/core/nodes/ExternalStdioNode.d.ts +13 -6
- package/dist/core/nodes/ExternalStdioNode.d.ts.map +1 -1
- package/dist/core/nodes/ExternalStdioNode.js +15 -8
- package/dist/core/nodes/FunctionNode.d.ts +36 -0
- package/dist/core/nodes/FunctionNode.d.ts.map +1 -1
- package/dist/core/nodes/FunctionNode.js +80 -1
- package/dist/core/nodes/ImportNode.d.ts +19 -5
- package/dist/core/nodes/ImportNode.d.ts.map +1 -1
- package/dist/core/nodes/ImportNode.js +23 -5
- package/dist/core/nodes/InterfaceNode.d.ts +46 -0
- package/dist/core/nodes/InterfaceNode.d.ts.map +1 -0
- package/dist/core/nodes/InterfaceNode.js +55 -0
- package/dist/core/nodes/IssueNode.d.ts +73 -0
- package/dist/core/nodes/IssueNode.d.ts.map +1 -0
- package/dist/core/nodes/IssueNode.js +129 -0
- package/dist/core/nodes/MethodCallNode.d.ts +30 -0
- package/dist/core/nodes/MethodCallNode.d.ts.map +1 -1
- package/dist/core/nodes/MethodCallNode.js +49 -0
- package/dist/core/nodes/MethodNode.d.ts +32 -0
- package/dist/core/nodes/MethodNode.d.ts.map +1 -1
- package/dist/core/nodes/MethodNode.js +48 -0
- package/dist/core/nodes/ModuleNode.d.ts +31 -0
- package/dist/core/nodes/ModuleNode.d.ts.map +1 -1
- package/dist/core/nodes/ModuleNode.js +37 -0
- package/dist/core/nodes/NetworkRequestNode.d.ts +54 -0
- package/dist/core/nodes/NetworkRequestNode.d.ts.map +1 -0
- package/dist/core/nodes/NetworkRequestNode.js +65 -0
- package/dist/core/nodes/ObjectLiteralNode.d.ts +27 -0
- package/dist/core/nodes/ObjectLiteralNode.d.ts.map +1 -0
- package/dist/core/nodes/ObjectLiteralNode.js +41 -0
- package/dist/core/nodes/ScopeNode.d.ts +31 -0
- package/dist/core/nodes/ScopeNode.d.ts.map +1 -1
- package/dist/core/nodes/ScopeNode.js +49 -0
- package/dist/core/nodes/TypeNode.d.ts +36 -0
- package/dist/core/nodes/TypeNode.d.ts.map +1 -0
- package/dist/core/nodes/TypeNode.js +53 -0
- package/dist/core/nodes/VariableDeclarationNode.d.ts +27 -0
- package/dist/core/nodes/VariableDeclarationNode.d.ts.map +1 -1
- package/dist/core/nodes/VariableDeclarationNode.js +40 -0
- package/dist/core/nodes/index.d.ts +12 -1
- package/dist/core/nodes/index.d.ts.map +1 -1
- package/dist/core/nodes/index.js +14 -0
- package/dist/diagnostics/DiagnosticCollector.d.ts +98 -0
- package/dist/diagnostics/DiagnosticCollector.d.ts.map +1 -0
- package/dist/diagnostics/DiagnosticCollector.js +129 -0
- package/dist/diagnostics/DiagnosticReporter.d.ts +77 -0
- package/dist/diagnostics/DiagnosticReporter.d.ts.map +1 -0
- package/dist/diagnostics/DiagnosticReporter.js +159 -0
- package/dist/diagnostics/DiagnosticWriter.d.ts +31 -0
- package/dist/diagnostics/DiagnosticWriter.d.ts.map +1 -0
- package/dist/diagnostics/DiagnosticWriter.js +43 -0
- package/dist/diagnostics/index.d.ts +14 -0
- package/dist/diagnostics/index.d.ts.map +1 -0
- package/dist/diagnostics/index.js +11 -0
- package/dist/errors/GrafemaError.d.ts +118 -0
- package/dist/errors/GrafemaError.d.ts.map +1 -0
- package/dist/errors/GrafemaError.js +131 -0
- package/dist/index.d.ts +57 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +54 -1
- package/dist/logging/Logger.d.ts +48 -0
- package/dist/logging/Logger.d.ts.map +1 -0
- package/dist/logging/Logger.js +134 -0
- package/dist/plugins/Plugin.d.ts +5 -1
- package/dist/plugins/Plugin.d.ts.map +1 -1
- package/dist/plugins/Plugin.js +33 -0
- package/dist/plugins/analysis/DatabaseAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/DatabaseAnalyzer.js +13 -6
- package/dist/plugins/analysis/ExpressAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/ExpressAnalyzer.js +27 -19
- package/dist/plugins/analysis/ExpressRouteAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/ExpressRouteAnalyzer.js +21 -14
- package/dist/plugins/analysis/FetchAnalyzer.d.ts +1 -0
- package/dist/plugins/analysis/FetchAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/FetchAnalyzer.js +34 -14
- package/dist/plugins/analysis/IncrementalAnalysisPlugin.d.ts +6 -3
- package/dist/plugins/analysis/IncrementalAnalysisPlugin.d.ts.map +1 -1
- package/dist/plugins/analysis/IncrementalAnalysisPlugin.js +76 -80
- package/dist/plugins/analysis/JSASTAnalyzer.d.ts +180 -17
- package/dist/plugins/analysis/JSASTAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/JSASTAnalyzer.js +1171 -471
- package/dist/plugins/analysis/ReactAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/ReactAnalyzer.js +56 -57
- package/dist/plugins/analysis/RustAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/RustAnalyzer.js +15 -10
- package/dist/plugins/analysis/SQLiteAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/SQLiteAnalyzer.js +9 -7
- package/dist/plugins/analysis/ServiceLayerAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/ServiceLayerAnalyzer.js +21 -9
- package/dist/plugins/analysis/SocketIOAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/SocketIOAnalyzer.js +27 -15
- package/dist/plugins/analysis/SystemDbAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/SystemDbAnalyzer.js +15 -5
- package/dist/plugins/analysis/ast/GraphBuilder.d.ts +34 -4
- package/dist/plugins/analysis/ast/GraphBuilder.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/GraphBuilder.js +318 -298
- package/dist/plugins/analysis/ast/IdGenerator.d.ts +105 -0
- package/dist/plugins/analysis/ast/IdGenerator.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/IdGenerator.js +116 -0
- package/dist/plugins/analysis/ast/types.d.ts +176 -5
- package/dist/plugins/analysis/ast/types.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/utils/createParameterNodes.d.ts +33 -0
- package/dist/plugins/analysis/ast/utils/createParameterNodes.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/utils/createParameterNodes.js +89 -0
- package/dist/plugins/analysis/ast/utils/index.d.ts +6 -0
- package/dist/plugins/analysis/ast/utils/index.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/utils/index.js +5 -0
- package/dist/plugins/analysis/ast/utils/location.d.ts +87 -0
- package/dist/plugins/analysis/ast/utils/location.d.ts.map +1 -0
- package/dist/plugins/analysis/ast/utils/location.js +78 -0
- package/dist/plugins/analysis/ast/visitors/ASTVisitor.d.ts +9 -4
- package/dist/plugins/analysis/ast/visitors/ASTVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/ASTVisitor.js +6 -5
- package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts +99 -9
- package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.js +663 -125
- package/dist/plugins/analysis/ast/visitors/ClassVisitor.d.ts +4 -1
- package/dist/plugins/analysis/ast/visitors/ClassVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/ClassVisitor.js +72 -32
- package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts +4 -1
- package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/FunctionVisitor.js +128 -63
- package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.js +11 -8
- package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.d.ts +12 -1
- package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.js +36 -14
- package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts +4 -1
- package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/VariableVisitor.js +17 -13
- package/dist/plugins/discovery/MonorepoServiceDiscovery.d.ts.map +1 -1
- package/dist/plugins/discovery/MonorepoServiceDiscovery.js +3 -2
- package/dist/plugins/discovery/SimpleProjectDiscovery.d.ts.map +1 -1
- package/dist/plugins/discovery/SimpleProjectDiscovery.js +5 -1
- package/dist/plugins/discovery/WorkspaceDiscovery.d.ts +22 -0
- package/dist/plugins/discovery/WorkspaceDiscovery.d.ts.map +1 -0
- package/dist/plugins/discovery/WorkspaceDiscovery.js +136 -0
- package/dist/plugins/discovery/resolveSourceEntrypoint.d.ts +46 -0
- package/dist/plugins/discovery/resolveSourceEntrypoint.d.ts.map +1 -0
- package/dist/plugins/discovery/resolveSourceEntrypoint.js +86 -0
- package/dist/plugins/discovery/workspaces/detector.d.ts +21 -0
- package/dist/plugins/discovery/workspaces/detector.d.ts.map +1 -0
- package/dist/plugins/discovery/workspaces/detector.js +49 -0
- package/dist/plugins/discovery/workspaces/globResolver.d.ts +35 -0
- package/dist/plugins/discovery/workspaces/globResolver.d.ts.map +1 -0
- package/dist/plugins/discovery/workspaces/globResolver.js +184 -0
- package/dist/plugins/discovery/workspaces/index.d.ts +9 -0
- package/dist/plugins/discovery/workspaces/index.d.ts.map +1 -0
- package/dist/plugins/discovery/workspaces/index.js +8 -0
- package/dist/plugins/discovery/workspaces/parsers.d.ts +38 -0
- package/dist/plugins/discovery/workspaces/parsers.d.ts.map +1 -0
- package/dist/plugins/discovery/workspaces/parsers.js +80 -0
- package/dist/plugins/enrichment/AliasTracker.d.ts.map +1 -1
- package/dist/plugins/enrichment/AliasTracker.js +14 -8
- package/dist/plugins/enrichment/HTTPConnectionEnricher.d.ts.map +1 -1
- package/dist/plugins/enrichment/HTTPConnectionEnricher.js +14 -7
- package/dist/plugins/enrichment/ImportExportLinker.d.ts.map +1 -1
- package/dist/plugins/enrichment/ImportExportLinker.js +23 -6
- package/dist/plugins/enrichment/MethodCallResolver.d.ts.map +1 -1
- package/dist/plugins/enrichment/MethodCallResolver.js +18 -12
- package/dist/plugins/enrichment/MountPointResolver.d.ts.map +1 -1
- package/dist/plugins/enrichment/MountPointResolver.js +8 -3
- package/dist/plugins/enrichment/PrefixEvaluator.d.ts.map +1 -1
- package/dist/plugins/enrichment/PrefixEvaluator.js +16 -7
- package/dist/plugins/enrichment/RustFFIEnricher.d.ts.map +1 -1
- package/dist/plugins/enrichment/RustFFIEnricher.js +6 -5
- package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts +17 -0
- package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts.map +1 -1
- package/dist/plugins/enrichment/ValueDomainAnalyzer.js +129 -10
- package/dist/plugins/indexing/IncrementalModuleIndexer.d.ts.map +1 -1
- package/dist/plugins/indexing/IncrementalModuleIndexer.js +23 -14
- package/dist/plugins/indexing/JSModuleIndexer.d.ts.map +1 -1
- package/dist/plugins/indexing/JSModuleIndexer.js +63 -31
- package/dist/plugins/indexing/RustModuleIndexer.d.ts.map +1 -1
- package/dist/plugins/indexing/RustModuleIndexer.js +5 -4
- package/dist/plugins/indexing/ServiceDetector.d.ts +10 -0
- package/dist/plugins/indexing/ServiceDetector.d.ts.map +1 -1
- package/dist/plugins/indexing/ServiceDetector.js +28 -15
- package/dist/plugins/validation/CallResolverValidator.d.ts.map +1 -1
- package/dist/plugins/validation/CallResolverValidator.js +8 -7
- package/dist/plugins/validation/DataFlowValidator.d.ts.map +1 -1
- package/dist/plugins/validation/DataFlowValidator.js +17 -12
- package/dist/plugins/validation/EvalBanValidator.d.ts.map +1 -1
- package/dist/plugins/validation/EvalBanValidator.js +17 -16
- package/dist/plugins/validation/GraphConnectivityValidator.d.ts.map +1 -1
- package/dist/plugins/validation/GraphConnectivityValidator.js +19 -23
- package/dist/plugins/validation/NodeCreationValidator.d.ts +85 -0
- package/dist/plugins/validation/NodeCreationValidator.d.ts.map +1 -0
- package/dist/plugins/validation/NodeCreationValidator.js +415 -0
- package/dist/plugins/validation/SQLInjectionValidator.d.ts.map +1 -1
- package/dist/plugins/validation/SQLInjectionValidator.js +59 -16
- package/dist/plugins/validation/ShadowingDetector.d.ts.map +1 -1
- package/dist/plugins/validation/ShadowingDetector.js +6 -5
- package/dist/plugins/validation/TypeScriptDeadCodeValidator.d.ts.map +1 -1
- package/dist/plugins/validation/TypeScriptDeadCodeValidator.js +12 -11
- package/dist/plugins/vcs/GitPlugin.d.ts.map +1 -1
- package/dist/plugins/vcs/GitPlugin.js +10 -12
- package/dist/plugins/vcs/VCSPlugin.d.ts +3 -2
- package/dist/plugins/vcs/VCSPlugin.d.ts.map +1 -1
- package/dist/plugins/vcs/VCSPlugin.js +5 -5
- package/dist/storage/backends/RFDBServerBackend.d.ts +10 -17
- package/dist/storage/backends/RFDBServerBackend.d.ts.map +1 -1
- package/dist/storage/backends/RFDBServerBackend.js +31 -10
- package/dist/validation/PathValidator.d.ts +1 -2
- package/dist/validation/PathValidator.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/Orchestrator.ts +237 -24
- package/src/config/ConfigLoader.ts +263 -0
- package/src/config/index.ts +5 -0
- package/src/core/ASTWorker.ts +143 -139
- package/src/core/CoverageAnalyzer.ts +243 -0
- package/src/core/FileNodeManager.ts +100 -0
- package/src/core/GraphFreshnessChecker.ts +143 -0
- package/src/core/HashUtils.ts +48 -0
- package/src/core/IncrementalReanalyzer.ts +192 -0
- package/src/core/NodeFactory.ts +401 -18
- package/src/core/ScopeTracker.ts +154 -0
- package/src/core/SemanticId.ts +192 -0
- package/src/core/VersionManager.ts +3 -2
- package/src/core/nodes/ArgumentExpressionNode.ts +89 -0
- package/src/core/nodes/ArrayLiteralNode.ts +65 -0
- package/src/core/nodes/CallSiteNode.ts +58 -0
- package/src/core/nodes/ClassNode.ts +63 -2
- package/src/core/nodes/DecoratorNode.ts +91 -0
- package/src/core/nodes/EnumNode.ts +86 -0
- package/src/core/nodes/ExportNode.ts +70 -2
- package/src/core/nodes/ExpressionNode.ts +231 -0
- package/src/core/nodes/ExternalModuleNode.ts +56 -0
- package/src/core/nodes/ExternalStdioNode.ts +17 -9
- package/src/core/nodes/FunctionNode.ts +101 -1
- package/src/core/nodes/ImportNode.ts +32 -10
- package/src/core/nodes/InterfaceNode.ts +91 -0
- package/src/core/nodes/IssueNode.ts +177 -0
- package/src/core/nodes/MethodCallNode.ts +64 -0
- package/src/core/nodes/MethodNode.ts +63 -0
- package/src/core/nodes/ModuleNode.ts +50 -0
- package/src/core/nodes/NetworkRequestNode.ts +77 -0
- package/src/core/nodes/ObjectLiteralNode.ts +65 -0
- package/src/core/nodes/ScopeNode.ts +65 -0
- package/src/core/nodes/TypeNode.ts +78 -0
- package/src/core/nodes/VariableDeclarationNode.ts +52 -0
- package/src/core/nodes/index.ts +18 -1
- package/src/diagnostics/DiagnosticCollector.ts +163 -0
- package/src/diagnostics/DiagnosticReporter.ts +204 -0
- package/src/diagnostics/DiagnosticWriter.ts +50 -0
- package/src/diagnostics/index.ts +16 -0
- package/src/errors/GrafemaError.ts +174 -0
- package/src/index.ts +148 -1
- package/src/logging/Logger.ts +152 -0
- package/src/plugins/Plugin.ts +42 -0
- package/src/plugins/analysis/DatabaseAnalyzer.ts +14 -8
- package/src/plugins/analysis/ExpressAnalyzer.ts +29 -19
- package/src/plugins/analysis/ExpressRouteAnalyzer.ts +22 -21
- package/src/plugins/analysis/FetchAnalyzer.ts +39 -16
- package/src/plugins/analysis/IncrementalAnalysisPlugin.ts +84 -101
- package/src/plugins/analysis/JSASTAnalyzer.ts +1483 -503
- package/src/plugins/analysis/ReactAnalyzer.ts +57 -57
- package/src/plugins/analysis/RustAnalyzer.ts +15 -10
- package/src/plugins/analysis/SQLiteAnalyzer.ts +10 -7
- package/src/plugins/analysis/ServiceLayerAnalyzer.ts +22 -16
- package/src/plugins/analysis/SocketIOAnalyzer.ts +31 -22
- package/src/plugins/analysis/SystemDbAnalyzer.ts +16 -11
- package/src/plugins/analysis/ast/GraphBuilder.ts +439 -327
- package/src/plugins/analysis/ast/IdGenerator.ts +177 -0
- package/src/plugins/analysis/ast/types.ts +209 -6
- package/src/plugins/analysis/ast/utils/createParameterNodes.ts +104 -0
- package/src/plugins/analysis/ast/utils/index.ts +12 -0
- package/src/plugins/analysis/ast/utils/location.ts +103 -0
- package/src/plugins/analysis/ast/visitors/ASTVisitor.ts +11 -8
- package/src/plugins/analysis/ast/visitors/CallExpressionVisitor.ts +909 -83
- package/src/plugins/analysis/ast/visitors/ClassVisitor.ts +97 -44
- package/src/plugins/analysis/ast/visitors/FunctionVisitor.ts +159 -93
- package/src/plugins/analysis/ast/visitors/ImportExportVisitor.ts +12 -8
- package/src/plugins/analysis/ast/visitors/TypeScriptVisitor.ts +41 -14
- package/src/plugins/analysis/ast/visitors/VariableVisitor.ts +37 -17
- package/src/plugins/discovery/MonorepoServiceDiscovery.ts +3 -2
- package/src/plugins/discovery/SimpleProjectDiscovery.ts +6 -1
- package/src/plugins/discovery/WorkspaceDiscovery.ts +177 -0
- package/src/plugins/discovery/resolveSourceEntrypoint.ts +103 -0
- package/src/plugins/discovery/workspaces/detector.ts +63 -0
- package/src/plugins/discovery/workspaces/globResolver.ts +229 -0
- package/src/plugins/discovery/workspaces/index.ts +23 -0
- package/src/plugins/discovery/workspaces/parsers.ts +99 -0
- package/src/plugins/enrichment/AliasTracker.ts +14 -8
- package/src/plugins/enrichment/HTTPConnectionEnricher.ts +14 -7
- package/src/plugins/enrichment/ImportExportLinker.ts +24 -6
- package/src/plugins/enrichment/MethodCallResolver.ts +18 -12
- package/src/plugins/enrichment/MountPointResolver.ts +8 -3
- package/src/plugins/enrichment/PrefixEvaluator.ts +16 -7
- package/src/plugins/enrichment/RustFFIEnricher.ts +6 -5
- package/src/plugins/enrichment/ValueDomainAnalyzer.ts +149 -12
- package/src/plugins/indexing/IncrementalModuleIndexer.ts +23 -14
- package/src/plugins/indexing/JSModuleIndexer.ts +74 -34
- package/src/plugins/indexing/RustModuleIndexer.ts +5 -4
- package/src/plugins/validation/CallResolverValidator.ts +8 -7
- package/src/plugins/validation/DataFlowValidator.ts +16 -12
- package/src/plugins/validation/EvalBanValidator.ts +17 -16
- package/src/plugins/validation/GraphConnectivityValidator.ts +19 -23
- package/src/plugins/validation/NodeCreationValidator.ts +554 -0
- package/src/plugins/validation/SQLInjectionValidator.ts +61 -15
- package/src/plugins/validation/ShadowingDetector.ts +6 -5
- package/src/plugins/validation/TypeScriptDeadCodeValidator.ts +12 -11
- package/src/plugins/vcs/GitPlugin.ts +40 -12
- package/src/plugins/vcs/VCSPlugin.ts +7 -5
- package/src/storage/backends/RFDBServerBackend.ts +43 -29
- package/src/validation/PathValidator.ts +1 -1
- package/dist/core/AnalysisWorker.d.ts +0 -14
- package/dist/core/AnalysisWorker.d.ts.map +0 -1
- package/dist/core/AnalysisWorker.js +0 -307
- package/dist/core/ParallelAnalyzer.d.ts +0 -120
- package/dist/core/ParallelAnalyzer.d.ts.map +0 -1
- package/dist/core/ParallelAnalyzer.js +0 -331
- package/dist/core/QueueWorker.d.ts +0 -12
- package/dist/core/QueueWorker.d.ts.map +0 -1
- package/dist/core/QueueWorker.js +0 -567
- package/dist/core/RFDBClient.d.ts +0 -179
- package/dist/core/RFDBClient.d.ts.map +0 -1
- package/dist/core/RFDBClient.js +0 -429
- package/dist/plugins/discovery/ZonServiceDiscovery.d.ts +0 -19
- package/dist/plugins/discovery/ZonServiceDiscovery.d.ts.map +0 -1
- package/dist/plugins/discovery/ZonServiceDiscovery.js +0 -204
- package/src/core/AnalysisWorker.ts +0 -410
- package/src/core/ParallelAnalyzer.ts +0 -476
- package/src/core/QueueWorker.ts +0 -780
- package/src/plugins/indexing/ServiceDetector.ts +0 -230
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NodeCreationValidator - validates that nodes are created through NodeFactory
|
|
3
|
+
*
|
|
4
|
+
* GUARANTEE: All nodes passed to graph.addNode() or graph.addNodes() must be
|
|
5
|
+
* created through NodeFactory methods, not constructed inline.
|
|
6
|
+
*
|
|
7
|
+
* This validator uses the data flow tracking (HAS_PROPERTY, HAS_ELEMENT, FLOWS_INTO edges)
|
|
8
|
+
* to trace object literals back to their source and verify they come from
|
|
9
|
+
* NodeFactory calls.
|
|
10
|
+
*
|
|
11
|
+
* FLOWS_INTO traversal: When an array variable is passed to addNodes(), we check:
|
|
12
|
+
* 1. Static array contents via HAS_ELEMENT edges
|
|
13
|
+
* 2. Dynamic array contents via FLOWS_INTO edges (from push, unshift, splice, indexed assignment)
|
|
14
|
+
*
|
|
15
|
+
* DATALOG RULES (conceptual):
|
|
16
|
+
*
|
|
17
|
+
* % Find all calls to addNodes (batch)
|
|
18
|
+
* add_nodes_call(Call) :-
|
|
19
|
+
* node(Call, "CALL"),
|
|
20
|
+
* attr(Call, "name", "addNodes").
|
|
21
|
+
*
|
|
22
|
+
* % Find array argument passed to addNodes (arg 0)
|
|
23
|
+
* add_nodes_array(Call, Arr) :-
|
|
24
|
+
* add_nodes_call(Call),
|
|
25
|
+
* edge(Call, Arr, "PASSES_ARGUMENT"),
|
|
26
|
+
* node(Arr, "ARRAY_LITERAL").
|
|
27
|
+
*
|
|
28
|
+
* % Find objects inside the array (static elements)
|
|
29
|
+
* add_nodes_object(Call, Obj) :-
|
|
30
|
+
* add_nodes_array(Call, Arr),
|
|
31
|
+
* edge(Arr, Obj, "HAS_ELEMENT"),
|
|
32
|
+
* node(Obj, "OBJECT_LITERAL").
|
|
33
|
+
*
|
|
34
|
+
* % Find objects pushed/unshifted/spliced into array (dynamic elements)
|
|
35
|
+
* add_nodes_object(Call, Obj) :-
|
|
36
|
+
* add_nodes_call(Call),
|
|
37
|
+
* edge(Call, ArrVar, "PASSES_ARGUMENT"),
|
|
38
|
+
* node(ArrVar, "VARIABLE"),
|
|
39
|
+
* incoming(ArrVar, Obj, "FLOWS_INTO"), % value --FLOWS_INTO--> array
|
|
40
|
+
* node(Obj, "OBJECT_LITERAL").
|
|
41
|
+
*
|
|
42
|
+
* % Object created via NodeFactory
|
|
43
|
+
* from_node_factory(Obj) :-
|
|
44
|
+
* incoming(Obj, Creator, "ASSIGNED_FROM"),
|
|
45
|
+
* node(Creator, "CALL"),
|
|
46
|
+
* attr(Creator, "object", "NodeFactory").
|
|
47
|
+
*
|
|
48
|
+
* % Violation: object in addNodes not from NodeFactory
|
|
49
|
+
* violation_batch(Call, Obj) :-
|
|
50
|
+
* add_nodes_object(Call, Obj),
|
|
51
|
+
* \+ from_node_factory(Obj).
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
import { Plugin, createSuccessResult } from '../Plugin.js';
|
|
55
|
+
import type { PluginContext, PluginResult, PluginMetadata } from '../Plugin.js';
|
|
56
|
+
import type { BaseNodeRecord } from '@grafema/types';
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Edge structure for querying
|
|
60
|
+
*/
|
|
61
|
+
interface EdgeRecord {
|
|
62
|
+
type: string;
|
|
63
|
+
src: string;
|
|
64
|
+
dst: string;
|
|
65
|
+
metadata?: Record<string, unknown>;
|
|
66
|
+
[key: string]: unknown;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Extended node with call properties
|
|
71
|
+
*/
|
|
72
|
+
interface CallNode extends BaseNodeRecord {
|
|
73
|
+
method?: string;
|
|
74
|
+
object?: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Validation issue
|
|
79
|
+
*/
|
|
80
|
+
interface NodeCreationIssue {
|
|
81
|
+
type: 'INLINE_OBJECT_LITERAL' | 'INLINE_ARRAY_ELEMENT' | 'UNKNOWN_SOURCE';
|
|
82
|
+
severity: 'ERROR' | 'WARNING';
|
|
83
|
+
message: string;
|
|
84
|
+
callSiteId: string;
|
|
85
|
+
objectId?: string;
|
|
86
|
+
file?: string;
|
|
87
|
+
line?: number;
|
|
88
|
+
suggestion: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Validation summary
|
|
93
|
+
*/
|
|
94
|
+
interface ValidationSummary {
|
|
95
|
+
addNodeCalls: number;
|
|
96
|
+
addNodesCalls: number;
|
|
97
|
+
inlineObjects: number;
|
|
98
|
+
factoryObjects: number;
|
|
99
|
+
unknownObjects: number;
|
|
100
|
+
totalViolations: number;
|
|
101
|
+
timeSeconds: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export class NodeCreationValidator extends Plugin {
|
|
105
|
+
get metadata(): PluginMetadata {
|
|
106
|
+
return {
|
|
107
|
+
name: 'NodeCreationValidator',
|
|
108
|
+
phase: 'VALIDATION',
|
|
109
|
+
priority: 90, // Run after data flow analysis
|
|
110
|
+
creates: {
|
|
111
|
+
nodes: [],
|
|
112
|
+
edges: []
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async execute(context: PluginContext): Promise<PluginResult> {
|
|
118
|
+
const { graph } = context;
|
|
119
|
+
const logger = this.log(context);
|
|
120
|
+
|
|
121
|
+
logger.info('Starting NodeFactory usage validation');
|
|
122
|
+
const startTime = Date.now();
|
|
123
|
+
|
|
124
|
+
const issues: NodeCreationIssue[] = [];
|
|
125
|
+
let addNodeCalls = 0;
|
|
126
|
+
let addNodesCalls = 0;
|
|
127
|
+
let inlineObjects = 0;
|
|
128
|
+
let factoryObjects = 0;
|
|
129
|
+
let unknownObjects = 0;
|
|
130
|
+
|
|
131
|
+
// Check if graph supports required methods
|
|
132
|
+
if (!graph.getAllEdges || !graph.getAllNodes) {
|
|
133
|
+
logger.debug('Graph does not support getAllEdges/getAllNodes, skipping validation');
|
|
134
|
+
return createSuccessResult({ nodes: 0, edges: 0 }, { skipped: true });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const allNodes = await graph.getAllNodes();
|
|
138
|
+
const allEdges = await graph.getAllEdges() as EdgeRecord[];
|
|
139
|
+
|
|
140
|
+
// Build lookup maps for efficient queries
|
|
141
|
+
const nodesById = new Map<string, BaseNodeRecord>();
|
|
142
|
+
for (const node of allNodes) {
|
|
143
|
+
nodesById.set(node.id, node);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const edgesBySrc = new Map<string, EdgeRecord[]>();
|
|
147
|
+
const edgesByDst = new Map<string, EdgeRecord[]>();
|
|
148
|
+
for (const edge of allEdges) {
|
|
149
|
+
if (!edgesBySrc.has(edge.src)) edgesBySrc.set(edge.src, []);
|
|
150
|
+
edgesBySrc.get(edge.src)!.push(edge);
|
|
151
|
+
if (!edgesByDst.has(edge.dst)) edgesByDst.set(edge.dst, []);
|
|
152
|
+
edgesByDst.get(edge.dst)!.push(edge);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// 1. Find all calls to addNode and addNodes
|
|
156
|
+
logger.debug('Searching for addNode/addNodes calls');
|
|
157
|
+
|
|
158
|
+
for (const node of allNodes) {
|
|
159
|
+
if (node.type !== 'CALL') continue;
|
|
160
|
+
const callNode = node as CallNode;
|
|
161
|
+
|
|
162
|
+
// Check for addNode() method call
|
|
163
|
+
if (callNode.method === 'addNode' || callNode.name === 'addNode' ||
|
|
164
|
+
(callNode.name && callNode.name.endsWith('.addNode'))) {
|
|
165
|
+
addNodeCalls++;
|
|
166
|
+
const argIssues = await this.validateAddNodeCall(
|
|
167
|
+
callNode,
|
|
168
|
+
edgesBySrc,
|
|
169
|
+
edgesByDst,
|
|
170
|
+
nodesById
|
|
171
|
+
);
|
|
172
|
+
issues.push(...argIssues);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Check for addNodes() method call
|
|
176
|
+
if (callNode.method === 'addNodes' || callNode.name === 'addNodes' ||
|
|
177
|
+
(callNode.name && callNode.name.endsWith('.addNodes'))) {
|
|
178
|
+
addNodesCalls++;
|
|
179
|
+
const argIssues = await this.validateAddNodesCall(
|
|
180
|
+
callNode,
|
|
181
|
+
edgesBySrc,
|
|
182
|
+
edgesByDst,
|
|
183
|
+
nodesById
|
|
184
|
+
);
|
|
185
|
+
issues.push(...argIssues);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Count violation types
|
|
190
|
+
for (const issue of issues) {
|
|
191
|
+
if (issue.type === 'INLINE_OBJECT_LITERAL' || issue.type === 'INLINE_ARRAY_ELEMENT') {
|
|
192
|
+
inlineObjects++;
|
|
193
|
+
} else if (issue.type === 'UNKNOWN_SOURCE') {
|
|
194
|
+
unknownObjects++;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const totalTime = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
199
|
+
const summary: ValidationSummary = {
|
|
200
|
+
addNodeCalls,
|
|
201
|
+
addNodesCalls,
|
|
202
|
+
inlineObjects,
|
|
203
|
+
factoryObjects, // Would need positive tracking to count
|
|
204
|
+
unknownObjects,
|
|
205
|
+
totalViolations: issues.length,
|
|
206
|
+
timeSeconds: totalTime
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
logger.info('Validation complete', { ...summary });
|
|
210
|
+
|
|
211
|
+
if (issues.length > 0) {
|
|
212
|
+
logger.warn('NodeFactory violations found', { count: issues.length });
|
|
213
|
+
for (const issue of issues.slice(0, 10)) { // Limit output
|
|
214
|
+
logger.warn(`[${issue.type}] ${issue.message}`, { suggestion: issue.suggestion });
|
|
215
|
+
}
|
|
216
|
+
if (issues.length > 10) {
|
|
217
|
+
logger.debug(`... and ${issues.length - 10} more violations`);
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
logger.info('All nodes created through NodeFactory');
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return createSuccessResult(
|
|
224
|
+
{ nodes: 0, edges: 0 },
|
|
225
|
+
{ summary, issues }
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Validate a single addNode(node) call
|
|
231
|
+
*/
|
|
232
|
+
private async validateAddNodeCall(
|
|
233
|
+
callNode: CallNode,
|
|
234
|
+
edgesBySrc: Map<string, EdgeRecord[]>,
|
|
235
|
+
edgesByDst: Map<string, EdgeRecord[]>,
|
|
236
|
+
nodesById: Map<string, BaseNodeRecord>
|
|
237
|
+
): Promise<NodeCreationIssue[]> {
|
|
238
|
+
const issues: NodeCreationIssue[] = [];
|
|
239
|
+
|
|
240
|
+
// Find PASSES_ARGUMENT edge (arg 0)
|
|
241
|
+
const passedArgs = edgesBySrc.get(callNode.id)?.filter(e =>
|
|
242
|
+
e.type === 'PASSES_ARGUMENT'
|
|
243
|
+
) || [];
|
|
244
|
+
|
|
245
|
+
for (const argEdge of passedArgs) {
|
|
246
|
+
const argNode = nodesById.get(argEdge.dst);
|
|
247
|
+
if (!argNode) continue;
|
|
248
|
+
|
|
249
|
+
// Check if it's an inline object literal
|
|
250
|
+
if (argNode.type === 'OBJECT_LITERAL') {
|
|
251
|
+
const isFromFactory = this.isFromNodeFactory(argNode.id, edgesByDst, nodesById);
|
|
252
|
+
if (!isFromFactory) {
|
|
253
|
+
issues.push({
|
|
254
|
+
type: 'INLINE_OBJECT_LITERAL',
|
|
255
|
+
severity: 'ERROR',
|
|
256
|
+
message: `Inline object literal passed to addNode() at ${callNode.file}:${callNode.line}`,
|
|
257
|
+
callSiteId: callNode.id,
|
|
258
|
+
objectId: argNode.id,
|
|
259
|
+
file: callNode.file,
|
|
260
|
+
line: callNode.line as number | undefined,
|
|
261
|
+
suggestion: 'Use NodeFactory.createX() to create the node instead of an inline object'
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Check if it's a variable - trace its origin
|
|
267
|
+
if (argNode.type === 'VARIABLE' || argNode.type === 'VARIABLE_DECLARATION') {
|
|
268
|
+
const source = this.traceVariableSource(argNode.id, edgesBySrc, nodesById);
|
|
269
|
+
if (source && source.type === 'OBJECT_LITERAL') {
|
|
270
|
+
const isFromFactory = this.isFromNodeFactory(source.id, edgesByDst, nodesById);
|
|
271
|
+
if (!isFromFactory) {
|
|
272
|
+
issues.push({
|
|
273
|
+
type: 'INLINE_OBJECT_LITERAL',
|
|
274
|
+
severity: 'ERROR',
|
|
275
|
+
message: `Variable "${argNode.name}" assigned from inline object literal, passed to addNode() at ${callNode.file}:${callNode.line}`,
|
|
276
|
+
callSiteId: callNode.id,
|
|
277
|
+
objectId: source.id,
|
|
278
|
+
file: callNode.file,
|
|
279
|
+
line: callNode.line as number | undefined,
|
|
280
|
+
suggestion: 'Use NodeFactory.createX() to create the node instead of an inline object'
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return issues;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Validate addNodes([...]) call
|
|
292
|
+
* Also checks for objects that flow into arrays via FLOWS_INTO edges
|
|
293
|
+
*/
|
|
294
|
+
private async validateAddNodesCall(
|
|
295
|
+
callNode: CallNode,
|
|
296
|
+
edgesBySrc: Map<string, EdgeRecord[]>,
|
|
297
|
+
edgesByDst: Map<string, EdgeRecord[]>,
|
|
298
|
+
nodesById: Map<string, BaseNodeRecord>
|
|
299
|
+
): Promise<NodeCreationIssue[]> {
|
|
300
|
+
const issues: NodeCreationIssue[] = [];
|
|
301
|
+
|
|
302
|
+
// Find PASSES_ARGUMENT edge (arg 0 - the array)
|
|
303
|
+
const passedArgs = edgesBySrc.get(callNode.id)?.filter(e =>
|
|
304
|
+
e.type === 'PASSES_ARGUMENT'
|
|
305
|
+
) || [];
|
|
306
|
+
|
|
307
|
+
for (const argEdge of passedArgs) {
|
|
308
|
+
const argNode = nodesById.get(argEdge.dst);
|
|
309
|
+
if (!argNode) continue;
|
|
310
|
+
|
|
311
|
+
// Check if it's an array literal
|
|
312
|
+
if (argNode.type === 'ARRAY_LITERAL') {
|
|
313
|
+
// Find all HAS_ELEMENT edges
|
|
314
|
+
const elements = edgesBySrc.get(argNode.id)?.filter(e =>
|
|
315
|
+
e.type === 'HAS_ELEMENT'
|
|
316
|
+
) || [];
|
|
317
|
+
|
|
318
|
+
for (const elemEdge of elements) {
|
|
319
|
+
const elemNode = nodesById.get(elemEdge.dst);
|
|
320
|
+
if (!elemNode) continue;
|
|
321
|
+
|
|
322
|
+
// Check if element is an inline object literal
|
|
323
|
+
if (elemNode.type === 'OBJECT_LITERAL') {
|
|
324
|
+
const isFromFactory = this.isFromNodeFactory(elemNode.id, edgesByDst, nodesById);
|
|
325
|
+
if (!isFromFactory) {
|
|
326
|
+
const elemIndex = elemEdge.metadata?.elementIndex ?? '?';
|
|
327
|
+
issues.push({
|
|
328
|
+
type: 'INLINE_ARRAY_ELEMENT',
|
|
329
|
+
severity: 'ERROR',
|
|
330
|
+
message: `Inline object literal at index ${elemIndex} in addNodes() array at ${callNode.file}:${callNode.line}`,
|
|
331
|
+
callSiteId: callNode.id,
|
|
332
|
+
objectId: elemNode.id,
|
|
333
|
+
file: callNode.file,
|
|
334
|
+
line: callNode.line as number | undefined,
|
|
335
|
+
suggestion: 'Use NodeFactory.createX() to create each node in the array'
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Check if element is a variable - trace its origin
|
|
341
|
+
if (elemNode.type === 'VARIABLE' || elemNode.type === 'VARIABLE_DECLARATION') {
|
|
342
|
+
const source = this.traceVariableSource(elemNode.id, edgesBySrc, nodesById);
|
|
343
|
+
if (source && source.type === 'OBJECT_LITERAL') {
|
|
344
|
+
const isFromFactory = this.isFromNodeFactory(source.id, edgesByDst, nodesById);
|
|
345
|
+
if (!isFromFactory) {
|
|
346
|
+
const elemIndex = elemEdge.metadata?.elementIndex ?? '?';
|
|
347
|
+
issues.push({
|
|
348
|
+
type: 'INLINE_ARRAY_ELEMENT',
|
|
349
|
+
severity: 'ERROR',
|
|
350
|
+
message: `Variable "${elemNode.name}" at index ${elemIndex} assigned from inline object, passed to addNodes() at ${callNode.file}:${callNode.line}`,
|
|
351
|
+
callSiteId: callNode.id,
|
|
352
|
+
objectId: source.id,
|
|
353
|
+
file: callNode.file,
|
|
354
|
+
line: callNode.line as number | undefined,
|
|
355
|
+
suggestion: 'Use NodeFactory.createX() to create the node'
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Check if it's a variable containing an array
|
|
364
|
+
if (argNode.type === 'VARIABLE' || argNode.type === 'VARIABLE_DECLARATION') {
|
|
365
|
+
// Check what flows INTO this variable (array mutations via push/unshift/splice/indexed)
|
|
366
|
+
const incomingFlows = this.getArrayContents(argNode.id, edgesByDst, nodesById);
|
|
367
|
+
|
|
368
|
+
for (const sourceNode of incomingFlows) {
|
|
369
|
+
// Check if the pushed value is an object literal
|
|
370
|
+
if (sourceNode.type === 'OBJECT_LITERAL') {
|
|
371
|
+
const isFromFactory = this.isFromNodeFactory(sourceNode.id, edgesByDst, nodesById);
|
|
372
|
+
if (!isFromFactory) {
|
|
373
|
+
issues.push({
|
|
374
|
+
type: 'INLINE_ARRAY_ELEMENT',
|
|
375
|
+
severity: 'ERROR',
|
|
376
|
+
message: `Object pushed into array "${argNode.name}" is not from NodeFactory, passed to addNodes() at ${callNode.file}:${callNode.line}`,
|
|
377
|
+
callSiteId: callNode.id,
|
|
378
|
+
objectId: sourceNode.id,
|
|
379
|
+
file: callNode.file,
|
|
380
|
+
line: callNode.line as number | undefined,
|
|
381
|
+
suggestion: 'Use NodeFactory.createX() to create nodes before pushing to array'
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Also trace if the pushed value is a variable
|
|
387
|
+
if (sourceNode.type === 'VARIABLE' || sourceNode.type === 'VARIABLE_DECLARATION') {
|
|
388
|
+
const source = this.traceVariableSource(sourceNode.id, edgesBySrc, nodesById);
|
|
389
|
+
if (source && source.type === 'OBJECT_LITERAL') {
|
|
390
|
+
const isFromFactory = this.isFromNodeFactory(source.id, edgesByDst, nodesById);
|
|
391
|
+
if (!isFromFactory) {
|
|
392
|
+
issues.push({
|
|
393
|
+
type: 'INLINE_ARRAY_ELEMENT',
|
|
394
|
+
severity: 'ERROR',
|
|
395
|
+
message: `Variable "${sourceNode.name}" pushed into array "${argNode.name}" is not from NodeFactory, passed to addNodes() at ${callNode.file}:${callNode.line}`,
|
|
396
|
+
callSiteId: callNode.id,
|
|
397
|
+
objectId: source.id,
|
|
398
|
+
file: callNode.file,
|
|
399
|
+
line: callNode.line as number | undefined,
|
|
400
|
+
suggestion: 'Use NodeFactory.createX() to create the node'
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Also check static array contents (HAS_ELEMENT) - existing logic
|
|
408
|
+
const source = this.traceVariableSource(argNode.id, edgesBySrc, nodesById);
|
|
409
|
+
if (source && source.type === 'ARRAY_LITERAL') {
|
|
410
|
+
// Recursively check array elements
|
|
411
|
+
const elements = edgesBySrc.get(source.id)?.filter(e =>
|
|
412
|
+
e.type === 'HAS_ELEMENT'
|
|
413
|
+
) || [];
|
|
414
|
+
|
|
415
|
+
for (const elemEdge of elements) {
|
|
416
|
+
const elemNode = nodesById.get(elemEdge.dst);
|
|
417
|
+
if (!elemNode) continue;
|
|
418
|
+
|
|
419
|
+
if (elemNode.type === 'OBJECT_LITERAL') {
|
|
420
|
+
const isFromFactory = this.isFromNodeFactory(elemNode.id, edgesByDst, nodesById);
|
|
421
|
+
if (!isFromFactory) {
|
|
422
|
+
const elemIndex = elemEdge.metadata?.elementIndex ?? '?';
|
|
423
|
+
issues.push({
|
|
424
|
+
type: 'INLINE_ARRAY_ELEMENT',
|
|
425
|
+
severity: 'ERROR',
|
|
426
|
+
message: `Inline object at index ${elemIndex} in array "${argNode.name}" passed to addNodes() at ${callNode.file}:${callNode.line}`,
|
|
427
|
+
callSiteId: callNode.id,
|
|
428
|
+
objectId: elemNode.id,
|
|
429
|
+
file: callNode.file,
|
|
430
|
+
line: callNode.line as number | undefined,
|
|
431
|
+
suggestion: 'Use NodeFactory.createX() to create each node in the array'
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
return issues;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Get all nodes that flow INTO an array variable via FLOWS_INTO edges
|
|
445
|
+
* These are objects/values that were pushed, unshifted, spliced, or assigned to the array
|
|
446
|
+
*
|
|
447
|
+
* Edge direction: value --FLOWS_INTO--> array
|
|
448
|
+
* So we look for INCOMING edges where dst === arrayNodeId
|
|
449
|
+
*/
|
|
450
|
+
private getArrayContents(
|
|
451
|
+
arrayNodeId: string,
|
|
452
|
+
edgesByDst: Map<string, EdgeRecord[]>,
|
|
453
|
+
nodesById: Map<string, BaseNodeRecord>
|
|
454
|
+
): BaseNodeRecord[] {
|
|
455
|
+
const contents: BaseNodeRecord[] = [];
|
|
456
|
+
|
|
457
|
+
// Find INCOMING FLOWS_INTO edges to this array
|
|
458
|
+
const incomingFlows = edgesByDst.get(arrayNodeId)?.filter(e =>
|
|
459
|
+
e.type === 'FLOWS_INTO'
|
|
460
|
+
) || [];
|
|
461
|
+
|
|
462
|
+
for (const edge of incomingFlows) {
|
|
463
|
+
const sourceNode = nodesById.get(edge.src);
|
|
464
|
+
if (sourceNode) {
|
|
465
|
+
contents.push(sourceNode);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return contents;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Check if a node is created from NodeFactory
|
|
474
|
+
* Traces ASSIGNED_FROM edges to find the source call
|
|
475
|
+
*/
|
|
476
|
+
private isFromNodeFactory(
|
|
477
|
+
nodeId: string,
|
|
478
|
+
edgesByDst: Map<string, EdgeRecord[]>,
|
|
479
|
+
nodesById: Map<string, BaseNodeRecord>,
|
|
480
|
+
visited: Set<string> = new Set()
|
|
481
|
+
): boolean {
|
|
482
|
+
if (visited.has(nodeId)) return false;
|
|
483
|
+
visited.add(nodeId);
|
|
484
|
+
|
|
485
|
+
// Find incoming ASSIGNED_FROM edges
|
|
486
|
+
const incomingEdges = edgesByDst.get(nodeId)?.filter(e =>
|
|
487
|
+
e.type === 'ASSIGNED_FROM'
|
|
488
|
+
) || [];
|
|
489
|
+
|
|
490
|
+
for (const edge of incomingEdges) {
|
|
491
|
+
const sourceNode = nodesById.get(edge.src);
|
|
492
|
+
if (!sourceNode) continue;
|
|
493
|
+
|
|
494
|
+
// Check if source is a CALL to NodeFactory
|
|
495
|
+
if (sourceNode.type === 'CALL') {
|
|
496
|
+
const callNode = sourceNode as CallNode;
|
|
497
|
+
// Check various ways NodeFactory calls can appear
|
|
498
|
+
if (callNode.object === 'NodeFactory' ||
|
|
499
|
+
callNode.name?.startsWith('NodeFactory.') ||
|
|
500
|
+
callNode.name === 'NodeFactory') {
|
|
501
|
+
return true;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Continue tracing through variables
|
|
506
|
+
if (sourceNode.type === 'VARIABLE' || sourceNode.type === 'VARIABLE_DECLARATION') {
|
|
507
|
+
if (this.isFromNodeFactory(sourceNode.id, edgesByDst, nodesById, visited)) {
|
|
508
|
+
return true;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Trace a variable back to its source node (through ASSIGNED_FROM edges)
|
|
518
|
+
*/
|
|
519
|
+
private traceVariableSource(
|
|
520
|
+
nodeId: string,
|
|
521
|
+
edgesBySrc: Map<string, EdgeRecord[]>,
|
|
522
|
+
nodesById: Map<string, BaseNodeRecord>,
|
|
523
|
+
visited: Set<string> = new Set()
|
|
524
|
+
): BaseNodeRecord | null {
|
|
525
|
+
if (visited.has(nodeId)) return null;
|
|
526
|
+
visited.add(nodeId);
|
|
527
|
+
|
|
528
|
+
// Find outgoing ASSIGNED_FROM edges (variable -> source)
|
|
529
|
+
const outgoingEdges = edgesBySrc.get(nodeId)?.filter(e =>
|
|
530
|
+
e.type === 'ASSIGNED_FROM'
|
|
531
|
+
) || [];
|
|
532
|
+
|
|
533
|
+
for (const edge of outgoingEdges) {
|
|
534
|
+
const targetNode = nodesById.get(edge.dst);
|
|
535
|
+
if (!targetNode) continue;
|
|
536
|
+
|
|
537
|
+
// If target is a literal/call/object, return it
|
|
538
|
+
if (targetNode.type === 'OBJECT_LITERAL' ||
|
|
539
|
+
targetNode.type === 'ARRAY_LITERAL' ||
|
|
540
|
+
targetNode.type === 'CALL' ||
|
|
541
|
+
targetNode.type === 'LITERAL') {
|
|
542
|
+
return targetNode;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Continue tracing through variables
|
|
546
|
+
if (targetNode.type === 'VARIABLE' || targetNode.type === 'VARIABLE_DECLARATION') {
|
|
547
|
+
const source = this.traceVariableSource(targetNode.id, edgesBySrc, nodesById, visited);
|
|
548
|
+
if (source) return source;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
}
|