@grafema/core 0.1.0-alpha.5 → 0.2.0-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (530) hide show
  1. package/README.md +0 -1
  2. package/dist/Orchestrator.d.ts +31 -2
  3. package/dist/Orchestrator.d.ts.map +1 -1
  4. package/dist/Orchestrator.js +222 -27
  5. package/dist/config/ConfigLoader.d.ts +90 -0
  6. package/dist/config/ConfigLoader.d.ts.map +1 -0
  7. package/dist/config/ConfigLoader.js +249 -0
  8. package/dist/config/index.d.ts +6 -0
  9. package/dist/config/index.d.ts.map +1 -0
  10. package/dist/config/index.js +4 -0
  11. package/dist/core/ASTWorker.d.ts +11 -36
  12. package/dist/core/ASTWorker.d.ts.map +1 -1
  13. package/dist/core/ASTWorker.js +93 -99
  14. package/dist/core/CoverageAnalyzer.d.ts +65 -0
  15. package/dist/core/CoverageAnalyzer.d.ts.map +1 -0
  16. package/dist/core/CoverageAnalyzer.js +198 -0
  17. package/dist/core/FileExplainer.d.ts +101 -0
  18. package/dist/core/FileExplainer.d.ts.map +1 -0
  19. package/dist/core/FileExplainer.js +139 -0
  20. package/dist/core/FileNodeManager.d.ts +40 -0
  21. package/dist/core/FileNodeManager.d.ts.map +1 -0
  22. package/dist/core/FileNodeManager.js +84 -0
  23. package/dist/core/GraphFreshnessChecker.d.ts +33 -0
  24. package/dist/core/GraphFreshnessChecker.d.ts.map +1 -0
  25. package/dist/core/GraphFreshnessChecker.js +101 -0
  26. package/dist/core/HashUtils.d.ts +24 -0
  27. package/dist/core/HashUtils.d.ts.map +1 -0
  28. package/dist/core/HashUtils.js +45 -0
  29. package/dist/core/IncrementalReanalyzer.d.ts +36 -0
  30. package/dist/core/IncrementalReanalyzer.d.ts.map +1 -0
  31. package/dist/core/IncrementalReanalyzer.js +132 -0
  32. package/dist/core/NodeFactory.d.ts +266 -19
  33. package/dist/core/NodeFactory.d.ts.map +1 -1
  34. package/dist/core/NodeFactory.js +256 -21
  35. package/dist/core/ScopeTracker.d.ts +84 -0
  36. package/dist/core/ScopeTracker.d.ts.map +1 -0
  37. package/dist/core/ScopeTracker.js +116 -0
  38. package/dist/core/SemanticId.d.ts +90 -0
  39. package/dist/core/SemanticId.d.ts.map +1 -0
  40. package/dist/core/SemanticId.js +115 -0
  41. package/dist/core/VersionManager.d.ts.map +1 -1
  42. package/dist/core/VersionManager.js +3 -2
  43. package/dist/core/nodes/ArgumentExpressionNode.d.ts +43 -0
  44. package/dist/core/nodes/ArgumentExpressionNode.d.ts.map +1 -0
  45. package/dist/core/nodes/ArgumentExpressionNode.js +60 -0
  46. package/dist/core/nodes/ArrayLiteralNode.d.ts +27 -0
  47. package/dist/core/nodes/ArrayLiteralNode.d.ts.map +1 -0
  48. package/dist/core/nodes/ArrayLiteralNode.js +43 -0
  49. package/dist/core/nodes/BranchNode.d.ts +41 -0
  50. package/dist/core/nodes/BranchNode.d.ts.map +1 -0
  51. package/dist/core/nodes/BranchNode.js +82 -0
  52. package/dist/core/nodes/CallSiteNode.d.ts +30 -2
  53. package/dist/core/nodes/CallSiteNode.d.ts.map +1 -1
  54. package/dist/core/nodes/CallSiteNode.js +54 -4
  55. package/dist/core/nodes/CaseNode.d.ts +43 -0
  56. package/dist/core/nodes/CaseNode.d.ts.map +1 -0
  57. package/dist/core/nodes/CaseNode.js +81 -0
  58. package/dist/core/nodes/ClassNode.d.ts +34 -2
  59. package/dist/core/nodes/ClassNode.d.ts.map +1 -1
  60. package/dist/core/nodes/ClassNode.js +52 -4
  61. package/dist/core/nodes/ConstantNode.d.ts +2 -2
  62. package/dist/core/nodes/ConstantNode.d.ts.map +1 -1
  63. package/dist/core/nodes/ConstantNode.js +6 -4
  64. package/dist/core/nodes/ConstructorCallNode.d.ts +51 -0
  65. package/dist/core/nodes/ConstructorCallNode.d.ts.map +1 -0
  66. package/dist/core/nodes/ConstructorCallNode.js +171 -0
  67. package/dist/core/nodes/DatabaseQueryNode.d.ts +3 -2
  68. package/dist/core/nodes/DatabaseQueryNode.d.ts.map +1 -1
  69. package/dist/core/nodes/DatabaseQueryNode.js +5 -2
  70. package/dist/core/nodes/DecoratorNode.d.ts +42 -0
  71. package/dist/core/nodes/DecoratorNode.d.ts.map +1 -0
  72. package/dist/core/nodes/DecoratorNode.js +64 -0
  73. package/dist/core/nodes/EnumNode.d.ts +42 -0
  74. package/dist/core/nodes/EnumNode.d.ts.map +1 -0
  75. package/dist/core/nodes/EnumNode.js +56 -0
  76. package/dist/core/nodes/EventListenerNode.d.ts +4 -4
  77. package/dist/core/nodes/EventListenerNode.d.ts.map +1 -1
  78. package/dist/core/nodes/EventListenerNode.js +7 -4
  79. package/dist/core/nodes/ExportNode.d.ts +38 -2
  80. package/dist/core/nodes/ExportNode.d.ts.map +1 -1
  81. package/dist/core/nodes/ExportNode.js +54 -4
  82. package/dist/core/nodes/ExpressionNode.d.ts +97 -0
  83. package/dist/core/nodes/ExpressionNode.d.ts.map +1 -0
  84. package/dist/core/nodes/ExpressionNode.js +180 -0
  85. package/dist/core/nodes/ExternalModuleNode.d.ts +32 -0
  86. package/dist/core/nodes/ExternalModuleNode.d.ts.map +1 -0
  87. package/dist/core/nodes/ExternalModuleNode.js +49 -0
  88. package/dist/core/nodes/ExternalStdioNode.d.ts +13 -6
  89. package/dist/core/nodes/ExternalStdioNode.d.ts.map +1 -1
  90. package/dist/core/nodes/ExternalStdioNode.js +15 -8
  91. package/dist/core/nodes/FunctionNode.d.ts +36 -0
  92. package/dist/core/nodes/FunctionNode.d.ts.map +1 -1
  93. package/dist/core/nodes/FunctionNode.js +80 -1
  94. package/dist/core/nodes/HttpRequestNode.d.ts +4 -4
  95. package/dist/core/nodes/HttpRequestNode.d.ts.map +1 -1
  96. package/dist/core/nodes/HttpRequestNode.js +7 -4
  97. package/dist/core/nodes/ImportNode.d.ts +28 -6
  98. package/dist/core/nodes/ImportNode.d.ts.map +1 -1
  99. package/dist/core/nodes/ImportNode.js +43 -8
  100. package/dist/core/nodes/InterfaceNode.d.ts +46 -0
  101. package/dist/core/nodes/InterfaceNode.d.ts.map +1 -0
  102. package/dist/core/nodes/InterfaceNode.js +57 -0
  103. package/dist/core/nodes/IssueNode.d.ts +73 -0
  104. package/dist/core/nodes/IssueNode.d.ts.map +1 -0
  105. package/dist/core/nodes/IssueNode.js +129 -0
  106. package/dist/core/nodes/LiteralNode.d.ts +2 -2
  107. package/dist/core/nodes/LiteralNode.d.ts.map +1 -1
  108. package/dist/core/nodes/LiteralNode.js +6 -4
  109. package/dist/core/nodes/MethodCallNode.d.ts +32 -2
  110. package/dist/core/nodes/MethodCallNode.d.ts.map +1 -1
  111. package/dist/core/nodes/MethodCallNode.js +57 -4
  112. package/dist/core/nodes/MethodNode.d.ts +34 -2
  113. package/dist/core/nodes/MethodNode.d.ts.map +1 -1
  114. package/dist/core/nodes/MethodNode.js +55 -3
  115. package/dist/core/nodes/ModuleNode.d.ts +31 -0
  116. package/dist/core/nodes/ModuleNode.d.ts.map +1 -1
  117. package/dist/core/nodes/ModuleNode.js +37 -0
  118. package/dist/core/nodes/NetworkRequestNode.d.ts +54 -0
  119. package/dist/core/nodes/NetworkRequestNode.d.ts.map +1 -0
  120. package/dist/core/nodes/NetworkRequestNode.js +65 -0
  121. package/dist/core/nodes/ObjectLiteralNode.d.ts +27 -0
  122. package/dist/core/nodes/ObjectLiteralNode.d.ts.map +1 -0
  123. package/dist/core/nodes/ObjectLiteralNode.js +43 -0
  124. package/dist/core/nodes/ParameterNode.d.ts +2 -2
  125. package/dist/core/nodes/ParameterNode.d.ts.map +1 -1
  126. package/dist/core/nodes/ParameterNode.js +5 -3
  127. package/dist/core/nodes/ScopeNode.d.ts +31 -0
  128. package/dist/core/nodes/ScopeNode.d.ts.map +1 -1
  129. package/dist/core/nodes/ScopeNode.js +49 -0
  130. package/dist/core/nodes/TypeNode.d.ts +36 -0
  131. package/dist/core/nodes/TypeNode.d.ts.map +1 -0
  132. package/dist/core/nodes/TypeNode.js +55 -0
  133. package/dist/core/nodes/VariableDeclarationNode.d.ts +29 -2
  134. package/dist/core/nodes/VariableDeclarationNode.d.ts.map +1 -1
  135. package/dist/core/nodes/VariableDeclarationNode.js +48 -4
  136. package/dist/core/nodes/index.d.ts +15 -1
  137. package/dist/core/nodes/index.d.ts.map +1 -1
  138. package/dist/core/nodes/index.js +17 -0
  139. package/dist/data/builtins/BuiltinRegistry.d.ts +78 -0
  140. package/dist/data/builtins/BuiltinRegistry.d.ts.map +1 -0
  141. package/dist/data/builtins/BuiltinRegistry.js +110 -0
  142. package/dist/data/builtins/definitions.d.ts +28 -0
  143. package/dist/data/builtins/definitions.d.ts.map +1 -0
  144. package/dist/data/builtins/definitions.js +250 -0
  145. package/dist/data/builtins/index.d.ts +10 -0
  146. package/dist/data/builtins/index.d.ts.map +1 -0
  147. package/dist/data/builtins/index.js +8 -0
  148. package/dist/data/builtins/jsGlobals.d.ts +18 -0
  149. package/dist/data/builtins/jsGlobals.d.ts.map +1 -0
  150. package/dist/data/builtins/jsGlobals.js +26 -0
  151. package/dist/data/builtins/types.d.ts +34 -0
  152. package/dist/data/builtins/types.d.ts.map +1 -0
  153. package/dist/data/builtins/types.js +7 -0
  154. package/dist/data/globals/definitions.d.ts +27 -0
  155. package/dist/data/globals/definitions.d.ts.map +1 -0
  156. package/dist/data/globals/definitions.js +117 -0
  157. package/dist/data/globals/index.d.ts +36 -0
  158. package/dist/data/globals/index.d.ts.map +1 -0
  159. package/dist/data/globals/index.js +52 -0
  160. package/dist/diagnostics/DiagnosticCollector.d.ts +98 -0
  161. package/dist/diagnostics/DiagnosticCollector.d.ts.map +1 -0
  162. package/dist/diagnostics/DiagnosticCollector.js +129 -0
  163. package/dist/diagnostics/DiagnosticReporter.d.ts +100 -0
  164. package/dist/diagnostics/DiagnosticReporter.d.ts.map +1 -0
  165. package/dist/diagnostics/DiagnosticReporter.js +247 -0
  166. package/dist/diagnostics/DiagnosticWriter.d.ts +31 -0
  167. package/dist/diagnostics/DiagnosticWriter.d.ts.map +1 -0
  168. package/dist/diagnostics/DiagnosticWriter.js +43 -0
  169. package/dist/diagnostics/index.d.ts +14 -0
  170. package/dist/diagnostics/index.d.ts.map +1 -0
  171. package/dist/diagnostics/index.js +11 -0
  172. package/dist/errors/GrafemaError.d.ts +161 -0
  173. package/dist/errors/GrafemaError.d.ts.map +1 -0
  174. package/dist/errors/GrafemaError.js +181 -0
  175. package/dist/index.d.ts +73 -1
  176. package/dist/index.d.ts.map +1 -1
  177. package/dist/index.js +70 -1
  178. package/dist/logging/Logger.d.ts +48 -0
  179. package/dist/logging/Logger.d.ts.map +1 -0
  180. package/dist/logging/Logger.js +134 -0
  181. package/dist/plugins/Plugin.d.ts +5 -1
  182. package/dist/plugins/Plugin.d.ts.map +1 -1
  183. package/dist/plugins/Plugin.js +33 -0
  184. package/dist/plugins/analysis/DatabaseAnalyzer.d.ts.map +1 -1
  185. package/dist/plugins/analysis/DatabaseAnalyzer.js +14 -6
  186. package/dist/plugins/analysis/ExpressAnalyzer.d.ts.map +1 -1
  187. package/dist/plugins/analysis/ExpressAnalyzer.js +29 -19
  188. package/dist/plugins/analysis/ExpressResponseAnalyzer.d.ts +148 -0
  189. package/dist/plugins/analysis/ExpressResponseAnalyzer.d.ts.map +1 -0
  190. package/dist/plugins/analysis/ExpressResponseAnalyzer.js +495 -0
  191. package/dist/plugins/analysis/ExpressRouteAnalyzer.d.ts.map +1 -1
  192. package/dist/plugins/analysis/ExpressRouteAnalyzer.js +71 -29
  193. package/dist/plugins/analysis/FetchAnalyzer.d.ts +41 -0
  194. package/dist/plugins/analysis/FetchAnalyzer.d.ts.map +1 -1
  195. package/dist/plugins/analysis/FetchAnalyzer.js +187 -19
  196. package/dist/plugins/analysis/IncrementalAnalysisPlugin.d.ts +6 -3
  197. package/dist/plugins/analysis/IncrementalAnalysisPlugin.d.ts.map +1 -1
  198. package/dist/plugins/analysis/IncrementalAnalysisPlugin.js +76 -80
  199. package/dist/plugins/analysis/JSASTAnalyzer.d.ts +313 -19
  200. package/dist/plugins/analysis/JSASTAnalyzer.d.ts.map +1 -1
  201. package/dist/plugins/analysis/JSASTAnalyzer.js +3430 -503
  202. package/dist/plugins/analysis/ReactAnalyzer.d.ts.map +1 -1
  203. package/dist/plugins/analysis/ReactAnalyzer.js +56 -57
  204. package/dist/plugins/analysis/RustAnalyzer.d.ts.map +1 -1
  205. package/dist/plugins/analysis/RustAnalyzer.js +16 -11
  206. package/dist/plugins/analysis/SQLiteAnalyzer.d.ts.map +1 -1
  207. package/dist/plugins/analysis/SQLiteAnalyzer.js +11 -7
  208. package/dist/plugins/analysis/ServiceLayerAnalyzer.d.ts.map +1 -1
  209. package/dist/plugins/analysis/ServiceLayerAnalyzer.js +21 -9
  210. package/dist/plugins/analysis/SocketIOAnalyzer.d.ts +9 -0
  211. package/dist/plugins/analysis/SocketIOAnalyzer.d.ts.map +1 -1
  212. package/dist/plugins/analysis/SocketIOAnalyzer.js +117 -21
  213. package/dist/plugins/analysis/SystemDbAnalyzer.d.ts.map +1 -1
  214. package/dist/plugins/analysis/SystemDbAnalyzer.js +15 -5
  215. package/dist/plugins/analysis/ast/GraphBuilder.d.ts +207 -4
  216. package/dist/plugins/analysis/ast/GraphBuilder.d.ts.map +1 -1
  217. package/dist/plugins/analysis/ast/GraphBuilder.js +1527 -316
  218. package/dist/plugins/analysis/ast/IdGenerator.d.ts +105 -0
  219. package/dist/plugins/analysis/ast/IdGenerator.d.ts.map +1 -0
  220. package/dist/plugins/analysis/ast/IdGenerator.js +116 -0
  221. package/dist/plugins/analysis/ast/types.d.ts +470 -5
  222. package/dist/plugins/analysis/ast/types.d.ts.map +1 -1
  223. package/dist/plugins/analysis/ast/utils/createParameterNodes.d.ts +33 -0
  224. package/dist/plugins/analysis/ast/utils/createParameterNodes.d.ts.map +1 -0
  225. package/dist/plugins/analysis/ast/utils/createParameterNodes.js +89 -0
  226. package/dist/plugins/analysis/ast/utils/index.d.ts +6 -0
  227. package/dist/plugins/analysis/ast/utils/index.d.ts.map +1 -0
  228. package/dist/plugins/analysis/ast/utils/index.js +5 -0
  229. package/dist/plugins/analysis/ast/utils/location.d.ts +87 -0
  230. package/dist/plugins/analysis/ast/utils/location.d.ts.map +1 -0
  231. package/dist/plugins/analysis/ast/utils/location.js +78 -0
  232. package/dist/plugins/analysis/ast/visitors/ASTVisitor.d.ts +14 -5
  233. package/dist/plugins/analysis/ast/visitors/ASTVisitor.d.ts.map +1 -1
  234. package/dist/plugins/analysis/ast/visitors/ASTVisitor.js +6 -5
  235. package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts +100 -9
  236. package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts.map +1 -1
  237. package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.js +674 -125
  238. package/dist/plugins/analysis/ast/visitors/ClassVisitor.d.ts +4 -1
  239. package/dist/plugins/analysis/ast/visitors/ClassVisitor.d.ts.map +1 -1
  240. package/dist/plugins/analysis/ast/visitors/ClassVisitor.js +72 -32
  241. package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts +14 -1
  242. package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts.map +1 -1
  243. package/dist/plugins/analysis/ast/visitors/FunctionVisitor.js +190 -63
  244. package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.d.ts +4 -0
  245. package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.d.ts.map +1 -1
  246. package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.js +112 -8
  247. package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.d.ts +12 -1
  248. package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.d.ts.map +1 -1
  249. package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.js +36 -14
  250. package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts +20 -2
  251. package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts.map +1 -1
  252. package/dist/plugins/analysis/ast/visitors/VariableVisitor.js +243 -45
  253. package/dist/plugins/discovery/MonorepoServiceDiscovery.d.ts.map +1 -1
  254. package/dist/plugins/discovery/MonorepoServiceDiscovery.js +3 -2
  255. package/dist/plugins/discovery/SimpleProjectDiscovery.d.ts.map +1 -1
  256. package/dist/plugins/discovery/SimpleProjectDiscovery.js +5 -1
  257. package/dist/plugins/discovery/WorkspaceDiscovery.d.ts +22 -0
  258. package/dist/plugins/discovery/WorkspaceDiscovery.d.ts.map +1 -0
  259. package/dist/plugins/discovery/WorkspaceDiscovery.js +141 -0
  260. package/dist/plugins/discovery/resolveSourceEntrypoint.d.ts +46 -0
  261. package/dist/plugins/discovery/resolveSourceEntrypoint.d.ts.map +1 -0
  262. package/dist/plugins/discovery/resolveSourceEntrypoint.js +86 -0
  263. package/dist/plugins/discovery/workspaces/detector.d.ts +21 -0
  264. package/dist/plugins/discovery/workspaces/detector.d.ts.map +1 -0
  265. package/dist/plugins/discovery/workspaces/detector.js +49 -0
  266. package/dist/plugins/discovery/workspaces/globResolver.d.ts +35 -0
  267. package/dist/plugins/discovery/workspaces/globResolver.d.ts.map +1 -0
  268. package/dist/plugins/discovery/workspaces/globResolver.js +184 -0
  269. package/dist/plugins/discovery/workspaces/index.d.ts +9 -0
  270. package/dist/plugins/discovery/workspaces/index.d.ts.map +1 -0
  271. package/dist/plugins/discovery/workspaces/index.js +8 -0
  272. package/dist/plugins/discovery/workspaces/parsers.d.ts +38 -0
  273. package/dist/plugins/discovery/workspaces/parsers.d.ts.map +1 -0
  274. package/dist/plugins/discovery/workspaces/parsers.js +80 -0
  275. package/dist/plugins/enrichment/AliasTracker.d.ts.map +1 -1
  276. package/dist/plugins/enrichment/AliasTracker.js +29 -8
  277. package/dist/plugins/enrichment/ArgumentParameterLinker.d.ts +32 -0
  278. package/dist/plugins/enrichment/ArgumentParameterLinker.d.ts.map +1 -0
  279. package/dist/plugins/enrichment/ArgumentParameterLinker.js +175 -0
  280. package/dist/plugins/enrichment/ClosureCaptureEnricher.d.ts +51 -0
  281. package/dist/plugins/enrichment/ClosureCaptureEnricher.d.ts.map +1 -0
  282. package/dist/plugins/enrichment/ClosureCaptureEnricher.js +205 -0
  283. package/dist/plugins/enrichment/ExternalCallResolver.d.ts +42 -0
  284. package/dist/plugins/enrichment/ExternalCallResolver.d.ts.map +1 -0
  285. package/dist/plugins/enrichment/ExternalCallResolver.js +213 -0
  286. package/dist/plugins/enrichment/FunctionCallResolver.d.ts +58 -0
  287. package/dist/plugins/enrichment/FunctionCallResolver.d.ts.map +1 -0
  288. package/dist/plugins/enrichment/FunctionCallResolver.js +340 -0
  289. package/dist/plugins/enrichment/HTTPConnectionEnricher.d.ts +16 -3
  290. package/dist/plugins/enrichment/HTTPConnectionEnricher.d.ts.map +1 -1
  291. package/dist/plugins/enrichment/HTTPConnectionEnricher.js +78 -27
  292. package/dist/plugins/enrichment/ImportExportLinker.d.ts.map +1 -1
  293. package/dist/plugins/enrichment/ImportExportLinker.js +23 -6
  294. package/dist/plugins/enrichment/MethodCallResolver.d.ts.map +1 -1
  295. package/dist/plugins/enrichment/MethodCallResolver.js +33 -13
  296. package/dist/plugins/enrichment/MountPointResolver.d.ts +14 -12
  297. package/dist/plugins/enrichment/MountPointResolver.d.ts.map +1 -1
  298. package/dist/plugins/enrichment/MountPointResolver.js +173 -147
  299. package/dist/plugins/enrichment/NodejsBuiltinsResolver.d.ts +44 -0
  300. package/dist/plugins/enrichment/NodejsBuiltinsResolver.d.ts.map +1 -0
  301. package/dist/plugins/enrichment/NodejsBuiltinsResolver.js +271 -0
  302. package/dist/plugins/enrichment/PrefixEvaluator.d.ts.map +1 -1
  303. package/dist/plugins/enrichment/PrefixEvaluator.js +16 -7
  304. package/dist/plugins/enrichment/RustFFIEnricher.d.ts.map +1 -1
  305. package/dist/plugins/enrichment/RustFFIEnricher.js +6 -5
  306. package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts +22 -27
  307. package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts.map +1 -1
  308. package/dist/plugins/enrichment/ValueDomainAnalyzer.js +185 -143
  309. package/dist/plugins/indexing/IncrementalModuleIndexer.d.ts.map +1 -1
  310. package/dist/plugins/indexing/IncrementalModuleIndexer.js +23 -14
  311. package/dist/plugins/indexing/JSModuleIndexer.d.ts +15 -0
  312. package/dist/plugins/indexing/JSModuleIndexer.d.ts.map +1 -1
  313. package/dist/plugins/indexing/JSModuleIndexer.js +121 -31
  314. package/dist/plugins/indexing/RustModuleIndexer.d.ts +1 -1
  315. package/dist/plugins/indexing/RustModuleIndexer.d.ts.map +1 -1
  316. package/dist/plugins/indexing/RustModuleIndexer.js +8 -7
  317. package/dist/plugins/indexing/ServiceDetector.d.ts +10 -0
  318. package/dist/plugins/indexing/ServiceDetector.d.ts.map +1 -1
  319. package/dist/plugins/indexing/ServiceDetector.js +28 -15
  320. package/dist/plugins/validation/BrokenImportValidator.d.ts +31 -0
  321. package/dist/plugins/validation/BrokenImportValidator.d.ts.map +1 -0
  322. package/dist/plugins/validation/BrokenImportValidator.js +249 -0
  323. package/dist/plugins/validation/CallResolverValidator.d.ts +21 -10
  324. package/dist/plugins/validation/CallResolverValidator.d.ts.map +1 -1
  325. package/dist/plugins/validation/CallResolverValidator.js +103 -77
  326. package/dist/plugins/validation/DataFlowValidator.d.ts.map +1 -1
  327. package/dist/plugins/validation/DataFlowValidator.js +62 -49
  328. package/dist/plugins/validation/EvalBanValidator.d.ts.map +1 -1
  329. package/dist/plugins/validation/EvalBanValidator.js +17 -16
  330. package/dist/plugins/validation/GraphConnectivityValidator.d.ts.map +1 -1
  331. package/dist/plugins/validation/GraphConnectivityValidator.js +44 -24
  332. package/dist/plugins/validation/NodeCreationValidator.d.ts +85 -0
  333. package/dist/plugins/validation/NodeCreationValidator.d.ts.map +1 -0
  334. package/dist/plugins/validation/NodeCreationValidator.js +415 -0
  335. package/dist/plugins/validation/SQLInjectionValidator.d.ts.map +1 -1
  336. package/dist/plugins/validation/SQLInjectionValidator.js +61 -19
  337. package/dist/plugins/validation/ShadowingDetector.d.ts.map +1 -1
  338. package/dist/plugins/validation/ShadowingDetector.js +6 -5
  339. package/dist/plugins/validation/TypeScriptDeadCodeValidator.d.ts.map +1 -1
  340. package/dist/plugins/validation/TypeScriptDeadCodeValidator.js +12 -11
  341. package/dist/plugins/vcs/GitPlugin.d.ts.map +1 -1
  342. package/dist/plugins/vcs/GitPlugin.js +10 -12
  343. package/dist/plugins/vcs/VCSPlugin.d.ts +3 -2
  344. package/dist/plugins/vcs/VCSPlugin.d.ts.map +1 -1
  345. package/dist/plugins/vcs/VCSPlugin.js +5 -5
  346. package/dist/queries/findCallsInFunction.d.ts +52 -0
  347. package/dist/queries/findCallsInFunction.d.ts.map +1 -0
  348. package/dist/queries/findCallsInFunction.js +135 -0
  349. package/dist/queries/findContainingFunction.d.ts +45 -0
  350. package/dist/queries/findContainingFunction.d.ts.map +1 -0
  351. package/dist/queries/findContainingFunction.js +54 -0
  352. package/dist/queries/index.d.ts +14 -0
  353. package/dist/queries/index.d.ts.map +1 -0
  354. package/dist/queries/index.js +11 -0
  355. package/dist/queries/traceValues.d.ts +70 -0
  356. package/dist/queries/traceValues.d.ts.map +1 -0
  357. package/dist/queries/traceValues.js +299 -0
  358. package/dist/queries/types.d.ts +163 -0
  359. package/dist/queries/types.d.ts.map +1 -0
  360. package/dist/queries/types.js +9 -0
  361. package/dist/schema/GraphSchemaExtractor.d.ts +53 -0
  362. package/dist/schema/GraphSchemaExtractor.d.ts.map +1 -0
  363. package/dist/schema/GraphSchemaExtractor.js +124 -0
  364. package/dist/schema/InterfaceSchemaExtractor.d.ts +73 -0
  365. package/dist/schema/InterfaceSchemaExtractor.d.ts.map +1 -0
  366. package/dist/schema/InterfaceSchemaExtractor.js +112 -0
  367. package/dist/schema/index.d.ts +5 -0
  368. package/dist/schema/index.d.ts.map +1 -0
  369. package/dist/schema/index.js +2 -0
  370. package/dist/storage/backends/RFDBServerBackend.d.ts +21 -34
  371. package/dist/storage/backends/RFDBServerBackend.d.ts.map +1 -1
  372. package/dist/storage/backends/RFDBServerBackend.js +72 -62
  373. package/dist/storage/backends/typeValidation.d.ts.map +1 -1
  374. package/dist/storage/backends/typeValidation.js +1 -0
  375. package/dist/validation/PathValidator.d.ts +1 -2
  376. package/dist/validation/PathValidator.d.ts.map +1 -1
  377. package/package.json +3 -3
  378. package/src/Orchestrator.ts +272 -27
  379. package/src/config/ConfigLoader.ts +354 -0
  380. package/src/config/index.ts +5 -0
  381. package/src/core/ASTWorker.ts +143 -139
  382. package/src/core/CoverageAnalyzer.ts +243 -0
  383. package/src/core/FileExplainer.ts +179 -0
  384. package/src/core/FileNodeManager.ts +100 -0
  385. package/src/core/GraphFreshnessChecker.ts +143 -0
  386. package/src/core/HashUtils.ts +48 -0
  387. package/src/core/IncrementalReanalyzer.ts +192 -0
  388. package/src/core/NodeFactory.ts +470 -23
  389. package/src/core/ScopeTracker.ts +154 -0
  390. package/src/core/SemanticId.ts +192 -0
  391. package/src/core/VersionManager.ts +3 -2
  392. package/src/core/nodes/ArgumentExpressionNode.ts +89 -0
  393. package/src/core/nodes/ArrayLiteralNode.ts +66 -0
  394. package/src/core/nodes/BranchNode.ts +113 -0
  395. package/src/core/nodes/CallSiteNode.ts +64 -4
  396. package/src/core/nodes/CaseNode.ts +123 -0
  397. package/src/core/nodes/ClassNode.ts +67 -4
  398. package/src/core/nodes/ConstantNode.ts +5 -4
  399. package/src/core/nodes/ConstructorCallNode.ts +217 -0
  400. package/src/core/nodes/DatabaseQueryNode.ts +5 -1
  401. package/src/core/nodes/DecoratorNode.ts +92 -0
  402. package/src/core/nodes/EnumNode.ts +87 -0
  403. package/src/core/nodes/EventListenerNode.ts +7 -4
  404. package/src/core/nodes/ExportNode.ts +74 -4
  405. package/src/core/nodes/ExpressionNode.ts +232 -0
  406. package/src/core/nodes/ExternalModuleNode.ts +65 -0
  407. package/src/core/nodes/ExternalStdioNode.ts +17 -9
  408. package/src/core/nodes/FunctionNode.ts +101 -1
  409. package/src/core/nodes/HttpRequestNode.ts +7 -4
  410. package/src/core/nodes/ImportNode.ts +62 -13
  411. package/src/core/nodes/InterfaceNode.ts +92 -0
  412. package/src/core/nodes/IssueNode.ts +177 -0
  413. package/src/core/nodes/LiteralNode.ts +5 -4
  414. package/src/core/nodes/MethodCallNode.ts +70 -4
  415. package/src/core/nodes/MethodNode.ts +68 -3
  416. package/src/core/nodes/ModuleNode.ts +50 -0
  417. package/src/core/nodes/NetworkRequestNode.ts +77 -0
  418. package/src/core/nodes/ObjectLiteralNode.ts +66 -0
  419. package/src/core/nodes/ParameterNode.ts +4 -3
  420. package/src/core/nodes/ScopeNode.ts +65 -0
  421. package/src/core/nodes/TypeNode.ts +79 -0
  422. package/src/core/nodes/VariableDeclarationNode.ts +58 -4
  423. package/src/core/nodes/index.ts +21 -1
  424. package/src/data/builtins/BuiltinRegistry.ts +124 -0
  425. package/src/data/builtins/definitions.ts +267 -0
  426. package/src/data/builtins/index.ts +10 -0
  427. package/src/data/builtins/jsGlobals.ts +28 -0
  428. package/src/data/builtins/types.ts +36 -0
  429. package/src/data/globals/definitions.ts +156 -0
  430. package/src/data/globals/index.ts +66 -0
  431. package/src/diagnostics/DiagnosticCollector.ts +163 -0
  432. package/src/diagnostics/DiagnosticReporter.ts +324 -0
  433. package/src/diagnostics/DiagnosticWriter.ts +50 -0
  434. package/src/diagnostics/index.ts +16 -0
  435. package/src/errors/GrafemaError.ts +239 -0
  436. package/src/index.ts +193 -1
  437. package/src/logging/Logger.ts +152 -0
  438. package/src/plugins/Plugin.ts +42 -0
  439. package/src/plugins/analysis/DatabaseAnalyzer.ts +16 -8
  440. package/src/plugins/analysis/ExpressAnalyzer.ts +33 -19
  441. package/src/plugins/analysis/ExpressResponseAnalyzer.ts +636 -0
  442. package/src/plugins/analysis/ExpressRouteAnalyzer.ts +76 -36
  443. package/src/plugins/analysis/FetchAnalyzer.ts +232 -21
  444. package/src/plugins/analysis/IncrementalAnalysisPlugin.ts +84 -101
  445. package/src/plugins/analysis/JSASTAnalyzer.ts +4265 -587
  446. package/src/plugins/analysis/ReactAnalyzer.ts +57 -57
  447. package/src/plugins/analysis/RustAnalyzer.ts +16 -11
  448. package/src/plugins/analysis/SQLiteAnalyzer.ts +13 -7
  449. package/src/plugins/analysis/ServiceLayerAnalyzer.ts +22 -16
  450. package/src/plugins/analysis/SocketIOAnalyzer.ts +151 -28
  451. package/src/plugins/analysis/SystemDbAnalyzer.ts +16 -11
  452. package/src/plugins/analysis/ast/GraphBuilder.ts +1947 -327
  453. package/src/plugins/analysis/ast/IdGenerator.ts +177 -0
  454. package/src/plugins/analysis/ast/types.ts +596 -6
  455. package/src/plugins/analysis/ast/utils/createParameterNodes.ts +104 -0
  456. package/src/plugins/analysis/ast/utils/index.ts +12 -0
  457. package/src/plugins/analysis/ast/utils/location.ts +103 -0
  458. package/src/plugins/analysis/ast/visitors/ASTVisitor.ts +19 -8
  459. package/src/plugins/analysis/ast/visitors/CallExpressionVisitor.ts +924 -83
  460. package/src/plugins/analysis/ast/visitors/ClassVisitor.ts +97 -44
  461. package/src/plugins/analysis/ast/visitors/FunctionVisitor.ts +234 -93
  462. package/src/plugins/analysis/ast/visitors/ImportExportVisitor.ts +124 -9
  463. package/src/plugins/analysis/ast/visitors/TypeScriptVisitor.ts +41 -14
  464. package/src/plugins/analysis/ast/visitors/VariableVisitor.ts +294 -49
  465. package/src/plugins/discovery/MonorepoServiceDiscovery.ts +3 -2
  466. package/src/plugins/discovery/SimpleProjectDiscovery.ts +6 -1
  467. package/src/plugins/discovery/WorkspaceDiscovery.ts +184 -0
  468. package/src/plugins/discovery/resolveSourceEntrypoint.ts +103 -0
  469. package/src/plugins/discovery/workspaces/detector.ts +63 -0
  470. package/src/plugins/discovery/workspaces/globResolver.ts +229 -0
  471. package/src/plugins/discovery/workspaces/index.ts +23 -0
  472. package/src/plugins/discovery/workspaces/parsers.ts +99 -0
  473. package/src/plugins/enrichment/AliasTracker.ts +35 -8
  474. package/src/plugins/enrichment/ArgumentParameterLinker.ts +240 -0
  475. package/src/plugins/enrichment/ClosureCaptureEnricher.ts +267 -0
  476. package/src/plugins/enrichment/ExternalCallResolver.ts +262 -0
  477. package/src/plugins/enrichment/FunctionCallResolver.ts +456 -0
  478. package/src/plugins/enrichment/HTTPConnectionEnricher.ts +84 -27
  479. package/src/plugins/enrichment/ImportExportLinker.ts +24 -6
  480. package/src/plugins/enrichment/MethodCallResolver.ts +39 -13
  481. package/src/plugins/enrichment/MountPointResolver.ts +208 -195
  482. package/src/plugins/enrichment/NodejsBuiltinsResolver.ts +365 -0
  483. package/src/plugins/enrichment/PrefixEvaluator.ts +16 -7
  484. package/src/plugins/enrichment/RustFFIEnricher.ts +6 -5
  485. package/src/plugins/enrichment/ValueDomainAnalyzer.ts +209 -189
  486. package/src/plugins/indexing/IncrementalModuleIndexer.ts +23 -14
  487. package/src/plugins/indexing/JSModuleIndexer.ts +140 -34
  488. package/src/plugins/indexing/RustModuleIndexer.ts +8 -7
  489. package/src/plugins/validation/BrokenImportValidator.ts +325 -0
  490. package/src/plugins/validation/CallResolverValidator.ts +131 -110
  491. package/src/plugins/validation/DataFlowValidator.ts +88 -67
  492. package/src/plugins/validation/EvalBanValidator.ts +17 -16
  493. package/src/plugins/validation/GraphConnectivityValidator.ts +58 -24
  494. package/src/plugins/validation/NodeCreationValidator.ts +554 -0
  495. package/src/plugins/validation/SQLInjectionValidator.ts +63 -20
  496. package/src/plugins/validation/ShadowingDetector.ts +6 -5
  497. package/src/plugins/validation/TypeScriptDeadCodeValidator.ts +12 -11
  498. package/src/plugins/vcs/GitPlugin.ts +40 -12
  499. package/src/plugins/vcs/VCSPlugin.ts +7 -5
  500. package/src/queries/README.md +46 -0
  501. package/src/queries/findCallsInFunction.ts +206 -0
  502. package/src/queries/findContainingFunction.ts +83 -0
  503. package/src/queries/index.ts +23 -0
  504. package/src/queries/traceValues.ts +398 -0
  505. package/src/queries/types.ts +187 -0
  506. package/src/schema/GraphSchemaExtractor.ts +177 -0
  507. package/src/schema/InterfaceSchemaExtractor.ts +173 -0
  508. package/src/schema/index.ts +5 -0
  509. package/src/storage/backends/RFDBServerBackend.ts +100 -98
  510. package/src/storage/backends/typeValidation.ts +1 -0
  511. package/src/validation/PathValidator.ts +1 -1
  512. package/dist/core/AnalysisWorker.d.ts +0 -14
  513. package/dist/core/AnalysisWorker.d.ts.map +0 -1
  514. package/dist/core/AnalysisWorker.js +0 -307
  515. package/dist/core/ParallelAnalyzer.d.ts +0 -120
  516. package/dist/core/ParallelAnalyzer.d.ts.map +0 -1
  517. package/dist/core/ParallelAnalyzer.js +0 -331
  518. package/dist/core/QueueWorker.d.ts +0 -12
  519. package/dist/core/QueueWorker.d.ts.map +0 -1
  520. package/dist/core/QueueWorker.js +0 -567
  521. package/dist/core/RFDBClient.d.ts +0 -179
  522. package/dist/core/RFDBClient.d.ts.map +0 -1
  523. package/dist/core/RFDBClient.js +0 -429
  524. package/dist/plugins/discovery/ZonServiceDiscovery.d.ts +0 -19
  525. package/dist/plugins/discovery/ZonServiceDiscovery.d.ts.map +0 -1
  526. package/dist/plugins/discovery/ZonServiceDiscovery.js +0 -204
  527. package/src/core/AnalysisWorker.ts +0 -410
  528. package/src/core/ParallelAnalyzer.ts +0 -476
  529. package/src/core/QueueWorker.ts +0 -780
  530. 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
- constructor(module, collections) {
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
- // Literal value
35
- const literalValue = ExpressionEvaluator.extractLiteralValue(actualArg);
36
- if (literalValue !== null) {
37
- const literalId = `LITERAL#arg${index}#${module.file}#${argInfo.line}:${argInfo.column}:${literalCounterRef.value++}`;
38
- literals.push({
39
- id: literalId,
40
- type: 'LITERAL',
41
- value: literalValue,
42
- valueType: typeof literalValue,
43
- file: module.file,
44
- line: argInfo.line,
45
- column: argInfo.column,
46
- parentCallId: callId,
47
- argIndex: index
48
- });
49
- argInfo.targetType = 'LITERAL';
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
- argInfo.targetType = 'EXPRESSION';
103
- argInfo.targetId = expressionId;
104
- argInfo.expressionType = actualArg.type;
105
- // Track DERIVES_FROM edges for identifiers in expression
106
- const identifiers = this.extractIdentifiers(actualArg);
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
- // Other expression types
112
+ // Literal value (primitives only - objects/arrays handled above)
129
113
  else {
130
- argInfo.targetType = 'EXPRESSION';
131
- argInfo.expressionType = actualArg.type;
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,446 @@ export class CallExpressionVisitor extends ASTVisitor {
186
252
  return Array.from(identifiers);
187
253
  }
188
254
  /**
189
- * Get a stable scope ID for a function parent
190
- * Format must match what FunctionVisitor creates:
191
- * - FunctionDeclaration: FUNCTION#name#file#line
192
- * - ArrowFunctionExpression: FUNCTION#name#file#line:col:counter
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
+ // REG-329: Capture scope path for spread variable resolution
276
+ propertyInfo.valueScopePath = this.scopeTracker?.getContext().scopePath ?? [];
277
+ }
278
+ objectProperties.push(propertyInfo);
279
+ continue;
280
+ }
281
+ // Handle regular properties
282
+ if (prop.type === 'ObjectProperty') {
283
+ const objProp = prop;
284
+ let propertyName;
285
+ // Get property name
286
+ if (objProp.key.type === 'Identifier') {
287
+ propertyName = objProp.key.name;
288
+ }
289
+ else if (objProp.key.type === 'StringLiteral') {
290
+ propertyName = objProp.key.value;
291
+ }
292
+ else if (objProp.key.type === 'NumericLiteral') {
293
+ propertyName = String(objProp.key.value);
294
+ }
295
+ else {
296
+ propertyName = '<computed>';
297
+ }
298
+ const propertyInfo = {
299
+ objectId,
300
+ propertyName,
301
+ file: module.file,
302
+ line: propLine,
303
+ column: propColumn,
304
+ valueType: 'EXPRESSION'
305
+ };
306
+ const value = objProp.value;
307
+ // Nested object literal - check BEFORE extractLiteralValue
308
+ if (value.type === 'ObjectExpression') {
309
+ // Use factory - do NOT pass argIndex for nested literals (uses 'obj' suffix)
310
+ const nestedObjectNode = ObjectLiteralNode.create(module.file, value.loc?.start.line || 0, value.loc?.start.column || 0, {
311
+ counter: objectLiteralCounterRef.value++
312
+ });
313
+ objectLiterals.push(nestedObjectNode);
314
+ const nestedObjectId = nestedObjectNode.id;
315
+ // Recursively extract nested properties
316
+ this.extractObjectProperties(value, nestedObjectId, module, objectProperties, objectLiterals, objectLiteralCounterRef, literals, literalCounterRef);
317
+ propertyInfo.valueType = 'OBJECT_LITERAL';
318
+ propertyInfo.nestedObjectId = nestedObjectId;
319
+ propertyInfo.valueNodeId = nestedObjectId;
320
+ }
321
+ // Nested array literal - check BEFORE extractLiteralValue
322
+ else if (value.type === 'ArrayExpression') {
323
+ const arrayLiteralCounterRef = (this.collections.arrayLiteralCounterRef ?? { value: 0 });
324
+ const arrayLiterals = this.collections.arrayLiterals ?? [];
325
+ const arrayElements = this.collections.arrayElements ?? [];
326
+ // Use factory - do NOT pass argIndex for nested literals (uses 'arr' suffix)
327
+ const nestedArrayNode = ArrayLiteralNode.create(module.file, value.loc?.start.line || 0, value.loc?.start.column || 0, {
328
+ counter: arrayLiteralCounterRef.value++
329
+ });
330
+ arrayLiterals.push(nestedArrayNode);
331
+ const nestedArrayId = nestedArrayNode.id;
332
+ // Recursively extract array elements
333
+ this.extractArrayElements(value, nestedArrayId, module, arrayElements, arrayLiterals, arrayLiteralCounterRef, objectLiterals, objectLiteralCounterRef, objectProperties, literals, literalCounterRef);
334
+ propertyInfo.valueType = 'ARRAY_LITERAL';
335
+ propertyInfo.nestedArrayId = nestedArrayId;
336
+ propertyInfo.valueNodeId = nestedArrayId;
337
+ }
338
+ // Literal value (primitives only - objects/arrays handled above)
339
+ else {
340
+ const literalValue = ExpressionEvaluator.extractLiteralValue(value);
341
+ // Handle both non-null literals AND explicit null literals (NullLiteral)
342
+ if (literalValue !== null || value.type === 'NullLiteral') {
343
+ const literalId = `LITERAL#${propertyName}#${module.file}#${propLine}:${propColumn}:${literalCounterRef.value++}`;
344
+ literals.push({
345
+ id: literalId,
346
+ type: 'LITERAL',
347
+ value: literalValue,
348
+ valueType: typeof literalValue,
349
+ file: module.file,
350
+ line: propLine,
351
+ column: propColumn,
352
+ parentCallId: objectId,
353
+ argIndex: 0
354
+ });
355
+ propertyInfo.valueType = 'LITERAL';
356
+ propertyInfo.valueNodeId = literalId;
357
+ propertyInfo.literalValue = literalValue;
358
+ }
359
+ // Variable reference
360
+ else if (value.type === 'Identifier') {
361
+ propertyInfo.valueType = 'VARIABLE';
362
+ propertyInfo.valueName = value.name;
363
+ // REG-329: Capture scope path for scope-aware variable resolution
364
+ propertyInfo.valueScopePath = this.scopeTracker?.getContext().scopePath ?? [];
365
+ }
366
+ // Call expression
367
+ else if (value.type === 'CallExpression') {
368
+ propertyInfo.valueType = 'CALL';
369
+ propertyInfo.callLine = value.loc?.start.line;
370
+ propertyInfo.callColumn = value.loc?.start.column;
371
+ }
372
+ // Other expressions
373
+ else {
374
+ propertyInfo.valueType = 'EXPRESSION';
375
+ }
376
+ }
377
+ objectProperties.push(propertyInfo);
378
+ }
379
+ // Handle object methods: { foo() {} }
380
+ else if (prop.type === 'ObjectMethod') {
381
+ const propertyName = prop.key.type === 'Identifier' ? prop.key.name : '<computed>';
382
+ objectProperties.push({
383
+ objectId,
384
+ propertyName,
385
+ valueType: 'EXPRESSION',
386
+ file: module.file,
387
+ line: propLine,
388
+ column: propColumn
389
+ });
390
+ }
391
+ }
392
+ }
393
+ /**
394
+ * Extract array elements and create ArrayElementInfo records
395
+ */
396
+ extractArrayElements(arrayExpr, arrayId, module, arrayElements, arrayLiterals, arrayLiteralCounterRef, objectLiterals, objectLiteralCounterRef, objectProperties, literals, literalCounterRef) {
397
+ arrayExpr.elements.forEach((element, index) => {
398
+ if (!element)
399
+ return; // Skip holes in arrays
400
+ const elemLine = element.loc?.start.line || 0;
401
+ const elemColumn = element.loc?.start.column || 0;
402
+ const elementInfo = {
403
+ arrayId,
404
+ index,
405
+ file: module.file,
406
+ line: elemLine,
407
+ column: elemColumn,
408
+ valueType: 'EXPRESSION'
409
+ };
410
+ // Handle spread elements: [...arr]
411
+ if (element.type === 'SpreadElement') {
412
+ const spreadArg = element.argument;
413
+ elementInfo.valueType = 'SPREAD';
414
+ if (spreadArg.type === 'Identifier') {
415
+ elementInfo.valueName = spreadArg.name;
416
+ }
417
+ arrayElements.push(elementInfo);
418
+ return;
419
+ }
420
+ // Nested object literal - check BEFORE extractLiteralValue
421
+ if (element.type === 'ObjectExpression') {
422
+ // Use factory - do NOT pass argIndex for nested literals (uses 'obj' suffix)
423
+ const nestedObjectNode = ObjectLiteralNode.create(module.file, elemLine, elemColumn, {
424
+ counter: objectLiteralCounterRef.value++
425
+ });
426
+ objectLiterals.push(nestedObjectNode);
427
+ const nestedObjectId = nestedObjectNode.id;
428
+ // Recursively extract properties
429
+ this.extractObjectProperties(element, nestedObjectId, module, objectProperties, objectLiterals, objectLiteralCounterRef, literals, literalCounterRef);
430
+ elementInfo.valueType = 'OBJECT_LITERAL';
431
+ elementInfo.nestedObjectId = nestedObjectId;
432
+ elementInfo.valueNodeId = nestedObjectId;
433
+ }
434
+ // Nested array literal - check BEFORE extractLiteralValue
435
+ else if (element.type === 'ArrayExpression') {
436
+ // Use factory - do NOT pass argIndex for nested literals (uses 'arr' suffix)
437
+ const nestedArrayNode = ArrayLiteralNode.create(module.file, elemLine, elemColumn, {
438
+ counter: arrayLiteralCounterRef.value++
439
+ });
440
+ arrayLiterals.push(nestedArrayNode);
441
+ const nestedArrayId = nestedArrayNode.id;
442
+ // Recursively extract elements
443
+ this.extractArrayElements(element, nestedArrayId, module, arrayElements, arrayLiterals, arrayLiteralCounterRef, objectLiterals, objectLiteralCounterRef, objectProperties, literals, literalCounterRef);
444
+ elementInfo.valueType = 'ARRAY_LITERAL';
445
+ elementInfo.nestedArrayId = nestedArrayId;
446
+ elementInfo.valueNodeId = nestedArrayId;
447
+ }
448
+ // Literal value (primitives only - objects/arrays handled above)
449
+ else {
450
+ const literalValue = ExpressionEvaluator.extractLiteralValue(element);
451
+ if (literalValue !== null) {
452
+ const literalId = `LITERAL#elem${index}#${module.file}#${elemLine}:${elemColumn}:${literalCounterRef.value++}`;
453
+ literals.push({
454
+ id: literalId,
455
+ type: 'LITERAL',
456
+ value: literalValue,
457
+ valueType: typeof literalValue,
458
+ file: module.file,
459
+ line: elemLine,
460
+ column: elemColumn,
461
+ parentCallId: arrayId,
462
+ argIndex: index
463
+ });
464
+ elementInfo.valueType = 'LITERAL';
465
+ elementInfo.valueNodeId = literalId;
466
+ elementInfo.literalValue = literalValue;
467
+ }
468
+ // Variable reference
469
+ else if (element.type === 'Identifier') {
470
+ elementInfo.valueType = 'VARIABLE';
471
+ elementInfo.valueName = element.name;
472
+ }
473
+ // Call expression
474
+ else if (element.type === 'CallExpression') {
475
+ elementInfo.valueType = 'CALL';
476
+ elementInfo.callLine = element.loc?.start.line;
477
+ elementInfo.callColumn = element.loc?.start.column;
478
+ }
479
+ // Other expressions
480
+ else {
481
+ elementInfo.valueType = 'EXPRESSION';
482
+ }
483
+ }
484
+ arrayElements.push(elementInfo);
485
+ });
486
+ }
487
+ /**
488
+ * Detect array mutation calls (push, unshift, splice) and collect mutation info
489
+ * for later FLOWS_INTO edge creation in GraphBuilder
490
+ *
491
+ * REG-117: Added isNested, baseObjectName, propertyName for nested mutations
492
+ */
493
+ detectArrayMutation(callNode, arrayName, method, module, isNested, baseObjectName, propertyName) {
494
+ // Initialize collection if not exists
495
+ if (!this.collections.arrayMutations) {
496
+ this.collections.arrayMutations = [];
497
+ }
498
+ const arrayMutations = this.collections.arrayMutations;
499
+ const mutationArgs = [];
500
+ // For splice, only arguments from index 2 onwards are insertions
501
+ // splice(start, deleteCount, item1, item2, ...)
502
+ callNode.arguments.forEach((arg, index) => {
503
+ // Skip start and deleteCount for splice
504
+ if (method === 'splice' && index < 2)
505
+ return;
506
+ const argInfo = {
507
+ argIndex: method === 'splice' ? index - 2 : index,
508
+ isSpread: arg.type === 'SpreadElement',
509
+ valueType: 'EXPRESSION' // Default
510
+ };
511
+ let actualArg = arg;
512
+ if (arg.type === 'SpreadElement') {
513
+ actualArg = arg.argument;
514
+ }
515
+ // Determine value type
516
+ const literalValue = ExpressionEvaluator.extractLiteralValue(actualArg);
517
+ if (literalValue !== null) {
518
+ argInfo.valueType = 'LITERAL';
519
+ argInfo.literalValue = literalValue;
520
+ }
521
+ else if (actualArg.type === 'Identifier') {
522
+ argInfo.valueType = 'VARIABLE';
523
+ argInfo.valueName = actualArg.name;
524
+ }
525
+ else if (actualArg.type === 'ObjectExpression') {
526
+ argInfo.valueType = 'OBJECT_LITERAL';
527
+ }
528
+ else if (actualArg.type === 'ArrayExpression') {
529
+ argInfo.valueType = 'ARRAY_LITERAL';
530
+ }
531
+ else if (actualArg.type === 'CallExpression') {
532
+ argInfo.valueType = 'CALL';
533
+ argInfo.callLine = actualArg.loc?.start.line;
534
+ argInfo.callColumn = actualArg.loc?.start.column;
535
+ }
536
+ mutationArgs.push(argInfo);
537
+ });
538
+ // Only record if there are actual insertions
539
+ if (mutationArgs.length > 0) {
540
+ const line = callNode.loc?.start.line ?? 0;
541
+ const column = callNode.loc?.start.column ?? 0;
542
+ // Generate semantic ID for array mutation if scopeTracker available
543
+ const scopeTracker = this.scopeTracker;
544
+ let mutationId;
545
+ // Capture scope path for scope-aware lookup (REG-309)
546
+ const scopePath = scopeTracker?.getContext().scopePath ?? [];
547
+ if (scopeTracker) {
548
+ const discriminator = scopeTracker.getItemCounter(`ARRAY_MUTATION:${arrayName}.${method}`);
549
+ mutationId = computeSemanticId('ARRAY_MUTATION', `${arrayName}.${method}`, scopeTracker.getContext(), { discriminator });
550
+ }
551
+ arrayMutations.push({
552
+ id: mutationId,
553
+ arrayName,
554
+ mutationScopePath: scopePath,
555
+ mutationMethod: method,
556
+ file: module.file,
557
+ line,
558
+ column,
559
+ insertedValues: mutationArgs,
560
+ // REG-117: Nested mutation fields
561
+ isNested,
562
+ baseObjectName,
563
+ propertyName
564
+ });
565
+ }
566
+ }
567
+ /**
568
+ * Detect Object.assign(target, source1, source2, ...) calls
569
+ * Creates ObjectMutationInfo for FLOWS_INTO edge generation in GraphBuilder
570
+ *
571
+ * @param callNode - The call expression node
572
+ * @param module - Current module being analyzed
573
+ */
574
+ detectObjectAssign(callNode, module) {
575
+ // Need at least 2 arguments: target and at least one source
576
+ if (callNode.arguments.length < 2)
577
+ return;
578
+ // Initialize object mutations collection if not exists
579
+ if (!this.collections.objectMutations) {
580
+ this.collections.objectMutations = [];
581
+ }
582
+ const objectMutations = this.collections.objectMutations;
583
+ // First argument is target
584
+ const targetArg = callNode.arguments[0];
585
+ let targetName;
586
+ if (targetArg.type === 'Identifier') {
587
+ targetName = targetArg.name;
588
+ }
589
+ else if (targetArg.type === 'ObjectExpression') {
590
+ targetName = '<anonymous>';
591
+ }
592
+ else {
593
+ return;
594
+ }
595
+ const line = callNode.loc?.start.line ?? 0;
596
+ const column = callNode.loc?.start.column ?? 0;
597
+ for (let i = 1; i < callNode.arguments.length; i++) {
598
+ let arg = callNode.arguments[i];
599
+ let isSpread = false;
600
+ if (arg.type === 'SpreadElement') {
601
+ isSpread = true;
602
+ arg = arg.argument;
603
+ }
604
+ const valueInfo = {
605
+ valueType: 'EXPRESSION',
606
+ argIndex: i - 1,
607
+ isSpread
608
+ };
609
+ const literalValue = ExpressionEvaluator.extractLiteralValue(arg);
610
+ if (literalValue !== null) {
611
+ valueInfo.valueType = 'LITERAL';
612
+ valueInfo.literalValue = literalValue;
613
+ }
614
+ else if (arg.type === 'Identifier') {
615
+ valueInfo.valueType = 'VARIABLE';
616
+ valueInfo.valueName = arg.name;
617
+ }
618
+ else if (arg.type === 'ObjectExpression') {
619
+ valueInfo.valueType = 'OBJECT_LITERAL';
620
+ }
621
+ else if (arg.type === 'ArrayExpression') {
622
+ valueInfo.valueType = 'ARRAY_LITERAL';
623
+ }
624
+ else if (arg.type === 'CallExpression') {
625
+ valueInfo.valueType = 'CALL';
626
+ valueInfo.callLine = arg.loc?.start.line;
627
+ valueInfo.callColumn = arg.loc?.start.column;
628
+ }
629
+ // Capture scope path for scope-aware lookup (REG-309)
630
+ const scopePath = this.scopeTracker?.getContext().scopePath ?? [];
631
+ let mutationId;
632
+ if (this.scopeTracker) {
633
+ const discriminator = this.scopeTracker.getItemCounter(`OBJECT_MUTATION:Object.assign:${targetName}`);
634
+ mutationId = computeSemanticId('OBJECT_MUTATION', `Object.assign:${targetName}`, this.scopeTracker.getContext(), { discriminator });
635
+ }
636
+ objectMutations.push({
637
+ id: mutationId,
638
+ objectName: targetName,
639
+ mutationScopePath: scopePath,
640
+ propertyName: '<assign>',
641
+ mutationType: 'assign',
642
+ file: module.file,
643
+ line,
644
+ column,
645
+ value: valueInfo
646
+ });
647
+ }
648
+ }
649
+ /**
650
+ * Get a stable scope ID for a function parent.
651
+ *
652
+ * Format must match what FunctionVisitor/ClassVisitor creates (semantic ID):
653
+ * - Module-level function: {file}->global->FUNCTION->{name}
654
+ * - Class method: {file}->{className}->FUNCTION->{methodName}
193
655
  *
194
- * NOTE: We don't have access to the counter here, so for arrow functions
195
- * we try to match by name+file+line:col. This may not always work for
196
- * multiple arrow functions on the same line.
656
+ * Reconstructs scope path by walking up the AST.
197
657
  */
198
658
  getFunctionScopeId(functionParent, module) {
199
659
  const funcNode = functionParent.node;
200
- const line = funcNode.loc?.start.line || 0;
201
- const col = funcNode.loc?.start.column || 0;
202
- // FunctionDeclaration with name
660
+ // Get function name
661
+ let funcName;
203
662
  if (funcNode.type === 'FunctionDeclaration' && funcNode.id?.name) {
204
- return `FUNCTION#${funcNode.id.name}#${module.file}#${line}`;
663
+ funcName = funcNode.id.name;
664
+ }
665
+ else if (funcNode.type === 'ClassMethod' && funcNode.key?.type === 'Identifier') {
666
+ funcName = funcNode.key.name;
667
+ }
668
+ if (!funcName) {
669
+ // Anonymous function - fall back to module scope
670
+ return module.id;
671
+ }
672
+ // Build scope path by walking up the AST
673
+ const scopePath = [];
674
+ let current = functionParent.parentPath;
675
+ while (current) {
676
+ const node = current.node;
677
+ if (node.type === 'ClassDeclaration' && node.id?.name) {
678
+ scopePath.unshift(node.id.name);
679
+ break; // Class is the outermost scope we need
680
+ }
681
+ else if (node.type === 'ClassBody') {
682
+ // Continue up to ClassDeclaration
683
+ }
684
+ else if (node.type === 'Program') {
685
+ break;
686
+ }
687
+ current = current.parentPath;
688
+ }
689
+ // If no class found, it's at module level (global scope)
690
+ if (scopePath.length === 0) {
691
+ scopePath.push('global');
205
692
  }
206
- // For arrow functions and other cases, we can't perfectly match the ID
207
- // because FunctionVisitor uses a counter. For now, use module.id as fallback
208
- // to avoid creating invalid edges. The CALL node will be connected to MODULE
209
- // instead of the specific function.
210
- return module.id;
693
+ // Compute semantic ID: {file}->{scopePath}->FUNCTION->{name}
694
+ return `${module.file}->${scopePath.join('->')}->FUNCTION->${funcName}`;
211
695
  }
212
696
  getHandlers() {
213
697
  const { module } = this;
@@ -220,6 +704,7 @@ export class CallExpressionVisitor extends ASTVisitor {
220
704
  const callSiteCounterRef = (this.collections.callSiteCounterRef ?? { value: 0 });
221
705
  const literalCounterRef = (this.collections.literalCounterRef ?? { value: 0 });
222
706
  const processedNodes = this.collections.processedNodes ?? { callSites: new Set(), methodCalls: new Set(), eventListeners: new Set() };
707
+ const scopeTracker = this.scopeTracker;
223
708
  return {
224
709
  CallExpression: (path) => {
225
710
  const callNode = path.node;
@@ -227,16 +712,24 @@ export class CallExpressionVisitor extends ASTVisitor {
227
712
  // Determine parent scope - if inside a function, use function's scope, otherwise module
228
713
  const parentScopeId = functionParent ? this.getFunctionScopeId(functionParent, module) : module.id;
229
714
  // Identifier calls (direct function calls)
715
+ // Skip if inside function - they will be processed by analyzeFunctionBody with proper scope tracking
230
716
  if (callNode.callee.type === 'Identifier') {
717
+ if (functionParent) {
718
+ return;
719
+ }
231
720
  const callee = callNode.callee;
232
- const callId = `CALL#${callee.name}#${module.file}#${callNode.loc.start.line}:${callNode.loc.start.column}:${callSiteCounterRef.value++}`;
721
+ const line = getLine(callNode);
722
+ const column = getColumn(callNode);
723
+ // Generate ID using centralized IdGenerator
724
+ const idGenerator = new IdGenerator(scopeTracker);
725
+ const callId = idGenerator.generate('CALL', callee.name, module.file, line, column, callSiteCounterRef, { useDiscriminator: true, discriminatorKey: `CALL:${callee.name}` });
233
726
  callSites.push({
234
727
  id: callId,
235
728
  type: 'CALL',
236
729
  name: callee.name,
237
730
  file: module.file,
238
- line: callNode.loc.start.line,
239
- column: callNode.loc.start.column,
731
+ line,
732
+ column,
240
733
  parentScopeId,
241
734
  targetFunctionName: callee.name
242
735
  });
@@ -245,8 +738,12 @@ export class CallExpressionVisitor extends ASTVisitor {
245
738
  this.extractArguments(callNode.arguments, callId, module, callArguments, literals, literalCounterRef);
246
739
  }
247
740
  }
248
- // MemberExpression calls (method calls at module level)
741
+ // MemberExpression calls (method calls)
742
+ // Skip if inside function - they will be processed by analyzeFunctionBody with proper scope tracking
249
743
  else if (callNode.callee.type === 'MemberExpression') {
744
+ if (functionParent) {
745
+ return;
746
+ }
250
747
  const memberCallee = callNode.callee;
251
748
  const object = memberCallee.object;
252
749
  const property = memberCallee.property;
@@ -268,13 +765,15 @@ export class CallExpressionVisitor extends ASTVisitor {
268
765
  return;
269
766
  }
270
767
  processedNodes.eventListeners.add(nodeKey);
768
+ const eventLine = getLine(callNode);
769
+ const eventColumn = getColumn(callNode);
271
770
  eventListeners.push({
272
- id: `event:listener#${eventName}#${module.file}#${callNode.loc.start.line}:${callNode.loc.start.column}:${callSiteCounterRef.value++}`,
771
+ id: `event:listener#${eventName}#${module.file}#${eventLine}:${eventColumn}:${callSiteCounterRef.value++}`,
273
772
  type: 'event:listener',
274
773
  name: eventName,
275
774
  object: objectName,
276
775
  file: module.file,
277
- line: callNode.loc.start.line,
776
+ line: eventLine,
278
777
  parentScopeId,
279
778
  callbackArg: secondArg
280
779
  });
@@ -288,7 +787,11 @@ export class CallExpressionVisitor extends ASTVisitor {
288
787
  }
289
788
  processedNodes.methodCalls.add(nodeKey);
290
789
  const fullName = `${objectName}.${methodName}`;
291
- const methodCallId = `CALL#${fullName}#${module.file}#${callNode.loc.start.line}:${callNode.loc.start.column}:${callSiteCounterRef.value++}`;
790
+ const methodLine = getLine(callNode);
791
+ const methodColumn = getColumn(callNode);
792
+ // Generate ID using centralized IdGenerator
793
+ const idGenerator = new IdGenerator(scopeTracker);
794
+ const methodCallId = idGenerator.generate('CALL', fullName, module.file, methodLine, methodColumn, callSiteCounterRef, { useDiscriminator: true, discriminatorKey: `CALL:${fullName}` });
292
795
  methodCalls.push({
293
796
  id: methodCallId,
294
797
  type: 'CALL',
@@ -298,10 +801,19 @@ export class CallExpressionVisitor extends ASTVisitor {
298
801
  computed: isComputed,
299
802
  computedPropertyVar, // Variable name used in obj[x]() calls
300
803
  file: module.file,
301
- line: callNode.loc.start.line,
302
- column: callNode.loc.start.column,
804
+ line: methodLine,
805
+ column: methodColumn,
303
806
  parentScopeId
304
807
  });
808
+ // Check for array mutation methods (push, unshift, splice)
809
+ const ARRAY_MUTATION_METHODS = ['push', 'unshift', 'splice'];
810
+ if (ARRAY_MUTATION_METHODS.includes(methodName)) {
811
+ this.detectArrayMutation(callNode, objectName, methodName, module);
812
+ }
813
+ // Check for Object.assign() calls
814
+ if (objectName === 'Object' && methodName === 'assign') {
815
+ this.detectObjectAssign(callNode, module);
816
+ }
305
817
  // Extract arguments for PASSES_ARGUMENT edges
306
818
  if (callNode.arguments.length > 0) {
307
819
  this.extractArguments(callNode.arguments, methodCallId, module, callArguments, literals, literalCounterRef);
@@ -310,8 +822,8 @@ export class CallExpressionVisitor extends ASTVisitor {
310
822
  if (arg.type === 'ArrowFunctionExpression' || arg.type === 'FunctionExpression') {
311
823
  methodCallbacks.push({
312
824
  methodCallId,
313
- callbackLine: arg.loc.start.line,
314
- callbackColumn: arg.loc.start.column,
825
+ callbackLine: getLine(arg),
826
+ callbackColumn: getColumn(arg),
315
827
  callbackType: arg.type
316
828
  });
317
829
  }
@@ -319,13 +831,40 @@ export class CallExpressionVisitor extends ASTVisitor {
319
831
  }
320
832
  }
321
833
  }
834
+ // REG-117: Nested array mutations like obj.arr.push(item)
835
+ // object is MemberExpression, property is the method name
836
+ else if (object.type === 'MemberExpression' && property.type === 'Identifier') {
837
+ const nestedMember = object;
838
+ const methodName = property.name;
839
+ const ARRAY_MUTATION_METHODS = ['push', 'unshift', 'splice'];
840
+ if (ARRAY_MUTATION_METHODS.includes(methodName)) {
841
+ // Extract base object and property from nested MemberExpression
842
+ const base = nestedMember.object;
843
+ const prop = nestedMember.property;
844
+ // Only handle single-level nesting: obj.arr.push() or this.items.push()
845
+ if ((base.type === 'Identifier' || base.type === 'ThisExpression') &&
846
+ !nestedMember.computed &&
847
+ prop.type === 'Identifier') {
848
+ const baseObjectName = base.type === 'Identifier' ? base.name : 'this';
849
+ const propertyName = prop.name;
850
+ this.detectArrayMutation(callNode, `${baseObjectName}.${propertyName}`, // arrayName for ID purposes
851
+ methodName, module, true, // isNested
852
+ baseObjectName, propertyName);
853
+ }
854
+ }
855
+ }
322
856
  }
323
857
  },
324
858
  // NewExpression: new Foo(), new Function(), new Map(), etc.
859
+ // Skip if inside function - they will be processed by analyzeFunctionBody with proper scope tracking
325
860
  NewExpression: (path) => {
326
861
  const newNode = path.node;
327
862
  const functionParent = path.getFunctionParent();
328
- const parentScopeId = functionParent ? this.getFunctionScopeId(functionParent, module) : module.id;
863
+ // Skip if inside function - handled by analyzeFunctionBody
864
+ if (functionParent) {
865
+ return;
866
+ }
867
+ const parentScopeId = module.id;
329
868
  // Dedup check
330
869
  const nodeKey = `new:${newNode.start}:${newNode.end}`;
331
870
  if (processedNodes.methodCalls.has(nodeKey)) {
@@ -336,13 +875,18 @@ export class CallExpressionVisitor extends ASTVisitor {
336
875
  if (newNode.callee.type === 'Identifier') {
337
876
  const callee = newNode.callee;
338
877
  const constructorName = callee.name;
878
+ const newLine = getLine(newNode);
879
+ const newColumn = getColumn(newNode);
880
+ // Generate ID using centralized IdGenerator
881
+ const idGenerator = new IdGenerator(scopeTracker);
882
+ const newCallId = idGenerator.generate('CALL', `new:${constructorName}`, module.file, newLine, newColumn, callSiteCounterRef, { useDiscriminator: true, discriminatorKey: `CALL:new:${constructorName}` });
339
883
  callSites.push({
340
- id: `CALL#new:${constructorName}#${module.file}#${newNode.loc.start.line}:${newNode.loc.start.column}:${callSiteCounterRef.value++}`,
884
+ id: newCallId,
341
885
  type: 'CALL',
342
886
  name: constructorName,
343
887
  file: module.file,
344
- line: newNode.loc.start.line,
345
- column: newNode.loc.start.column,
888
+ line: newLine,
889
+ column: newColumn,
346
890
  parentScopeId,
347
891
  targetFunctionName: constructorName,
348
892
  isNew: true // Mark as constructor call
@@ -357,15 +901,20 @@ export class CallExpressionVisitor extends ASTVisitor {
357
901
  const objectName = object.name;
358
902
  const constructorName = property.name;
359
903
  const fullName = `${objectName}.${constructorName}`;
904
+ const memberNewLine = getLine(newNode);
905
+ const memberNewColumn = getColumn(newNode);
906
+ // Generate ID using centralized IdGenerator
907
+ const idGenerator = new IdGenerator(scopeTracker);
908
+ const newMethodCallId = idGenerator.generate('CALL', `new:${fullName}`, module.file, memberNewLine, memberNewColumn, callSiteCounterRef, { useDiscriminator: true, discriminatorKey: `CALL:new:${fullName}` });
360
909
  methodCalls.push({
361
- id: `CALL#new:${fullName}#${module.file}#${newNode.loc.start.line}:${newNode.loc.start.column}:${callSiteCounterRef.value++}`,
910
+ id: newMethodCallId,
362
911
  type: 'CALL',
363
912
  name: fullName,
364
913
  object: objectName,
365
914
  method: constructorName,
366
915
  file: module.file,
367
- line: newNode.loc.start.line,
368
- column: newNode.loc.start.column,
916
+ line: memberNewLine,
917
+ column: memberNewColumn,
369
918
  parentScopeId,
370
919
  isNew: true // Mark as constructor call
371
920
  });