@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
@@ -8,10 +8,85 @@
8
8
  * - Constructor calls: new Foo(), new Function()
9
9
  */
10
10
 
11
- import type { Node, CallExpression, NewExpression, Identifier, MemberExpression } from '@babel/types';
11
+ import type { Node, CallExpression, NewExpression, Identifier, MemberExpression, ObjectExpression, ArrayExpression, ObjectProperty, SpreadElement } from '@babel/types';
12
12
  import type { NodePath } from '@babel/traverse';
13
13
  import { ASTVisitor, type VisitorModule, type VisitorCollections, type VisitorHandlers, type CounterRef } from './ASTVisitor.js';
14
14
  import { ExpressionEvaluator } from '../ExpressionEvaluator.js';
15
+ import type { ArrayMutationInfo, ArrayMutationArgument, ObjectMutationInfo, ObjectMutationValue } from '../types.js';
16
+ import { ScopeTracker } from '../../../../core/ScopeTracker.js';
17
+ import { computeSemanticId } from '../../../../core/SemanticId.js';
18
+ import { IdGenerator } from '../IdGenerator.js';
19
+ import { NodeFactory } from '../../../../core/NodeFactory.js';
20
+ import { ObjectLiteralNode } from '../../../../core/nodes/ObjectLiteralNode.js';
21
+ import { ArrayLiteralNode } from '../../../../core/nodes/ArrayLiteralNode.js';
22
+ import { getLine, getColumn } from '../utils/location.js';
23
+
24
+ /**
25
+ * Object literal info for OBJECT_LITERAL nodes
26
+ */
27
+ interface ObjectLiteralInfo {
28
+ id: string;
29
+ type: 'OBJECT_LITERAL';
30
+ file: string;
31
+ line: number;
32
+ column: number;
33
+ parentCallId?: string;
34
+ argIndex?: number;
35
+ isSpread?: boolean;
36
+ }
37
+
38
+ /**
39
+ * Object property info for HAS_PROPERTY edges
40
+ */
41
+ interface ObjectPropertyInfo {
42
+ objectId: string;
43
+ propertyName: string;
44
+ valueNodeId?: string;
45
+ valueType: 'LITERAL' | 'VARIABLE' | 'CALL' | 'EXPRESSION' | 'OBJECT_LITERAL' | 'ARRAY_LITERAL' | 'SPREAD';
46
+ valueName?: string;
47
+ literalValue?: unknown;
48
+ file: string;
49
+ line: number;
50
+ column: number;
51
+ callLine?: number;
52
+ callColumn?: number;
53
+ nestedObjectId?: string;
54
+ nestedArrayId?: string;
55
+ // REG-329: Scope path for variable resolution
56
+ valueScopePath?: string[];
57
+ }
58
+
59
+ /**
60
+ * Array literal info for ARRAY_LITERAL nodes
61
+ */
62
+ interface ArrayLiteralInfo {
63
+ id: string;
64
+ type: 'ARRAY_LITERAL';
65
+ file: string;
66
+ line: number;
67
+ column: number;
68
+ parentCallId?: string;
69
+ argIndex?: number;
70
+ }
71
+
72
+ /**
73
+ * Array element info for HAS_ELEMENT edges
74
+ */
75
+ interface ArrayElementInfo {
76
+ arrayId: string;
77
+ index: number;
78
+ valueNodeId?: string;
79
+ valueType: 'LITERAL' | 'VARIABLE' | 'CALL' | 'EXPRESSION' | 'OBJECT_LITERAL' | 'ARRAY_LITERAL' | 'SPREAD';
80
+ valueName?: string;
81
+ literalValue?: unknown;
82
+ file: string;
83
+ line: number;
84
+ column: number;
85
+ callLine?: number;
86
+ callColumn?: number;
87
+ nestedObjectId?: string;
88
+ nestedArrayId?: string;
89
+ }
15
90
 
16
91
  /**
17
92
  * Argument info for PASSES_ARGUMENT edges
@@ -112,8 +187,16 @@ interface LiteralInfo {
112
187
  }
113
188
 
114
189
  export class CallExpressionVisitor extends ASTVisitor {
115
- constructor(module: VisitorModule, collections: VisitorCollections) {
190
+ private scopeTracker?: ScopeTracker;
191
+
192
+ /**
193
+ * @param module - Current module being analyzed
194
+ * @param collections - Must contain arrays and counter refs
195
+ * @param scopeTracker - Optional ScopeTracker for semantic ID generation
196
+ */
197
+ constructor(module: VisitorModule, collections: VisitorCollections, scopeTracker?: ScopeTracker) {
116
198
  super(module, collections);
199
+ this.scopeTracker = scopeTracker;
117
200
  }
118
201
 
119
202
  /**
@@ -143,27 +226,130 @@ export class CallExpressionVisitor extends ASTVisitor {
143
226
  actualArg = arg.argument; // Get the actual argument
144
227
  }
145
228
 
146
- // Literal value
147
- const literalValue = ExpressionEvaluator.extractLiteralValue(actualArg);
148
- if (literalValue !== null) {
149
- const literalId = `LITERAL#arg${index}#${module.file}#${argInfo.line}:${argInfo.column}:${literalCounterRef.value++}`;
150
- literals.push({
151
- id: literalId,
152
- type: 'LITERAL',
153
- value: literalValue,
154
- valueType: typeof literalValue,
155
- file: module.file,
156
- line: argInfo.line,
157
- column: argInfo.column,
158
- parentCallId: callId,
159
- argIndex: index
160
- });
161
- argInfo.targetType = 'LITERAL';
162
- argInfo.targetId = literalId;
163
- argInfo.literalValue = literalValue;
229
+ // Object literal - check BEFORE extractLiteralValue to handle object-typed args properly
230
+ if (actualArg.type === 'ObjectExpression') {
231
+ const objectExpr = actualArg as ObjectExpression;
232
+ // Initialize collections if not exist (must assign back to this.collections!)
233
+ if (!this.collections.objectLiteralCounterRef) {
234
+ this.collections.objectLiteralCounterRef = { value: 0 };
235
+ }
236
+ if (!this.collections.objectLiterals) {
237
+ this.collections.objectLiterals = [];
238
+ }
239
+ if (!this.collections.objectProperties) {
240
+ this.collections.objectProperties = [];
241
+ }
242
+ const objectLiteralCounterRef = this.collections.objectLiteralCounterRef as CounterRef;
243
+
244
+ // Use factory to create OBJECT_LITERAL node
245
+ const objectNode = ObjectLiteralNode.create(
246
+ module.file,
247
+ argInfo.line,
248
+ argInfo.column,
249
+ {
250
+ parentCallId: callId,
251
+ argIndex: index,
252
+ counter: objectLiteralCounterRef.value++
253
+ }
254
+ );
255
+ // Factory guarantees line is set, cast to ObjectLiteralInfo
256
+ (this.collections.objectLiterals as ObjectLiteralInfo[]).push(objectNode as unknown as ObjectLiteralInfo);
257
+ const objectId = objectNode.id;
258
+
259
+ // Extract properties
260
+ this.extractObjectProperties(
261
+ objectExpr,
262
+ objectId,
263
+ module,
264
+ this.collections.objectProperties as ObjectPropertyInfo[],
265
+ this.collections.objectLiterals as ObjectLiteralInfo[],
266
+ objectLiteralCounterRef,
267
+ literals as LiteralInfo[],
268
+ literalCounterRef
269
+ );
270
+
271
+ argInfo.targetType = 'OBJECT_LITERAL';
272
+ argInfo.targetId = objectId;
164
273
  }
165
- // Variable reference
166
- else if (actualArg.type === 'Identifier') {
274
+ // Array literal - check BEFORE extractLiteralValue to handle array-typed args properly
275
+ else if (actualArg.type === 'ArrayExpression') {
276
+ const arrayExpr = actualArg as ArrayExpression;
277
+ // Initialize collections if not exist (must assign back to this.collections!)
278
+ if (!this.collections.arrayLiteralCounterRef) {
279
+ this.collections.arrayLiteralCounterRef = { value: 0 };
280
+ }
281
+ if (!this.collections.arrayLiterals) {
282
+ this.collections.arrayLiterals = [];
283
+ }
284
+ if (!this.collections.arrayElements) {
285
+ this.collections.arrayElements = [];
286
+ }
287
+ if (!this.collections.objectLiteralCounterRef) {
288
+ this.collections.objectLiteralCounterRef = { value: 0 };
289
+ }
290
+ if (!this.collections.objectLiterals) {
291
+ this.collections.objectLiterals = [];
292
+ }
293
+ if (!this.collections.objectProperties) {
294
+ this.collections.objectProperties = [];
295
+ }
296
+ const arrayLiteralCounterRef = this.collections.arrayLiteralCounterRef as CounterRef;
297
+
298
+ // Use factory to create ARRAY_LITERAL node
299
+ const arrayNode = ArrayLiteralNode.create(
300
+ module.file,
301
+ argInfo.line,
302
+ argInfo.column,
303
+ {
304
+ parentCallId: callId,
305
+ argIndex: index,
306
+ counter: arrayLiteralCounterRef.value++
307
+ }
308
+ );
309
+ // Factory guarantees line is set, cast to ArrayLiteralInfo
310
+ (this.collections.arrayLiterals as ArrayLiteralInfo[]).push(arrayNode as unknown as ArrayLiteralInfo);
311
+ const arrayId = arrayNode.id;
312
+
313
+ // Extract elements
314
+ this.extractArrayElements(
315
+ arrayExpr,
316
+ arrayId,
317
+ module,
318
+ this.collections.arrayElements as ArrayElementInfo[],
319
+ this.collections.arrayLiterals as ArrayLiteralInfo[],
320
+ arrayLiteralCounterRef,
321
+ this.collections.objectLiterals as ObjectLiteralInfo[],
322
+ this.collections.objectLiteralCounterRef as CounterRef,
323
+ this.collections.objectProperties as ObjectPropertyInfo[],
324
+ literals as LiteralInfo[],
325
+ literalCounterRef
326
+ );
327
+
328
+ argInfo.targetType = 'ARRAY_LITERAL';
329
+ argInfo.targetId = arrayId;
330
+ }
331
+ // Literal value (primitives only - objects/arrays handled above)
332
+ else {
333
+ const literalValue = ExpressionEvaluator.extractLiteralValue(actualArg);
334
+ if (literalValue !== null) {
335
+ const literalId = `LITERAL#arg${index}#${module.file}#${argInfo.line}:${argInfo.column}:${literalCounterRef.value++}`;
336
+ literals.push({
337
+ id: literalId,
338
+ type: 'LITERAL',
339
+ value: literalValue,
340
+ valueType: typeof literalValue,
341
+ file: module.file,
342
+ line: argInfo.line,
343
+ column: argInfo.column,
344
+ parentCallId: callId,
345
+ argIndex: index
346
+ });
347
+ argInfo.targetType = 'LITERAL';
348
+ argInfo.targetId = literalId;
349
+ argInfo.literalValue = literalValue;
350
+ }
351
+ // Variable reference
352
+ else if (actualArg.type === 'Identifier') {
167
353
  argInfo.targetType = 'VARIABLE';
168
354
  argInfo.targetName = (actualArg as Identifier).name; // Will be resolved in GraphBuilder
169
355
  }
@@ -196,25 +382,26 @@ export class CallExpressionVisitor extends ASTVisitor {
196
382
  else if (actualArg.type === 'BinaryExpression' || actualArg.type === 'LogicalExpression') {
197
383
  const expr = actualArg as { operator?: string; type: string };
198
384
  const operator = expr.operator || '?';
199
- const exprName = `<${actualArg.type}:${operator}>`;
200
- const expressionId = `EXPRESSION#${exprName}#${module.file}#${argInfo.line}:${argInfo.column}:${literalCounterRef.value++}`;
201
-
202
- // Create EXPRESSION node
203
- literals.push({
204
- id: expressionId,
205
- type: 'EXPRESSION',
206
- expressionType: actualArg.type,
207
- operator: operator,
208
- name: exprName,
209
- file: module.file,
210
- line: argInfo.line,
211
- column: argInfo.column,
212
- parentCallId: callId,
213
- argIndex: index
214
- });
385
+ const counter = literalCounterRef.value++;
386
+
387
+ // Create EXPRESSION node via NodeFactory
388
+ const expressionNode = NodeFactory.createArgumentExpression(
389
+ actualArg.type,
390
+ module.file,
391
+ argInfo.line,
392
+ argInfo.column,
393
+ {
394
+ parentCallId: callId,
395
+ argIndex: index,
396
+ operator,
397
+ counter
398
+ }
399
+ );
400
+
401
+ literals.push(expressionNode as LiteralInfo);
215
402
 
216
403
  argInfo.targetType = 'EXPRESSION';
217
- argInfo.targetId = expressionId;
404
+ argInfo.targetId = expressionNode.id;
218
405
  argInfo.expressionType = actualArg.type;
219
406
 
220
407
  // Track DERIVES_FROM edges for identifiers in expression
@@ -223,7 +410,7 @@ export class CallExpressionVisitor extends ASTVisitor {
223
410
  if (variableAssignments) {
224
411
  for (const identName of identifiers) {
225
412
  variableAssignments.push({
226
- variableId: expressionId,
413
+ variableId: expressionNode.id,
227
414
  sourceId: null,
228
415
  sourceName: identName,
229
416
  sourceType: 'DERIVES_FROM_VARIABLE',
@@ -232,19 +419,12 @@ export class CallExpressionVisitor extends ASTVisitor {
232
419
  }
233
420
  }
234
421
  }
235
- // Object literal
236
- else if (actualArg.type === 'ObjectExpression') {
237
- argInfo.targetType = 'OBJECT_LITERAL';
238
- }
239
- // Array literal
240
- else if (actualArg.type === 'ArrayExpression') {
241
- argInfo.targetType = 'ARRAY_LITERAL';
242
- }
243
- // Other expression types
422
+ // Other expression types (fallback for unhandled expression types)
244
423
  else {
245
424
  argInfo.targetType = 'EXPRESSION';
246
425
  argInfo.expressionType = actualArg.type;
247
426
  }
427
+ }
248
428
 
249
429
  callArguments.push(argInfo);
250
430
  });
@@ -298,34 +478,585 @@ export class CallExpressionVisitor extends ASTVisitor {
298
478
  }
299
479
 
300
480
  /**
301
- * Get a stable scope ID for a function parent
302
- * Format must match what FunctionVisitor creates:
303
- * - FunctionDeclaration: FUNCTION#name#file#line
304
- * - ArrowFunctionExpression: FUNCTION#name#file#line:col:counter
481
+ * Extract object properties and create ObjectPropertyInfo records
482
+ */
483
+ extractObjectProperties(
484
+ objectExpr: ObjectExpression,
485
+ objectId: string,
486
+ module: VisitorModule,
487
+ objectProperties: ObjectPropertyInfo[],
488
+ objectLiterals: ObjectLiteralInfo[],
489
+ objectLiteralCounterRef: CounterRef,
490
+ literals: LiteralInfo[],
491
+ literalCounterRef: CounterRef
492
+ ): void {
493
+ for (const prop of objectExpr.properties) {
494
+ const propLine = prop.loc?.start.line || 0;
495
+ const propColumn = prop.loc?.start.column || 0;
496
+
497
+ // Handle spread properties: { ...other }
498
+ if (prop.type === 'SpreadElement') {
499
+ const spreadArg = prop.argument;
500
+ const propertyInfo: ObjectPropertyInfo = {
501
+ objectId,
502
+ propertyName: '<spread>',
503
+ valueType: 'SPREAD',
504
+ file: module.file,
505
+ line: propLine,
506
+ column: propColumn
507
+ };
508
+
509
+ if (spreadArg.type === 'Identifier') {
510
+ propertyInfo.valueName = spreadArg.name;
511
+ propertyInfo.valueType = 'VARIABLE';
512
+ // REG-329: Capture scope path for spread variable resolution
513
+ propertyInfo.valueScopePath = this.scopeTracker?.getContext().scopePath ?? [];
514
+ }
515
+
516
+ objectProperties.push(propertyInfo);
517
+ continue;
518
+ }
519
+
520
+ // Handle regular properties
521
+ if (prop.type === 'ObjectProperty') {
522
+ const objProp = prop as ObjectProperty;
523
+ let propertyName: string;
524
+
525
+ // Get property name
526
+ if (objProp.key.type === 'Identifier') {
527
+ propertyName = objProp.key.name;
528
+ } else if (objProp.key.type === 'StringLiteral') {
529
+ propertyName = objProp.key.value;
530
+ } else if (objProp.key.type === 'NumericLiteral') {
531
+ propertyName = String(objProp.key.value);
532
+ } else {
533
+ propertyName = '<computed>';
534
+ }
535
+
536
+ const propertyInfo: ObjectPropertyInfo = {
537
+ objectId,
538
+ propertyName,
539
+ file: module.file,
540
+ line: propLine,
541
+ column: propColumn,
542
+ valueType: 'EXPRESSION'
543
+ };
544
+
545
+ const value = objProp.value;
546
+
547
+ // Nested object literal - check BEFORE extractLiteralValue
548
+ if (value.type === 'ObjectExpression') {
549
+ // Use factory - do NOT pass argIndex for nested literals (uses 'obj' suffix)
550
+ const nestedObjectNode = ObjectLiteralNode.create(
551
+ module.file,
552
+ value.loc?.start.line || 0,
553
+ value.loc?.start.column || 0,
554
+ {
555
+ counter: objectLiteralCounterRef.value++
556
+ }
557
+ );
558
+ objectLiterals.push(nestedObjectNode as unknown as ObjectLiteralInfo);
559
+ const nestedObjectId = nestedObjectNode.id;
560
+
561
+ // Recursively extract nested properties
562
+ this.extractObjectProperties(
563
+ value,
564
+ nestedObjectId,
565
+ module,
566
+ objectProperties,
567
+ objectLiterals,
568
+ objectLiteralCounterRef,
569
+ literals,
570
+ literalCounterRef
571
+ );
572
+
573
+ propertyInfo.valueType = 'OBJECT_LITERAL';
574
+ propertyInfo.nestedObjectId = nestedObjectId;
575
+ propertyInfo.valueNodeId = nestedObjectId;
576
+ }
577
+ // Nested array literal - check BEFORE extractLiteralValue
578
+ else if (value.type === 'ArrayExpression') {
579
+ const arrayLiteralCounterRef = (this.collections.arrayLiteralCounterRef ?? { value: 0 }) as CounterRef;
580
+ const arrayLiterals = this.collections.arrayLiterals ?? [];
581
+ const arrayElements = this.collections.arrayElements ?? [];
582
+
583
+ // Use factory - do NOT pass argIndex for nested literals (uses 'arr' suffix)
584
+ const nestedArrayNode = ArrayLiteralNode.create(
585
+ module.file,
586
+ value.loc?.start.line || 0,
587
+ value.loc?.start.column || 0,
588
+ {
589
+ counter: arrayLiteralCounterRef.value++
590
+ }
591
+ );
592
+ (arrayLiterals as ArrayLiteralInfo[]).push(nestedArrayNode as unknown as ArrayLiteralInfo);
593
+ const nestedArrayId = nestedArrayNode.id;
594
+
595
+ // Recursively extract array elements
596
+ this.extractArrayElements(
597
+ value,
598
+ nestedArrayId,
599
+ module,
600
+ arrayElements as ArrayElementInfo[],
601
+ arrayLiterals as ArrayLiteralInfo[],
602
+ arrayLiteralCounterRef,
603
+ objectLiterals,
604
+ objectLiteralCounterRef,
605
+ objectProperties,
606
+ literals,
607
+ literalCounterRef
608
+ );
609
+
610
+ propertyInfo.valueType = 'ARRAY_LITERAL';
611
+ propertyInfo.nestedArrayId = nestedArrayId;
612
+ propertyInfo.valueNodeId = nestedArrayId;
613
+ }
614
+ // Literal value (primitives only - objects/arrays handled above)
615
+ else {
616
+ const literalValue = ExpressionEvaluator.extractLiteralValue(value);
617
+ // Handle both non-null literals AND explicit null literals (NullLiteral)
618
+ if (literalValue !== null || value.type === 'NullLiteral') {
619
+ const literalId = `LITERAL#${propertyName}#${module.file}#${propLine}:${propColumn}:${literalCounterRef.value++}`;
620
+ literals.push({
621
+ id: literalId,
622
+ type: 'LITERAL',
623
+ value: literalValue,
624
+ valueType: typeof literalValue,
625
+ file: module.file,
626
+ line: propLine,
627
+ column: propColumn,
628
+ parentCallId: objectId,
629
+ argIndex: 0
630
+ });
631
+ propertyInfo.valueType = 'LITERAL';
632
+ propertyInfo.valueNodeId = literalId;
633
+ propertyInfo.literalValue = literalValue;
634
+ }
635
+ // Variable reference
636
+ else if (value.type === 'Identifier') {
637
+ propertyInfo.valueType = 'VARIABLE';
638
+ propertyInfo.valueName = value.name;
639
+ // REG-329: Capture scope path for scope-aware variable resolution
640
+ propertyInfo.valueScopePath = this.scopeTracker?.getContext().scopePath ?? [];
641
+ }
642
+ // Call expression
643
+ else if (value.type === 'CallExpression') {
644
+ propertyInfo.valueType = 'CALL';
645
+ propertyInfo.callLine = value.loc?.start.line;
646
+ propertyInfo.callColumn = value.loc?.start.column;
647
+ }
648
+ // Other expressions
649
+ else {
650
+ propertyInfo.valueType = 'EXPRESSION';
651
+ }
652
+ }
653
+
654
+ objectProperties.push(propertyInfo);
655
+ }
656
+ // Handle object methods: { foo() {} }
657
+ else if (prop.type === 'ObjectMethod') {
658
+ const propertyName = prop.key.type === 'Identifier' ? prop.key.name : '<computed>';
659
+ objectProperties.push({
660
+ objectId,
661
+ propertyName,
662
+ valueType: 'EXPRESSION',
663
+ file: module.file,
664
+ line: propLine,
665
+ column: propColumn
666
+ });
667
+ }
668
+ }
669
+ }
670
+
671
+ /**
672
+ * Extract array elements and create ArrayElementInfo records
673
+ */
674
+ extractArrayElements(
675
+ arrayExpr: ArrayExpression,
676
+ arrayId: string,
677
+ module: VisitorModule,
678
+ arrayElements: ArrayElementInfo[],
679
+ arrayLiterals: ArrayLiteralInfo[],
680
+ arrayLiteralCounterRef: CounterRef,
681
+ objectLiterals: ObjectLiteralInfo[],
682
+ objectLiteralCounterRef: CounterRef,
683
+ objectProperties: ObjectPropertyInfo[],
684
+ literals: LiteralInfo[],
685
+ literalCounterRef: CounterRef
686
+ ): void {
687
+ arrayExpr.elements.forEach((element, index) => {
688
+ if (!element) return; // Skip holes in arrays
689
+
690
+ const elemLine = element.loc?.start.line || 0;
691
+ const elemColumn = element.loc?.start.column || 0;
692
+
693
+ const elementInfo: ArrayElementInfo = {
694
+ arrayId,
695
+ index,
696
+ file: module.file,
697
+ line: elemLine,
698
+ column: elemColumn,
699
+ valueType: 'EXPRESSION'
700
+ };
701
+
702
+ // Handle spread elements: [...arr]
703
+ if (element.type === 'SpreadElement') {
704
+ const spreadArg = element.argument;
705
+ elementInfo.valueType = 'SPREAD';
706
+ if (spreadArg.type === 'Identifier') {
707
+ elementInfo.valueName = spreadArg.name;
708
+ }
709
+ arrayElements.push(elementInfo);
710
+ return;
711
+ }
712
+
713
+ // Nested object literal - check BEFORE extractLiteralValue
714
+ if (element.type === 'ObjectExpression') {
715
+ // Use factory - do NOT pass argIndex for nested literals (uses 'obj' suffix)
716
+ const nestedObjectNode = ObjectLiteralNode.create(
717
+ module.file,
718
+ elemLine,
719
+ elemColumn,
720
+ {
721
+ counter: objectLiteralCounterRef.value++
722
+ }
723
+ );
724
+ objectLiterals.push(nestedObjectNode as unknown as ObjectLiteralInfo);
725
+ const nestedObjectId = nestedObjectNode.id;
726
+
727
+ // Recursively extract properties
728
+ this.extractObjectProperties(
729
+ element,
730
+ nestedObjectId,
731
+ module,
732
+ objectProperties,
733
+ objectLiterals,
734
+ objectLiteralCounterRef,
735
+ literals,
736
+ literalCounterRef
737
+ );
738
+
739
+ elementInfo.valueType = 'OBJECT_LITERAL';
740
+ elementInfo.nestedObjectId = nestedObjectId;
741
+ elementInfo.valueNodeId = nestedObjectId;
742
+ }
743
+ // Nested array literal - check BEFORE extractLiteralValue
744
+ else if (element.type === 'ArrayExpression') {
745
+ // Use factory - do NOT pass argIndex for nested literals (uses 'arr' suffix)
746
+ const nestedArrayNode = ArrayLiteralNode.create(
747
+ module.file,
748
+ elemLine,
749
+ elemColumn,
750
+ {
751
+ counter: arrayLiteralCounterRef.value++
752
+ }
753
+ );
754
+ arrayLiterals.push(nestedArrayNode as unknown as ArrayLiteralInfo);
755
+ const nestedArrayId = nestedArrayNode.id;
756
+
757
+ // Recursively extract elements
758
+ this.extractArrayElements(
759
+ element,
760
+ nestedArrayId,
761
+ module,
762
+ arrayElements,
763
+ arrayLiterals,
764
+ arrayLiteralCounterRef,
765
+ objectLiterals,
766
+ objectLiteralCounterRef,
767
+ objectProperties,
768
+ literals,
769
+ literalCounterRef
770
+ );
771
+
772
+ elementInfo.valueType = 'ARRAY_LITERAL';
773
+ elementInfo.nestedArrayId = nestedArrayId;
774
+ elementInfo.valueNodeId = nestedArrayId;
775
+ }
776
+ // Literal value (primitives only - objects/arrays handled above)
777
+ else {
778
+ const literalValue = ExpressionEvaluator.extractLiteralValue(element);
779
+ if (literalValue !== null) {
780
+ const literalId = `LITERAL#elem${index}#${module.file}#${elemLine}:${elemColumn}:${literalCounterRef.value++}`;
781
+ literals.push({
782
+ id: literalId,
783
+ type: 'LITERAL',
784
+ value: literalValue,
785
+ valueType: typeof literalValue,
786
+ file: module.file,
787
+ line: elemLine,
788
+ column: elemColumn,
789
+ parentCallId: arrayId,
790
+ argIndex: index
791
+ });
792
+ elementInfo.valueType = 'LITERAL';
793
+ elementInfo.valueNodeId = literalId;
794
+ elementInfo.literalValue = literalValue;
795
+ }
796
+ // Variable reference
797
+ else if (element.type === 'Identifier') {
798
+ elementInfo.valueType = 'VARIABLE';
799
+ elementInfo.valueName = element.name;
800
+ }
801
+ // Call expression
802
+ else if (element.type === 'CallExpression') {
803
+ elementInfo.valueType = 'CALL';
804
+ elementInfo.callLine = element.loc?.start.line;
805
+ elementInfo.callColumn = element.loc?.start.column;
806
+ }
807
+ // Other expressions
808
+ else {
809
+ elementInfo.valueType = 'EXPRESSION';
810
+ }
811
+ }
812
+
813
+ arrayElements.push(elementInfo);
814
+ });
815
+ }
816
+
817
+ /**
818
+ * Detect array mutation calls (push, unshift, splice) and collect mutation info
819
+ * for later FLOWS_INTO edge creation in GraphBuilder
305
820
  *
306
- * NOTE: We don't have access to the counter here, so for arrow functions
307
- * we try to match by name+file+line:col. This may not always work for
308
- * multiple arrow functions on the same line.
821
+ * REG-117: Added isNested, baseObjectName, propertyName for nested mutations
822
+ */
823
+ private detectArrayMutation(
824
+ callNode: CallExpression,
825
+ arrayName: string,
826
+ method: 'push' | 'unshift' | 'splice',
827
+ module: VisitorModule,
828
+ isNested?: boolean,
829
+ baseObjectName?: string,
830
+ propertyName?: string
831
+ ): void {
832
+ // Initialize collection if not exists
833
+ if (!this.collections.arrayMutations) {
834
+ this.collections.arrayMutations = [];
835
+ }
836
+ const arrayMutations = this.collections.arrayMutations as ArrayMutationInfo[];
837
+
838
+ const mutationArgs: ArrayMutationArgument[] = [];
839
+
840
+ // For splice, only arguments from index 2 onwards are insertions
841
+ // splice(start, deleteCount, item1, item2, ...)
842
+ callNode.arguments.forEach((arg, index) => {
843
+ // Skip start and deleteCount for splice
844
+ if (method === 'splice' && index < 2) return;
845
+
846
+ const argInfo: ArrayMutationArgument = {
847
+ argIndex: method === 'splice' ? index - 2 : index,
848
+ isSpread: arg.type === 'SpreadElement',
849
+ valueType: 'EXPRESSION' // Default
850
+ };
851
+
852
+ let actualArg = arg;
853
+ if (arg.type === 'SpreadElement') {
854
+ actualArg = arg.argument;
855
+ }
856
+
857
+ // Determine value type
858
+ const literalValue = ExpressionEvaluator.extractLiteralValue(actualArg);
859
+ if (literalValue !== null) {
860
+ argInfo.valueType = 'LITERAL';
861
+ argInfo.literalValue = literalValue;
862
+ } else if (actualArg.type === 'Identifier') {
863
+ argInfo.valueType = 'VARIABLE';
864
+ argInfo.valueName = actualArg.name;
865
+ } else if (actualArg.type === 'ObjectExpression') {
866
+ argInfo.valueType = 'OBJECT_LITERAL';
867
+ } else if (actualArg.type === 'ArrayExpression') {
868
+ argInfo.valueType = 'ARRAY_LITERAL';
869
+ } else if (actualArg.type === 'CallExpression') {
870
+ argInfo.valueType = 'CALL';
871
+ argInfo.callLine = actualArg.loc?.start.line;
872
+ argInfo.callColumn = actualArg.loc?.start.column;
873
+ }
874
+
875
+ mutationArgs.push(argInfo);
876
+ });
877
+
878
+ // Only record if there are actual insertions
879
+ if (mutationArgs.length > 0) {
880
+ const line = callNode.loc?.start.line ?? 0;
881
+ const column = callNode.loc?.start.column ?? 0;
882
+
883
+ // Generate semantic ID for array mutation if scopeTracker available
884
+ const scopeTracker = this.scopeTracker;
885
+ let mutationId: string | undefined;
886
+ // Capture scope path for scope-aware lookup (REG-309)
887
+ const scopePath = scopeTracker?.getContext().scopePath ?? [];
888
+
889
+ if (scopeTracker) {
890
+ const discriminator = scopeTracker.getItemCounter(`ARRAY_MUTATION:${arrayName}.${method}`);
891
+ mutationId = computeSemanticId('ARRAY_MUTATION', `${arrayName}.${method}`, scopeTracker.getContext(), { discriminator });
892
+ }
893
+
894
+ arrayMutations.push({
895
+ id: mutationId,
896
+ arrayName,
897
+ mutationScopePath: scopePath,
898
+ mutationMethod: method,
899
+ file: module.file,
900
+ line,
901
+ column,
902
+ insertedValues: mutationArgs,
903
+ // REG-117: Nested mutation fields
904
+ isNested,
905
+ baseObjectName,
906
+ propertyName
907
+ });
908
+ }
909
+ }
910
+
911
+ /**
912
+ * Detect Object.assign(target, source1, source2, ...) calls
913
+ * Creates ObjectMutationInfo for FLOWS_INTO edge generation in GraphBuilder
914
+ *
915
+ * @param callNode - The call expression node
916
+ * @param module - Current module being analyzed
917
+ */
918
+ private detectObjectAssign(
919
+ callNode: CallExpression,
920
+ module: VisitorModule
921
+ ): void {
922
+ // Need at least 2 arguments: target and at least one source
923
+ if (callNode.arguments.length < 2) return;
924
+
925
+ // Initialize object mutations collection if not exists
926
+ if (!this.collections.objectMutations) {
927
+ this.collections.objectMutations = [];
928
+ }
929
+ const objectMutations = this.collections.objectMutations as ObjectMutationInfo[];
930
+
931
+ // First argument is target
932
+ const targetArg = callNode.arguments[0];
933
+ let targetName: string;
934
+
935
+ if (targetArg.type === 'Identifier') {
936
+ targetName = targetArg.name;
937
+ } else if (targetArg.type === 'ObjectExpression') {
938
+ targetName = '<anonymous>';
939
+ } else {
940
+ return;
941
+ }
942
+
943
+ const line = callNode.loc?.start.line ?? 0;
944
+ const column = callNode.loc?.start.column ?? 0;
945
+
946
+ for (let i = 1; i < callNode.arguments.length; i++) {
947
+ let arg = callNode.arguments[i];
948
+ let isSpread = false;
949
+
950
+ if (arg.type === 'SpreadElement') {
951
+ isSpread = true;
952
+ arg = arg.argument;
953
+ }
954
+
955
+ const valueInfo: ObjectMutationValue = {
956
+ valueType: 'EXPRESSION',
957
+ argIndex: i - 1,
958
+ isSpread
959
+ };
960
+
961
+ const literalValue = ExpressionEvaluator.extractLiteralValue(arg);
962
+ if (literalValue !== null) {
963
+ valueInfo.valueType = 'LITERAL';
964
+ valueInfo.literalValue = literalValue;
965
+ } else if (arg.type === 'Identifier') {
966
+ valueInfo.valueType = 'VARIABLE';
967
+ valueInfo.valueName = arg.name;
968
+ } else if (arg.type === 'ObjectExpression') {
969
+ valueInfo.valueType = 'OBJECT_LITERAL';
970
+ } else if (arg.type === 'ArrayExpression') {
971
+ valueInfo.valueType = 'ARRAY_LITERAL';
972
+ } else if (arg.type === 'CallExpression') {
973
+ valueInfo.valueType = 'CALL';
974
+ valueInfo.callLine = arg.loc?.start.line;
975
+ valueInfo.callColumn = arg.loc?.start.column;
976
+ }
977
+
978
+ // Capture scope path for scope-aware lookup (REG-309)
979
+ const scopePath = this.scopeTracker?.getContext().scopePath ?? [];
980
+
981
+ let mutationId: string | undefined;
982
+ if (this.scopeTracker) {
983
+ const discriminator = this.scopeTracker.getItemCounter(`OBJECT_MUTATION:Object.assign:${targetName}`);
984
+ mutationId = computeSemanticId('OBJECT_MUTATION', `Object.assign:${targetName}`, this.scopeTracker.getContext(), { discriminator });
985
+ }
986
+
987
+ objectMutations.push({
988
+ id: mutationId,
989
+ objectName: targetName,
990
+ mutationScopePath: scopePath,
991
+ propertyName: '<assign>',
992
+ mutationType: 'assign',
993
+ file: module.file,
994
+ line,
995
+ column,
996
+ value: valueInfo
997
+ });
998
+ }
999
+ }
1000
+
1001
+ /**
1002
+ * Get a stable scope ID for a function parent.
1003
+ *
1004
+ * Format must match what FunctionVisitor/ClassVisitor creates (semantic ID):
1005
+ * - Module-level function: {file}->global->FUNCTION->{name}
1006
+ * - Class method: {file}->{className}->FUNCTION->{methodName}
1007
+ *
1008
+ * Reconstructs scope path by walking up the AST.
309
1009
  */
310
1010
  getFunctionScopeId(functionParent: NodePath, module: VisitorModule): string {
311
1011
  const funcNode = functionParent.node as Node & {
312
1012
  id?: { name: string } | null;
1013
+ key?: { name?: string; type: string };
313
1014
  loc?: { start: { line: number; column: number } };
314
1015
  type: string;
315
1016
  };
316
- const line = funcNode.loc?.start.line || 0;
317
- const col = funcNode.loc?.start.column || 0;
318
1017
 
319
- // FunctionDeclaration with name
1018
+ // Get function name
1019
+ let funcName: string | undefined;
320
1020
  if (funcNode.type === 'FunctionDeclaration' && funcNode.id?.name) {
321
- return `FUNCTION#${funcNode.id.name}#${module.file}#${line}`;
1021
+ funcName = funcNode.id.name;
1022
+ } else if (funcNode.type === 'ClassMethod' && funcNode.key?.type === 'Identifier') {
1023
+ funcName = funcNode.key.name;
1024
+ }
1025
+
1026
+ if (!funcName) {
1027
+ // Anonymous function - fall back to module scope
1028
+ return module.id;
1029
+ }
1030
+
1031
+ // Build scope path by walking up the AST
1032
+ const scopePath: string[] = [];
1033
+ let current: NodePath | null = functionParent.parentPath;
1034
+
1035
+ while (current) {
1036
+ const node = current.node as Node & {
1037
+ id?: { name: string } | null;
1038
+ type: string;
1039
+ };
1040
+
1041
+ if (node.type === 'ClassDeclaration' && node.id?.name) {
1042
+ scopePath.unshift(node.id.name);
1043
+ break; // Class is the outermost scope we need
1044
+ } else if (node.type === 'ClassBody') {
1045
+ // Continue up to ClassDeclaration
1046
+ } else if (node.type === 'Program') {
1047
+ break;
1048
+ }
1049
+
1050
+ current = current.parentPath;
1051
+ }
1052
+
1053
+ // If no class found, it's at module level (global scope)
1054
+ if (scopePath.length === 0) {
1055
+ scopePath.push('global');
322
1056
  }
323
1057
 
324
- // For arrow functions and other cases, we can't perfectly match the ID
325
- // because FunctionVisitor uses a counter. For now, use module.id as fallback
326
- // to avoid creating invalid edges. The CALL node will be connected to MODULE
327
- // instead of the specific function.
328
- return module.id;
1058
+ // Compute semantic ID: {file}->{scopePath}->FUNCTION->{name}
1059
+ return `${module.file}->${scopePath.join('->')}->FUNCTION->${funcName}`;
329
1060
  }
330
1061
 
331
1062
  getHandlers(): VisitorHandlers {
@@ -339,26 +1070,43 @@ export class CallExpressionVisitor extends ASTVisitor {
339
1070
  const callSiteCounterRef = (this.collections.callSiteCounterRef ?? { value: 0 }) as CounterRef;
340
1071
  const literalCounterRef = (this.collections.literalCounterRef ?? { value: 0 }) as CounterRef;
341
1072
  const processedNodes = this.collections.processedNodes ?? { callSites: new Set(), methodCalls: new Set(), eventListeners: new Set() };
1073
+ const scopeTracker = this.scopeTracker;
342
1074
 
343
1075
  return {
344
1076
  CallExpression: (path: NodePath) => {
345
1077
  const callNode = path.node as CallExpression;
346
1078
  const functionParent = path.getFunctionParent();
1079
+
347
1080
  // Determine parent scope - if inside a function, use function's scope, otherwise module
348
1081
  const parentScopeId = functionParent ? this.getFunctionScopeId(functionParent, module) : module.id;
349
1082
 
350
1083
  // Identifier calls (direct function calls)
1084
+ // Skip if inside function - they will be processed by analyzeFunctionBody with proper scope tracking
351
1085
  if (callNode.callee.type === 'Identifier') {
1086
+ if (functionParent) {
1087
+ return;
1088
+ }
352
1089
  const callee = callNode.callee as Identifier;
353
- const callId = `CALL#${callee.name}#${module.file}#${callNode.loc!.start.line}:${callNode.loc!.start.column}:${callSiteCounterRef.value++}`;
1090
+
1091
+ const line = getLine(callNode);
1092
+ const column = getColumn(callNode);
1093
+
1094
+ // Generate ID using centralized IdGenerator
1095
+ const idGenerator = new IdGenerator(scopeTracker);
1096
+ const callId = idGenerator.generate(
1097
+ 'CALL', callee.name, module.file,
1098
+ line, column,
1099
+ callSiteCounterRef,
1100
+ { useDiscriminator: true, discriminatorKey: `CALL:${callee.name}` }
1101
+ );
354
1102
 
355
1103
  (callSites as CallSiteInfo[]).push({
356
1104
  id: callId,
357
1105
  type: 'CALL',
358
1106
  name: callee.name,
359
1107
  file: module.file,
360
- line: callNode.loc!.start.line,
361
- column: callNode.loc!.start.column,
1108
+ line,
1109
+ column,
362
1110
  parentScopeId,
363
1111
  targetFunctionName: callee.name
364
1112
  });
@@ -375,8 +1123,12 @@ export class CallExpressionVisitor extends ASTVisitor {
375
1123
  );
376
1124
  }
377
1125
  }
378
- // MemberExpression calls (method calls at module level)
1126
+ // MemberExpression calls (method calls)
1127
+ // Skip if inside function - they will be processed by analyzeFunctionBody with proper scope tracking
379
1128
  else if (callNode.callee.type === 'MemberExpression') {
1129
+ if (functionParent) {
1130
+ return;
1131
+ }
380
1132
  const memberCallee = callNode.callee as MemberExpression;
381
1133
  const object = memberCallee.object;
382
1134
  const property = memberCallee.property;
@@ -403,13 +1155,16 @@ export class CallExpressionVisitor extends ASTVisitor {
403
1155
  }
404
1156
  processedNodes.eventListeners.add(nodeKey);
405
1157
 
1158
+ const eventLine = getLine(callNode);
1159
+ const eventColumn = getColumn(callNode);
1160
+
406
1161
  (eventListeners as EventListenerInfo[]).push({
407
- id: `event:listener#${eventName}#${module.file}#${callNode.loc!.start.line}:${callNode.loc!.start.column}:${callSiteCounterRef.value++}`,
1162
+ id: `event:listener#${eventName}#${module.file}#${eventLine}:${eventColumn}:${callSiteCounterRef.value++}`,
408
1163
  type: 'event:listener',
409
1164
  name: eventName,
410
1165
  object: objectName,
411
1166
  file: module.file,
412
- line: callNode.loc!.start.line,
1167
+ line: eventLine,
413
1168
  parentScopeId,
414
1169
  callbackArg: secondArg
415
1170
  });
@@ -423,7 +1178,17 @@ export class CallExpressionVisitor extends ASTVisitor {
423
1178
  processedNodes.methodCalls.add(nodeKey);
424
1179
 
425
1180
  const fullName = `${objectName}.${methodName}`;
426
- const methodCallId = `CALL#${fullName}#${module.file}#${callNode.loc!.start.line}:${callNode.loc!.start.column}:${callSiteCounterRef.value++}`;
1181
+ const methodLine = getLine(callNode);
1182
+ const methodColumn = getColumn(callNode);
1183
+
1184
+ // Generate ID using centralized IdGenerator
1185
+ const idGenerator = new IdGenerator(scopeTracker);
1186
+ const methodCallId = idGenerator.generate(
1187
+ 'CALL', fullName, module.file,
1188
+ methodLine, methodColumn,
1189
+ callSiteCounterRef,
1190
+ { useDiscriminator: true, discriminatorKey: `CALL:${fullName}` }
1191
+ );
427
1192
 
428
1193
  (methodCalls as MethodCallInfo[]).push({
429
1194
  id: methodCallId,
@@ -434,11 +1199,27 @@ export class CallExpressionVisitor extends ASTVisitor {
434
1199
  computed: isComputed,
435
1200
  computedPropertyVar, // Variable name used in obj[x]() calls
436
1201
  file: module.file,
437
- line: callNode.loc!.start.line,
438
- column: callNode.loc!.start.column,
1202
+ line: methodLine,
1203
+ column: methodColumn,
439
1204
  parentScopeId
440
1205
  });
441
1206
 
1207
+ // Check for array mutation methods (push, unshift, splice)
1208
+ const ARRAY_MUTATION_METHODS = ['push', 'unshift', 'splice'];
1209
+ if (ARRAY_MUTATION_METHODS.includes(methodName)) {
1210
+ this.detectArrayMutation(
1211
+ callNode,
1212
+ objectName,
1213
+ methodName as 'push' | 'unshift' | 'splice',
1214
+ module
1215
+ );
1216
+ }
1217
+
1218
+ // Check for Object.assign() calls
1219
+ if (objectName === 'Object' && methodName === 'assign') {
1220
+ this.detectObjectAssign(callNode, module);
1221
+ }
1222
+
442
1223
  // Extract arguments for PASSES_ARGUMENT edges
443
1224
  if (callNode.arguments.length > 0) {
444
1225
  this.extractArguments(
@@ -455,8 +1236,8 @@ export class CallExpressionVisitor extends ASTVisitor {
455
1236
  if (arg.type === 'ArrowFunctionExpression' || arg.type === 'FunctionExpression') {
456
1237
  (methodCallbacks as MethodCallbackInfo[]).push({
457
1238
  methodCallId,
458
- callbackLine: arg.loc!.start.line,
459
- callbackColumn: arg.loc!.start.column,
1239
+ callbackLine: getLine(arg),
1240
+ callbackColumn: getColumn(arg),
460
1241
  callbackType: arg.type
461
1242
  });
462
1243
  }
@@ -464,14 +1245,52 @@ export class CallExpressionVisitor extends ASTVisitor {
464
1245
  }
465
1246
  }
466
1247
  }
1248
+ // REG-117: Nested array mutations like obj.arr.push(item)
1249
+ // object is MemberExpression, property is the method name
1250
+ else if (object.type === 'MemberExpression' && property.type === 'Identifier') {
1251
+ const nestedMember = object as MemberExpression;
1252
+ const methodName = (property as Identifier).name;
1253
+ const ARRAY_MUTATION_METHODS = ['push', 'unshift', 'splice'];
1254
+
1255
+ if (ARRAY_MUTATION_METHODS.includes(methodName)) {
1256
+ // Extract base object and property from nested MemberExpression
1257
+ const base = nestedMember.object;
1258
+ const prop = nestedMember.property;
1259
+
1260
+ // Only handle single-level nesting: obj.arr.push() or this.items.push()
1261
+ if ((base.type === 'Identifier' || base.type === 'ThisExpression') &&
1262
+ !nestedMember.computed &&
1263
+ prop.type === 'Identifier') {
1264
+ const baseObjectName = base.type === 'Identifier' ? (base as Identifier).name : 'this';
1265
+ const propertyName = (prop as Identifier).name;
1266
+
1267
+ this.detectArrayMutation(
1268
+ callNode,
1269
+ `${baseObjectName}.${propertyName}`, // arrayName for ID purposes
1270
+ methodName as 'push' | 'unshift' | 'splice',
1271
+ module,
1272
+ true, // isNested
1273
+ baseObjectName,
1274
+ propertyName
1275
+ );
1276
+ }
1277
+ }
1278
+ }
467
1279
  }
468
1280
  },
469
1281
 
470
1282
  // NewExpression: new Foo(), new Function(), new Map(), etc.
1283
+ // Skip if inside function - they will be processed by analyzeFunctionBody with proper scope tracking
471
1284
  NewExpression: (path: NodePath) => {
472
1285
  const newNode = path.node as NewExpression;
473
1286
  const functionParent = path.getFunctionParent();
474
- const parentScopeId = functionParent ? this.getFunctionScopeId(functionParent, module) : module.id;
1287
+
1288
+ // Skip if inside function - handled by analyzeFunctionBody
1289
+ if (functionParent) {
1290
+ return;
1291
+ }
1292
+
1293
+ const parentScopeId = module.id;
475
1294
 
476
1295
  // Dedup check
477
1296
  const nodeKey = `new:${newNode.start}:${newNode.end}`;
@@ -484,14 +1303,25 @@ export class CallExpressionVisitor extends ASTVisitor {
484
1303
  if (newNode.callee.type === 'Identifier') {
485
1304
  const callee = newNode.callee as Identifier;
486
1305
  const constructorName = callee.name;
1306
+ const newLine = getLine(newNode);
1307
+ const newColumn = getColumn(newNode);
1308
+
1309
+ // Generate ID using centralized IdGenerator
1310
+ const idGenerator = new IdGenerator(scopeTracker);
1311
+ const newCallId = idGenerator.generate(
1312
+ 'CALL', `new:${constructorName}`, module.file,
1313
+ newLine, newColumn,
1314
+ callSiteCounterRef,
1315
+ { useDiscriminator: true, discriminatorKey: `CALL:new:${constructorName}` }
1316
+ );
487
1317
 
488
1318
  (callSites as CallSiteInfo[]).push({
489
- id: `CALL#new:${constructorName}#${module.file}#${newNode.loc!.start.line}:${newNode.loc!.start.column}:${callSiteCounterRef.value++}`,
1319
+ id: newCallId,
490
1320
  type: 'CALL',
491
1321
  name: constructorName,
492
1322
  file: module.file,
493
- line: newNode.loc!.start.line,
494
- column: newNode.loc!.start.column,
1323
+ line: newLine,
1324
+ column: newColumn,
495
1325
  parentScopeId,
496
1326
  targetFunctionName: constructorName,
497
1327
  isNew: true // Mark as constructor call
@@ -507,16 +1337,27 @@ export class CallExpressionVisitor extends ASTVisitor {
507
1337
  const objectName = (object as Identifier).name;
508
1338
  const constructorName = (property as Identifier).name;
509
1339
  const fullName = `${objectName}.${constructorName}`;
1340
+ const memberNewLine = getLine(newNode);
1341
+ const memberNewColumn = getColumn(newNode);
1342
+
1343
+ // Generate ID using centralized IdGenerator
1344
+ const idGenerator = new IdGenerator(scopeTracker);
1345
+ const newMethodCallId = idGenerator.generate(
1346
+ 'CALL', `new:${fullName}`, module.file,
1347
+ memberNewLine, memberNewColumn,
1348
+ callSiteCounterRef,
1349
+ { useDiscriminator: true, discriminatorKey: `CALL:new:${fullName}` }
1350
+ );
510
1351
 
511
1352
  (methodCalls as MethodCallInfo[]).push({
512
- id: `CALL#new:${fullName}#${module.file}#${newNode.loc!.start.line}:${newNode.loc!.start.column}:${callSiteCounterRef.value++}`,
1353
+ id: newMethodCallId,
513
1354
  type: 'CALL',
514
1355
  name: fullName,
515
1356
  object: objectName,
516
1357
  method: constructorName,
517
1358
  file: module.file,
518
- line: newNode.loc!.start.line,
519
- column: newNode.loc!.start.column,
1359
+ line: memberNewLine,
1360
+ column: memberNewColumn,
520
1361
  parentScopeId,
521
1362
  isNew: true // Mark as constructor call
522
1363
  });