@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
|
@@ -9,9 +9,22 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { ASTVisitor } from './ASTVisitor.js';
|
|
11
11
|
import { ExpressionEvaluator } from '../ExpressionEvaluator.js';
|
|
12
|
+
import { computeSemanticId } from '../../../../core/SemanticId.js';
|
|
13
|
+
import { IdGenerator } from '../IdGenerator.js';
|
|
14
|
+
import { NodeFactory } from '../../../../core/NodeFactory.js';
|
|
15
|
+
import { ObjectLiteralNode } from '../../../../core/nodes/ObjectLiteralNode.js';
|
|
16
|
+
import { ArrayLiteralNode } from '../../../../core/nodes/ArrayLiteralNode.js';
|
|
17
|
+
import { getLine, getColumn } from '../utils/location.js';
|
|
12
18
|
export class CallExpressionVisitor extends ASTVisitor {
|
|
13
|
-
|
|
19
|
+
scopeTracker;
|
|
20
|
+
/**
|
|
21
|
+
* @param module - Current module being analyzed
|
|
22
|
+
* @param collections - Must contain arrays and counter refs
|
|
23
|
+
* @param scopeTracker - Optional ScopeTracker for semantic ID generation
|
|
24
|
+
*/
|
|
25
|
+
constructor(module, collections, scopeTracker) {
|
|
14
26
|
super(module, collections);
|
|
27
|
+
this.scopeTracker = scopeTracker;
|
|
15
28
|
}
|
|
16
29
|
/**
|
|
17
30
|
* Extract argument information for PASSES_ARGUMENT edges
|
|
@@ -31,104 +44,157 @@ export class CallExpressionVisitor extends ASTVisitor {
|
|
|
31
44
|
argInfo.isSpread = true;
|
|
32
45
|
actualArg = arg.argument; // Get the actual argument
|
|
33
46
|
}
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
argInfo.
|
|
50
|
-
argInfo.targetId = literalId;
|
|
51
|
-
argInfo.literalValue = literalValue;
|
|
52
|
-
}
|
|
53
|
-
// Variable reference
|
|
54
|
-
else if (actualArg.type === 'Identifier') {
|
|
55
|
-
argInfo.targetType = 'VARIABLE';
|
|
56
|
-
argInfo.targetName = actualArg.name; // Will be resolved in GraphBuilder
|
|
57
|
-
}
|
|
58
|
-
// Function expression (callback)
|
|
59
|
-
else if (actualArg.type === 'ArrowFunctionExpression' || actualArg.type === 'FunctionExpression') {
|
|
60
|
-
argInfo.targetType = 'FUNCTION';
|
|
61
|
-
argInfo.functionLine = actualArg.loc?.start.line;
|
|
62
|
-
argInfo.functionColumn = actualArg.loc?.start.column;
|
|
63
|
-
}
|
|
64
|
-
// Call expression (nested call)
|
|
65
|
-
else if (actualArg.type === 'CallExpression') {
|
|
66
|
-
argInfo.targetType = 'CALL';
|
|
67
|
-
// Nested calls will be processed separately, link by position
|
|
68
|
-
argInfo.nestedCallLine = actualArg.loc?.start.line;
|
|
69
|
-
argInfo.nestedCallColumn = actualArg.loc?.start.column;
|
|
70
|
-
}
|
|
71
|
-
// Member expression: obj.prop or obj[x]
|
|
72
|
-
else if (actualArg.type === 'MemberExpression') {
|
|
73
|
-
const memberExpr = actualArg;
|
|
74
|
-
argInfo.targetType = 'EXPRESSION';
|
|
75
|
-
argInfo.expressionType = 'MemberExpression';
|
|
76
|
-
if (memberExpr.object.type === 'Identifier') {
|
|
77
|
-
argInfo.objectName = memberExpr.object.name;
|
|
78
|
-
}
|
|
79
|
-
if (!memberExpr.computed && memberExpr.property.type === 'Identifier') {
|
|
80
|
-
argInfo.propertyName = memberExpr.property.name;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
// Binary/Logical expression: a + b, a && b
|
|
84
|
-
else if (actualArg.type === 'BinaryExpression' || actualArg.type === 'LogicalExpression') {
|
|
85
|
-
const expr = actualArg;
|
|
86
|
-
const operator = expr.operator || '?';
|
|
87
|
-
const exprName = `<${actualArg.type}:${operator}>`;
|
|
88
|
-
const expressionId = `EXPRESSION#${exprName}#${module.file}#${argInfo.line}:${argInfo.column}:${literalCounterRef.value++}`;
|
|
89
|
-
// Create EXPRESSION node
|
|
90
|
-
literals.push({
|
|
91
|
-
id: expressionId,
|
|
92
|
-
type: 'EXPRESSION',
|
|
93
|
-
expressionType: actualArg.type,
|
|
94
|
-
operator: operator,
|
|
95
|
-
name: exprName,
|
|
96
|
-
file: module.file,
|
|
97
|
-
line: argInfo.line,
|
|
98
|
-
column: argInfo.column,
|
|
47
|
+
// Object literal - check BEFORE extractLiteralValue to handle object-typed args properly
|
|
48
|
+
if (actualArg.type === 'ObjectExpression') {
|
|
49
|
+
const objectExpr = actualArg;
|
|
50
|
+
// Initialize collections if not exist (must assign back to this.collections!)
|
|
51
|
+
if (!this.collections.objectLiteralCounterRef) {
|
|
52
|
+
this.collections.objectLiteralCounterRef = { value: 0 };
|
|
53
|
+
}
|
|
54
|
+
if (!this.collections.objectLiterals) {
|
|
55
|
+
this.collections.objectLiterals = [];
|
|
56
|
+
}
|
|
57
|
+
if (!this.collections.objectProperties) {
|
|
58
|
+
this.collections.objectProperties = [];
|
|
59
|
+
}
|
|
60
|
+
const objectLiteralCounterRef = this.collections.objectLiteralCounterRef;
|
|
61
|
+
// Use factory to create OBJECT_LITERAL node
|
|
62
|
+
const objectNode = ObjectLiteralNode.create(module.file, argInfo.line, argInfo.column, {
|
|
99
63
|
parentCallId: callId,
|
|
100
|
-
argIndex: index
|
|
64
|
+
argIndex: index,
|
|
65
|
+
counter: objectLiteralCounterRef.value++
|
|
101
66
|
});
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
const { variableAssignments } = this.collections;
|
|
108
|
-
if (variableAssignments) {
|
|
109
|
-
for (const identName of identifiers) {
|
|
110
|
-
variableAssignments.push({
|
|
111
|
-
variableId: expressionId,
|
|
112
|
-
sourceId: null,
|
|
113
|
-
sourceName: identName,
|
|
114
|
-
sourceType: 'DERIVES_FROM_VARIABLE',
|
|
115
|
-
file: module.file
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
// Object literal
|
|
121
|
-
else if (actualArg.type === 'ObjectExpression') {
|
|
67
|
+
// Factory guarantees line is set, cast to ObjectLiteralInfo
|
|
68
|
+
this.collections.objectLiterals.push(objectNode);
|
|
69
|
+
const objectId = objectNode.id;
|
|
70
|
+
// Extract properties
|
|
71
|
+
this.extractObjectProperties(objectExpr, objectId, module, this.collections.objectProperties, this.collections.objectLiterals, objectLiteralCounterRef, literals, literalCounterRef);
|
|
122
72
|
argInfo.targetType = 'OBJECT_LITERAL';
|
|
73
|
+
argInfo.targetId = objectId;
|
|
123
74
|
}
|
|
124
|
-
// Array literal
|
|
75
|
+
// Array literal - check BEFORE extractLiteralValue to handle array-typed args properly
|
|
125
76
|
else if (actualArg.type === 'ArrayExpression') {
|
|
77
|
+
const arrayExpr = actualArg;
|
|
78
|
+
// Initialize collections if not exist (must assign back to this.collections!)
|
|
79
|
+
if (!this.collections.arrayLiteralCounterRef) {
|
|
80
|
+
this.collections.arrayLiteralCounterRef = { value: 0 };
|
|
81
|
+
}
|
|
82
|
+
if (!this.collections.arrayLiterals) {
|
|
83
|
+
this.collections.arrayLiterals = [];
|
|
84
|
+
}
|
|
85
|
+
if (!this.collections.arrayElements) {
|
|
86
|
+
this.collections.arrayElements = [];
|
|
87
|
+
}
|
|
88
|
+
if (!this.collections.objectLiteralCounterRef) {
|
|
89
|
+
this.collections.objectLiteralCounterRef = { value: 0 };
|
|
90
|
+
}
|
|
91
|
+
if (!this.collections.objectLiterals) {
|
|
92
|
+
this.collections.objectLiterals = [];
|
|
93
|
+
}
|
|
94
|
+
if (!this.collections.objectProperties) {
|
|
95
|
+
this.collections.objectProperties = [];
|
|
96
|
+
}
|
|
97
|
+
const arrayLiteralCounterRef = this.collections.arrayLiteralCounterRef;
|
|
98
|
+
// Use factory to create ARRAY_LITERAL node
|
|
99
|
+
const arrayNode = ArrayLiteralNode.create(module.file, argInfo.line, argInfo.column, {
|
|
100
|
+
parentCallId: callId,
|
|
101
|
+
argIndex: index,
|
|
102
|
+
counter: arrayLiteralCounterRef.value++
|
|
103
|
+
});
|
|
104
|
+
// Factory guarantees line is set, cast to ArrayLiteralInfo
|
|
105
|
+
this.collections.arrayLiterals.push(arrayNode);
|
|
106
|
+
const arrayId = arrayNode.id;
|
|
107
|
+
// Extract elements
|
|
108
|
+
this.extractArrayElements(arrayExpr, arrayId, module, this.collections.arrayElements, this.collections.arrayLiterals, arrayLiteralCounterRef, this.collections.objectLiterals, this.collections.objectLiteralCounterRef, this.collections.objectProperties, literals, literalCounterRef);
|
|
126
109
|
argInfo.targetType = 'ARRAY_LITERAL';
|
|
110
|
+
argInfo.targetId = arrayId;
|
|
127
111
|
}
|
|
128
|
-
//
|
|
112
|
+
// Literal value (primitives only - objects/arrays handled above)
|
|
129
113
|
else {
|
|
130
|
-
|
|
131
|
-
|
|
114
|
+
const literalValue = ExpressionEvaluator.extractLiteralValue(actualArg);
|
|
115
|
+
if (literalValue !== null) {
|
|
116
|
+
const literalId = `LITERAL#arg${index}#${module.file}#${argInfo.line}:${argInfo.column}:${literalCounterRef.value++}`;
|
|
117
|
+
literals.push({
|
|
118
|
+
id: literalId,
|
|
119
|
+
type: 'LITERAL',
|
|
120
|
+
value: literalValue,
|
|
121
|
+
valueType: typeof literalValue,
|
|
122
|
+
file: module.file,
|
|
123
|
+
line: argInfo.line,
|
|
124
|
+
column: argInfo.column,
|
|
125
|
+
parentCallId: callId,
|
|
126
|
+
argIndex: index
|
|
127
|
+
});
|
|
128
|
+
argInfo.targetType = 'LITERAL';
|
|
129
|
+
argInfo.targetId = literalId;
|
|
130
|
+
argInfo.literalValue = literalValue;
|
|
131
|
+
}
|
|
132
|
+
// Variable reference
|
|
133
|
+
else if (actualArg.type === 'Identifier') {
|
|
134
|
+
argInfo.targetType = 'VARIABLE';
|
|
135
|
+
argInfo.targetName = actualArg.name; // Will be resolved in GraphBuilder
|
|
136
|
+
}
|
|
137
|
+
// Function expression (callback)
|
|
138
|
+
else if (actualArg.type === 'ArrowFunctionExpression' || actualArg.type === 'FunctionExpression') {
|
|
139
|
+
argInfo.targetType = 'FUNCTION';
|
|
140
|
+
argInfo.functionLine = actualArg.loc?.start.line;
|
|
141
|
+
argInfo.functionColumn = actualArg.loc?.start.column;
|
|
142
|
+
}
|
|
143
|
+
// Call expression (nested call)
|
|
144
|
+
else if (actualArg.type === 'CallExpression') {
|
|
145
|
+
argInfo.targetType = 'CALL';
|
|
146
|
+
// Nested calls will be processed separately, link by position
|
|
147
|
+
argInfo.nestedCallLine = actualArg.loc?.start.line;
|
|
148
|
+
argInfo.nestedCallColumn = actualArg.loc?.start.column;
|
|
149
|
+
}
|
|
150
|
+
// Member expression: obj.prop or obj[x]
|
|
151
|
+
else if (actualArg.type === 'MemberExpression') {
|
|
152
|
+
const memberExpr = actualArg;
|
|
153
|
+
argInfo.targetType = 'EXPRESSION';
|
|
154
|
+
argInfo.expressionType = 'MemberExpression';
|
|
155
|
+
if (memberExpr.object.type === 'Identifier') {
|
|
156
|
+
argInfo.objectName = memberExpr.object.name;
|
|
157
|
+
}
|
|
158
|
+
if (!memberExpr.computed && memberExpr.property.type === 'Identifier') {
|
|
159
|
+
argInfo.propertyName = memberExpr.property.name;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Binary/Logical expression: a + b, a && b
|
|
163
|
+
else if (actualArg.type === 'BinaryExpression' || actualArg.type === 'LogicalExpression') {
|
|
164
|
+
const expr = actualArg;
|
|
165
|
+
const operator = expr.operator || '?';
|
|
166
|
+
const counter = literalCounterRef.value++;
|
|
167
|
+
// Create EXPRESSION node via NodeFactory
|
|
168
|
+
const expressionNode = NodeFactory.createArgumentExpression(actualArg.type, module.file, argInfo.line, argInfo.column, {
|
|
169
|
+
parentCallId: callId,
|
|
170
|
+
argIndex: index,
|
|
171
|
+
operator,
|
|
172
|
+
counter
|
|
173
|
+
});
|
|
174
|
+
literals.push(expressionNode);
|
|
175
|
+
argInfo.targetType = 'EXPRESSION';
|
|
176
|
+
argInfo.targetId = expressionNode.id;
|
|
177
|
+
argInfo.expressionType = actualArg.type;
|
|
178
|
+
// Track DERIVES_FROM edges for identifiers in expression
|
|
179
|
+
const identifiers = this.extractIdentifiers(actualArg);
|
|
180
|
+
const { variableAssignments } = this.collections;
|
|
181
|
+
if (variableAssignments) {
|
|
182
|
+
for (const identName of identifiers) {
|
|
183
|
+
variableAssignments.push({
|
|
184
|
+
variableId: expressionNode.id,
|
|
185
|
+
sourceId: null,
|
|
186
|
+
sourceName: identName,
|
|
187
|
+
sourceType: 'DERIVES_FROM_VARIABLE',
|
|
188
|
+
file: module.file
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Other expression types (fallback for unhandled expression types)
|
|
194
|
+
else {
|
|
195
|
+
argInfo.targetType = 'EXPRESSION';
|
|
196
|
+
argInfo.expressionType = actualArg.type;
|
|
197
|
+
}
|
|
132
198
|
}
|
|
133
199
|
callArguments.push(argInfo);
|
|
134
200
|
});
|
|
@@ -186,28 +252,435 @@ export class CallExpressionVisitor extends ASTVisitor {
|
|
|
186
252
|
return Array.from(identifiers);
|
|
187
253
|
}
|
|
188
254
|
/**
|
|
189
|
-
*
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
255
|
+
* Extract object properties and create ObjectPropertyInfo records
|
|
256
|
+
*/
|
|
257
|
+
extractObjectProperties(objectExpr, objectId, module, objectProperties, objectLiterals, objectLiteralCounterRef, literals, literalCounterRef) {
|
|
258
|
+
for (const prop of objectExpr.properties) {
|
|
259
|
+
const propLine = prop.loc?.start.line || 0;
|
|
260
|
+
const propColumn = prop.loc?.start.column || 0;
|
|
261
|
+
// Handle spread properties: { ...other }
|
|
262
|
+
if (prop.type === 'SpreadElement') {
|
|
263
|
+
const spreadArg = prop.argument;
|
|
264
|
+
const propertyInfo = {
|
|
265
|
+
objectId,
|
|
266
|
+
propertyName: '<spread>',
|
|
267
|
+
valueType: 'SPREAD',
|
|
268
|
+
file: module.file,
|
|
269
|
+
line: propLine,
|
|
270
|
+
column: propColumn
|
|
271
|
+
};
|
|
272
|
+
if (spreadArg.type === 'Identifier') {
|
|
273
|
+
propertyInfo.valueName = spreadArg.name;
|
|
274
|
+
propertyInfo.valueType = 'VARIABLE';
|
|
275
|
+
}
|
|
276
|
+
objectProperties.push(propertyInfo);
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
// Handle regular properties
|
|
280
|
+
if (prop.type === 'ObjectProperty') {
|
|
281
|
+
const objProp = prop;
|
|
282
|
+
let propertyName;
|
|
283
|
+
// Get property name
|
|
284
|
+
if (objProp.key.type === 'Identifier') {
|
|
285
|
+
propertyName = objProp.key.name;
|
|
286
|
+
}
|
|
287
|
+
else if (objProp.key.type === 'StringLiteral') {
|
|
288
|
+
propertyName = objProp.key.value;
|
|
289
|
+
}
|
|
290
|
+
else if (objProp.key.type === 'NumericLiteral') {
|
|
291
|
+
propertyName = String(objProp.key.value);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
propertyName = '<computed>';
|
|
295
|
+
}
|
|
296
|
+
const propertyInfo = {
|
|
297
|
+
objectId,
|
|
298
|
+
propertyName,
|
|
299
|
+
file: module.file,
|
|
300
|
+
line: propLine,
|
|
301
|
+
column: propColumn,
|
|
302
|
+
valueType: 'EXPRESSION'
|
|
303
|
+
};
|
|
304
|
+
const value = objProp.value;
|
|
305
|
+
// Nested object literal - check BEFORE extractLiteralValue
|
|
306
|
+
if (value.type === 'ObjectExpression') {
|
|
307
|
+
// Use factory - do NOT pass argIndex for nested literals (uses 'obj' suffix)
|
|
308
|
+
const nestedObjectNode = ObjectLiteralNode.create(module.file, value.loc?.start.line || 0, value.loc?.start.column || 0, {
|
|
309
|
+
counter: objectLiteralCounterRef.value++
|
|
310
|
+
});
|
|
311
|
+
objectLiterals.push(nestedObjectNode);
|
|
312
|
+
const nestedObjectId = nestedObjectNode.id;
|
|
313
|
+
// Recursively extract nested properties
|
|
314
|
+
this.extractObjectProperties(value, nestedObjectId, module, objectProperties, objectLiterals, objectLiteralCounterRef, literals, literalCounterRef);
|
|
315
|
+
propertyInfo.valueType = 'OBJECT_LITERAL';
|
|
316
|
+
propertyInfo.nestedObjectId = nestedObjectId;
|
|
317
|
+
propertyInfo.valueNodeId = nestedObjectId;
|
|
318
|
+
}
|
|
319
|
+
// Nested array literal - check BEFORE extractLiteralValue
|
|
320
|
+
else if (value.type === 'ArrayExpression') {
|
|
321
|
+
const arrayLiteralCounterRef = (this.collections.arrayLiteralCounterRef ?? { value: 0 });
|
|
322
|
+
const arrayLiterals = this.collections.arrayLiterals ?? [];
|
|
323
|
+
const arrayElements = this.collections.arrayElements ?? [];
|
|
324
|
+
// Use factory - do NOT pass argIndex for nested literals (uses 'arr' suffix)
|
|
325
|
+
const nestedArrayNode = ArrayLiteralNode.create(module.file, value.loc?.start.line || 0, value.loc?.start.column || 0, {
|
|
326
|
+
counter: arrayLiteralCounterRef.value++
|
|
327
|
+
});
|
|
328
|
+
arrayLiterals.push(nestedArrayNode);
|
|
329
|
+
const nestedArrayId = nestedArrayNode.id;
|
|
330
|
+
// Recursively extract array elements
|
|
331
|
+
this.extractArrayElements(value, nestedArrayId, module, arrayElements, arrayLiterals, arrayLiteralCounterRef, objectLiterals, objectLiteralCounterRef, objectProperties, literals, literalCounterRef);
|
|
332
|
+
propertyInfo.valueType = 'ARRAY_LITERAL';
|
|
333
|
+
propertyInfo.nestedArrayId = nestedArrayId;
|
|
334
|
+
propertyInfo.valueNodeId = nestedArrayId;
|
|
335
|
+
}
|
|
336
|
+
// Literal value (primitives only - objects/arrays handled above)
|
|
337
|
+
else {
|
|
338
|
+
const literalValue = ExpressionEvaluator.extractLiteralValue(value);
|
|
339
|
+
if (literalValue !== null) {
|
|
340
|
+
const literalId = `LITERAL#${propertyName}#${module.file}#${propLine}:${propColumn}:${literalCounterRef.value++}`;
|
|
341
|
+
literals.push({
|
|
342
|
+
id: literalId,
|
|
343
|
+
type: 'LITERAL',
|
|
344
|
+
value: literalValue,
|
|
345
|
+
valueType: typeof literalValue,
|
|
346
|
+
file: module.file,
|
|
347
|
+
line: propLine,
|
|
348
|
+
column: propColumn,
|
|
349
|
+
parentCallId: objectId,
|
|
350
|
+
argIndex: 0
|
|
351
|
+
});
|
|
352
|
+
propertyInfo.valueType = 'LITERAL';
|
|
353
|
+
propertyInfo.valueNodeId = literalId;
|
|
354
|
+
propertyInfo.literalValue = literalValue;
|
|
355
|
+
}
|
|
356
|
+
// Variable reference
|
|
357
|
+
else if (value.type === 'Identifier') {
|
|
358
|
+
propertyInfo.valueType = 'VARIABLE';
|
|
359
|
+
propertyInfo.valueName = value.name;
|
|
360
|
+
}
|
|
361
|
+
// Call expression
|
|
362
|
+
else if (value.type === 'CallExpression') {
|
|
363
|
+
propertyInfo.valueType = 'CALL';
|
|
364
|
+
propertyInfo.callLine = value.loc?.start.line;
|
|
365
|
+
propertyInfo.callColumn = value.loc?.start.column;
|
|
366
|
+
}
|
|
367
|
+
// Other expressions
|
|
368
|
+
else {
|
|
369
|
+
propertyInfo.valueType = 'EXPRESSION';
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
objectProperties.push(propertyInfo);
|
|
373
|
+
}
|
|
374
|
+
// Handle object methods: { foo() {} }
|
|
375
|
+
else if (prop.type === 'ObjectMethod') {
|
|
376
|
+
const propertyName = prop.key.type === 'Identifier' ? prop.key.name : '<computed>';
|
|
377
|
+
objectProperties.push({
|
|
378
|
+
objectId,
|
|
379
|
+
propertyName,
|
|
380
|
+
valueType: 'EXPRESSION',
|
|
381
|
+
file: module.file,
|
|
382
|
+
line: propLine,
|
|
383
|
+
column: propColumn
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Extract array elements and create ArrayElementInfo records
|
|
390
|
+
*/
|
|
391
|
+
extractArrayElements(arrayExpr, arrayId, module, arrayElements, arrayLiterals, arrayLiteralCounterRef, objectLiterals, objectLiteralCounterRef, objectProperties, literals, literalCounterRef) {
|
|
392
|
+
arrayExpr.elements.forEach((element, index) => {
|
|
393
|
+
if (!element)
|
|
394
|
+
return; // Skip holes in arrays
|
|
395
|
+
const elemLine = element.loc?.start.line || 0;
|
|
396
|
+
const elemColumn = element.loc?.start.column || 0;
|
|
397
|
+
const elementInfo = {
|
|
398
|
+
arrayId,
|
|
399
|
+
index,
|
|
400
|
+
file: module.file,
|
|
401
|
+
line: elemLine,
|
|
402
|
+
column: elemColumn,
|
|
403
|
+
valueType: 'EXPRESSION'
|
|
404
|
+
};
|
|
405
|
+
// Handle spread elements: [...arr]
|
|
406
|
+
if (element.type === 'SpreadElement') {
|
|
407
|
+
const spreadArg = element.argument;
|
|
408
|
+
elementInfo.valueType = 'SPREAD';
|
|
409
|
+
if (spreadArg.type === 'Identifier') {
|
|
410
|
+
elementInfo.valueName = spreadArg.name;
|
|
411
|
+
}
|
|
412
|
+
arrayElements.push(elementInfo);
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
// Nested object literal - check BEFORE extractLiteralValue
|
|
416
|
+
if (element.type === 'ObjectExpression') {
|
|
417
|
+
// Use factory - do NOT pass argIndex for nested literals (uses 'obj' suffix)
|
|
418
|
+
const nestedObjectNode = ObjectLiteralNode.create(module.file, elemLine, elemColumn, {
|
|
419
|
+
counter: objectLiteralCounterRef.value++
|
|
420
|
+
});
|
|
421
|
+
objectLiterals.push(nestedObjectNode);
|
|
422
|
+
const nestedObjectId = nestedObjectNode.id;
|
|
423
|
+
// Recursively extract properties
|
|
424
|
+
this.extractObjectProperties(element, nestedObjectId, module, objectProperties, objectLiterals, objectLiteralCounterRef, literals, literalCounterRef);
|
|
425
|
+
elementInfo.valueType = 'OBJECT_LITERAL';
|
|
426
|
+
elementInfo.nestedObjectId = nestedObjectId;
|
|
427
|
+
elementInfo.valueNodeId = nestedObjectId;
|
|
428
|
+
}
|
|
429
|
+
// Nested array literal - check BEFORE extractLiteralValue
|
|
430
|
+
else if (element.type === 'ArrayExpression') {
|
|
431
|
+
// Use factory - do NOT pass argIndex for nested literals (uses 'arr' suffix)
|
|
432
|
+
const nestedArrayNode = ArrayLiteralNode.create(module.file, elemLine, elemColumn, {
|
|
433
|
+
counter: arrayLiteralCounterRef.value++
|
|
434
|
+
});
|
|
435
|
+
arrayLiterals.push(nestedArrayNode);
|
|
436
|
+
const nestedArrayId = nestedArrayNode.id;
|
|
437
|
+
// Recursively extract elements
|
|
438
|
+
this.extractArrayElements(element, nestedArrayId, module, arrayElements, arrayLiterals, arrayLiteralCounterRef, objectLiterals, objectLiteralCounterRef, objectProperties, literals, literalCounterRef);
|
|
439
|
+
elementInfo.valueType = 'ARRAY_LITERAL';
|
|
440
|
+
elementInfo.nestedArrayId = nestedArrayId;
|
|
441
|
+
elementInfo.valueNodeId = nestedArrayId;
|
|
442
|
+
}
|
|
443
|
+
// Literal value (primitives only - objects/arrays handled above)
|
|
444
|
+
else {
|
|
445
|
+
const literalValue = ExpressionEvaluator.extractLiteralValue(element);
|
|
446
|
+
if (literalValue !== null) {
|
|
447
|
+
const literalId = `LITERAL#elem${index}#${module.file}#${elemLine}:${elemColumn}:${literalCounterRef.value++}`;
|
|
448
|
+
literals.push({
|
|
449
|
+
id: literalId,
|
|
450
|
+
type: 'LITERAL',
|
|
451
|
+
value: literalValue,
|
|
452
|
+
valueType: typeof literalValue,
|
|
453
|
+
file: module.file,
|
|
454
|
+
line: elemLine,
|
|
455
|
+
column: elemColumn,
|
|
456
|
+
parentCallId: arrayId,
|
|
457
|
+
argIndex: index
|
|
458
|
+
});
|
|
459
|
+
elementInfo.valueType = 'LITERAL';
|
|
460
|
+
elementInfo.valueNodeId = literalId;
|
|
461
|
+
elementInfo.literalValue = literalValue;
|
|
462
|
+
}
|
|
463
|
+
// Variable reference
|
|
464
|
+
else if (element.type === 'Identifier') {
|
|
465
|
+
elementInfo.valueType = 'VARIABLE';
|
|
466
|
+
elementInfo.valueName = element.name;
|
|
467
|
+
}
|
|
468
|
+
// Call expression
|
|
469
|
+
else if (element.type === 'CallExpression') {
|
|
470
|
+
elementInfo.valueType = 'CALL';
|
|
471
|
+
elementInfo.callLine = element.loc?.start.line;
|
|
472
|
+
elementInfo.callColumn = element.loc?.start.column;
|
|
473
|
+
}
|
|
474
|
+
// Other expressions
|
|
475
|
+
else {
|
|
476
|
+
elementInfo.valueType = 'EXPRESSION';
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
arrayElements.push(elementInfo);
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Detect array mutation calls (push, unshift, splice) and collect mutation info
|
|
484
|
+
* for later FLOWS_INTO edge creation in GraphBuilder
|
|
485
|
+
*
|
|
486
|
+
* REG-117: Added isNested, baseObjectName, propertyName for nested mutations
|
|
487
|
+
*/
|
|
488
|
+
detectArrayMutation(callNode, arrayName, method, module, isNested, baseObjectName, propertyName) {
|
|
489
|
+
// Initialize collection if not exists
|
|
490
|
+
if (!this.collections.arrayMutations) {
|
|
491
|
+
this.collections.arrayMutations = [];
|
|
492
|
+
}
|
|
493
|
+
const arrayMutations = this.collections.arrayMutations;
|
|
494
|
+
const mutationArgs = [];
|
|
495
|
+
// For splice, only arguments from index 2 onwards are insertions
|
|
496
|
+
// splice(start, deleteCount, item1, item2, ...)
|
|
497
|
+
callNode.arguments.forEach((arg, index) => {
|
|
498
|
+
// Skip start and deleteCount for splice
|
|
499
|
+
if (method === 'splice' && index < 2)
|
|
500
|
+
return;
|
|
501
|
+
const argInfo = {
|
|
502
|
+
argIndex: method === 'splice' ? index - 2 : index,
|
|
503
|
+
isSpread: arg.type === 'SpreadElement',
|
|
504
|
+
valueType: 'EXPRESSION' // Default
|
|
505
|
+
};
|
|
506
|
+
let actualArg = arg;
|
|
507
|
+
if (arg.type === 'SpreadElement') {
|
|
508
|
+
actualArg = arg.argument;
|
|
509
|
+
}
|
|
510
|
+
// Determine value type
|
|
511
|
+
const literalValue = ExpressionEvaluator.extractLiteralValue(actualArg);
|
|
512
|
+
if (literalValue !== null) {
|
|
513
|
+
argInfo.valueType = 'LITERAL';
|
|
514
|
+
argInfo.literalValue = literalValue;
|
|
515
|
+
}
|
|
516
|
+
else if (actualArg.type === 'Identifier') {
|
|
517
|
+
argInfo.valueType = 'VARIABLE';
|
|
518
|
+
argInfo.valueName = actualArg.name;
|
|
519
|
+
}
|
|
520
|
+
else if (actualArg.type === 'ObjectExpression') {
|
|
521
|
+
argInfo.valueType = 'OBJECT_LITERAL';
|
|
522
|
+
}
|
|
523
|
+
else if (actualArg.type === 'ArrayExpression') {
|
|
524
|
+
argInfo.valueType = 'ARRAY_LITERAL';
|
|
525
|
+
}
|
|
526
|
+
else if (actualArg.type === 'CallExpression') {
|
|
527
|
+
argInfo.valueType = 'CALL';
|
|
528
|
+
argInfo.callLine = actualArg.loc?.start.line;
|
|
529
|
+
argInfo.callColumn = actualArg.loc?.start.column;
|
|
530
|
+
}
|
|
531
|
+
mutationArgs.push(argInfo);
|
|
532
|
+
});
|
|
533
|
+
// Only record if there are actual insertions
|
|
534
|
+
if (mutationArgs.length > 0) {
|
|
535
|
+
const line = callNode.loc?.start.line ?? 0;
|
|
536
|
+
const column = callNode.loc?.start.column ?? 0;
|
|
537
|
+
// Generate semantic ID for array mutation if scopeTracker available
|
|
538
|
+
const scopeTracker = this.scopeTracker;
|
|
539
|
+
let mutationId;
|
|
540
|
+
if (scopeTracker) {
|
|
541
|
+
const discriminator = scopeTracker.getItemCounter(`ARRAY_MUTATION:${arrayName}.${method}`);
|
|
542
|
+
mutationId = computeSemanticId('ARRAY_MUTATION', `${arrayName}.${method}`, scopeTracker.getContext(), { discriminator });
|
|
543
|
+
}
|
|
544
|
+
arrayMutations.push({
|
|
545
|
+
id: mutationId,
|
|
546
|
+
arrayName,
|
|
547
|
+
mutationMethod: method,
|
|
548
|
+
file: module.file,
|
|
549
|
+
line,
|
|
550
|
+
column,
|
|
551
|
+
insertedValues: mutationArgs,
|
|
552
|
+
// REG-117: Nested mutation fields
|
|
553
|
+
isNested,
|
|
554
|
+
baseObjectName,
|
|
555
|
+
propertyName
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Detect Object.assign(target, source1, source2, ...) calls
|
|
561
|
+
* Creates ObjectMutationInfo for FLOWS_INTO edge generation in GraphBuilder
|
|
562
|
+
*
|
|
563
|
+
* @param callNode - The call expression node
|
|
564
|
+
* @param module - Current module being analyzed
|
|
565
|
+
*/
|
|
566
|
+
detectObjectAssign(callNode, module) {
|
|
567
|
+
// Need at least 2 arguments: target and at least one source
|
|
568
|
+
if (callNode.arguments.length < 2)
|
|
569
|
+
return;
|
|
570
|
+
// Initialize object mutations collection if not exists
|
|
571
|
+
if (!this.collections.objectMutations) {
|
|
572
|
+
this.collections.objectMutations = [];
|
|
573
|
+
}
|
|
574
|
+
const objectMutations = this.collections.objectMutations;
|
|
575
|
+
// First argument is target
|
|
576
|
+
const targetArg = callNode.arguments[0];
|
|
577
|
+
let targetName;
|
|
578
|
+
if (targetArg.type === 'Identifier') {
|
|
579
|
+
targetName = targetArg.name;
|
|
580
|
+
}
|
|
581
|
+
else if (targetArg.type === 'ObjectExpression') {
|
|
582
|
+
targetName = '<anonymous>';
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
const line = callNode.loc?.start.line ?? 0;
|
|
588
|
+
const column = callNode.loc?.start.column ?? 0;
|
|
589
|
+
for (let i = 1; i < callNode.arguments.length; i++) {
|
|
590
|
+
let arg = callNode.arguments[i];
|
|
591
|
+
let isSpread = false;
|
|
592
|
+
if (arg.type === 'SpreadElement') {
|
|
593
|
+
isSpread = true;
|
|
594
|
+
arg = arg.argument;
|
|
595
|
+
}
|
|
596
|
+
const valueInfo = {
|
|
597
|
+
valueType: 'EXPRESSION',
|
|
598
|
+
argIndex: i - 1,
|
|
599
|
+
isSpread
|
|
600
|
+
};
|
|
601
|
+
const literalValue = ExpressionEvaluator.extractLiteralValue(arg);
|
|
602
|
+
if (literalValue !== null) {
|
|
603
|
+
valueInfo.valueType = 'LITERAL';
|
|
604
|
+
valueInfo.literalValue = literalValue;
|
|
605
|
+
}
|
|
606
|
+
else if (arg.type === 'Identifier') {
|
|
607
|
+
valueInfo.valueType = 'VARIABLE';
|
|
608
|
+
valueInfo.valueName = arg.name;
|
|
609
|
+
}
|
|
610
|
+
else if (arg.type === 'ObjectExpression') {
|
|
611
|
+
valueInfo.valueType = 'OBJECT_LITERAL';
|
|
612
|
+
}
|
|
613
|
+
else if (arg.type === 'ArrayExpression') {
|
|
614
|
+
valueInfo.valueType = 'ARRAY_LITERAL';
|
|
615
|
+
}
|
|
616
|
+
else if (arg.type === 'CallExpression') {
|
|
617
|
+
valueInfo.valueType = 'CALL';
|
|
618
|
+
valueInfo.callLine = arg.loc?.start.line;
|
|
619
|
+
valueInfo.callColumn = arg.loc?.start.column;
|
|
620
|
+
}
|
|
621
|
+
let mutationId;
|
|
622
|
+
if (this.scopeTracker) {
|
|
623
|
+
const discriminator = this.scopeTracker.getItemCounter(`OBJECT_MUTATION:Object.assign:${targetName}`);
|
|
624
|
+
mutationId = computeSemanticId('OBJECT_MUTATION', `Object.assign:${targetName}`, this.scopeTracker.getContext(), { discriminator });
|
|
625
|
+
}
|
|
626
|
+
objectMutations.push({
|
|
627
|
+
id: mutationId,
|
|
628
|
+
objectName: targetName,
|
|
629
|
+
propertyName: '<assign>',
|
|
630
|
+
mutationType: 'assign',
|
|
631
|
+
file: module.file,
|
|
632
|
+
line,
|
|
633
|
+
column,
|
|
634
|
+
value: valueInfo
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Get a stable scope ID for a function parent.
|
|
640
|
+
*
|
|
641
|
+
* Format must match what FunctionVisitor/ClassVisitor creates (semantic ID):
|
|
642
|
+
* - Module-level function: {file}->global->FUNCTION->{name}
|
|
643
|
+
* - Class method: {file}->{className}->FUNCTION->{methodName}
|
|
193
644
|
*
|
|
194
|
-
*
|
|
195
|
-
* we try to match by name+file+line:col. This may not always work for
|
|
196
|
-
* multiple arrow functions on the same line.
|
|
645
|
+
* Reconstructs scope path by walking up the AST.
|
|
197
646
|
*/
|
|
198
647
|
getFunctionScopeId(functionParent, module) {
|
|
199
648
|
const funcNode = functionParent.node;
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
// FunctionDeclaration with name
|
|
649
|
+
// Get function name
|
|
650
|
+
let funcName;
|
|
203
651
|
if (funcNode.type === 'FunctionDeclaration' && funcNode.id?.name) {
|
|
204
|
-
|
|
652
|
+
funcName = funcNode.id.name;
|
|
653
|
+
}
|
|
654
|
+
else if (funcNode.type === 'ClassMethod' && funcNode.key?.type === 'Identifier') {
|
|
655
|
+
funcName = funcNode.key.name;
|
|
656
|
+
}
|
|
657
|
+
if (!funcName) {
|
|
658
|
+
// Anonymous function - fall back to module scope
|
|
659
|
+
return module.id;
|
|
660
|
+
}
|
|
661
|
+
// Build scope path by walking up the AST
|
|
662
|
+
const scopePath = [];
|
|
663
|
+
let current = functionParent.parentPath;
|
|
664
|
+
while (current) {
|
|
665
|
+
const node = current.node;
|
|
666
|
+
if (node.type === 'ClassDeclaration' && node.id?.name) {
|
|
667
|
+
scopePath.unshift(node.id.name);
|
|
668
|
+
break; // Class is the outermost scope we need
|
|
669
|
+
}
|
|
670
|
+
else if (node.type === 'ClassBody') {
|
|
671
|
+
// Continue up to ClassDeclaration
|
|
672
|
+
}
|
|
673
|
+
else if (node.type === 'Program') {
|
|
674
|
+
break;
|
|
675
|
+
}
|
|
676
|
+
current = current.parentPath;
|
|
677
|
+
}
|
|
678
|
+
// If no class found, it's at module level (global scope)
|
|
679
|
+
if (scopePath.length === 0) {
|
|
680
|
+
scopePath.push('global');
|
|
205
681
|
}
|
|
206
|
-
//
|
|
207
|
-
|
|
208
|
-
// to avoid creating invalid edges. The CALL node will be connected to MODULE
|
|
209
|
-
// instead of the specific function.
|
|
210
|
-
return module.id;
|
|
682
|
+
// Compute semantic ID: {file}->{scopePath}->FUNCTION->{name}
|
|
683
|
+
return `${module.file}->${scopePath.join('->')}->FUNCTION->${funcName}`;
|
|
211
684
|
}
|
|
212
685
|
getHandlers() {
|
|
213
686
|
const { module } = this;
|
|
@@ -220,6 +693,7 @@ export class CallExpressionVisitor extends ASTVisitor {
|
|
|
220
693
|
const callSiteCounterRef = (this.collections.callSiteCounterRef ?? { value: 0 });
|
|
221
694
|
const literalCounterRef = (this.collections.literalCounterRef ?? { value: 0 });
|
|
222
695
|
const processedNodes = this.collections.processedNodes ?? { callSites: new Set(), methodCalls: new Set(), eventListeners: new Set() };
|
|
696
|
+
const scopeTracker = this.scopeTracker;
|
|
223
697
|
return {
|
|
224
698
|
CallExpression: (path) => {
|
|
225
699
|
const callNode = path.node;
|
|
@@ -227,16 +701,24 @@ export class CallExpressionVisitor extends ASTVisitor {
|
|
|
227
701
|
// Determine parent scope - if inside a function, use function's scope, otherwise module
|
|
228
702
|
const parentScopeId = functionParent ? this.getFunctionScopeId(functionParent, module) : module.id;
|
|
229
703
|
// Identifier calls (direct function calls)
|
|
704
|
+
// Skip if inside function - they will be processed by analyzeFunctionBody with proper scope tracking
|
|
230
705
|
if (callNode.callee.type === 'Identifier') {
|
|
706
|
+
if (functionParent) {
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
231
709
|
const callee = callNode.callee;
|
|
232
|
-
const
|
|
710
|
+
const line = getLine(callNode);
|
|
711
|
+
const column = getColumn(callNode);
|
|
712
|
+
// Generate ID using centralized IdGenerator
|
|
713
|
+
const idGenerator = new IdGenerator(scopeTracker);
|
|
714
|
+
const callId = idGenerator.generate('CALL', callee.name, module.file, line, column, callSiteCounterRef, { useDiscriminator: true, discriminatorKey: `CALL:${callee.name}` });
|
|
233
715
|
callSites.push({
|
|
234
716
|
id: callId,
|
|
235
717
|
type: 'CALL',
|
|
236
718
|
name: callee.name,
|
|
237
719
|
file: module.file,
|
|
238
|
-
line
|
|
239
|
-
column
|
|
720
|
+
line,
|
|
721
|
+
column,
|
|
240
722
|
parentScopeId,
|
|
241
723
|
targetFunctionName: callee.name
|
|
242
724
|
});
|
|
@@ -245,8 +727,12 @@ export class CallExpressionVisitor extends ASTVisitor {
|
|
|
245
727
|
this.extractArguments(callNode.arguments, callId, module, callArguments, literals, literalCounterRef);
|
|
246
728
|
}
|
|
247
729
|
}
|
|
248
|
-
// MemberExpression calls (method calls
|
|
730
|
+
// MemberExpression calls (method calls)
|
|
731
|
+
// Skip if inside function - they will be processed by analyzeFunctionBody with proper scope tracking
|
|
249
732
|
else if (callNode.callee.type === 'MemberExpression') {
|
|
733
|
+
if (functionParent) {
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
250
736
|
const memberCallee = callNode.callee;
|
|
251
737
|
const object = memberCallee.object;
|
|
252
738
|
const property = memberCallee.property;
|
|
@@ -268,13 +754,15 @@ export class CallExpressionVisitor extends ASTVisitor {
|
|
|
268
754
|
return;
|
|
269
755
|
}
|
|
270
756
|
processedNodes.eventListeners.add(nodeKey);
|
|
757
|
+
const eventLine = getLine(callNode);
|
|
758
|
+
const eventColumn = getColumn(callNode);
|
|
271
759
|
eventListeners.push({
|
|
272
|
-
id: `event:listener#${eventName}#${module.file}#${
|
|
760
|
+
id: `event:listener#${eventName}#${module.file}#${eventLine}:${eventColumn}:${callSiteCounterRef.value++}`,
|
|
273
761
|
type: 'event:listener',
|
|
274
762
|
name: eventName,
|
|
275
763
|
object: objectName,
|
|
276
764
|
file: module.file,
|
|
277
|
-
line:
|
|
765
|
+
line: eventLine,
|
|
278
766
|
parentScopeId,
|
|
279
767
|
callbackArg: secondArg
|
|
280
768
|
});
|
|
@@ -288,7 +776,11 @@ export class CallExpressionVisitor extends ASTVisitor {
|
|
|
288
776
|
}
|
|
289
777
|
processedNodes.methodCalls.add(nodeKey);
|
|
290
778
|
const fullName = `${objectName}.${methodName}`;
|
|
291
|
-
const
|
|
779
|
+
const methodLine = getLine(callNode);
|
|
780
|
+
const methodColumn = getColumn(callNode);
|
|
781
|
+
// Generate ID using centralized IdGenerator
|
|
782
|
+
const idGenerator = new IdGenerator(scopeTracker);
|
|
783
|
+
const methodCallId = idGenerator.generate('CALL', fullName, module.file, methodLine, methodColumn, callSiteCounterRef, { useDiscriminator: true, discriminatorKey: `CALL:${fullName}` });
|
|
292
784
|
methodCalls.push({
|
|
293
785
|
id: methodCallId,
|
|
294
786
|
type: 'CALL',
|
|
@@ -298,10 +790,19 @@ export class CallExpressionVisitor extends ASTVisitor {
|
|
|
298
790
|
computed: isComputed,
|
|
299
791
|
computedPropertyVar, // Variable name used in obj[x]() calls
|
|
300
792
|
file: module.file,
|
|
301
|
-
line:
|
|
302
|
-
column:
|
|
793
|
+
line: methodLine,
|
|
794
|
+
column: methodColumn,
|
|
303
795
|
parentScopeId
|
|
304
796
|
});
|
|
797
|
+
// Check for array mutation methods (push, unshift, splice)
|
|
798
|
+
const ARRAY_MUTATION_METHODS = ['push', 'unshift', 'splice'];
|
|
799
|
+
if (ARRAY_MUTATION_METHODS.includes(methodName)) {
|
|
800
|
+
this.detectArrayMutation(callNode, objectName, methodName, module);
|
|
801
|
+
}
|
|
802
|
+
// Check for Object.assign() calls
|
|
803
|
+
if (objectName === 'Object' && methodName === 'assign') {
|
|
804
|
+
this.detectObjectAssign(callNode, module);
|
|
805
|
+
}
|
|
305
806
|
// Extract arguments for PASSES_ARGUMENT edges
|
|
306
807
|
if (callNode.arguments.length > 0) {
|
|
307
808
|
this.extractArguments(callNode.arguments, methodCallId, module, callArguments, literals, literalCounterRef);
|
|
@@ -310,8 +811,8 @@ export class CallExpressionVisitor extends ASTVisitor {
|
|
|
310
811
|
if (arg.type === 'ArrowFunctionExpression' || arg.type === 'FunctionExpression') {
|
|
311
812
|
methodCallbacks.push({
|
|
312
813
|
methodCallId,
|
|
313
|
-
callbackLine: arg
|
|
314
|
-
callbackColumn: arg
|
|
814
|
+
callbackLine: getLine(arg),
|
|
815
|
+
callbackColumn: getColumn(arg),
|
|
315
816
|
callbackType: arg.type
|
|
316
817
|
});
|
|
317
818
|
}
|
|
@@ -319,13 +820,40 @@ export class CallExpressionVisitor extends ASTVisitor {
|
|
|
319
820
|
}
|
|
320
821
|
}
|
|
321
822
|
}
|
|
823
|
+
// REG-117: Nested array mutations like obj.arr.push(item)
|
|
824
|
+
// object is MemberExpression, property is the method name
|
|
825
|
+
else if (object.type === 'MemberExpression' && property.type === 'Identifier') {
|
|
826
|
+
const nestedMember = object;
|
|
827
|
+
const methodName = property.name;
|
|
828
|
+
const ARRAY_MUTATION_METHODS = ['push', 'unshift', 'splice'];
|
|
829
|
+
if (ARRAY_MUTATION_METHODS.includes(methodName)) {
|
|
830
|
+
// Extract base object and property from nested MemberExpression
|
|
831
|
+
const base = nestedMember.object;
|
|
832
|
+
const prop = nestedMember.property;
|
|
833
|
+
// Only handle single-level nesting: obj.arr.push() or this.items.push()
|
|
834
|
+
if ((base.type === 'Identifier' || base.type === 'ThisExpression') &&
|
|
835
|
+
!nestedMember.computed &&
|
|
836
|
+
prop.type === 'Identifier') {
|
|
837
|
+
const baseObjectName = base.type === 'Identifier' ? base.name : 'this';
|
|
838
|
+
const propertyName = prop.name;
|
|
839
|
+
this.detectArrayMutation(callNode, `${baseObjectName}.${propertyName}`, // arrayName for ID purposes
|
|
840
|
+
methodName, module, true, // isNested
|
|
841
|
+
baseObjectName, propertyName);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
}
|
|
322
845
|
}
|
|
323
846
|
},
|
|
324
847
|
// NewExpression: new Foo(), new Function(), new Map(), etc.
|
|
848
|
+
// Skip if inside function - they will be processed by analyzeFunctionBody with proper scope tracking
|
|
325
849
|
NewExpression: (path) => {
|
|
326
850
|
const newNode = path.node;
|
|
327
851
|
const functionParent = path.getFunctionParent();
|
|
328
|
-
|
|
852
|
+
// Skip if inside function - handled by analyzeFunctionBody
|
|
853
|
+
if (functionParent) {
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
const parentScopeId = module.id;
|
|
329
857
|
// Dedup check
|
|
330
858
|
const nodeKey = `new:${newNode.start}:${newNode.end}`;
|
|
331
859
|
if (processedNodes.methodCalls.has(nodeKey)) {
|
|
@@ -336,13 +864,18 @@ export class CallExpressionVisitor extends ASTVisitor {
|
|
|
336
864
|
if (newNode.callee.type === 'Identifier') {
|
|
337
865
|
const callee = newNode.callee;
|
|
338
866
|
const constructorName = callee.name;
|
|
867
|
+
const newLine = getLine(newNode);
|
|
868
|
+
const newColumn = getColumn(newNode);
|
|
869
|
+
// Generate ID using centralized IdGenerator
|
|
870
|
+
const idGenerator = new IdGenerator(scopeTracker);
|
|
871
|
+
const newCallId = idGenerator.generate('CALL', `new:${constructorName}`, module.file, newLine, newColumn, callSiteCounterRef, { useDiscriminator: true, discriminatorKey: `CALL:new:${constructorName}` });
|
|
339
872
|
callSites.push({
|
|
340
|
-
id:
|
|
873
|
+
id: newCallId,
|
|
341
874
|
type: 'CALL',
|
|
342
875
|
name: constructorName,
|
|
343
876
|
file: module.file,
|
|
344
|
-
line:
|
|
345
|
-
column:
|
|
877
|
+
line: newLine,
|
|
878
|
+
column: newColumn,
|
|
346
879
|
parentScopeId,
|
|
347
880
|
targetFunctionName: constructorName,
|
|
348
881
|
isNew: true // Mark as constructor call
|
|
@@ -357,15 +890,20 @@ export class CallExpressionVisitor extends ASTVisitor {
|
|
|
357
890
|
const objectName = object.name;
|
|
358
891
|
const constructorName = property.name;
|
|
359
892
|
const fullName = `${objectName}.${constructorName}`;
|
|
893
|
+
const memberNewLine = getLine(newNode);
|
|
894
|
+
const memberNewColumn = getColumn(newNode);
|
|
895
|
+
// Generate ID using centralized IdGenerator
|
|
896
|
+
const idGenerator = new IdGenerator(scopeTracker);
|
|
897
|
+
const newMethodCallId = idGenerator.generate('CALL', `new:${fullName}`, module.file, memberNewLine, memberNewColumn, callSiteCounterRef, { useDiscriminator: true, discriminatorKey: `CALL:new:${fullName}` });
|
|
360
898
|
methodCalls.push({
|
|
361
|
-
id:
|
|
899
|
+
id: newMethodCallId,
|
|
362
900
|
type: 'CALL',
|
|
363
901
|
name: fullName,
|
|
364
902
|
object: objectName,
|
|
365
903
|
method: constructorName,
|
|
366
904
|
file: module.file,
|
|
367
|
-
line:
|
|
368
|
-
column:
|
|
905
|
+
line: memberNewLine,
|
|
906
|
+
column: memberNewColumn,
|
|
369
907
|
parentScopeId,
|
|
370
908
|
isNew: true // Mark as constructor call
|
|
371
909
|
});
|