@grafema/core 0.2.5-beta → 0.2.7

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 (769) hide show
  1. package/README.md +61 -23
  2. package/dist/DiscoveryManager.d.ts +59 -0
  3. package/dist/DiscoveryManager.d.ts.map +1 -0
  4. package/dist/DiscoveryManager.js +249 -0
  5. package/dist/DiscoveryManager.js.map +1 -0
  6. package/dist/GraphInitializer.d.ts +44 -0
  7. package/dist/GraphInitializer.d.ts.map +1 -0
  8. package/dist/GraphInitializer.js +121 -0
  9. package/dist/GraphInitializer.js.map +1 -0
  10. package/dist/GuaranteeChecker.d.ts +35 -0
  11. package/dist/GuaranteeChecker.d.ts.map +1 -0
  12. package/dist/GuaranteeChecker.js +81 -0
  13. package/dist/GuaranteeChecker.js.map +1 -0
  14. package/dist/Orchestrator.d.ts +34 -151
  15. package/dist/Orchestrator.d.ts.map +1 -1
  16. package/dist/Orchestrator.js +173 -741
  17. package/dist/Orchestrator.js.map +1 -1
  18. package/dist/OrchestratorTypes.d.ts +115 -0
  19. package/dist/OrchestratorTypes.d.ts.map +1 -0
  20. package/dist/OrchestratorTypes.js +6 -0
  21. package/dist/OrchestratorTypes.js.map +1 -0
  22. package/dist/ParallelAnalysisRunner.d.ts +43 -0
  23. package/dist/ParallelAnalysisRunner.d.ts.map +1 -0
  24. package/dist/ParallelAnalysisRunner.js +161 -0
  25. package/dist/ParallelAnalysisRunner.js.map +1 -0
  26. package/dist/PhaseRunner.d.ts +94 -0
  27. package/dist/PhaseRunner.d.ts.map +1 -0
  28. package/dist/PhaseRunner.js +332 -0
  29. package/dist/PhaseRunner.js.map +1 -0
  30. package/dist/config/ConfigLoader.d.ts +51 -1
  31. package/dist/config/ConfigLoader.d.ts.map +1 -1
  32. package/dist/config/ConfigLoader.js +121 -1
  33. package/dist/config/ConfigLoader.js.map +1 -1
  34. package/dist/config/index.d.ts +1 -1
  35. package/dist/config/index.d.ts.map +1 -1
  36. package/dist/config/index.js +1 -1
  37. package/dist/config/index.js.map +1 -1
  38. package/dist/core/ASTWorker.d.ts +2 -0
  39. package/dist/core/ASTWorker.d.ts.map +1 -1
  40. package/dist/core/ASTWorker.js +6 -2
  41. package/dist/core/ASTWorker.js.map +1 -1
  42. package/dist/core/FileOverview.d.ts +124 -0
  43. package/dist/core/FileOverview.d.ts.map +1 -0
  44. package/dist/core/FileOverview.js +257 -0
  45. package/dist/core/FileOverview.js.map +1 -0
  46. package/dist/core/GraphFreshnessChecker.d.ts +1 -1
  47. package/dist/core/GraphFreshnessChecker.d.ts.map +1 -1
  48. package/dist/core/GraphFreshnessChecker.js +7 -5
  49. package/dist/core/GraphFreshnessChecker.js.map +1 -1
  50. package/dist/core/GuaranteeManager.d.ts +13 -0
  51. package/dist/core/GuaranteeManager.d.ts.map +1 -1
  52. package/dist/core/GuaranteeManager.js +63 -2
  53. package/dist/core/GuaranteeManager.js.map +1 -1
  54. package/dist/core/IncrementalReanalyzer.d.ts.map +1 -1
  55. package/dist/core/IncrementalReanalyzer.js +6 -3
  56. package/dist/core/IncrementalReanalyzer.js.map +1 -1
  57. package/dist/core/NodeFactory.d.ts +81 -415
  58. package/dist/core/NodeFactory.d.ts.map +1 -1
  59. package/dist/core/NodeFactory.js +139 -336
  60. package/dist/core/NodeFactory.js.map +1 -1
  61. package/dist/core/ResourceRegistry.d.ts +17 -0
  62. package/dist/core/ResourceRegistry.d.ts.map +1 -0
  63. package/dist/core/ResourceRegistry.js +32 -0
  64. package/dist/core/ResourceRegistry.js.map +1 -0
  65. package/dist/core/ScopeTracker.d.ts +12 -0
  66. package/dist/core/ScopeTracker.d.ts.map +1 -1
  67. package/dist/core/ScopeTracker.js +24 -0
  68. package/dist/core/ScopeTracker.js.map +1 -1
  69. package/dist/core/SemanticId.d.ts +69 -0
  70. package/dist/core/SemanticId.d.ts.map +1 -1
  71. package/dist/core/SemanticId.js +134 -0
  72. package/dist/core/SemanticId.js.map +1 -1
  73. package/dist/core/brandNodeInternal.d.ts +14 -0
  74. package/dist/core/brandNodeInternal.d.ts.map +1 -0
  75. package/dist/core/brandNodeInternal.js +4 -0
  76. package/dist/core/brandNodeInternal.js.map +1 -0
  77. package/dist/core/buildDependencyGraph.d.ts +36 -0
  78. package/dist/core/buildDependencyGraph.d.ts.map +1 -0
  79. package/dist/core/buildDependencyGraph.js +78 -0
  80. package/dist/core/buildDependencyGraph.js.map +1 -0
  81. package/dist/core/factories/CoreFactory.d.ts +223 -0
  82. package/dist/core/factories/CoreFactory.d.ts.map +1 -0
  83. package/dist/core/factories/CoreFactory.js +127 -0
  84. package/dist/core/factories/CoreFactory.js.map +1 -0
  85. package/dist/core/factories/DatabaseFactory.d.ts +29 -0
  86. package/dist/core/factories/DatabaseFactory.d.ts.map +1 -0
  87. package/dist/core/factories/DatabaseFactory.js +25 -0
  88. package/dist/core/factories/DatabaseFactory.js.map +1 -0
  89. package/dist/core/factories/ExternalFactory.d.ts +11 -0
  90. package/dist/core/factories/ExternalFactory.d.ts.map +1 -0
  91. package/dist/core/factories/ExternalFactory.js +16 -0
  92. package/dist/core/factories/ExternalFactory.js.map +1 -0
  93. package/dist/core/factories/HttpFactory.d.ts +22 -0
  94. package/dist/core/factories/HttpFactory.d.ts.map +1 -0
  95. package/dist/core/factories/HttpFactory.js +32 -0
  96. package/dist/core/factories/HttpFactory.js.map +1 -0
  97. package/dist/core/factories/ReactFactory.d.ts +14 -0
  98. package/dist/core/factories/ReactFactory.d.ts.map +1 -0
  99. package/dist/core/factories/ReactFactory.js +13 -0
  100. package/dist/core/factories/ReactFactory.js.map +1 -0
  101. package/dist/core/factories/RustFactory.d.ts +62 -0
  102. package/dist/core/factories/RustFactory.d.ts.map +1 -0
  103. package/dist/core/factories/RustFactory.js +32 -0
  104. package/dist/core/factories/RustFactory.js.map +1 -0
  105. package/dist/core/factories/ServiceFactory.d.ts +12 -0
  106. package/dist/core/factories/ServiceFactory.d.ts.map +1 -0
  107. package/dist/core/factories/ServiceFactory.js +22 -0
  108. package/dist/core/factories/ServiceFactory.js.map +1 -0
  109. package/dist/core/factories/SocketFactory.d.ts +31 -0
  110. package/dist/core/factories/SocketFactory.d.ts.map +1 -0
  111. package/dist/core/factories/SocketFactory.js +35 -0
  112. package/dist/core/factories/SocketFactory.js.map +1 -0
  113. package/dist/core/nodes/DatabaseNode.d.ts +85 -0
  114. package/dist/core/nodes/DatabaseNode.d.ts.map +1 -0
  115. package/dist/core/nodes/DatabaseNode.js +118 -0
  116. package/dist/core/nodes/DatabaseNode.js.map +1 -0
  117. package/dist/core/nodes/ExpressMiddlewareNode.d.ts +47 -0
  118. package/dist/core/nodes/ExpressMiddlewareNode.d.ts.map +1 -0
  119. package/dist/core/nodes/ExpressMiddlewareNode.js +63 -0
  120. package/dist/core/nodes/ExpressMiddlewareNode.js.map +1 -0
  121. package/dist/core/nodes/ExpressMountNode.d.ts +44 -0
  122. package/dist/core/nodes/ExpressMountNode.d.ts.map +1 -0
  123. package/dist/core/nodes/ExpressMountNode.js +61 -0
  124. package/dist/core/nodes/ExpressMountNode.js.map +1 -0
  125. package/dist/core/nodes/ExternalApiNode.d.ts +29 -0
  126. package/dist/core/nodes/ExternalApiNode.d.ts.map +1 -0
  127. package/dist/core/nodes/ExternalApiNode.js +41 -0
  128. package/dist/core/nodes/ExternalApiNode.js.map +1 -0
  129. package/dist/core/nodes/ExternalFunctionNode.d.ts +40 -0
  130. package/dist/core/nodes/ExternalFunctionNode.d.ts.map +1 -0
  131. package/dist/core/nodes/ExternalFunctionNode.js +54 -0
  132. package/dist/core/nodes/ExternalFunctionNode.js.map +1 -0
  133. package/dist/core/nodes/FetchRequestNode.d.ts +54 -0
  134. package/dist/core/nodes/FetchRequestNode.d.ts.map +1 -0
  135. package/dist/core/nodes/FetchRequestNode.js +67 -0
  136. package/dist/core/nodes/FetchRequestNode.js.map +1 -0
  137. package/dist/core/nodes/HttpRouteNode.d.ts +58 -0
  138. package/dist/core/nodes/HttpRouteNode.d.ts.map +1 -0
  139. package/dist/core/nodes/HttpRouteNode.js +72 -0
  140. package/dist/core/nodes/HttpRouteNode.js.map +1 -0
  141. package/dist/core/nodes/NodeKind.d.ts +1 -0
  142. package/dist/core/nodes/NodeKind.d.ts.map +1 -1
  143. package/dist/core/nodes/NodeKind.js +1 -0
  144. package/dist/core/nodes/NodeKind.js.map +1 -1
  145. package/dist/core/nodes/ReactNode.d.ts +53 -0
  146. package/dist/core/nodes/ReactNode.d.ts.map +1 -0
  147. package/dist/core/nodes/ReactNode.js +70 -0
  148. package/dist/core/nodes/ReactNode.js.map +1 -0
  149. package/dist/core/nodes/RustCallNode.d.ts +46 -0
  150. package/dist/core/nodes/RustCallNode.d.ts.map +1 -0
  151. package/dist/core/nodes/RustCallNode.js +62 -0
  152. package/dist/core/nodes/RustCallNode.js.map +1 -0
  153. package/dist/core/nodes/RustFunctionNode.d.ts +58 -0
  154. package/dist/core/nodes/RustFunctionNode.d.ts.map +1 -0
  155. package/dist/core/nodes/RustFunctionNode.js +67 -0
  156. package/dist/core/nodes/RustFunctionNode.js.map +1 -0
  157. package/dist/core/nodes/RustImplNode.d.ts +35 -0
  158. package/dist/core/nodes/RustImplNode.d.ts.map +1 -0
  159. package/dist/core/nodes/RustImplNode.js +55 -0
  160. package/dist/core/nodes/RustImplNode.js.map +1 -0
  161. package/dist/core/nodes/RustMethodNode.d.ts +64 -0
  162. package/dist/core/nodes/RustMethodNode.d.ts.map +1 -0
  163. package/dist/core/nodes/RustMethodNode.js +76 -0
  164. package/dist/core/nodes/RustMethodNode.js.map +1 -0
  165. package/dist/core/nodes/RustModuleNode.d.ts +40 -0
  166. package/dist/core/nodes/RustModuleNode.d.ts.map +1 -0
  167. package/dist/core/nodes/RustModuleNode.js +57 -0
  168. package/dist/core/nodes/RustModuleNode.js.map +1 -0
  169. package/dist/core/nodes/RustStructNode.d.ts +38 -0
  170. package/dist/core/nodes/RustStructNode.d.ts.map +1 -0
  171. package/dist/core/nodes/RustStructNode.js +54 -0
  172. package/dist/core/nodes/RustStructNode.js.map +1 -0
  173. package/dist/core/nodes/RustTraitNode.d.ts +40 -0
  174. package/dist/core/nodes/RustTraitNode.d.ts.map +1 -0
  175. package/dist/core/nodes/RustTraitNode.js +52 -0
  176. package/dist/core/nodes/RustTraitNode.js.map +1 -0
  177. package/dist/core/nodes/ServiceLayerNode.d.ts +85 -0
  178. package/dist/core/nodes/ServiceLayerNode.d.ts.map +1 -0
  179. package/dist/core/nodes/ServiceLayerNode.js +122 -0
  180. package/dist/core/nodes/ServiceLayerNode.js.map +1 -0
  181. package/dist/core/nodes/SocketIONode.d.ts +71 -0
  182. package/dist/core/nodes/SocketIONode.d.ts.map +1 -0
  183. package/dist/core/nodes/SocketIONode.js +111 -0
  184. package/dist/core/nodes/SocketIONode.js.map +1 -0
  185. package/dist/core/nodes/SocketNode.d.ts +87 -0
  186. package/dist/core/nodes/SocketNode.d.ts.map +1 -0
  187. package/dist/core/nodes/SocketNode.js +124 -0
  188. package/dist/core/nodes/SocketNode.js.map +1 -0
  189. package/dist/core/nodes/TypeNode.d.ts +26 -1
  190. package/dist/core/nodes/TypeNode.d.ts.map +1 -1
  191. package/dist/core/nodes/TypeNode.js +21 -3
  192. package/dist/core/nodes/TypeNode.js.map +1 -1
  193. package/dist/core/nodes/TypeParameterNode.d.ts +44 -0
  194. package/dist/core/nodes/TypeParameterNode.d.ts.map +1 -0
  195. package/dist/core/nodes/TypeParameterNode.js +64 -0
  196. package/dist/core/nodes/TypeParameterNode.js.map +1 -0
  197. package/dist/core/nodes/index.d.ts +19 -0
  198. package/dist/core/nodes/index.d.ts.map +1 -1
  199. package/dist/core/nodes/index.js +26 -0
  200. package/dist/core/nodes/index.js.map +1 -1
  201. package/dist/index.d.ts +33 -6
  202. package/dist/index.d.ts.map +1 -1
  203. package/dist/index.js +30 -3
  204. package/dist/index.js.map +1 -1
  205. package/dist/plugins/InfraAnalyzer.d.ts +110 -0
  206. package/dist/plugins/InfraAnalyzer.d.ts.map +1 -0
  207. package/dist/plugins/InfraAnalyzer.js +170 -0
  208. package/dist/plugins/InfraAnalyzer.js.map +1 -0
  209. package/dist/plugins/analysis/DatabaseAnalyzer.d.ts.map +1 -1
  210. package/dist/plugins/analysis/DatabaseAnalyzer.js +18 -15
  211. package/dist/plugins/analysis/DatabaseAnalyzer.js.map +1 -1
  212. package/dist/plugins/analysis/ExpressAnalyzer.d.ts.map +1 -1
  213. package/dist/plugins/analysis/ExpressAnalyzer.js +27 -26
  214. package/dist/plugins/analysis/ExpressAnalyzer.js.map +1 -1
  215. package/dist/plugins/analysis/ExpressResponseAnalyzer.d.ts.map +1 -1
  216. package/dist/plugins/analysis/ExpressResponseAnalyzer.js +5 -3
  217. package/dist/plugins/analysis/ExpressResponseAnalyzer.js.map +1 -1
  218. package/dist/plugins/analysis/ExpressRouteAnalyzer.d.ts.map +1 -1
  219. package/dist/plugins/analysis/ExpressRouteAnalyzer.js +36 -39
  220. package/dist/plugins/analysis/ExpressRouteAnalyzer.js.map +1 -1
  221. package/dist/plugins/analysis/FetchAnalyzer.d.ts.map +1 -1
  222. package/dist/plugins/analysis/FetchAnalyzer.js +23 -39
  223. package/dist/plugins/analysis/FetchAnalyzer.js.map +1 -1
  224. package/dist/plugins/analysis/IncrementalAnalysisPlugin.d.ts.map +1 -1
  225. package/dist/plugins/analysis/IncrementalAnalysisPlugin.js +3 -2
  226. package/dist/plugins/analysis/IncrementalAnalysisPlugin.js.map +1 -1
  227. package/dist/plugins/analysis/JSASTAnalyzer.d.ts +23 -85
  228. package/dist/plugins/analysis/JSASTAnalyzer.d.ts.map +1 -1
  229. package/dist/plugins/analysis/JSASTAnalyzer.js +351 -1887
  230. package/dist/plugins/analysis/JSASTAnalyzer.js.map +1 -1
  231. package/dist/plugins/analysis/NestJSRouteAnalyzer.d.ts +28 -0
  232. package/dist/plugins/analysis/NestJSRouteAnalyzer.d.ts.map +1 -0
  233. package/dist/plugins/analysis/NestJSRouteAnalyzer.js +196 -0
  234. package/dist/plugins/analysis/NestJSRouteAnalyzer.js.map +1 -0
  235. package/dist/plugins/analysis/ReactAnalyzer.d.ts +1 -61
  236. package/dist/plugins/analysis/ReactAnalyzer.d.ts.map +1 -1
  237. package/dist/plugins/analysis/ReactAnalyzer.js +24 -915
  238. package/dist/plugins/analysis/ReactAnalyzer.js.map +1 -1
  239. package/dist/plugins/analysis/RustAnalyzer.d.ts.map +1 -1
  240. package/dist/plugins/analysis/RustAnalyzer.js +31 -66
  241. package/dist/plugins/analysis/RustAnalyzer.js.map +1 -1
  242. package/dist/plugins/analysis/SQLiteAnalyzer.d.ts.map +1 -1
  243. package/dist/plugins/analysis/SQLiteAnalyzer.js +13 -6
  244. package/dist/plugins/analysis/SQLiteAnalyzer.js.map +1 -1
  245. package/dist/plugins/analysis/ServiceLayerAnalyzer.d.ts.map +1 -1
  246. package/dist/plugins/analysis/ServiceLayerAnalyzer.js +10 -7
  247. package/dist/plugins/analysis/ServiceLayerAnalyzer.js.map +1 -1
  248. package/dist/plugins/analysis/SocketAnalyzer.d.ts +81 -0
  249. package/dist/plugins/analysis/SocketAnalyzer.d.ts.map +1 -0
  250. package/dist/plugins/analysis/SocketAnalyzer.js +475 -0
  251. package/dist/plugins/analysis/SocketAnalyzer.js.map +1 -0
  252. package/dist/plugins/analysis/SocketIOAnalyzer.d.ts.map +1 -1
  253. package/dist/plugins/analysis/SocketIOAnalyzer.js +13 -18
  254. package/dist/plugins/analysis/SocketIOAnalyzer.js.map +1 -1
  255. package/dist/plugins/analysis/SystemDbAnalyzer.d.ts.map +1 -1
  256. package/dist/plugins/analysis/SystemDbAnalyzer.js +8 -5
  257. package/dist/plugins/analysis/SystemDbAnalyzer.js.map +1 -1
  258. package/dist/plugins/analysis/ast/CollisionResolver.d.ts +65 -0
  259. package/dist/plugins/analysis/ast/CollisionResolver.d.ts.map +1 -0
  260. package/dist/plugins/analysis/ast/CollisionResolver.js +106 -0
  261. package/dist/plugins/analysis/ast/CollisionResolver.js.map +1 -0
  262. package/dist/plugins/analysis/ast/FunctionBodyContext.d.ts +124 -0
  263. package/dist/plugins/analysis/ast/FunctionBodyContext.d.ts.map +1 -0
  264. package/dist/plugins/analysis/ast/FunctionBodyContext.js +151 -0
  265. package/dist/plugins/analysis/ast/FunctionBodyContext.js.map +1 -0
  266. package/dist/plugins/analysis/ast/GraphBuilder.d.ts +26 -261
  267. package/dist/plugins/analysis/ast/GraphBuilder.d.ts.map +1 -1
  268. package/dist/plugins/analysis/ast/GraphBuilder.js +251 -2494
  269. package/dist/plugins/analysis/ast/GraphBuilder.js.map +1 -1
  270. package/dist/plugins/analysis/ast/IdGenerator.d.ts +42 -0
  271. package/dist/plugins/analysis/ast/IdGenerator.d.ts.map +1 -1
  272. package/dist/plugins/analysis/ast/IdGenerator.js +61 -1
  273. package/dist/plugins/analysis/ast/IdGenerator.js.map +1 -1
  274. package/dist/plugins/analysis/ast/builders/AssignmentBuilder.d.ts +15 -0
  275. package/dist/plugins/analysis/ast/builders/AssignmentBuilder.d.ts.map +1 -0
  276. package/dist/plugins/analysis/ast/builders/AssignmentBuilder.js +274 -0
  277. package/dist/plugins/analysis/ast/builders/AssignmentBuilder.js.map +1 -0
  278. package/dist/plugins/analysis/ast/builders/CallFlowBuilder.d.ts +22 -0
  279. package/dist/plugins/analysis/ast/builders/CallFlowBuilder.d.ts.map +1 -0
  280. package/dist/plugins/analysis/ast/builders/CallFlowBuilder.js +178 -0
  281. package/dist/plugins/analysis/ast/builders/CallFlowBuilder.js.map +1 -0
  282. package/dist/plugins/analysis/ast/builders/ControlFlowBuilder.d.ts +76 -0
  283. package/dist/plugins/analysis/ast/builders/ControlFlowBuilder.d.ts.map +1 -0
  284. package/dist/plugins/analysis/ast/builders/ControlFlowBuilder.js +387 -0
  285. package/dist/plugins/analysis/ast/builders/ControlFlowBuilder.js.map +1 -0
  286. package/dist/plugins/analysis/ast/builders/CoreBuilder.d.ts +38 -0
  287. package/dist/plugins/analysis/ast/builders/CoreBuilder.d.ts.map +1 -0
  288. package/dist/plugins/analysis/ast/builders/CoreBuilder.js +240 -0
  289. package/dist/plugins/analysis/ast/builders/CoreBuilder.js.map +1 -0
  290. package/dist/plugins/analysis/ast/builders/ModuleRuntimeBuilder.d.ts +53 -0
  291. package/dist/plugins/analysis/ast/builders/ModuleRuntimeBuilder.d.ts.map +1 -0
  292. package/dist/plugins/analysis/ast/builders/ModuleRuntimeBuilder.js +355 -0
  293. package/dist/plugins/analysis/ast/builders/ModuleRuntimeBuilder.js.map +1 -0
  294. package/dist/plugins/analysis/ast/builders/MutationBuilder.d.ts +46 -0
  295. package/dist/plugins/analysis/ast/builders/MutationBuilder.d.ts.map +1 -0
  296. package/dist/plugins/analysis/ast/builders/MutationBuilder.js +264 -0
  297. package/dist/plugins/analysis/ast/builders/MutationBuilder.js.map +1 -0
  298. package/dist/plugins/analysis/ast/builders/ReturnBuilder.d.ts +23 -0
  299. package/dist/plugins/analysis/ast/builders/ReturnBuilder.d.ts.map +1 -0
  300. package/dist/plugins/analysis/ast/builders/ReturnBuilder.js +206 -0
  301. package/dist/plugins/analysis/ast/builders/ReturnBuilder.js.map +1 -0
  302. package/dist/plugins/analysis/ast/builders/TypeSystemBuilder.d.ts +64 -0
  303. package/dist/plugins/analysis/ast/builders/TypeSystemBuilder.d.ts.map +1 -0
  304. package/dist/plugins/analysis/ast/builders/TypeSystemBuilder.js +370 -0
  305. package/dist/plugins/analysis/ast/builders/TypeSystemBuilder.js.map +1 -0
  306. package/dist/plugins/analysis/ast/builders/UpdateExpressionBuilder.d.ts +46 -0
  307. package/dist/plugins/analysis/ast/builders/UpdateExpressionBuilder.d.ts.map +1 -0
  308. package/dist/plugins/analysis/ast/builders/UpdateExpressionBuilder.js +191 -0
  309. package/dist/plugins/analysis/ast/builders/UpdateExpressionBuilder.js.map +1 -0
  310. package/dist/plugins/analysis/ast/builders/YieldBuilder.d.ts +30 -0
  311. package/dist/plugins/analysis/ast/builders/YieldBuilder.d.ts.map +1 -0
  312. package/dist/plugins/analysis/ast/builders/YieldBuilder.js +214 -0
  313. package/dist/plugins/analysis/ast/builders/YieldBuilder.js.map +1 -0
  314. package/dist/plugins/analysis/ast/builders/index.d.ts +12 -0
  315. package/dist/plugins/analysis/ast/builders/index.d.ts.map +1 -0
  316. package/dist/plugins/analysis/ast/builders/index.js +11 -0
  317. package/dist/plugins/analysis/ast/builders/index.js.map +1 -0
  318. package/dist/plugins/analysis/ast/builders/types.d.ts +30 -0
  319. package/dist/plugins/analysis/ast/builders/types.d.ts.map +1 -0
  320. package/dist/plugins/analysis/ast/builders/types.js +8 -0
  321. package/dist/plugins/analysis/ast/builders/types.js.map +1 -0
  322. package/dist/plugins/analysis/ast/handlers/AnalyzerDelegate.d.ts +50 -0
  323. package/dist/plugins/analysis/ast/handlers/AnalyzerDelegate.d.ts.map +1 -0
  324. package/dist/plugins/analysis/ast/handlers/AnalyzerDelegate.js +2 -0
  325. package/dist/plugins/analysis/ast/handlers/AnalyzerDelegate.js.map +1 -0
  326. package/dist/plugins/analysis/ast/handlers/BranchHandler.d.ts +18 -0
  327. package/dist/plugins/analysis/ast/handlers/BranchHandler.d.ts.map +1 -0
  328. package/dist/plugins/analysis/ast/handlers/BranchHandler.js +244 -0
  329. package/dist/plugins/analysis/ast/handlers/BranchHandler.js.map +1 -0
  330. package/dist/plugins/analysis/ast/handlers/CallExpressionHandler.d.ts +7 -0
  331. package/dist/plugins/analysis/ast/handlers/CallExpressionHandler.d.ts.map +1 -0
  332. package/dist/plugins/analysis/ast/handlers/CallExpressionHandler.js +295 -0
  333. package/dist/plugins/analysis/ast/handlers/CallExpressionHandler.js.map +1 -0
  334. package/dist/plugins/analysis/ast/handlers/FunctionBodyHandler.d.ts +22 -0
  335. package/dist/plugins/analysis/ast/handlers/FunctionBodyHandler.d.ts.map +1 -0
  336. package/dist/plugins/analysis/ast/handlers/FunctionBodyHandler.js +9 -0
  337. package/dist/plugins/analysis/ast/handlers/FunctionBodyHandler.js.map +1 -0
  338. package/dist/plugins/analysis/ast/handlers/LoopHandler.d.ts +13 -0
  339. package/dist/plugins/analysis/ast/handlers/LoopHandler.d.ts.map +1 -0
  340. package/dist/plugins/analysis/ast/handlers/LoopHandler.js +207 -0
  341. package/dist/plugins/analysis/ast/handlers/LoopHandler.js.map +1 -0
  342. package/dist/plugins/analysis/ast/handlers/NestedFunctionHandler.d.ts +13 -0
  343. package/dist/plugins/analysis/ast/handlers/NestedFunctionHandler.d.ts.map +1 -0
  344. package/dist/plugins/analysis/ast/handlers/NestedFunctionHandler.js +174 -0
  345. package/dist/plugins/analysis/ast/handlers/NestedFunctionHandler.js.map +1 -0
  346. package/dist/plugins/analysis/ast/handlers/NewExpressionHandler.d.ts +12 -0
  347. package/dist/plugins/analysis/ast/handlers/NewExpressionHandler.d.ts.map +1 -0
  348. package/dist/plugins/analysis/ast/handlers/NewExpressionHandler.js +135 -0
  349. package/dist/plugins/analysis/ast/handlers/NewExpressionHandler.js.map +1 -0
  350. package/dist/plugins/analysis/ast/handlers/PropertyAccessHandler.d.ts +13 -0
  351. package/dist/plugins/analysis/ast/handlers/PropertyAccessHandler.d.ts.map +1 -0
  352. package/dist/plugins/analysis/ast/handlers/PropertyAccessHandler.js +71 -0
  353. package/dist/plugins/analysis/ast/handlers/PropertyAccessHandler.js.map +1 -0
  354. package/dist/plugins/analysis/ast/handlers/ReturnYieldHandler.d.ts +12 -0
  355. package/dist/plugins/analysis/ast/handlers/ReturnYieldHandler.d.ts.map +1 -0
  356. package/dist/plugins/analysis/ast/handlers/ReturnYieldHandler.js +135 -0
  357. package/dist/plugins/analysis/ast/handlers/ReturnYieldHandler.js.map +1 -0
  358. package/dist/plugins/analysis/ast/handlers/ThrowHandler.d.ts +12 -0
  359. package/dist/plugins/analysis/ast/handlers/ThrowHandler.d.ts.map +1 -0
  360. package/dist/plugins/analysis/ast/handlers/ThrowHandler.js +82 -0
  361. package/dist/plugins/analysis/ast/handlers/ThrowHandler.js.map +1 -0
  362. package/dist/plugins/analysis/ast/handlers/TryCatchHandler.d.ts +14 -0
  363. package/dist/plugins/analysis/ast/handlers/TryCatchHandler.d.ts.map +1 -0
  364. package/dist/plugins/analysis/ast/handlers/TryCatchHandler.js +220 -0
  365. package/dist/plugins/analysis/ast/handlers/TryCatchHandler.js.map +1 -0
  366. package/dist/plugins/analysis/ast/handlers/VariableHandler.d.ts +12 -0
  367. package/dist/plugins/analysis/ast/handlers/VariableHandler.d.ts.map +1 -0
  368. package/dist/plugins/analysis/ast/handlers/VariableHandler.js +57 -0
  369. package/dist/plugins/analysis/ast/handlers/VariableHandler.js.map +1 -0
  370. package/dist/plugins/analysis/ast/handlers/index.d.ts +13 -0
  371. package/dist/plugins/analysis/ast/handlers/index.d.ts.map +1 -0
  372. package/dist/plugins/analysis/ast/handlers/index.js +12 -0
  373. package/dist/plugins/analysis/ast/handlers/index.js.map +1 -0
  374. package/dist/plugins/analysis/ast/types.d.ts +57 -6
  375. package/dist/plugins/analysis/ast/types.d.ts.map +1 -1
  376. package/dist/plugins/analysis/ast/utils/createParameterNodes.d.ts +5 -4
  377. package/dist/plugins/analysis/ast/utils/createParameterNodes.d.ts.map +1 -1
  378. package/dist/plugins/analysis/ast/utils/createParameterNodes.js +94 -13
  379. package/dist/plugins/analysis/ast/utils/createParameterNodes.js.map +1 -1
  380. package/dist/plugins/analysis/ast/utils/extractNamesFromPattern.d.ts +81 -0
  381. package/dist/plugins/analysis/ast/utils/extractNamesFromPattern.d.ts.map +1 -0
  382. package/dist/plugins/analysis/ast/utils/extractNamesFromPattern.js +140 -0
  383. package/dist/plugins/analysis/ast/utils/extractNamesFromPattern.js.map +1 -0
  384. package/dist/plugins/analysis/ast/utils/getExpressionValue.d.ts +22 -0
  385. package/dist/plugins/analysis/ast/utils/getExpressionValue.d.ts.map +1 -0
  386. package/dist/plugins/analysis/ast/utils/getExpressionValue.js +35 -0
  387. package/dist/plugins/analysis/ast/utils/getExpressionValue.js.map +1 -0
  388. package/dist/plugins/analysis/ast/utils/getMemberExpressionName.d.ts +25 -0
  389. package/dist/plugins/analysis/ast/utils/getMemberExpressionName.d.ts.map +1 -0
  390. package/dist/plugins/analysis/ast/utils/getMemberExpressionName.js +21 -0
  391. package/dist/plugins/analysis/ast/utils/getMemberExpressionName.js.map +1 -0
  392. package/dist/plugins/analysis/ast/utils/index.d.ts +2 -0
  393. package/dist/plugins/analysis/ast/utils/index.d.ts.map +1 -1
  394. package/dist/plugins/analysis/ast/utils/index.js +2 -0
  395. package/dist/plugins/analysis/ast/utils/index.js.map +1 -1
  396. package/dist/plugins/analysis/ast/visitors/ArgumentExtractor.d.ts +23 -0
  397. package/dist/plugins/analysis/ast/visitors/ArgumentExtractor.d.ts.map +1 -0
  398. package/dist/plugins/analysis/ast/visitors/ArgumentExtractor.js +241 -0
  399. package/dist/plugins/analysis/ast/visitors/ArgumentExtractor.js.map +1 -0
  400. package/dist/plugins/analysis/ast/visitors/ArrayElementExtractor.d.ts +20 -0
  401. package/dist/plugins/analysis/ast/visitors/ArrayElementExtractor.d.ts.map +1 -0
  402. package/dist/plugins/analysis/ast/visitors/ArrayElementExtractor.js +110 -0
  403. package/dist/plugins/analysis/ast/visitors/ArrayElementExtractor.js.map +1 -0
  404. package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts +15 -142
  405. package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts.map +1 -1
  406. package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.js +304 -937
  407. package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.js.map +1 -1
  408. package/dist/plugins/analysis/ast/visitors/ClassVisitor.d.ts.map +1 -1
  409. package/dist/plugins/analysis/ast/visitors/ClassVisitor.js +26 -11
  410. package/dist/plugins/analysis/ast/visitors/ClassVisitor.js.map +1 -1
  411. package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts.map +1 -1
  412. package/dist/plugins/analysis/ast/visitors/FunctionVisitor.js +21 -6
  413. package/dist/plugins/analysis/ast/visitors/FunctionVisitor.js.map +1 -1
  414. package/dist/plugins/analysis/ast/visitors/MutationDetector.d.ts +25 -0
  415. package/dist/plugins/analysis/ast/visitors/MutationDetector.d.ts.map +1 -0
  416. package/dist/plugins/analysis/ast/visitors/MutationDetector.js +181 -0
  417. package/dist/plugins/analysis/ast/visitors/MutationDetector.js.map +1 -0
  418. package/dist/plugins/analysis/ast/visitors/ObjectPropertyExtractor.d.ts +20 -0
  419. package/dist/plugins/analysis/ast/visitors/ObjectPropertyExtractor.d.ts.map +1 -0
  420. package/dist/plugins/analysis/ast/visitors/ObjectPropertyExtractor.js +155 -0
  421. package/dist/plugins/analysis/ast/visitors/ObjectPropertyExtractor.js.map +1 -0
  422. package/dist/plugins/analysis/ast/visitors/PropertyAccessVisitor.d.ts +9 -1
  423. package/dist/plugins/analysis/ast/visitors/PropertyAccessVisitor.d.ts.map +1 -1
  424. package/dist/plugins/analysis/ast/visitors/PropertyAccessVisitor.js +51 -3
  425. package/dist/plugins/analysis/ast/visitors/PropertyAccessVisitor.js.map +1 -1
  426. package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.d.ts +20 -0
  427. package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.d.ts.map +1 -1
  428. package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.js +188 -12
  429. package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.js.map +1 -1
  430. package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts.map +1 -1
  431. package/dist/plugins/analysis/ast/visitors/VariableVisitor.js +6 -4
  432. package/dist/plugins/analysis/ast/visitors/VariableVisitor.js.map +1 -1
  433. package/dist/plugins/analysis/ast/visitors/call-expression-helpers.d.ts +19 -0
  434. package/dist/plugins/analysis/ast/visitors/call-expression-helpers.d.ts.map +1 -0
  435. package/dist/plugins/analysis/ast/visitors/call-expression-helpers.js +57 -0
  436. package/dist/plugins/analysis/ast/visitors/call-expression-helpers.js.map +1 -0
  437. package/dist/plugins/analysis/ast/visitors/call-expression-types.d.ts +168 -0
  438. package/dist/plugins/analysis/ast/visitors/call-expression-types.d.ts.map +1 -0
  439. package/dist/plugins/analysis/ast/visitors/call-expression-types.js +7 -0
  440. package/dist/plugins/analysis/ast/visitors/call-expression-types.js.map +1 -0
  441. package/dist/plugins/analysis/react-internal/browser-api.d.ts +20 -0
  442. package/dist/plugins/analysis/react-internal/browser-api.d.ts.map +1 -0
  443. package/dist/plugins/analysis/react-internal/browser-api.js +140 -0
  444. package/dist/plugins/analysis/react-internal/browser-api.js.map +1 -0
  445. package/dist/plugins/analysis/react-internal/hooks.d.ts +31 -0
  446. package/dist/plugins/analysis/react-internal/hooks.d.ts.map +1 -0
  447. package/dist/plugins/analysis/react-internal/hooks.js +465 -0
  448. package/dist/plugins/analysis/react-internal/hooks.js.map +1 -0
  449. package/dist/plugins/analysis/react-internal/jsx.d.ts +43 -0
  450. package/dist/plugins/analysis/react-internal/jsx.d.ts.map +1 -0
  451. package/dist/plugins/analysis/react-internal/jsx.js +231 -0
  452. package/dist/plugins/analysis/react-internal/jsx.js.map +1 -0
  453. package/dist/plugins/analysis/react-internal/types.d.ts +116 -0
  454. package/dist/plugins/analysis/react-internal/types.d.ts.map +1 -0
  455. package/dist/plugins/analysis/react-internal/types.js +83 -0
  456. package/dist/plugins/analysis/react-internal/types.js.map +1 -0
  457. package/dist/plugins/discovery/MonorepoServiceDiscovery.d.ts.map +1 -1
  458. package/dist/plugins/discovery/MonorepoServiceDiscovery.js +6 -13
  459. package/dist/plugins/discovery/MonorepoServiceDiscovery.js.map +1 -1
  460. package/dist/plugins/enrichment/AliasTracker.d.ts.map +1 -1
  461. package/dist/plugins/enrichment/AliasTracker.js +3 -1
  462. package/dist/plugins/enrichment/AliasTracker.js.map +1 -1
  463. package/dist/plugins/enrichment/ArgumentParameterLinker.d.ts.map +1 -1
  464. package/dist/plugins/enrichment/ArgumentParameterLinker.js +3 -1
  465. package/dist/plugins/enrichment/ArgumentParameterLinker.js.map +1 -1
  466. package/dist/plugins/enrichment/CallbackCallResolver.d.ts +42 -0
  467. package/dist/plugins/enrichment/CallbackCallResolver.d.ts.map +1 -0
  468. package/dist/plugins/enrichment/CallbackCallResolver.js +311 -0
  469. package/dist/plugins/enrichment/CallbackCallResolver.js.map +1 -0
  470. package/dist/plugins/enrichment/ClosureCaptureEnricher.d.ts.map +1 -1
  471. package/dist/plugins/enrichment/ClosureCaptureEnricher.js +3 -1
  472. package/dist/plugins/enrichment/ClosureCaptureEnricher.js.map +1 -1
  473. package/dist/plugins/enrichment/ConfigRoutingMapBuilder.d.ts +17 -0
  474. package/dist/plugins/enrichment/ConfigRoutingMapBuilder.d.ts.map +1 -0
  475. package/dist/plugins/enrichment/ConfigRoutingMapBuilder.js +55 -0
  476. package/dist/plugins/enrichment/ConfigRoutingMapBuilder.js.map +1 -0
  477. package/dist/plugins/enrichment/ExpressHandlerLinker.d.ts.map +1 -1
  478. package/dist/plugins/enrichment/ExpressHandlerLinker.js +3 -1
  479. package/dist/plugins/enrichment/ExpressHandlerLinker.js.map +1 -1
  480. package/dist/plugins/enrichment/ExternalCallResolver.d.ts.map +1 -1
  481. package/dist/plugins/enrichment/ExternalCallResolver.js +5 -8
  482. package/dist/plugins/enrichment/ExternalCallResolver.js.map +1 -1
  483. package/dist/plugins/enrichment/FunctionCallResolver.d.ts.map +1 -1
  484. package/dist/plugins/enrichment/FunctionCallResolver.js +6 -9
  485. package/dist/plugins/enrichment/FunctionCallResolver.js.map +1 -1
  486. package/dist/plugins/enrichment/HTTPConnectionEnricher.d.ts.map +1 -1
  487. package/dist/plugins/enrichment/HTTPConnectionEnricher.js +3 -1
  488. package/dist/plugins/enrichment/HTTPConnectionEnricher.js.map +1 -1
  489. package/dist/plugins/enrichment/ImportExportLinker.d.ts.map +1 -1
  490. package/dist/plugins/enrichment/ImportExportLinker.js +5 -3
  491. package/dist/plugins/enrichment/ImportExportLinker.js.map +1 -1
  492. package/dist/plugins/enrichment/InstanceOfResolver.d.ts.map +1 -1
  493. package/dist/plugins/enrichment/InstanceOfResolver.js +3 -1
  494. package/dist/plugins/enrichment/InstanceOfResolver.js.map +1 -1
  495. package/dist/plugins/enrichment/MethodCallResolver.d.ts +17 -68
  496. package/dist/plugins/enrichment/MethodCallResolver.d.ts.map +1 -1
  497. package/dist/plugins/enrichment/MethodCallResolver.js +42 -517
  498. package/dist/plugins/enrichment/MethodCallResolver.js.map +1 -1
  499. package/dist/plugins/enrichment/MountPointResolver.d.ts.map +1 -1
  500. package/dist/plugins/enrichment/MountPointResolver.js +9 -2
  501. package/dist/plugins/enrichment/MountPointResolver.js.map +1 -1
  502. package/dist/plugins/enrichment/NodejsBuiltinsResolver.d.ts.map +1 -1
  503. package/dist/plugins/enrichment/NodejsBuiltinsResolver.js +7 -16
  504. package/dist/plugins/enrichment/NodejsBuiltinsResolver.js.map +1 -1
  505. package/dist/plugins/enrichment/PrefixEvaluator.d.ts.map +1 -1
  506. package/dist/plugins/enrichment/PrefixEvaluator.js +6 -2
  507. package/dist/plugins/enrichment/PrefixEvaluator.js.map +1 -1
  508. package/dist/plugins/enrichment/RejectionPropagationEnricher.d.ts.map +1 -1
  509. package/dist/plugins/enrichment/RejectionPropagationEnricher.js +3 -1
  510. package/dist/plugins/enrichment/RejectionPropagationEnricher.js.map +1 -1
  511. package/dist/plugins/enrichment/RustFFIEnricher.d.ts.map +1 -1
  512. package/dist/plugins/enrichment/RustFFIEnricher.js +3 -1
  513. package/dist/plugins/enrichment/RustFFIEnricher.js.map +1 -1
  514. package/dist/plugins/enrichment/ServiceConnectionEnricher.d.ts +76 -0
  515. package/dist/plugins/enrichment/ServiceConnectionEnricher.d.ts.map +1 -0
  516. package/dist/plugins/enrichment/ServiceConnectionEnricher.js +355 -0
  517. package/dist/plugins/enrichment/ServiceConnectionEnricher.js.map +1 -0
  518. package/dist/plugins/enrichment/SocketConnectionEnricher.d.ts +42 -0
  519. package/dist/plugins/enrichment/SocketConnectionEnricher.d.ts.map +1 -0
  520. package/dist/plugins/enrichment/SocketConnectionEnricher.js +166 -0
  521. package/dist/plugins/enrichment/SocketConnectionEnricher.js.map +1 -0
  522. package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts.map +1 -1
  523. package/dist/plugins/enrichment/ValueDomainAnalyzer.js +3 -1
  524. package/dist/plugins/enrichment/ValueDomainAnalyzer.js.map +1 -1
  525. package/dist/plugins/enrichment/method-call/MethodCallData.d.ts +68 -0
  526. package/dist/plugins/enrichment/method-call/MethodCallData.d.ts.map +1 -0
  527. package/dist/plugins/enrichment/method-call/MethodCallData.js +227 -0
  528. package/dist/plugins/enrichment/method-call/MethodCallData.js.map +1 -0
  529. package/dist/plugins/enrichment/method-call/MethodCallDetectors.d.ts +21 -0
  530. package/dist/plugins/enrichment/method-call/MethodCallDetectors.d.ts.map +1 -0
  531. package/dist/plugins/enrichment/method-call/MethodCallDetectors.js +52 -0
  532. package/dist/plugins/enrichment/method-call/MethodCallDetectors.js.map +1 -0
  533. package/dist/plugins/enrichment/method-call/MethodCallErrorAnalysis.d.ts +22 -0
  534. package/dist/plugins/enrichment/method-call/MethodCallErrorAnalysis.d.ts.map +1 -0
  535. package/dist/plugins/enrichment/method-call/MethodCallErrorAnalysis.js +105 -0
  536. package/dist/plugins/enrichment/method-call/MethodCallErrorAnalysis.js.map +1 -0
  537. package/dist/plugins/enrichment/method-call/MethodCallIndexers.d.ts +19 -0
  538. package/dist/plugins/enrichment/method-call/MethodCallIndexers.d.ts.map +1 -0
  539. package/dist/plugins/enrichment/method-call/MethodCallIndexers.js +63 -0
  540. package/dist/plugins/enrichment/method-call/MethodCallIndexers.js.map +1 -0
  541. package/dist/plugins/enrichment/method-call/MethodCallResolution.d.ts +30 -0
  542. package/dist/plugins/enrichment/method-call/MethodCallResolution.d.ts.map +1 -0
  543. package/dist/plugins/enrichment/method-call/MethodCallResolution.js +138 -0
  544. package/dist/plugins/enrichment/method-call/MethodCallResolution.js.map +1 -0
  545. package/dist/plugins/indexing/IncrementalModuleIndexer.d.ts.map +1 -1
  546. package/dist/plugins/indexing/IncrementalModuleIndexer.js +2 -8
  547. package/dist/plugins/indexing/IncrementalModuleIndexer.js.map +1 -1
  548. package/dist/plugins/indexing/JSModuleIndexer.d.ts.map +1 -1
  549. package/dist/plugins/indexing/JSModuleIndexer.js +13 -20
  550. package/dist/plugins/indexing/JSModuleIndexer.js.map +1 -1
  551. package/dist/plugins/indexing/RustModuleIndexer.d.ts.map +1 -1
  552. package/dist/plugins/indexing/RustModuleIndexer.js +4 -8
  553. package/dist/plugins/indexing/RustModuleIndexer.js.map +1 -1
  554. package/dist/plugins/validation/AwaitInLoopValidator.d.ts +24 -0
  555. package/dist/plugins/validation/AwaitInLoopValidator.d.ts.map +1 -0
  556. package/dist/plugins/validation/AwaitInLoopValidator.js +69 -0
  557. package/dist/plugins/validation/AwaitInLoopValidator.js.map +1 -0
  558. package/dist/plugins/validation/PackageCoverageValidator.d.ts +33 -0
  559. package/dist/plugins/validation/PackageCoverageValidator.d.ts.map +1 -0
  560. package/dist/plugins/validation/PackageCoverageValidator.js +149 -0
  561. package/dist/plugins/validation/PackageCoverageValidator.js.map +1 -0
  562. package/dist/plugins/validation/UnconnectedRouteValidator.d.ts +18 -0
  563. package/dist/plugins/validation/UnconnectedRouteValidator.d.ts.map +1 -0
  564. package/dist/plugins/validation/UnconnectedRouteValidator.js +68 -0
  565. package/dist/plugins/validation/UnconnectedRouteValidator.js.map +1 -0
  566. package/dist/queries/NodeContext.d.ts +81 -0
  567. package/dist/queries/NodeContext.d.ts.map +1 -0
  568. package/dist/queries/NodeContext.js +193 -0
  569. package/dist/queries/NodeContext.js.map +1 -0
  570. package/dist/queries/findCallsInFunction.d.ts.map +1 -1
  571. package/dist/queries/findCallsInFunction.js +10 -2
  572. package/dist/queries/findCallsInFunction.js.map +1 -1
  573. package/dist/queries/findContainingFunction.d.ts +3 -2
  574. package/dist/queries/findContainingFunction.d.ts.map +1 -1
  575. package/dist/queries/findContainingFunction.js +13 -3
  576. package/dist/queries/findContainingFunction.js.map +1 -1
  577. package/dist/queries/index.d.ts +2 -0
  578. package/dist/queries/index.d.ts.map +1 -1
  579. package/dist/queries/index.js +1 -0
  580. package/dist/queries/index.js.map +1 -1
  581. package/dist/resources/InfraResourceMapImpl.d.ts +31 -0
  582. package/dist/resources/InfraResourceMapImpl.d.ts.map +1 -0
  583. package/dist/resources/InfraResourceMapImpl.js +110 -0
  584. package/dist/resources/InfraResourceMapImpl.js.map +1 -0
  585. package/dist/resources/RoutingMapImpl.d.ts +33 -0
  586. package/dist/resources/RoutingMapImpl.d.ts.map +1 -0
  587. package/dist/resources/RoutingMapImpl.js +115 -0
  588. package/dist/resources/RoutingMapImpl.js.map +1 -0
  589. package/dist/storage/backends/RFDBServerBackend.d.ts +35 -6
  590. package/dist/storage/backends/RFDBServerBackend.d.ts.map +1 -1
  591. package/dist/storage/backends/RFDBServerBackend.js +102 -70
  592. package/dist/storage/backends/RFDBServerBackend.js.map +1 -1
  593. package/dist/utils/findRfdbBinary.d.ts +3 -2
  594. package/dist/utils/findRfdbBinary.d.ts.map +1 -1
  595. package/dist/utils/findRfdbBinary.js +22 -7
  596. package/dist/utils/findRfdbBinary.js.map +1 -1
  597. package/dist/utils/moduleResolution.d.ts.map +1 -1
  598. package/dist/utils/moduleResolution.js +26 -1
  599. package/dist/utils/moduleResolution.js.map +1 -1
  600. package/dist/utils/resolveNodeFile.d.ts +13 -0
  601. package/dist/utils/resolveNodeFile.d.ts.map +1 -0
  602. package/dist/utils/resolveNodeFile.js +18 -0
  603. package/dist/utils/resolveNodeFile.js.map +1 -0
  604. package/dist/version.d.ts +11 -0
  605. package/dist/version.d.ts.map +1 -0
  606. package/dist/version.js +26 -0
  607. package/dist/version.js.map +1 -0
  608. package/package.json +3 -3
  609. package/src/DiscoveryManager.ts +279 -0
  610. package/src/GraphInitializer.ts +131 -0
  611. package/src/GuaranteeChecker.ts +90 -0
  612. package/src/Orchestrator.ts +222 -963
  613. package/src/OrchestratorTypes.ts +122 -0
  614. package/src/ParallelAnalysisRunner.ts +188 -0
  615. package/src/PhaseRunner.ts +450 -0
  616. package/src/config/ConfigLoader.ts +176 -2
  617. package/src/config/index.ts +2 -0
  618. package/src/core/ASTWorker.ts +9 -2
  619. package/src/core/FileOverview.ts +374 -0
  620. package/src/core/GraphFreshnessChecker.ts +7 -5
  621. package/src/core/GuaranteeManager.ts +70 -2
  622. package/src/core/IncrementalReanalyzer.ts +6 -3
  623. package/src/core/NodeFactory.ts +173 -652
  624. package/src/core/ResourceRegistry.ts +39 -0
  625. package/src/core/ScopeTracker.ts +23 -0
  626. package/src/core/SemanticId.ts +183 -0
  627. package/src/core/brandNodeInternal.ts +16 -0
  628. package/src/core/buildDependencyGraph.ts +98 -0
  629. package/src/core/factories/CoreFactory.ts +489 -0
  630. package/src/core/factories/DatabaseFactory.ts +63 -0
  631. package/src/core/factories/ExternalFactory.ts +23 -0
  632. package/src/core/factories/HttpFactory.ts +57 -0
  633. package/src/core/factories/ReactFactory.ts +15 -0
  634. package/src/core/factories/RustFactory.ts +128 -0
  635. package/src/core/factories/ServiceFactory.ts +27 -0
  636. package/src/core/factories/SocketFactory.ts +94 -0
  637. package/src/core/nodes/DatabaseNode.ts +175 -0
  638. package/src/core/nodes/ExpressMiddlewareNode.ts +98 -0
  639. package/src/core/nodes/ExpressMountNode.ts +94 -0
  640. package/src/core/nodes/ExternalApiNode.ts +53 -0
  641. package/src/core/nodes/ExternalFunctionNode.ts +77 -0
  642. package/src/core/nodes/FetchRequestNode.ts +105 -0
  643. package/src/core/nodes/HttpRouteNode.ts +113 -0
  644. package/src/core/nodes/NodeKind.ts +1 -0
  645. package/src/core/nodes/ReactNode.ts +78 -0
  646. package/src/core/nodes/RustCallNode.ts +96 -0
  647. package/src/core/nodes/RustFunctionNode.ts +112 -0
  648. package/src/core/nodes/RustImplNode.ts +78 -0
  649. package/src/core/nodes/RustMethodNode.ts +125 -0
  650. package/src/core/nodes/RustModuleNode.ts +84 -0
  651. package/src/core/nodes/RustStructNode.ts +80 -0
  652. package/src/core/nodes/RustTraitNode.ts +82 -0
  653. package/src/core/nodes/ServiceLayerNode.ts +183 -0
  654. package/src/core/nodes/SocketIONode.ts +177 -0
  655. package/src/core/nodes/SocketNode.ts +206 -0
  656. package/src/core/nodes/TypeNode.ts +46 -3
  657. package/src/core/nodes/TypeParameterNode.ts +91 -0
  658. package/src/core/nodes/index.ts +57 -0
  659. package/src/index.ts +60 -4
  660. package/src/plugins/InfraAnalyzer.ts +208 -0
  661. package/src/plugins/analysis/DatabaseAnalyzer.ts +27 -17
  662. package/src/plugins/analysis/ExpressAnalyzer.ts +51 -38
  663. package/src/plugins/analysis/ExpressResponseAnalyzer.ts +15 -12
  664. package/src/plugins/analysis/ExpressRouteAnalyzer.ts +56 -56
  665. package/src/plugins/analysis/FetchAnalyzer.ts +42 -52
  666. package/src/plugins/analysis/IncrementalAnalysisPlugin.ts +3 -2
  667. package/src/plugins/analysis/JSASTAnalyzer.ts +391 -2304
  668. package/src/plugins/analysis/NestJSRouteAnalyzer.ts +241 -0
  669. package/src/plugins/analysis/ReactAnalyzer.ts +33 -1085
  670. package/src/plugins/analysis/RustAnalyzer.ts +112 -116
  671. package/src/plugins/analysis/SQLiteAnalyzer.ts +23 -9
  672. package/src/plugins/analysis/ServiceLayerAnalyzer.ts +32 -10
  673. package/src/plugins/analysis/SocketAnalyzer.ts +601 -0
  674. package/src/plugins/analysis/SocketIOAnalyzer.ts +25 -34
  675. package/src/plugins/analysis/SystemDbAnalyzer.ts +15 -12
  676. package/src/plugins/analysis/ast/CollisionResolver.ts +137 -0
  677. package/src/plugins/analysis/ast/FunctionBodyContext.ts +291 -0
  678. package/src/plugins/analysis/ast/GraphBuilder.ts +274 -3180
  679. package/src/plugins/analysis/ast/IdGenerator.ts +81 -1
  680. package/src/plugins/analysis/ast/builders/AssignmentBuilder.ts +407 -0
  681. package/src/plugins/analysis/ast/builders/CallFlowBuilder.ts +255 -0
  682. package/src/plugins/analysis/ast/builders/ControlFlowBuilder.ts +470 -0
  683. package/src/plugins/analysis/ast/builders/CoreBuilder.ts +306 -0
  684. package/src/plugins/analysis/ast/builders/ModuleRuntimeBuilder.ts +452 -0
  685. package/src/plugins/analysis/ast/builders/MutationBuilder.ts +372 -0
  686. package/src/plugins/analysis/ast/builders/ReturnBuilder.ts +279 -0
  687. package/src/plugins/analysis/ast/builders/TypeSystemBuilder.ts +475 -0
  688. package/src/plugins/analysis/ast/builders/UpdateExpressionBuilder.ts +262 -0
  689. package/src/plugins/analysis/ast/builders/YieldBuilder.ts +287 -0
  690. package/src/plugins/analysis/ast/builders/index.ts +11 -0
  691. package/src/plugins/analysis/ast/builders/types.ts +65 -0
  692. package/src/plugins/analysis/ast/handlers/AnalyzerDelegate.ts +183 -0
  693. package/src/plugins/analysis/ast/handlers/BranchHandler.ts +313 -0
  694. package/src/plugins/analysis/ast/handlers/CallExpressionHandler.ts +347 -0
  695. package/src/plugins/analysis/ast/handlers/FunctionBodyHandler.ts +24 -0
  696. package/src/plugins/analysis/ast/handlers/LoopHandler.ts +240 -0
  697. package/src/plugins/analysis/ast/handlers/NestedFunctionHandler.ts +201 -0
  698. package/src/plugins/analysis/ast/handlers/NewExpressionHandler.ts +159 -0
  699. package/src/plugins/analysis/ast/handlers/PropertyAccessHandler.ts +112 -0
  700. package/src/plugins/analysis/ast/handlers/ReturnYieldHandler.ts +166 -0
  701. package/src/plugins/analysis/ast/handlers/ThrowHandler.ts +101 -0
  702. package/src/plugins/analysis/ast/handlers/TryCatchHandler.ts +262 -0
  703. package/src/plugins/analysis/ast/handlers/VariableHandler.ts +93 -0
  704. package/src/plugins/analysis/ast/handlers/index.ts +12 -0
  705. package/src/plugins/analysis/ast/types.ts +68 -9
  706. package/src/plugins/analysis/ast/utils/createParameterNodes.ts +118 -13
  707. package/src/plugins/analysis/ast/utils/extractNamesFromPattern.ts +166 -0
  708. package/src/plugins/analysis/ast/utils/getExpressionValue.ts +34 -0
  709. package/src/plugins/analysis/ast/utils/getMemberExpressionName.ts +33 -0
  710. package/src/plugins/analysis/ast/utils/index.ts +2 -0
  711. package/src/plugins/analysis/ast/visitors/ArgumentExtractor.ts +307 -0
  712. package/src/plugins/analysis/ast/visitors/ArrayElementExtractor.ts +172 -0
  713. package/src/plugins/analysis/ast/visitors/CallExpressionVisitor.ts +425 -1374
  714. package/src/plugins/analysis/ast/visitors/ClassVisitor.ts +43 -12
  715. package/src/plugins/analysis/ast/visitors/FunctionVisitor.ts +39 -8
  716. package/src/plugins/analysis/ast/visitors/MutationDetector.ts +211 -0
  717. package/src/plugins/analysis/ast/visitors/ObjectPropertyExtractor.ts +217 -0
  718. package/src/plugins/analysis/ast/visitors/PropertyAccessVisitor.ts +69 -4
  719. package/src/plugins/analysis/ast/visitors/TypeScriptVisitor.ts +232 -13
  720. package/src/plugins/analysis/ast/visitors/VariableVisitor.ts +8 -11
  721. package/src/plugins/analysis/ast/visitors/call-expression-helpers.ts +65 -0
  722. package/src/plugins/analysis/ast/visitors/call-expression-types.ts +179 -0
  723. package/src/plugins/analysis/react-internal/browser-api.ts +168 -0
  724. package/src/plugins/analysis/react-internal/hooks.ts +517 -0
  725. package/src/plugins/analysis/react-internal/jsx.ts +279 -0
  726. package/src/plugins/analysis/react-internal/types.ts +183 -0
  727. package/src/plugins/discovery/MonorepoServiceDiscovery.ts +6 -14
  728. package/src/plugins/enrichment/AliasTracker.ts +3 -1
  729. package/src/plugins/enrichment/ArgumentParameterLinker.ts +3 -1
  730. package/src/plugins/enrichment/CallbackCallResolver.ts +398 -0
  731. package/src/plugins/enrichment/ClosureCaptureEnricher.ts +3 -1
  732. package/src/plugins/enrichment/ConfigRoutingMapBuilder.ts +67 -0
  733. package/src/plugins/enrichment/ExpressHandlerLinker.ts +3 -1
  734. package/src/plugins/enrichment/ExternalCallResolver.ts +5 -8
  735. package/src/plugins/enrichment/FunctionCallResolver.ts +6 -9
  736. package/src/plugins/enrichment/HTTPConnectionEnricher.ts +3 -1
  737. package/src/plugins/enrichment/ImportExportLinker.ts +5 -3
  738. package/src/plugins/enrichment/InstanceOfResolver.ts +3 -1
  739. package/src/plugins/enrichment/MethodCallResolver.ts +48 -659
  740. package/src/plugins/enrichment/MountPointResolver.ts +9 -2
  741. package/src/plugins/enrichment/NodejsBuiltinsResolver.ts +13 -18
  742. package/src/plugins/enrichment/PrefixEvaluator.ts +6 -2
  743. package/src/plugins/enrichment/RejectionPropagationEnricher.ts +3 -1
  744. package/src/plugins/enrichment/RustFFIEnricher.ts +3 -1
  745. package/src/plugins/enrichment/ServiceConnectionEnricher.ts +472 -0
  746. package/src/plugins/enrichment/SocketConnectionEnricher.ts +228 -0
  747. package/src/plugins/enrichment/ValueDomainAnalyzer.ts +3 -1
  748. package/src/plugins/enrichment/method-call/MethodCallData.ts +299 -0
  749. package/src/plugins/enrichment/method-call/MethodCallDetectors.ts +70 -0
  750. package/src/plugins/enrichment/method-call/MethodCallErrorAnalysis.ts +131 -0
  751. package/src/plugins/enrichment/method-call/MethodCallIndexers.ts +83 -0
  752. package/src/plugins/enrichment/method-call/MethodCallResolution.ts +181 -0
  753. package/src/plugins/indexing/IncrementalModuleIndexer.ts +5 -10
  754. package/src/plugins/indexing/JSModuleIndexer.ts +17 -21
  755. package/src/plugins/indexing/RustModuleIndexer.ts +14 -13
  756. package/src/plugins/validation/AwaitInLoopValidator.ts +91 -0
  757. package/src/plugins/validation/PackageCoverageValidator.ts +181 -0
  758. package/src/plugins/validation/UnconnectedRouteValidator.ts +93 -0
  759. package/src/queries/NodeContext.ts +277 -0
  760. package/src/queries/findCallsInFunction.ts +11 -2
  761. package/src/queries/findContainingFunction.ts +14 -3
  762. package/src/queries/index.ts +13 -0
  763. package/src/resources/InfraResourceMapImpl.ts +119 -0
  764. package/src/resources/RoutingMapImpl.ts +133 -0
  765. package/src/storage/backends/RFDBServerBackend.ts +106 -77
  766. package/src/utils/findRfdbBinary.ts +22 -7
  767. package/src/utils/moduleResolution.ts +28 -1
  768. package/src/utils/resolveNodeFile.ts +18 -0
  769. package/src/version.ts +28 -0
@@ -1,21 +1,53 @@
1
1
  /**
2
- * GraphBuilder - создание узлов и рёбер графа из собранных AST данных
2
+ * GraphBuilder - orchestrator that delegates to domain-specific builders
3
3
  * OPTIMIZED: Uses batched writes to reduce FFI overhead
4
4
  */
5
- import { basename } from 'path';
6
- import { ImportNode } from '../../../core/nodes/ImportNode.js';
7
- import { InterfaceNode } from '../../../core/nodes/InterfaceNode.js';
8
- import { EnumNode } from '../../../core/nodes/EnumNode.js';
9
- import { DecoratorNode } from '../../../core/nodes/DecoratorNode.js';
10
- import { NetworkRequestNode } from '../../../core/nodes/NetworkRequestNode.js';
11
- import { NodeFactory } from '../../../core/NodeFactory.js';
12
- import { computeSemanticId, parseSemanticId } from '../../../core/SemanticId.js';
5
+ import { brandNodeInternal } from '../../../core/brandNodeInternal.js';
6
+ import { parseSemanticId } from '../../../core/SemanticId.js';
7
+ import { CoreBuilder, ControlFlowBuilder, AssignmentBuilder, CallFlowBuilder, MutationBuilder, UpdateExpressionBuilder, ReturnBuilder, YieldBuilder, TypeSystemBuilder, ModuleRuntimeBuilder, } from './builders/index.js';
13
8
  export class GraphBuilder {
14
9
  // Track singleton nodes to avoid duplicates (net:stdio, net:request, etc.)
15
10
  _createdSingletons = new Set();
16
11
  // Batching buffers for optimized writes
17
12
  _nodeBuffer = [];
18
13
  _edgeBuffer = [];
14
+ // Domain builders
15
+ _coreBuilder;
16
+ _controlFlowBuilder;
17
+ _assignmentBuilder;
18
+ _callFlowBuilder;
19
+ _mutationBuilder;
20
+ _updateExpressionBuilder;
21
+ _returnBuilder;
22
+ _yieldBuilder;
23
+ _typeSystemBuilder;
24
+ _moduleRuntimeBuilder;
25
+ constructor() {
26
+ const ctx = this._createContext();
27
+ this._coreBuilder = new CoreBuilder(ctx);
28
+ this._controlFlowBuilder = new ControlFlowBuilder(ctx);
29
+ this._assignmentBuilder = new AssignmentBuilder(ctx);
30
+ this._callFlowBuilder = new CallFlowBuilder(ctx);
31
+ this._mutationBuilder = new MutationBuilder(ctx);
32
+ this._updateExpressionBuilder = new UpdateExpressionBuilder(ctx);
33
+ this._returnBuilder = new ReturnBuilder(ctx);
34
+ this._yieldBuilder = new YieldBuilder(ctx);
35
+ this._typeSystemBuilder = new TypeSystemBuilder(ctx);
36
+ this._moduleRuntimeBuilder = new ModuleRuntimeBuilder(ctx);
37
+ }
38
+ _createContext() {
39
+ return {
40
+ bufferNode: (node) => this._bufferNode(node),
41
+ bufferEdge: (edge) => this._bufferEdge(edge),
42
+ isCreated: (key) => this._createdSingletons.has(key),
43
+ markCreated: (key) => { this._createdSingletons.add(key); },
44
+ findBufferedNode: (id) => this._nodeBuffer.find(n => n.id === id),
45
+ findFunctionByName: (functions, name, file, callScopeId) => this.findFunctionByName(functions, name, file, callScopeId),
46
+ resolveVariableInScope: (name, scopePath, file, variables) => this.resolveVariableInScope(name, scopePath, file, variables),
47
+ resolveParameterInScope: (name, scopePath, file, parameters) => this.resolveParameterInScope(name, scopePath, file, parameters),
48
+ scopePathsMatch: (a, b) => this.scopePathsMatch(a, b),
49
+ };
50
+ }
19
51
  /**
20
52
  * Buffer a node for batched writing
21
53
  */
@@ -33,8 +65,9 @@ export class GraphBuilder {
33
65
  */
34
66
  async _flushNodes(graph) {
35
67
  if (this._nodeBuffer.length > 0) {
36
- // Cast to unknown first since GraphNode is more permissive than NodeRecord
37
- await graph.addNodes(this._nodeBuffer);
68
+ // Brand nodes before flushing - they're validated by builders
69
+ const brandedNodes = this._nodeBuffer.map(node => brandNodeInternal(node));
70
+ await graph.addNodes(brandedNodes);
38
71
  const count = this._nodeBuffer.length;
39
72
  this._nodeBuffer = [];
40
73
  return count;
@@ -58,44 +91,32 @@ export class GraphBuilder {
58
91
  * Создаёт ноды и рёбра в графе (BATCHED VERSION)
59
92
  */
60
93
  async build(module, graph, projectPath, data) {
61
- const { functions, parameters = [], scopes,
62
- // Branching
63
- branches = [], cases = [],
64
- // Control flow (loops)
65
- loops = [],
66
- // Control flow (try/catch/finally) - Phase 4
67
- tryBlocks = [], catchBlocks = [], finallyBlocks = [], variableDeclarations, callSites, methodCalls = [], eventListeners = [], classInstantiations = [], constructorCalls = [], classDeclarations = [], methodCallbacks = [], callArguments = [], imports = [], exports = [], httpRequests = [], literals = [], variableAssignments = [],
68
- // TypeScript-specific collections
69
- interfaces = [], typeAliases = [], enums = [], decorators = [],
70
- // Array mutation tracking for FLOWS_INTO edges
71
- arrayMutations = [],
72
- // Object mutation tracking for FLOWS_INTO edges
73
- objectMutations = [],
74
- // Variable reassignment tracking for FLOWS_INTO edges (REG-290)
75
- variableReassignments = [],
76
- // Update expression tracking for UPDATE_EXPRESSION nodes and MODIFIES edges (REG-288, REG-312)
77
- updateExpressions = [],
78
- // Return statement tracking for RETURNS edges
79
- returnStatements = [],
80
- // Yield expression tracking for YIELDS/DELEGATES_TO edges (REG-270)
81
- yieldExpressions = [],
82
- // Promise resolution tracking for RESOLVES_TO edges (REG-334)
83
- promiseResolutions = [],
84
- // Object/Array literal tracking
85
- objectLiterals = [], objectProperties = [], arrayLiterals = [],
86
- // REG-311: Rejection pattern tracking for async error analysis
87
- rejectionPatterns = [],
88
- // REG-311: CATCHES_FROM tracking for catch parameter error sources
89
- catchesFromInfos = [],
90
- // Property access tracking for PROPERTY_ACCESS nodes (REG-395)
91
- propertyAccesses = [] } = data;
94
+ // Phase 1 node buffering + post-flush fields only; builders receive `data` directly
95
+ const { functions, parameters = [], scopes, branches = [], cases = [], loops = [], tryBlocks = [], catchBlocks = [], finallyBlocks = [], variableDeclarations, callSites, constructorCalls = [],
96
+ // Post-flush fields
97
+ variableAssignments = [], propertyAccesses = [], hasTopLevelAwait = false } = data;
92
98
  // Reset buffers for this build
93
99
  this._nodeBuffer = [];
94
100
  this._edgeBuffer = [];
95
101
  // 1. Buffer all functions (without edges)
102
+ // REG-401: Strip invokesParamIndexes from node data and store in metadata
96
103
  for (const func of functions) {
97
- const { parentScopeId: _parentScopeId, ...funcData } = func;
98
- this._bufferNode(funcData);
104
+ const { parentScopeId: _parentScopeId, invokesParamIndexes: _invokesParamIndexes, invokesParamBindings: _invokesParamBindings, ...funcData } = func;
105
+ const node = funcData;
106
+ if (_invokesParamIndexes && _invokesParamIndexes.length > 0) {
107
+ if (!node.metadata) {
108
+ node.metadata = {};
109
+ }
110
+ node.metadata.invokesParamIndexes = _invokesParamIndexes;
111
+ }
112
+ // REG-417: Store property paths for destructured param bindings
113
+ if (_invokesParamBindings && _invokesParamBindings.length > 0) {
114
+ if (!node.metadata) {
115
+ node.metadata = {};
116
+ }
117
+ node.metadata.invokesParamBindings = _invokesParamBindings;
118
+ }
119
+ this._bufferNode(node);
99
120
  }
100
121
  // 2. Buffer all SCOPE (without edges)
101
122
  for (const scope of scopes) {
@@ -169,2504 +190,240 @@ export class GraphBuilder {
169
190
  column: constructorCall.column
170
191
  });
171
192
  }
172
- // 5. Buffer edges for functions
173
- this.bufferFunctionEdges(module, functions);
174
- // 6. Buffer edges for SCOPE
175
- this.bufferScopeEdges(scopes, variableDeclarations);
176
- // 6.3. Buffer edges for LOOP (HAS_BODY, ITERATES_OVER, CONTAINS)
177
- this.bufferLoopEdges(loops, scopes, variableDeclarations, parameters);
178
- // 6.35. Buffer HAS_CONDITION edges for LOOP (REG-280)
179
- this.bufferLoopConditionEdges(loops, callSites);
180
- // 6.37. Buffer EXPRESSION nodes for loop conditions (REG-280)
181
- this.bufferLoopConditionExpressions(loops);
182
- // 6.5. Buffer edges for BRANCH (needs callSites for CallExpression discriminant lookup)
183
- // Phase 3 (REG-267): Now includes scopes for if-branches HAS_CONSEQUENT/HAS_ALTERNATE
184
- this.bufferBranchEdges(branches, callSites, scopes);
185
- // 6.6. Buffer edges for CASE
186
- this.bufferCaseEdges(cases);
187
- // 6.65. Buffer edges for TRY_BLOCK, CATCH_BLOCK, FINALLY_BLOCK (Phase 4)
188
- this.bufferTryCatchFinallyEdges(tryBlocks, catchBlocks, finallyBlocks);
189
- // 6.7. Buffer EXPRESSION nodes for switch discriminants (needs callSites for CallExpression)
190
- this.bufferDiscriminantExpressions(branches, callSites);
191
- // 7. Buffer edges for variables
192
- this.bufferVariableEdges(variableDeclarations);
193
- // 8. Buffer edges for CALL_SITE
194
- this.bufferCallSiteEdges(callSites, functions);
195
- // 9. Buffer METHOD_CALL nodes, CONTAINS edges, and USES edges (REG-262)
196
- this.bufferMethodCalls(methodCalls, variableDeclarations, parameters);
197
- // 9.5. Buffer PROPERTY_ACCESS nodes and CONTAINS edges (REG-395)
198
- this.bufferPropertyAccessNodes(module, propertyAccesses);
199
- // 10. Buffer net:stdio and WRITES_TO edges for console.log/error
200
- this.bufferStdioNodes(methodCalls);
201
- // 11. Buffer CLASS nodes for class declarations and CONTAINS edges
202
- this.bufferClassDeclarationNodes(classDeclarations);
203
- // 12. Buffer CLASS nodes and INSTANCE_OF edges for NewExpression
204
- this.bufferClassNodes(module, classInstantiations, classDeclarations);
205
- // 13. Buffer PASSES_ARGUMENT edges (METHOD_CALL -> FUNCTION)
206
- this.bufferCallbackEdges(methodCallbacks, functions);
207
- // 14. Buffer IMPORT nodes
208
- this.bufferImportNodes(module, imports);
209
- // 15. Buffer EXPORT nodes
210
- this.bufferExportNodes(module, exports);
211
- // 16. Buffer EVENT_LISTENER nodes and HANDLED_BY edges
212
- this.bufferEventListeners(eventListeners, functions);
213
- // 17. Buffer HTTP requests
214
- this.bufferHttpRequests(httpRequests, functions);
215
- // 18. Buffer LITERAL nodes
216
- this.bufferLiterals(literals);
217
- // 18.5. Buffer OBJECT_LITERAL nodes (moved before bufferArgumentEdges)
218
- this.bufferObjectLiteralNodes(objectLiterals);
219
- // 18.6. Buffer ARRAY_LITERAL nodes (moved before bufferArgumentEdges)
220
- this.bufferArrayLiteralNodes(arrayLiterals);
221
- // 18.7. Buffer HAS_PROPERTY edges (OBJECT_LITERAL -> property values)
222
- // REG-329: Pass variableDeclarations and parameters for scope-aware variable resolution
223
- this.bufferObjectPropertyEdges(objectProperties, variableDeclarations, parameters);
224
- // 19. Buffer ASSIGNED_FROM edges for data flow (some need to create EXPRESSION nodes)
225
- this.bufferAssignmentEdges(variableAssignments, variableDeclarations, callSites, methodCalls, functions, classInstantiations, parameters);
226
- // 20. Buffer PASSES_ARGUMENT edges (CALL -> argument)
227
- this.bufferArgumentEdges(callArguments, variableDeclarations, functions, callSites, methodCalls);
228
- // 21. Buffer INTERFACE nodes and EXTENDS edges
229
- this.bufferInterfaceNodes(module, interfaces);
230
- // 22. Buffer TYPE nodes
231
- this.bufferTypeAliasNodes(module, typeAliases);
232
- // 23. Buffer ENUM nodes
233
- this.bufferEnumNodes(module, enums);
234
- // 24. Buffer DECORATOR nodes and DECORATED_BY edges
235
- this.bufferDecoratorNodes(decorators);
236
- // 25. Buffer IMPLEMENTS edges (CLASS -> INTERFACE)
237
- this.bufferImplementsEdges(classDeclarations, interfaces);
238
- // 26. Buffer FLOWS_INTO edges for array mutations (push, unshift, splice, indexed assignment)
239
- // REG-392: Pass literals, objectLiterals, arrayLiterals, callSites for non-variable value lookups
240
- this.bufferArrayMutationEdges(arrayMutations, variableDeclarations, parameters, literals, objectLiterals, arrayLiterals, callSites);
241
- // 27. Buffer FLOWS_INTO edges for object mutations (property assignment, Object.assign)
242
- // REG-152: Now includes classDeclarations for this.prop = value patterns
243
- this.bufferObjectMutationEdges(objectMutations, variableDeclarations, parameters, functions, classDeclarations);
244
- // 28. Buffer FLOWS_INTO edges for variable reassignments (REG-290)
245
- this.bufferVariableReassignmentEdges(variableReassignments, variableDeclarations, callSites, methodCalls, parameters);
246
- // 29. Buffer RETURNS edges for return statements
247
- this.bufferReturnEdges(returnStatements, callSites, methodCalls, variableDeclarations, parameters);
248
- // 30. Buffer UPDATE_EXPRESSION nodes and MODIFIES edges (REG-288, REG-312)
249
- this.bufferUpdateExpressionEdges(updateExpressions, variableDeclarations, parameters, classDeclarations);
250
- // 31. Buffer RESOLVES_TO edges for Promise data flow (REG-334)
251
- this.bufferPromiseResolutionEdges(promiseResolutions);
252
- // 32. Buffer YIELDS/DELEGATES_TO edges for generator yields (REG-270)
253
- this.bufferYieldEdges(yieldExpressions, callSites, methodCalls, variableDeclarations, parameters);
254
- // 33. Buffer REJECTS edges for async error tracking (REG-311)
255
- this.bufferRejectionEdges(functions, rejectionPatterns);
256
- // 34. Buffer CATCHES_FROM edges linking catch blocks to error sources (REG-311)
257
- this.bufferCatchesFromEdges(catchesFromInfos);
193
+ // Phase 2: Delegate to domain builders
194
+ this._coreBuilder.buffer(module, data);
195
+ this._controlFlowBuilder.buffer(module, data);
196
+ this._callFlowBuilder.buffer(module, data);
197
+ this._assignmentBuilder.buffer(module, data);
198
+ this._mutationBuilder.buffer(module, data);
199
+ this._updateExpressionBuilder.buffer(module, data);
200
+ this._returnBuilder.buffer(module, data);
201
+ this._yieldBuilder.buffer(module, data);
202
+ this._typeSystemBuilder.buffer(module, data);
203
+ this._moduleRuntimeBuilder.buffer(module, data);
258
204
  // FLUSH: Write all nodes first, then edges in single batch calls
259
205
  const nodesCreated = await this._flushNodes(graph);
260
206
  const edgesCreated = await this._flushEdges(graph);
261
207
  // Handle async operations for ASSIGNED_FROM with CLASS lookups
262
208
  const classAssignmentEdges = await this.createClassAssignmentEdges(variableAssignments, graph);
209
+ // REG-300: Update MODULE node with import.meta metadata
210
+ const importMetaProps = this.collectImportMetaProperties(propertyAccesses);
211
+ await this.updateModuleImportMetaMetadata(module, graph, importMetaProps);
212
+ // REG-297: Update MODULE node with hasTopLevelAwait metadata
213
+ await this.updateModuleTopLevelAwaitMetadata(module, graph, hasTopLevelAwait);
263
214
  return { nodes: nodesCreated, edges: edgesCreated + classAssignmentEdges };
264
215
  }
265
- // ============= BUFFERED METHODS (synchronous, no awaits) =============
266
- bufferFunctionEdges(module, functions) {
267
- for (const func of functions) {
268
- const { parentScopeId, ...funcData } = func;
269
- // MODULE -> CONTAINS -> FUNCTION (для функций верхнего уровня)
270
- // или SCOPE -> CONTAINS -> FUNCTION (для вложенных функций)
271
- if (parentScopeId) {
272
- this._bufferEdge({
273
- type: 'CONTAINS',
274
- src: parentScopeId,
275
- dst: funcData.id
276
- });
277
- }
278
- else {
279
- this._bufferEdge({
280
- type: 'CONTAINS',
281
- src: module.id,
282
- dst: funcData.id
283
- });
284
- }
285
- }
286
- }
287
- bufferScopeEdges(scopes, variableDeclarations) {
288
- for (const scope of scopes) {
289
- const { parentFunctionId, parentScopeId, capturesFrom, ...scopeData } = scope;
290
- // FUNCTION -> HAS_SCOPE -> SCOPE (для function_body)
291
- if (parentFunctionId) {
292
- this._bufferEdge({
293
- type: 'HAS_SCOPE',
294
- src: parentFunctionId,
295
- dst: scopeData.id
296
- });
297
- }
298
- // SCOPE -> CONTAINS -> SCOPE (для вложенных scope, типа if внутри function)
299
- if (parentScopeId) {
300
- this._bufferEdge({
301
- type: 'CONTAINS',
302
- src: parentScopeId,
303
- dst: scopeData.id
304
- });
305
- }
306
- // CAPTURES - замыкания захватывают переменные из родительского scope
307
- if (capturesFrom && scopeData.scopeType === 'closure') {
308
- const parentVars = variableDeclarations.filter(v => v.parentScopeId === capturesFrom);
309
- for (const parentVar of parentVars) {
310
- this._bufferEdge({
311
- type: 'CAPTURES',
312
- src: scopeData.id,
313
- dst: parentVar.id
314
- });
315
- }
316
- }
317
- // REG-288: MODIFIES edges removed - now come from UPDATE_EXPRESSION nodes
318
- }
319
- }
216
+ // ============= SHARED UTILITY METHODS =============
320
217
  /**
321
- * Buffer LOOP edges (CONTAINS, HAS_BODY, ITERATES_OVER)
322
- *
323
- * Creates edges for:
324
- * - Parent -> CONTAINS -> LOOP
325
- * - LOOP -> HAS_BODY -> body SCOPE
326
- * - LOOP -> ITERATES_OVER -> collection VARIABLE/PARAMETER (for for-in/for-of)
327
- *
328
- * Scope-aware variable lookup for ITERATES_OVER:
329
- * For for-of/for-in, finds the iterated variable preferring:
330
- * 1. Variables declared before the loop on same or earlier line (closest first)
331
- * 2. Parameters (function arguments)
218
+ * Scope-aware function lookup: when multiple functions share the same name
219
+ * (e.g., inner function shadows outer), prefer the one in the same scope.
220
+ * Falls back to module-level function if no scope match found.
332
221
  */
333
- bufferLoopEdges(loops, scopes, variableDeclarations, parameters) {
334
- for (const loop of loops) {
335
- // Parent -> CONTAINS -> LOOP
336
- if (loop.parentScopeId) {
337
- this._bufferEdge({
338
- type: 'CONTAINS',
339
- src: loop.parentScopeId,
340
- dst: loop.id
341
- });
342
- }
343
- // LOOP -> HAS_BODY -> body SCOPE
344
- // Find the body scope by matching parentScopeId to loop.id
345
- const bodyScope = scopes.find(s => s.parentScopeId === loop.id);
346
- if (bodyScope) {
347
- this._bufferEdge({
348
- type: 'HAS_BODY',
349
- src: loop.id,
350
- dst: bodyScope.id
351
- });
352
- }
353
- // LOOP -> ITERATES_OVER -> collection VARIABLE/PARAMETER (for for-in/for-of)
354
- if (loop.iteratesOverName && (loop.loopType === 'for-in' || loop.loopType === 'for-of')) {
355
- // For MemberExpression iterables (obj.items), extract base object
356
- const iterableName = loop.iteratesOverName.includes('.')
357
- ? loop.iteratesOverName.split('.')[0]
358
- : loop.iteratesOverName;
359
- // Scope-aware lookup: prefer parameters over variables
360
- // Parameters are function-local and shadow outer variables
361
- const param = parameters.find(p => p.name === iterableName && p.file === loop.file);
362
- // Determine iteration type: for-in iterates keys, for-of iterates values
363
- const iterates = loop.loopType === 'for-in' ? 'keys' : 'values';
364
- if (param) {
365
- // Parameter found - most local binding
366
- this._bufferEdge({
367
- type: 'ITERATES_OVER',
368
- src: loop.id,
369
- dst: param.id,
370
- metadata: { iterates }
371
- });
372
- }
373
- else {
374
- // Find variable by name and line proximity (scope-aware heuristic)
375
- // Prefer variables declared before the loop in the same file
376
- const candidateVars = variableDeclarations.filter(v => v.name === iterableName &&
377
- v.file === loop.file &&
378
- (v.line ?? 0) <= loop.line // Declared before or on loop line
379
- );
380
- // Sort by line descending to find closest declaration
381
- candidateVars.sort((a, b) => (b.line ?? 0) - (a.line ?? 0));
382
- if (candidateVars.length > 0) {
383
- this._bufferEdge({
384
- type: 'ITERATES_OVER',
385
- src: loop.id,
386
- dst: candidateVars[0].id,
387
- metadata: { iterates }
388
- });
389
- }
390
- }
391
- }
392
- // REG-282: LOOP (for) -> HAS_INIT -> VARIABLE (let i = 0)
393
- if (loop.loopType === 'for' && loop.initVariableName && loop.initLine) {
394
- // Find the variable declared in the init on this line
395
- const initVar = variableDeclarations.find(v => v.name === loop.initVariableName &&
396
- v.file === loop.file &&
397
- v.line === loop.initLine);
398
- if (initVar) {
399
- this._bufferEdge({
400
- type: 'HAS_INIT',
401
- src: loop.id,
402
- dst: initVar.id
403
- });
404
- }
405
- }
406
- // REG-282: LOOP -> HAS_CONDITION -> EXPRESSION (i < 10 or condition for while/do-while)
407
- if (loop.testExpressionId && loop.testExpressionType) {
408
- // Create EXPRESSION node for the test
409
- this._bufferNode({
410
- id: loop.testExpressionId,
411
- type: 'EXPRESSION',
412
- name: loop.testExpressionType,
413
- file: loop.file,
414
- line: loop.testLine,
415
- column: loop.testColumn,
416
- expressionType: loop.testExpressionType
417
- });
418
- this._bufferEdge({
419
- type: 'HAS_CONDITION',
420
- src: loop.id,
421
- dst: loop.testExpressionId
422
- });
423
- }
424
- // REG-282: LOOP (for) -> HAS_UPDATE -> EXPRESSION (i++)
425
- if (loop.loopType === 'for' && loop.updateExpressionId && loop.updateExpressionType) {
426
- // Create EXPRESSION node for the update
427
- this._bufferNode({
428
- id: loop.updateExpressionId,
429
- type: 'EXPRESSION',
430
- name: loop.updateExpressionType,
431
- file: loop.file,
432
- line: loop.updateLine,
433
- column: loop.updateColumn,
434
- expressionType: loop.updateExpressionType
435
- });
436
- this._bufferEdge({
437
- type: 'HAS_UPDATE',
438
- src: loop.id,
439
- dst: loop.updateExpressionId
440
- });
441
- }
222
+ findFunctionByName(functions, name, file, callScopeId) {
223
+ if (!name)
224
+ return undefined;
225
+ // Find all functions with matching name in the same file
226
+ const candidates = functions.filter(f => f.name === name && f.file === file);
227
+ if (candidates.length === 0) {
228
+ // Fallback: try without file constraint (legacy behavior)
229
+ return functions.find(f => f.name === name);
442
230
  }
443
- }
444
- /**
445
- * Buffer HAS_CONDITION edges from LOOP to condition EXPRESSION/CALL nodes.
446
- * Also creates EXPRESSION nodes for non-CallExpression conditions.
447
- *
448
- * REG-280: For while/do-while/for loops, creates HAS_CONDITION edge to the
449
- * condition expression. For-in/for-of loops don't have conditions (use ITERATES_OVER).
450
- *
451
- * For CallExpression conditions, links to existing CALL_SITE node by coordinates.
452
- */
453
- bufferLoopConditionEdges(loops, callSites) {
454
- for (const loop of loops) {
455
- // Skip for-in/for-of loops - they don't have test expressions
456
- if (loop.loopType === 'for-in' || loop.loopType === 'for-of') {
457
- continue;
458
- }
459
- // Skip if no condition (e.g., infinite for loop: for(;;))
460
- if (!loop.conditionExpressionId) {
461
- continue;
462
- }
463
- // LOOP -> HAS_CONDITION -> EXPRESSION/CALL
464
- let targetId = loop.conditionExpressionId;
465
- // For CallExpression conditions, look up the actual CALL_SITE by coordinates
466
- // because CALL_SITE uses semantic IDs that don't match the generated ID
467
- if (loop.conditionExpressionType === 'CallExpression' && loop.conditionLine && loop.conditionColumn !== undefined) {
468
- const callSite = callSites.find(cs => cs.file === loop.file &&
469
- cs.line === loop.conditionLine &&
470
- cs.column === loop.conditionColumn);
471
- if (callSite) {
472
- targetId = callSite.id;
473
- }
474
- }
475
- this._bufferEdge({
476
- type: 'HAS_CONDITION',
477
- src: loop.id,
478
- dst: targetId
479
- });
231
+ if (candidates.length === 1) {
232
+ return candidates[0];
480
233
  }
234
+ // Multiple candidates: prefer same scope, then module-level
235
+ const sameScope = candidates.find(f => f.parentScopeId === callScopeId);
236
+ if (sameScope)
237
+ return sameScope;
238
+ // Fallback: prefer module-level function (parentScopeId contains MODULE)
239
+ const moduleLevel = candidates.find(f => f.parentScopeId?.includes(':MODULE:'));
240
+ return moduleLevel || candidates[0];
481
241
  }
482
242
  /**
483
- * Buffer EXPRESSION nodes for loop condition expressions (non-CallExpression).
484
- * Similar to bufferDiscriminantExpressions but for loops.
243
+ * Resolve variable by name using scope chain lookup (REG-309).
244
+ * Mirrors JavaScript lexical scoping: search current scope, then parent, then grandparent, etc.
485
245
  *
486
- * REG-280: Creates EXPRESSION nodes for while/do-while/for loop conditions.
487
- * CallExpression conditions use existing CALL_SITE nodes (no EXPRESSION created).
246
+ * @param name - Variable name
247
+ * @param scopePath - Scope path where reference occurs (from ScopeTracker)
248
+ * @param file - File path
249
+ * @param variables - All variable declarations
250
+ * @returns Variable declaration or null if not found
488
251
  */
489
- bufferLoopConditionExpressions(loops) {
490
- for (const loop of loops) {
491
- // Skip for-in/for-of loops - they don't have test expressions
492
- if (loop.loopType === 'for-in' || loop.loopType === 'for-of') {
493
- continue;
494
- }
495
- if (loop.conditionExpressionId && loop.conditionExpressionType) {
496
- // Skip CallExpression - we link to existing CALL_SITE in bufferLoopConditionEdges
497
- if (loop.conditionExpressionType === 'CallExpression') {
498
- continue;
252
+ resolveVariableInScope(name, scopePath, file, variables) {
253
+ // Try current scope, then parent, then grandparent, etc.
254
+ for (let i = scopePath.length; i >= 0; i--) {
255
+ const searchScopePath = scopePath.slice(0, i);
256
+ const matchingVar = variables.find(v => {
257
+ if (v.name !== name || v.file !== file)
258
+ return false;
259
+ // REG-464: v2 path use scopePath field if available (set by visitors)
260
+ if (v.scopePath) {
261
+ if (searchScopePath.length === 0) {
262
+ return v.scopePath.length === 0;
263
+ }
264
+ return this.scopePathsMatch(v.scopePath, searchScopePath);
499
265
  }
500
- // Only create if it looks like an EXPRESSION ID
501
- if (loop.conditionExpressionId.includes(':EXPRESSION:')) {
502
- this._bufferNode({
503
- id: loop.conditionExpressionId,
504
- type: 'EXPRESSION',
505
- name: loop.conditionExpressionType,
506
- file: loop.file,
507
- line: loop.conditionLine,
508
- column: loop.conditionColumn,
509
- expressionType: loop.conditionExpressionType
510
- });
266
+ // v1 fallback: parse semanticId
267
+ // Variable ID IS the semantic ID (when scopeTracker was available during analysis)
268
+ // Format: file->scope1->scope2->TYPE->name
269
+ // Legacy format: VARIABLE#name#file#line:column:counter
270
+ // Try parsing as semantic ID
271
+ const parsed = parseSemanticId(v.id);
272
+ // REG-329: Check for both VARIABLE and CONSTANT (const declarations)
273
+ if (parsed && (parsed.type === 'VARIABLE' || parsed.type === 'CONSTANT')) {
274
+ // FIXED (REG-309): Handle module-level scope matching
275
+ // Empty search scope [] should match semantic ID scope ['global']
276
+ if (searchScopePath.length === 0) {
277
+ return parsed.scopePath.length === 1 && parsed.scopePath[0] === 'global';
278
+ }
279
+ // Non-empty scope: exact match
280
+ return this.scopePathsMatch(parsed.scopePath, searchScopePath);
511
281
  }
512
- }
282
+ // Legacy ID - assume module-level if no semantic ID
283
+ return searchScopePath.length === 0;
284
+ });
285
+ if (matchingVar)
286
+ return matchingVar;
513
287
  }
288
+ return null;
514
289
  }
515
290
  /**
516
- * Buffer BRANCH edges (CONTAINS, HAS_CONDITION, HAS_CONSEQUENT, HAS_ALTERNATE)
517
- *
518
- * REG-275: For CallExpression discriminants (switch(getType())), looks up the
519
- * actual CALL_SITE node by coordinates since the CALL_SITE uses semantic IDs.
291
+ * Resolve parameter by name using scope chain lookup (REG-309).
292
+ * Same semantics as resolveVariableInScope but for parameters.
520
293
  *
521
- * Phase 3 (REG-267): For if-branches, creates HAS_CONSEQUENT and HAS_ALTERNATE edges
522
- * pointing to the if-body and else-body SCOPEs.
294
+ * @param name - Parameter name
295
+ * @param scopePath - Scope path where reference occurs (from ScopeTracker)
296
+ * @param file - File path
297
+ * @param parameters - All parameter declarations
298
+ * @returns Parameter declaration or null if not found
523
299
  */
524
- bufferBranchEdges(branches, callSites, scopes) {
525
- for (const branch of branches) {
526
- // Parent SCOPE -> CONTAINS -> BRANCH
527
- if (branch.parentScopeId) {
528
- this._bufferEdge({
529
- type: 'CONTAINS',
530
- src: branch.parentScopeId,
531
- dst: branch.id
532
- });
533
- }
534
- // BRANCH -> HAS_CONDITION -> EXPRESSION/CALL (discriminant)
535
- if (branch.discriminantExpressionId) {
536
- let targetId = branch.discriminantExpressionId;
537
- // For CallExpression discriminants, look up the actual CALL_SITE by coordinates
538
- // because CALL_SITE uses semantic IDs that don't match the generated ID
539
- if (branch.discriminantExpressionType === 'CallExpression' && branch.discriminantLine && branch.discriminantColumn !== undefined) {
540
- const callSite = callSites.find(cs => cs.file === branch.file &&
541
- cs.line === branch.discriminantLine &&
542
- cs.column === branch.discriminantColumn);
543
- if (callSite) {
544
- targetId = callSite.id;
300
+ resolveParameterInScope(name, scopePath, file, parameters) {
301
+ // Parameters have semanticId field populated (unlike variables which use id field)
302
+ return parameters.find(p => {
303
+ if (p.name !== name || p.file !== file)
304
+ return false;
305
+ // REG-464: v2 path — use scopePath field if available (set by visitors)
306
+ if (p.scopePath) {
307
+ for (let i = scopePath.length; i >= 0; i--) {
308
+ const searchScopePath = scopePath.slice(0, i);
309
+ if (searchScopePath.length === 0) {
310
+ if (p.scopePath.length === 0)
311
+ return true;
312
+ }
313
+ else {
314
+ if (this.scopePathsMatch(p.scopePath, searchScopePath))
315
+ return true;
545
316
  }
546
317
  }
547
- this._bufferEdge({
548
- type: 'HAS_CONDITION',
549
- src: branch.id,
550
- dst: targetId
551
- });
552
- }
553
- // Phase 3: For if-branches, create HAS_CONSEQUENT and HAS_ALTERNATE edges
554
- if (branch.branchType === 'if') {
555
- // Find consequent (if-body) scope - parentScopeId matches branch.id, scopeType is 'if_statement'
556
- const consequentScope = scopes.find(s => s.parentScopeId === branch.id && s.scopeType === 'if_statement');
557
- if (consequentScope) {
558
- this._bufferEdge({
559
- type: 'HAS_CONSEQUENT',
560
- src: branch.id,
561
- dst: consequentScope.id
562
- });
563
- }
564
- // Find alternate (else-body) scope - parentScopeId matches branch.id, scopeType is 'else_statement'
565
- const alternateScope = scopes.find(s => s.parentScopeId === branch.id && s.scopeType === 'else_statement');
566
- if (alternateScope) {
567
- this._bufferEdge({
568
- type: 'HAS_ALTERNATE',
569
- src: branch.id,
570
- dst: alternateScope.id
571
- });
572
- }
573
- // For else-if chains: if this branch is the alternate of another branch
574
- // This is handled differently - see below
318
+ return false;
575
319
  }
576
- // REG-287: For ternary branches, create HAS_CONSEQUENT and HAS_ALTERNATE edges to expressions
577
- if (branch.branchType === 'ternary') {
578
- if (branch.consequentExpressionId) {
579
- this._bufferEdge({
580
- type: 'HAS_CONSEQUENT',
581
- src: branch.id,
582
- dst: branch.consequentExpressionId
583
- });
584
- }
585
- if (branch.alternateExpressionId) {
586
- this._bufferEdge({
587
- type: 'HAS_ALTERNATE',
588
- src: branch.id,
589
- dst: branch.alternateExpressionId
590
- });
320
+ // v1 fallback: parse semanticId
321
+ if (p.semanticId) {
322
+ const parsed = parseSemanticId(p.semanticId);
323
+ if (parsed && parsed.type === 'PARAMETER') {
324
+ // Check if parameter's scope matches any scope in the chain
325
+ for (let i = scopePath.length; i >= 0; i--) {
326
+ const searchScopePath = scopePath.slice(0, i);
327
+ // FIXED (REG-309): Handle module-level scope matching for parameters
328
+ if (searchScopePath.length === 0) {
329
+ if (parsed.scopePath.length === 1 && parsed.scopePath[0] === 'global') {
330
+ return true;
331
+ }
332
+ }
333
+ else {
334
+ if (this.scopePathsMatch(parsed.scopePath, searchScopePath)) {
335
+ return true;
336
+ }
337
+ }
338
+ }
591
339
  }
592
340
  }
593
- // Phase 3: For else-if chains, create HAS_ALTERNATE from parent branch to this branch
594
- if (branch.isAlternateOfBranchId) {
595
- this._bufferEdge({
596
- type: 'HAS_ALTERNATE',
597
- src: branch.isAlternateOfBranchId,
598
- dst: branch.id
599
- });
600
- }
601
- }
341
+ return false;
342
+ }) ?? null;
602
343
  }
603
344
  /**
604
- * Buffer CASE edges (HAS_CASE, HAS_DEFAULT)
345
+ * Check if two scope paths match (REG-309).
346
+ * Handles: ['foo', 'if#0'] vs ['foo', 'if#0']
605
347
  */
606
- bufferCaseEdges(cases) {
607
- for (const caseInfo of cases) {
608
- // BRANCH -> HAS_CASE or HAS_DEFAULT -> CASE
609
- const edgeType = caseInfo.isDefault ? 'HAS_DEFAULT' : 'HAS_CASE';
610
- this._bufferEdge({
611
- type: edgeType,
612
- src: caseInfo.parentBranchId,
613
- dst: caseInfo.id
614
- });
615
- }
348
+ scopePathsMatch(a, b) {
349
+ if (a.length !== b.length)
350
+ return false;
351
+ return a.every((item, idx) => item === b[idx]);
616
352
  }
353
+ // ============= POST-FLUSH METHODS (need graph queries) =============
617
354
  /**
618
- * Buffer edges for TRY_BLOCK, CATCH_BLOCK, FINALLY_BLOCK nodes (Phase 4)
619
- *
620
- * Creates edges for:
621
- * - Parent -> CONTAINS -> TRY_BLOCK
622
- * - TRY_BLOCK -> HAS_CATCH -> CATCH_BLOCK
623
- * - TRY_BLOCK -> HAS_FINALLY -> FINALLY_BLOCK
355
+ * Collect unique import.meta property names from property accesses (REG-300).
356
+ * Returns deduplicated array of property names (e.g., ["url", "env"]).
624
357
  */
625
- bufferTryCatchFinallyEdges(tryBlocks, catchBlocks, finallyBlocks) {
626
- // Buffer TRY_BLOCK edges
627
- for (const tryBlock of tryBlocks) {
628
- // Parent -> CONTAINS -> TRY_BLOCK
629
- if (tryBlock.parentScopeId) {
630
- this._bufferEdge({
631
- type: 'CONTAINS',
632
- src: tryBlock.parentScopeId,
633
- dst: tryBlock.id
634
- });
358
+ collectImportMetaProperties(propertyAccesses) {
359
+ const metaProps = new Set();
360
+ for (const propAccess of propertyAccesses) {
361
+ if (propAccess.objectName === 'import.meta') {
362
+ metaProps.add(propAccess.propertyName);
635
363
  }
636
364
  }
637
- // Buffer CATCH_BLOCK edges (HAS_CATCH from TRY_BLOCK)
638
- for (const catchBlock of catchBlocks) {
639
- // TRY_BLOCK -> HAS_CATCH -> CATCH_BLOCK
640
- this._bufferEdge({
641
- type: 'HAS_CATCH',
642
- src: catchBlock.parentTryBlockId,
643
- dst: catchBlock.id
644
- });
645
- }
646
- // Buffer FINALLY_BLOCK edges (HAS_FINALLY from TRY_BLOCK)
647
- for (const finallyBlock of finallyBlocks) {
648
- // TRY_BLOCK -> HAS_FINALLY -> FINALLY_BLOCK
649
- this._bufferEdge({
650
- type: 'HAS_FINALLY',
651
- src: finallyBlock.parentTryBlockId,
652
- dst: finallyBlock.id
653
- });
654
- }
365
+ return [...metaProps];
655
366
  }
656
367
  /**
657
- * Buffer EXPRESSION nodes for switch discriminants
658
- * Uses stored metadata directly instead of parsing from ID (Linus improvement)
659
- *
660
- * REG-275: For CallExpression discriminants, we don't create nodes here since
661
- * bufferBranchEdges links to the existing CALL_SITE node by coordinates.
368
+ * Update MODULE node with import.meta metadata (REG-300).
369
+ * Reads existing MODULE node, adds importMeta property list, re-adds it.
662
370
  */
663
- bufferDiscriminantExpressions(branches, _callSites) {
664
- for (const branch of branches) {
665
- if (branch.discriminantExpressionId && branch.discriminantExpressionType) {
666
- // Skip CallExpression - we link to existing CALL_SITE in bufferBranchEdges
667
- if (branch.discriminantExpressionType === 'CallExpression') {
668
- continue;
669
- }
670
- // Only create if it looks like an EXPRESSION ID
671
- if (branch.discriminantExpressionId.includes(':EXPRESSION:')) {
672
- this._bufferNode({
673
- id: branch.discriminantExpressionId,
674
- type: 'EXPRESSION',
675
- name: branch.discriminantExpressionType,
676
- file: branch.file,
677
- line: branch.discriminantLine,
678
- column: branch.discriminantColumn,
679
- expressionType: branch.discriminantExpressionType
680
- });
681
- }
682
- }
683
- }
684
- }
685
- bufferVariableEdges(variableDeclarations) {
686
- for (const varDecl of variableDeclarations) {
687
- const { parentScopeId, isClassProperty, ...varData } = varDecl;
688
- // REG-271: Skip class properties - they get HAS_PROPERTY edges from CLASS, not DECLARES from SCOPE
689
- if (isClassProperty) {
690
- continue;
691
- }
692
- // SCOPE -> DECLARES -> VARIABLE
693
- this._bufferEdge({
694
- type: 'DECLARES',
695
- src: parentScopeId,
696
- dst: varData.id
697
- });
698
- }
699
- }
700
- bufferCallSiteEdges(callSites, functions) {
701
- for (const callSite of callSites) {
702
- const { parentScopeId, targetFunctionName, ...callData } = callSite;
703
- // SCOPE -> CONTAINS -> CALL_SITE
704
- this._bufferEdge({
705
- type: 'CONTAINS',
706
- src: parentScopeId,
707
- dst: callData.id
708
- });
709
- // CALL_SITE -> CALLS -> FUNCTION
710
- const targetFunction = functions.find(f => f.name === targetFunctionName);
711
- if (targetFunction) {
712
- this._bufferEdge({
713
- type: 'CALLS',
714
- src: callData.id,
715
- dst: targetFunction.id
716
- });
717
- }
718
- }
719
- }
720
- bufferMethodCalls(methodCalls, variableDeclarations, parameters) {
721
- for (const methodCall of methodCalls) {
722
- // Keep parentScopeId on node for queries
723
- this._bufferNode(methodCall);
724
- // SCOPE -> CONTAINS -> METHOD_CALL
725
- this._bufferEdge({
726
- type: 'CONTAINS',
727
- src: methodCall.parentScopeId,
728
- dst: methodCall.id
729
- });
730
- // REG-262: Create USES edge from METHOD_CALL to receiver variable
731
- // Skip 'this' - it's not a variable node
732
- if (methodCall.object && methodCall.object !== 'this') {
733
- // Handle nested member expressions: obj.nested.method() -> use base 'obj'
734
- const receiverName = methodCall.object.includes('.')
735
- ? methodCall.object.split('.')[0]
736
- : methodCall.object;
737
- // Find receiver variable in current file
738
- const receiverVar = variableDeclarations.find(v => v.name === receiverName && v.file === methodCall.file);
739
- if (receiverVar) {
740
- this._bufferEdge({
741
- type: 'USES',
742
- src: methodCall.id,
743
- dst: receiverVar.id
744
- });
745
- }
746
- else {
747
- // Check parameters (function arguments)
748
- const receiverParam = parameters.find(p => p.name === receiverName && p.file === methodCall.file);
749
- if (receiverParam) {
750
- this._bufferEdge({
751
- type: 'USES',
752
- src: methodCall.id,
753
- dst: receiverParam.id
754
- });
755
- }
756
- }
757
- }
758
- }
371
+ async updateModuleImportMetaMetadata(module, graph, importMetaProps) {
372
+ if (importMetaProps.length === 0)
373
+ return;
374
+ const existingNode = await graph.getNode(module.id);
375
+ if (!existingNode)
376
+ return;
377
+ // Re-add with importMeta at top level — addNode is upsert in RFDB,
378
+ // and backend spreads metadata fields to top level on read
379
+ await graph.addNode({
380
+ ...existingNode,
381
+ importMeta: importMetaProps
382
+ });
759
383
  }
760
384
  /**
761
- * Buffer PROPERTY_ACCESS nodes and CONTAINS edges (REG-395).
762
- *
763
- * Creates nodes for property reads (obj.prop, a.b.c) and
764
- * CONTAINS edges from the enclosing scope (function or module).
385
+ * Update MODULE node with hasTopLevelAwait metadata (REG-297).
386
+ * Reads existing MODULE node, adds hasTopLevelAwait flag, re-adds it.
765
387
  */
766
- bufferPropertyAccessNodes(module, propertyAccesses) {
767
- for (const propAccess of propertyAccesses) {
768
- // Buffer node with all relevant fields
769
- this._bufferNode({
770
- id: propAccess.id,
771
- type: 'PROPERTY_ACCESS',
772
- name: propAccess.propertyName,
773
- objectName: propAccess.objectName,
774
- file: propAccess.file,
775
- line: propAccess.line,
776
- column: propAccess.column,
777
- semanticId: propAccess.semanticId,
778
- optional: propAccess.optional,
779
- computed: propAccess.computed
780
- });
781
- // SCOPE/FUNCTION/MODULE -> CONTAINS -> PROPERTY_ACCESS
782
- const containsSrc = propAccess.parentScopeId ?? module.id;
783
- this._bufferEdge({
784
- type: 'CONTAINS',
785
- src: containsSrc,
786
- dst: propAccess.id
787
- });
788
- }
789
- }
790
- bufferStdioNodes(methodCalls) {
791
- const consoleIOMethods = methodCalls.filter(mc => (mc.object === 'console' && (mc.method === 'log' || mc.method === 'error')));
792
- if (consoleIOMethods.length > 0) {
793
- const stdioNode = NodeFactory.createExternalStdio();
794
- // Buffer net:stdio node only once (singleton)
795
- if (!this._createdSingletons.has(stdioNode.id)) {
796
- this._bufferNode(stdioNode);
797
- this._createdSingletons.add(stdioNode.id);
798
- }
799
- // Buffer WRITES_TO edges for console.log/error
800
- for (const methodCall of consoleIOMethods) {
801
- this._bufferEdge({
802
- type: 'WRITES_TO',
803
- src: methodCall.id,
804
- dst: stdioNode.id
805
- });
806
- }
807
- }
388
+ async updateModuleTopLevelAwaitMetadata(module, graph, hasTopLevelAwait) {
389
+ if (!hasTopLevelAwait)
390
+ return;
391
+ const existingNode = await graph.getNode(module.id);
392
+ if (!existingNode)
393
+ return;
394
+ await graph.addNode({
395
+ ...existingNode,
396
+ hasTopLevelAwait: true
397
+ });
808
398
  }
809
- bufferClassDeclarationNodes(classDeclarations) {
810
- for (const classDecl of classDeclarations) {
811
- const { id, type, name, file, line, column, superClass, methods, properties, staticBlocks } = classDecl;
812
- // Buffer CLASS node
813
- this._bufferNode({
814
- id,
815
- type,
816
- name,
817
- file,
818
- line,
819
- column,
820
- superClass
821
- });
822
- // Buffer CONTAINS edges: CLASS -> METHOD
823
- for (const methodId of methods) {
824
- this._bufferEdge({
825
- type: 'CONTAINS',
826
- src: id,
827
- dst: methodId
828
- });
829
- }
830
- // REG-271: Buffer HAS_PROPERTY edges: CLASS -> VARIABLE (private fields)
831
- if (properties) {
832
- for (const propertyId of properties) {
833
- this._bufferEdge({
834
- type: 'HAS_PROPERTY',
835
- src: id,
836
- dst: propertyId
837
- });
399
+ /**
400
+ * Handle CLASS ASSIGNED_FROM edges asynchronously (needs graph queries)
401
+ */
402
+ async createClassAssignmentEdges(variableAssignments, graph) {
403
+ let edgesCreated = 0;
404
+ for (const assignment of variableAssignments) {
405
+ const { variableId, sourceType, className } = assignment;
406
+ if (sourceType === 'CLASS' && className) {
407
+ const parts = variableId.split('#');
408
+ const file = parts.length >= 3 ? parts[2] : null;
409
+ let classNode = null;
410
+ for await (const node of graph.queryNodes({ type: 'CLASS' })) {
411
+ if (node.name === className && (!file || node.file === file)) {
412
+ classNode = node;
413
+ break;
414
+ }
838
415
  }
839
- }
840
- // REG-271: Buffer CONTAINS edges: CLASS -> SCOPE (static blocks)
841
- if (staticBlocks) {
842
- for (const staticBlockId of staticBlocks) {
843
- this._bufferEdge({
844
- type: 'CONTAINS',
845
- src: id,
846
- dst: staticBlockId
416
+ if (classNode) {
417
+ await graph.addEdge({
418
+ type: 'ASSIGNED_FROM',
419
+ src: variableId,
420
+ dst: classNode.id
847
421
  });
848
- }
849
- }
850
- // If superClass, buffer DERIVES_FROM edge with computed ID
851
- if (superClass) {
852
- // Compute superclass ID using semantic ID format
853
- // Assume superclass is in same file at global scope (most common case)
854
- // When superclass is in different file, edge will be dangling until that file analyzed
855
- const globalContext = { file, scopePath: [] };
856
- const superClassId = computeSemanticId('CLASS', superClass, globalContext);
857
- this._bufferEdge({
858
- type: 'DERIVES_FROM',
859
- src: id,
860
- dst: superClassId
861
- });
862
- }
863
- }
864
- }
865
- bufferClassNodes(module, classInstantiations, classDeclarations) {
866
- // Create lookup map: className → declaration ID
867
- // Use basename for comparison because CLASS nodes use scopeTracker.file (basename)
868
- const moduleBasename = basename(module.file);
869
- const declarationMap = new Map();
870
- for (const decl of classDeclarations) {
871
- if (decl.file === moduleBasename) {
872
- declarationMap.set(decl.name, decl.id);
873
- }
874
- }
875
- for (const instantiation of classInstantiations) {
876
- const { variableId, className, line: _line } = instantiation;
877
- let classId = declarationMap.get(className);
878
- if (!classId) {
879
- // External class - compute semantic ID
880
- // Use basename to match CLASS node format (scopeTracker uses basename)
881
- // When class is in different file, edge will be dangling until that file analyzed
882
- const globalContext = { file: moduleBasename, scopePath: [] };
883
- classId = computeSemanticId('CLASS', className, globalContext);
884
- // NO node creation - node will exist when class file analyzed
885
- }
886
- // Buffer INSTANCE_OF edge
887
- this._bufferEdge({
888
- type: 'INSTANCE_OF',
889
- src: variableId,
890
- dst: classId
891
- });
892
- }
893
- }
894
- bufferCallbackEdges(methodCallbacks, functions) {
895
- for (const callback of methodCallbacks) {
896
- const { methodCallId, callbackLine, callbackColumn } = callback;
897
- const callbackFunction = functions.find(f => f.line === callbackLine && f.column === callbackColumn);
898
- if (callbackFunction) {
899
- this._bufferEdge({
900
- type: 'HAS_CALLBACK',
901
- src: methodCallId,
902
- dst: callbackFunction.id
903
- });
904
- }
905
- }
906
- }
907
- bufferImportNodes(module, imports) {
908
- for (const imp of imports) {
909
- const { source, specifiers, line, column, isDynamic, isResolvable, dynamicPath } = imp;
910
- // REG-273: Handle side-effect-only imports (no specifiers)
911
- if (specifiers.length === 0) {
912
- // Side-effect import: import './polyfill.js'
913
- const importNode = ImportNode.create(source, // name = source (no local binding)
914
- module.file, // file
915
- line, // line (stored as field, not in ID)
916
- column || 0, // column
917
- source, // source module
918
- {
919
- imported: '*', // no specific export
920
- local: source, // source becomes local
921
- sideEffect: true // mark as side-effect import
922
- });
923
- this._bufferNode(importNode);
924
- // MODULE -> CONTAINS -> IMPORT
925
- this._bufferEdge({
926
- type: 'CONTAINS',
927
- src: module.id,
928
- dst: importNode.id
929
- });
930
- // Create EXTERNAL_MODULE node for external modules
931
- const isRelative = source.startsWith('./') || source.startsWith('../');
932
- if (!isRelative) {
933
- const externalModule = NodeFactory.createExternalModule(source);
934
- // Avoid duplicate EXTERNAL_MODULE nodes
935
- if (!this._createdSingletons.has(externalModule.id)) {
936
- this._bufferNode(externalModule);
937
- this._createdSingletons.add(externalModule.id);
938
- }
939
- this._bufferEdge({
940
- type: 'IMPORTS',
941
- src: module.id,
942
- dst: externalModule.id
943
- });
944
- }
945
- }
946
- else {
947
- // Regular imports with specifiers
948
- for (const spec of specifiers) {
949
- // Use ImportNode factory for proper semantic IDs and field population
950
- const importNode = ImportNode.create(spec.local, // name = local binding
951
- module.file, // file
952
- line, // line (stored as field, not in ID)
953
- column || 0, // column
954
- source, // source module
955
- {
956
- imported: spec.imported,
957
- local: spec.local,
958
- sideEffect: false, // regular imports are not side-effects
959
- // importType is auto-detected from imported field
960
- // Dynamic import fields
961
- isDynamic,
962
- isResolvable,
963
- dynamicPath
964
- });
965
- this._bufferNode(importNode);
966
- // MODULE -> CONTAINS -> IMPORT
967
- this._bufferEdge({
968
- type: 'CONTAINS',
969
- src: module.id,
970
- dst: importNode.id
971
- });
972
- // Create EXTERNAL_MODULE node for external modules
973
- const isRelative = source.startsWith('./') || source.startsWith('../');
974
- if (!isRelative) {
975
- const externalModule = NodeFactory.createExternalModule(source);
976
- // Avoid duplicate EXTERNAL_MODULE nodes
977
- if (!this._createdSingletons.has(externalModule.id)) {
978
- this._bufferNode(externalModule);
979
- this._createdSingletons.add(externalModule.id);
980
- }
981
- this._bufferEdge({
982
- type: 'IMPORTS',
983
- src: module.id,
984
- dst: externalModule.id
985
- });
986
- }
987
- }
988
- }
989
- }
990
- }
991
- bufferExportNodes(module, exports) {
992
- for (const exp of exports) {
993
- const { type, line, name, specifiers, source } = exp;
994
- if (type === 'default') {
995
- const exportNode = NodeFactory.createExport('default', module.file, line, 0, { default: true, exportType: 'default' });
996
- this._bufferNode(exportNode);
997
- this._bufferEdge({
998
- type: 'CONTAINS',
999
- src: module.id,
1000
- dst: exportNode.id
1001
- });
1002
- }
1003
- else if (type === 'named') {
1004
- if (specifiers) {
1005
- for (const spec of specifiers) {
1006
- const exportNode = NodeFactory.createExport(spec.exported, module.file, line, 0, {
1007
- local: spec.local,
1008
- source: source,
1009
- exportType: 'named'
1010
- });
1011
- this._bufferNode(exportNode);
1012
- this._bufferEdge({
1013
- type: 'CONTAINS',
1014
- src: module.id,
1015
- dst: exportNode.id
1016
- });
1017
- }
1018
- }
1019
- else if (name) {
1020
- const exportNode = NodeFactory.createExport(name, module.file, line, 0, { exportType: 'named' });
1021
- this._bufferNode(exportNode);
1022
- this._bufferEdge({
1023
- type: 'CONTAINS',
1024
- src: module.id,
1025
- dst: exportNode.id
1026
- });
1027
- }
1028
- }
1029
- else if (type === 'all') {
1030
- const exportNode = NodeFactory.createExport('*', module.file, line, 0, {
1031
- source: source,
1032
- exportType: 'all'
1033
- });
1034
- this._bufferNode(exportNode);
1035
- this._bufferEdge({
1036
- type: 'CONTAINS',
1037
- src: module.id,
1038
- dst: exportNode.id
1039
- });
1040
- }
1041
- }
1042
- }
1043
- bufferEventListeners(eventListeners, functions) {
1044
- for (const eventListener of eventListeners) {
1045
- const { parentScopeId, callbackArg, ...listenerData } = eventListener;
1046
- this._bufferNode(listenerData);
1047
- this._bufferEdge({
1048
- type: 'CONTAINS',
1049
- src: parentScopeId,
1050
- dst: listenerData.id
1051
- });
1052
- if (callbackArg && callbackArg.type === 'ArrowFunctionExpression') {
1053
- const callbackLine = callbackArg.loc.start.line;
1054
- const callbackFunction = functions.find(f => f.line === callbackLine && f.arrowFunction);
1055
- if (callbackFunction) {
1056
- this._bufferEdge({
1057
- type: 'HANDLED_BY',
1058
- src: listenerData.id,
1059
- dst: callbackFunction.id
1060
- });
1061
- }
1062
- }
1063
- }
1064
- }
1065
- bufferHttpRequests(httpRequests, functions) {
1066
- if (httpRequests.length > 0) {
1067
- // Create net:request singleton using factory
1068
- const networkNode = NetworkRequestNode.create();
1069
- if (!this._createdSingletons.has(networkNode.id)) {
1070
- this._bufferNode(networkNode);
1071
- this._createdSingletons.add(networkNode.id);
1072
- }
1073
- for (const request of httpRequests) {
1074
- const { parentScopeId, ...requestData } = request;
1075
- this._bufferNode(requestData);
1076
- this._bufferEdge({
1077
- type: 'CALLS',
1078
- src: request.id,
1079
- dst: networkNode.id
1080
- });
1081
- if (parentScopeId) {
1082
- const scopeParts = parentScopeId.split(':');
1083
- if (scopeParts.length >= 3 && scopeParts[1] === 'SCOPE') {
1084
- const functionName = scopeParts[2];
1085
- const file = scopeParts[0];
1086
- const parentFunction = functions.find(f => f.file === file && f.name === functionName);
1087
- if (parentFunction) {
1088
- this._bufferEdge({
1089
- type: 'MAKES_REQUEST',
1090
- src: parentFunction.id,
1091
- dst: request.id
1092
- });
1093
- }
1094
- }
1095
- }
1096
- }
1097
- }
1098
- }
1099
- bufferLiterals(literals) {
1100
- for (const literal of literals) {
1101
- const { parentCallId: _parentCallId, argIndex: _argIndex, ...literalData } = literal;
1102
- this._bufferNode(literalData);
1103
- }
1104
- }
1105
- bufferAssignmentEdges(variableAssignments, variableDeclarations, callSites, methodCalls, functions, classInstantiations, parameters) {
1106
- for (const assignment of variableAssignments) {
1107
- const { variableId, sourceId, sourceType, sourceName, sourceLine, sourceColumn, sourceFile, functionName, line, column, className } = assignment;
1108
- // Skip CLASS sourceType - handled async in createClassAssignmentEdges
1109
- if (sourceType === 'CLASS') {
1110
- continue;
1111
- }
1112
- // CONSTRUCTOR_CALL: create ASSIGNED_FROM edge to existing node
1113
- // Note: CONSTRUCTOR_CALL nodes are already created from constructorCalls collection in step 4.5
1114
- if (sourceType === 'CONSTRUCTOR_CALL' && className) {
1115
- const constructorLine = line ?? 0;
1116
- const constructorColumn = column ?? 0;
1117
- const constructorFile = assignment.file ?? '';
1118
- // Generate ID matching the one created in NewExpression visitor
1119
- const constructorCallId = NodeFactory.generateConstructorCallId(className, constructorFile, constructorLine, constructorColumn);
1120
- this._bufferEdge({
1121
- type: 'ASSIGNED_FROM',
1122
- src: variableId,
1123
- dst: constructorCallId
1124
- });
1125
- continue;
1126
- }
1127
- // Direct LITERAL assignment
1128
- if (sourceId && sourceType !== 'EXPRESSION') {
1129
- this._bufferEdge({
1130
- type: 'ASSIGNED_FROM',
1131
- src: variableId,
1132
- dst: sourceId
1133
- });
1134
- }
1135
- // METHOD_CALL by coordinates
1136
- else if (sourceType === 'METHOD_CALL' && sourceLine && sourceColumn) {
1137
- const methodCall = methodCalls.find(mc => mc.line === sourceLine &&
1138
- mc.column === sourceColumn &&
1139
- mc.file === sourceFile);
1140
- if (methodCall) {
1141
- this._bufferEdge({
1142
- type: 'ASSIGNED_FROM',
1143
- src: variableId,
1144
- dst: methodCall.id
1145
- });
1146
- }
1147
- }
1148
- // CALL_SITE by coordinates
1149
- else if (sourceType === 'CALL_SITE') {
1150
- const searchLine = sourceLine || assignment.callLine;
1151
- const searchColumn = sourceColumn || assignment.callColumn;
1152
- const searchName = assignment.callName;
1153
- if (searchLine && searchColumn) {
1154
- const callSite = callSites.find(cs => cs.line === searchLine &&
1155
- cs.column === searchColumn &&
1156
- (searchName ? cs.name === searchName : true));
1157
- if (callSite) {
1158
- this._bufferEdge({
1159
- type: 'ASSIGNED_FROM',
1160
- src: variableId,
1161
- dst: callSite.id
1162
- });
1163
- }
1164
- }
1165
- }
1166
- // VARIABLE by name
1167
- else if (sourceType === 'VARIABLE' && sourceName) {
1168
- // Find the current variable's file by looking it up in variableDeclarations
1169
- // (semantic IDs don't have predictable file positions like old hash-based IDs)
1170
- const currentVar = variableDeclarations.find(v => v.id === variableId);
1171
- const varFile = currentVar?.file ?? null;
1172
- const sourceVariable = variableDeclarations.find(v => v.name === sourceName && v.file === varFile);
1173
- if (sourceVariable) {
1174
- this._bufferEdge({
1175
- type: 'ASSIGNED_FROM',
1176
- src: variableId,
1177
- dst: sourceVariable.id
1178
- });
1179
- }
1180
- else {
1181
- const sourceParam = parameters.find(p => p.name === sourceName && p.file === varFile);
1182
- if (sourceParam) {
1183
- this._bufferEdge({
1184
- type: 'DERIVES_FROM',
1185
- src: variableId,
1186
- dst: sourceParam.id
1187
- });
1188
- }
1189
- }
1190
- }
1191
- // FUNCTION (arrow function assigned to variable)
1192
- else if (sourceType === 'FUNCTION' && functionName && line) {
1193
- const sourceFunction = functions.find(f => f.name === functionName && f.line === line);
1194
- if (sourceFunction) {
1195
- this._bufferEdge({
1196
- type: 'ASSIGNED_FROM',
1197
- src: variableId,
1198
- dst: sourceFunction.id
1199
- });
1200
- }
1201
- }
1202
- // EXPRESSION node creation using NodeFactory
1203
- else if (sourceType === 'EXPRESSION' && sourceId) {
1204
- const { expressionType, object, property, computed, computedPropertyVar, operator, objectSourceName, leftSourceName, rightSourceName, consequentSourceName, alternateSourceName, file: exprFile, line: exprLine, column: exprColumn,
1205
- // Destructuring support (REG-201)
1206
- path, baseName, propertyPath, arrayIndex } = assignment;
1207
- // Create node from upstream metadata using factory
1208
- const expressionNode = NodeFactory.createExpressionFromMetadata(expressionType || 'Unknown', exprFile || '', exprLine || 0, exprColumn || 0, {
1209
- id: sourceId, // ID from JSASTAnalyzer
1210
- object,
1211
- property,
1212
- computed,
1213
- computedPropertyVar: computedPropertyVar ?? undefined,
1214
- operator,
1215
- // Destructuring support (REG-201)
1216
- path,
1217
- baseName,
1218
- propertyPath,
1219
- arrayIndex
1220
- });
1221
- this._bufferNode(expressionNode);
1222
- this._bufferEdge({
1223
- type: 'ASSIGNED_FROM',
1224
- src: variableId,
1225
- dst: sourceId
1226
- });
1227
- // Buffer DERIVES_FROM edges
1228
- const varParts = variableId.split('#');
1229
- const varFile = varParts.length >= 3 ? varParts[2] : null;
1230
- if (expressionType === 'MemberExpression' && objectSourceName) {
1231
- const objectVar = variableDeclarations.find(v => v.name === objectSourceName && (!varFile || v.file === varFile));
1232
- if (objectVar) {
1233
- this._bufferEdge({
1234
- type: 'DERIVES_FROM',
1235
- src: sourceId,
1236
- dst: objectVar.id
1237
- });
1238
- }
1239
- }
1240
- // Call-based source lookup (REG-223)
1241
- else if (expressionType === 'MemberExpression' && assignment.callSourceLine !== undefined) {
1242
- const { callSourceLine, callSourceColumn, callSourceName, callSourceFile } = assignment;
1243
- // Try CALL_SITE first (direct function calls)
1244
- const callSite = callSites.find(cs => cs.line === callSourceLine &&
1245
- cs.column === callSourceColumn &&
1246
- (callSourceName ? cs.name === callSourceName : true));
1247
- if (callSite) {
1248
- this._bufferEdge({
1249
- type: 'DERIVES_FROM',
1250
- src: sourceId,
1251
- dst: callSite.id
1252
- });
1253
- }
1254
- // Fall back to methodCalls (arr.map(), obj.getConfig())
1255
- else {
1256
- const methodCall = methodCalls.find(mc => mc.line === callSourceLine &&
1257
- mc.column === callSourceColumn &&
1258
- (callSourceName ? mc.name === callSourceName : true));
1259
- if (methodCall) {
1260
- this._bufferEdge({
1261
- type: 'DERIVES_FROM',
1262
- src: sourceId,
1263
- dst: methodCall.id
1264
- });
1265
- }
1266
- // Log warning when lookup fails (per Linus review - no silent failures)
1267
- else {
1268
- console.warn(`[REG-223] DERIVES_FROM lookup failed for EXPRESSION(${assignment.object}.${assignment.property}) ` +
1269
- `at ${callSourceFile}:${callSourceLine}:${callSourceColumn}. ` +
1270
- `Expected CALL_SITE or methodCall for "${callSourceName}". ` +
1271
- `This indicates a coordinate mismatch or missing call node.`);
1272
- }
1273
- }
1274
- }
1275
- if ((expressionType === 'BinaryExpression' || expressionType === 'LogicalExpression')) {
1276
- if (leftSourceName) {
1277
- const leftVar = variableDeclarations.find(v => v.name === leftSourceName && (!varFile || v.file === varFile));
1278
- if (leftVar) {
1279
- this._bufferEdge({
1280
- type: 'DERIVES_FROM',
1281
- src: sourceId,
1282
- dst: leftVar.id
1283
- });
1284
- }
1285
- }
1286
- if (rightSourceName) {
1287
- const rightVar = variableDeclarations.find(v => v.name === rightSourceName && (!varFile || v.file === varFile));
1288
- if (rightVar) {
1289
- this._bufferEdge({
1290
- type: 'DERIVES_FROM',
1291
- src: sourceId,
1292
- dst: rightVar.id
1293
- });
1294
- }
1295
- }
1296
- }
1297
- if (expressionType === 'ConditionalExpression') {
1298
- if (consequentSourceName) {
1299
- const consequentVar = variableDeclarations.find(v => v.name === consequentSourceName && (!varFile || v.file === varFile));
1300
- if (consequentVar) {
1301
- this._bufferEdge({
1302
- type: 'DERIVES_FROM',
1303
- src: sourceId,
1304
- dst: consequentVar.id
1305
- });
1306
- }
1307
- }
1308
- if (alternateSourceName) {
1309
- const alternateVar = variableDeclarations.find(v => v.name === alternateSourceName && (!varFile || v.file === varFile));
1310
- if (alternateVar) {
1311
- this._bufferEdge({
1312
- type: 'DERIVES_FROM',
1313
- src: sourceId,
1314
- dst: alternateVar.id
1315
- });
1316
- }
1317
- }
1318
- }
1319
- if (expressionType === 'TemplateLiteral') {
1320
- const { expressionSourceNames } = assignment;
1321
- if (expressionSourceNames && expressionSourceNames.length > 0) {
1322
- for (const exprSourceName of expressionSourceNames) {
1323
- const sourceVar = variableDeclarations.find(v => v.name === exprSourceName && (!varFile || v.file === varFile));
1324
- if (sourceVar) {
1325
- this._bufferEdge({
1326
- type: 'DERIVES_FROM',
1327
- src: sourceId,
1328
- dst: sourceVar.id
1329
- });
1330
- }
1331
- }
1332
- }
1333
- }
1334
- }
1335
- // DERIVES_FROM_VARIABLE
1336
- else if (sourceType === 'DERIVES_FROM_VARIABLE' && sourceName) {
1337
- const expressionId = variableId;
1338
- const exprParts = expressionId.split('#');
1339
- const exprFile = exprParts.length >= 3 ? exprParts[2] : assignment.file;
1340
- const sourceVariable = variableDeclarations.find(v => v.name === sourceName && v.file === exprFile);
1341
- if (sourceVariable) {
1342
- this._bufferEdge({
1343
- type: 'DERIVES_FROM',
1344
- src: expressionId,
1345
- dst: sourceVariable.id
1346
- });
1347
- }
1348
- else {
1349
- const sourceParam = parameters.find(p => p.name === sourceName && p.file === exprFile);
1350
- if (sourceParam) {
1351
- this._bufferEdge({
1352
- type: 'DERIVES_FROM',
1353
- src: expressionId,
1354
- dst: sourceParam.id
1355
- });
1356
- }
1357
- }
1358
- }
1359
- }
1360
- }
1361
- bufferArgumentEdges(callArguments, variableDeclarations, functions, callSites, methodCalls) {
1362
- for (const arg of callArguments) {
1363
- const { callId, argIndex, targetType, targetId, targetName, file, isSpread, functionLine, functionColumn, nestedCallLine, nestedCallColumn } = arg;
1364
- let targetNodeId = targetId;
1365
- if (targetType === 'VARIABLE' && targetName) {
1366
- const varNode = variableDeclarations.find(v => v.name === targetName && v.file === file);
1367
- if (varNode) {
1368
- targetNodeId = varNode.id;
1369
- }
1370
- }
1371
- else if (targetType === 'FUNCTION' && functionLine && functionColumn) {
1372
- const funcNode = functions.find(f => f.file === file && f.line === functionLine && f.column === functionColumn);
1373
- if (funcNode) {
1374
- targetNodeId = funcNode.id;
1375
- }
1376
- }
1377
- else if (targetType === 'CALL' && nestedCallLine && nestedCallColumn) {
1378
- const nestedCall = callSites.find(c => c.file === file && c.line === nestedCallLine && c.column === nestedCallColumn) || methodCalls.find(c => c.file === file && c.line === nestedCallLine && c.column === nestedCallColumn);
1379
- if (nestedCall) {
1380
- targetNodeId = nestedCall.id;
1381
- }
1382
- }
1383
- else if (targetType === 'LITERAL' ||
1384
- targetType === 'OBJECT_LITERAL' ||
1385
- targetType === 'ARRAY_LITERAL') {
1386
- // targetId is already set by CallExpressionVisitor
1387
- targetNodeId = targetId;
1388
- }
1389
- if (targetNodeId) {
1390
- const edgeData = {
1391
- type: 'PASSES_ARGUMENT',
1392
- src: callId,
1393
- dst: targetNodeId,
1394
- metadata: { argIndex }
1395
- };
1396
- if (isSpread) {
1397
- edgeData.metadata = { ...edgeData.metadata, isSpread: true };
1398
- }
1399
- this._bufferEdge(edgeData);
1400
- }
1401
- }
1402
- }
1403
- // ============= TypeScript-specific buffer methods =============
1404
- /**
1405
- * Buffer INTERFACE nodes and EXTENDS edges
1406
- *
1407
- * Uses two-pass approach:
1408
- * 1. First pass: create all interface nodes, store in Map
1409
- * 2. Second pass: create EXTENDS edges using stored node IDs
1410
- */
1411
- bufferInterfaceNodes(module, interfaces) {
1412
- // First pass: create all interface nodes and store them
1413
- const interfaceNodes = new Map();
1414
- for (const iface of interfaces) {
1415
- const interfaceNode = InterfaceNode.create(iface.name, iface.file, iface.line, iface.column || 0, {
1416
- extends: iface.extends,
1417
- properties: iface.properties
1418
- });
1419
- interfaceNodes.set(iface.name, interfaceNode);
1420
- this._bufferNode(interfaceNode);
1421
- // MODULE -> CONTAINS -> INTERFACE
1422
- this._bufferEdge({
1423
- type: 'CONTAINS',
1424
- src: module.id,
1425
- dst: interfaceNode.id
1426
- });
1427
- }
1428
- // Second pass: create EXTENDS edges
1429
- for (const iface of interfaces) {
1430
- if (iface.extends && iface.extends.length > 0) {
1431
- const srcNode = interfaceNodes.get(iface.name);
1432
- for (const parentName of iface.extends) {
1433
- const parentNode = interfaceNodes.get(parentName);
1434
- if (parentNode) {
1435
- // Same-file interface
1436
- this._bufferEdge({
1437
- type: 'EXTENDS',
1438
- src: srcNode.id,
1439
- dst: parentNode.id
1440
- });
1441
- }
1442
- else {
1443
- // External interface - create a reference node
1444
- const externalInterface = NodeFactory.createInterface(parentName, iface.file, iface.line, 0, { isExternal: true });
1445
- this._bufferNode(externalInterface);
1446
- this._bufferEdge({
1447
- type: 'EXTENDS',
1448
- src: srcNode.id,
1449
- dst: externalInterface.id
1450
- });
1451
- }
1452
- }
1453
- }
1454
- }
1455
- }
1456
- /**
1457
- * Buffer TYPE alias nodes
1458
- */
1459
- bufferTypeAliasNodes(module, typeAliases) {
1460
- for (const typeAlias of typeAliases) {
1461
- // Create TYPE node using factory
1462
- const typeNode = NodeFactory.createType(typeAlias.name, typeAlias.file, typeAlias.line, typeAlias.column || 0, { aliasOf: typeAlias.aliasOf });
1463
- this._bufferNode(typeNode);
1464
- // MODULE -> CONTAINS -> TYPE
1465
- this._bufferEdge({
1466
- type: 'CONTAINS',
1467
- src: module.id,
1468
- dst: typeNode.id
1469
- });
1470
- }
1471
- }
1472
- /**
1473
- * Buffer ENUM nodes
1474
- * Uses EnumNode.create() to ensure consistent ID format (colon separator)
1475
- */
1476
- bufferEnumNodes(module, enums) {
1477
- for (const enumDecl of enums) {
1478
- // Use EnumNode.create() to generate proper ID (colon format)
1479
- // Do NOT use enumDecl.id which has legacy # format from TypeScriptVisitor
1480
- const enumNode = EnumNode.create(enumDecl.name, enumDecl.file, enumDecl.line, enumDecl.column || 0, {
1481
- isConst: enumDecl.isConst || false,
1482
- members: enumDecl.members || []
1483
- });
1484
- this._bufferNode(enumNode);
1485
- // MODULE -> CONTAINS -> ENUM
1486
- this._bufferEdge({
1487
- type: 'CONTAINS',
1488
- src: module.id,
1489
- dst: enumNode.id // Use factory-generated ID (colon format)
1490
- });
1491
- }
1492
- }
1493
- /**
1494
- * Buffer DECORATOR nodes and DECORATED_BY edges
1495
- */
1496
- bufferDecoratorNodes(decorators) {
1497
- for (const decorator of decorators) {
1498
- // Create DECORATOR node using factory (generates colon-format ID)
1499
- const decoratorNode = DecoratorNode.create(decorator.name, decorator.file, decorator.line, decorator.column || 0, decorator.targetId, // Now included in the node!
1500
- decorator.targetType, { arguments: decorator.arguments });
1501
- this._bufferNode(decoratorNode);
1502
- // TARGET -> DECORATED_BY -> DECORATOR
1503
- this._bufferEdge({
1504
- type: 'DECORATED_BY',
1505
- src: decorator.targetId,
1506
- dst: decoratorNode.id // Use factory-generated ID (colon format)
1507
- });
1508
- }
1509
- }
1510
- /**
1511
- * Buffer IMPLEMENTS edges (CLASS -> INTERFACE)
1512
- */
1513
- bufferImplementsEdges(classDeclarations, interfaces) {
1514
- for (const classDecl of classDeclarations) {
1515
- if (classDecl.implements && classDecl.implements.length > 0) {
1516
- for (const ifaceName of classDecl.implements) {
1517
- // Try to find the interface in the same file
1518
- const iface = interfaces.find(i => i.name === ifaceName);
1519
- if (iface) {
1520
- // Compute interface ID using same formula as InterfaceNode.create()
1521
- // Format: {file}:INTERFACE:{name}:{line}
1522
- const interfaceId = `${iface.file}:INTERFACE:${iface.name}:${iface.line}`;
1523
- this._bufferEdge({
1524
- type: 'IMPLEMENTS',
1525
- src: classDecl.id,
1526
- dst: interfaceId
1527
- });
1528
- }
1529
- else {
1530
- // External interface - create a reference node
1531
- const externalInterface = NodeFactory.createInterface(ifaceName, classDecl.file, classDecl.line, 0, { isExternal: true });
1532
- this._bufferNode(externalInterface);
1533
- this._bufferEdge({
1534
- type: 'IMPLEMENTS',
1535
- src: classDecl.id,
1536
- dst: externalInterface.id
1537
- });
1538
- }
1539
- }
1540
- }
1541
- }
1542
- }
1543
- /**
1544
- * Buffer FLOWS_INTO edges for array mutations (push, unshift, splice, indexed assignment)
1545
- * Creates edges from inserted values to the array variable.
1546
- *
1547
- * REG-117: Handles nested mutations like obj.arr.push(item)
1548
- * REG-392: Handles non-variable values (LITERAL, OBJECT_LITERAL, ARRAY_LITERAL, CALL)
1549
- */
1550
- bufferArrayMutationEdges(arrayMutations, variableDeclarations, parameters, literals, objectLiterals, arrayLiterals, callSites) {
1551
- for (const mutation of arrayMutations) {
1552
- const { arrayName, mutationScopePath, mutationMethod, insertedValues, file, isNested, baseObjectName, propertyName } = mutation;
1553
- const scopePath = mutationScopePath ?? [];
1554
- // REG-117: For nested mutations (obj.arr.push), resolve target node
1555
- let targetNodeId = null;
1556
- let nestedProperty;
1557
- if (isNested && baseObjectName) {
1558
- // Skip 'this.items.push' - 'this' is not a variable node
1559
- if (baseObjectName === 'this')
1560
- continue;
1561
- // Nested mutation: try base object lookup with scope chain (REG-309)
1562
- const baseVar = this.resolveVariableInScope(baseObjectName, scopePath, file, variableDeclarations);
1563
- const baseParam = !baseVar ? this.resolveParameterInScope(baseObjectName, scopePath, file, parameters) : null;
1564
- targetNodeId = baseVar?.id ?? baseParam?.id ?? null;
1565
- nestedProperty = propertyName;
1566
- }
1567
- else {
1568
- // Direct mutation: arr.push() (REG-309)
1569
- const arrayVar = this.resolveVariableInScope(arrayName, scopePath, file, variableDeclarations);
1570
- const arrayParam = !arrayVar ? this.resolveParameterInScope(arrayName, scopePath, file, parameters) : null;
1571
- targetNodeId = arrayVar?.id ?? arrayParam?.id ?? null;
1572
- }
1573
- if (!targetNodeId)
1574
- continue;
1575
- // Create FLOWS_INTO edges for each inserted value
1576
- for (const arg of insertedValues) {
1577
- let sourceNodeId;
1578
- if (arg.valueType === 'VARIABLE' && arg.valueName) {
1579
- // Scope-aware lookup for source variable (REG-309)
1580
- const sourceVar = this.resolveVariableInScope(arg.valueName, scopePath, file, variableDeclarations);
1581
- const sourceParam = !sourceVar ? this.resolveParameterInScope(arg.valueName, scopePath, file, parameters) : null;
1582
- sourceNodeId = sourceVar?.id ?? sourceParam?.id;
1583
- }
1584
- else if (arg.valueNodeId) {
1585
- // REG-392: Direct node ID for indexed assignments (LITERAL, OBJECT_LITERAL, ARRAY_LITERAL)
1586
- sourceNodeId = arg.valueNodeId;
1587
- }
1588
- else if (arg.valueType === 'LITERAL' && arg.valueLine !== undefined && arg.valueColumn !== undefined) {
1589
- // REG-392: Find LITERAL node by coordinates (push/unshift — nodes created by extractArguments)
1590
- const literalNode = literals.find(l => l.line === arg.valueLine && l.column === arg.valueColumn && l.file === file);
1591
- sourceNodeId = literalNode?.id;
1592
- }
1593
- else if (arg.valueType === 'OBJECT_LITERAL' && arg.valueLine !== undefined && arg.valueColumn !== undefined) {
1594
- // REG-392: Find OBJECT_LITERAL node by coordinates
1595
- const objNode = objectLiterals.find(o => o.line === arg.valueLine && o.column === arg.valueColumn && o.file === file);
1596
- sourceNodeId = objNode?.id;
1597
- }
1598
- else if (arg.valueType === 'ARRAY_LITERAL' && arg.valueLine !== undefined && arg.valueColumn !== undefined) {
1599
- // REG-392: Find ARRAY_LITERAL node by coordinates
1600
- const arrNode = arrayLiterals.find(a => a.line === arg.valueLine && a.column === arg.valueColumn && a.file === file);
1601
- sourceNodeId = arrNode?.id;
1602
- }
1603
- else if (arg.valueType === 'CALL' && arg.callLine !== undefined && arg.callColumn !== undefined) {
1604
- // REG-392: Find CALL_SITE node by coordinates
1605
- const callSite = callSites.find(cs => cs.line === arg.callLine && cs.column === arg.callColumn && cs.file === file);
1606
- sourceNodeId = callSite?.id;
1607
- }
1608
- if (sourceNodeId) {
1609
- const edgeData = {
1610
- type: 'FLOWS_INTO',
1611
- src: sourceNodeId,
1612
- dst: targetNodeId,
1613
- mutationMethod,
1614
- argIndex: arg.argIndex
1615
- };
1616
- if (arg.isSpread) {
1617
- edgeData.isSpread = true;
1618
- }
1619
- if (nestedProperty) {
1620
- edgeData.nestedProperty = nestedProperty;
1621
- }
1622
- this._bufferEdge(edgeData);
1623
- }
1624
- }
1625
- }
1626
- }
1627
- /**
1628
- * Buffer FLOWS_INTO edges for object mutations (property assignment, Object.assign)
1629
- * Creates edges from source values to the object variable being mutated.
1630
- *
1631
- * REG-152: For 'this.prop = value' patterns inside classes, creates edges
1632
- * to the CLASS node with mutationType: 'this_property'.
1633
- */
1634
- bufferObjectMutationEdges(objectMutations, variableDeclarations, parameters, functions, classDeclarations) {
1635
- for (const mutation of objectMutations) {
1636
- const { objectName, mutationScopePath, propertyName, mutationType, computedPropertyVar, value, file, enclosingClassName } = mutation;
1637
- const scopePath = mutationScopePath ?? [];
1638
- // Find the target node (object variable, parameter, or class for 'this')
1639
- let objectNodeId = null;
1640
- let effectiveMutationType = mutationType;
1641
- if (objectName !== 'this') {
1642
- // Regular object - find variable, parameter, or function using scope chain (REG-309)
1643
- const objectVar = this.resolveVariableInScope(objectName, scopePath, file, variableDeclarations);
1644
- const objectParam = !objectVar ? this.resolveParameterInScope(objectName, scopePath, file, parameters) : null;
1645
- const objectFunc = !objectVar && !objectParam ? functions.find(f => f.name === objectName && f.file === file) : null;
1646
- objectNodeId = objectVar?.id ?? objectParam?.id ?? objectFunc?.id ?? null;
1647
- if (!objectNodeId)
1648
- continue;
1649
- }
1650
- else {
1651
- // REG-152: 'this' mutations - find the CLASS node
1652
- if (!enclosingClassName)
1653
- continue; // Skip if no class context (e.g., standalone function)
1654
- // Compare using basename since classes use scopeTracker.file (basename)
1655
- // but mutations use module.file (full path)
1656
- const fileBasename = basename(file);
1657
- const classDecl = classDeclarations.find(c => c.name === enclosingClassName && c.file === fileBasename);
1658
- objectNodeId = classDecl?.id ?? null;
1659
- if (!objectNodeId)
1660
- continue; // Skip if class not found
1661
- // Use special mutation type to distinguish from regular property mutations
1662
- effectiveMutationType = 'this_property';
1663
- }
1664
- // Create FLOWS_INTO edge for VARIABLE value type
1665
- if (value.valueType === 'VARIABLE' && value.valueName) {
1666
- // Find the source: can be variable, parameter, or function using scope chain (REG-309)
1667
- const sourceVar = this.resolveVariableInScope(value.valueName, scopePath, file, variableDeclarations);
1668
- const sourceParam = !sourceVar ? this.resolveParameterInScope(value.valueName, scopePath, file, parameters) : null;
1669
- const sourceFunc = !sourceVar && !sourceParam ? functions.find(f => f.name === value.valueName && f.file === file) : null;
1670
- const sourceNodeId = sourceVar?.id ?? sourceParam?.id ?? sourceFunc?.id;
1671
- if (sourceNodeId && objectNodeId) {
1672
- const edgeData = {
1673
- type: 'FLOWS_INTO',
1674
- src: sourceNodeId,
1675
- dst: objectNodeId,
1676
- mutationType: effectiveMutationType,
1677
- propertyName,
1678
- computedPropertyVar // For enrichment phase resolution
1679
- };
1680
- if (value.argIndex !== undefined) {
1681
- edgeData.argIndex = value.argIndex;
1682
- }
1683
- if (value.isSpread) {
1684
- edgeData.isSpread = true;
1685
- }
1686
- this._bufferEdge(edgeData);
1687
- }
1688
- }
1689
- // For literals, object literals, etc. - we just track variable -> object flows for now
1690
- }
1691
- }
1692
- /**
1693
- * Resolve variable by name using scope chain lookup (REG-309).
1694
- * Mirrors JavaScript lexical scoping: search current scope, then parent, then grandparent, etc.
1695
- *
1696
- * @param name - Variable name
1697
- * @param scopePath - Scope path where reference occurs (from ScopeTracker)
1698
- * @param file - File path
1699
- * @param variables - All variable declarations
1700
- * @returns Variable declaration or null if not found
1701
- */
1702
- resolveVariableInScope(name, scopePath, file, variables) {
1703
- // Try current scope, then parent, then grandparent, etc.
1704
- for (let i = scopePath.length; i >= 0; i--) {
1705
- const searchScopePath = scopePath.slice(0, i);
1706
- const matchingVar = variables.find(v => {
1707
- if (v.name !== name || v.file !== file)
1708
- return false;
1709
- // Variable ID IS the semantic ID (when scopeTracker was available during analysis)
1710
- // Format: file->scope1->scope2->TYPE->name
1711
- // Legacy format: VARIABLE#name#file#line:column:counter
1712
- // Try parsing as semantic ID
1713
- const parsed = parseSemanticId(v.id);
1714
- // REG-329: Check for both VARIABLE and CONSTANT (const declarations)
1715
- if (parsed && (parsed.type === 'VARIABLE' || parsed.type === 'CONSTANT')) {
1716
- // FIXED (REG-309): Handle module-level scope matching
1717
- // Empty search scope [] should match semantic ID scope ['global']
1718
- if (searchScopePath.length === 0) {
1719
- return parsed.scopePath.length === 1 && parsed.scopePath[0] === 'global';
1720
- }
1721
- // Non-empty scope: exact match
1722
- return this.scopePathsMatch(parsed.scopePath, searchScopePath);
1723
- }
1724
- // Legacy ID - assume module-level if no semantic ID
1725
- return searchScopePath.length === 0;
1726
- });
1727
- if (matchingVar)
1728
- return matchingVar;
1729
- }
1730
- return null;
1731
- }
1732
- /**
1733
- * Resolve parameter by name using scope chain lookup (REG-309).
1734
- * Same semantics as resolveVariableInScope but for parameters.
1735
- *
1736
- * @param name - Parameter name
1737
- * @param scopePath - Scope path where reference occurs (from ScopeTracker)
1738
- * @param file - File path
1739
- * @param parameters - All parameter declarations
1740
- * @returns Parameter declaration or null if not found
1741
- */
1742
- resolveParameterInScope(name, scopePath, file, parameters) {
1743
- // Parameters have semanticId field populated (unlike variables which use id field)
1744
- return parameters.find(p => {
1745
- if (p.name !== name || p.file !== file)
1746
- return false;
1747
- if (p.semanticId) {
1748
- const parsed = parseSemanticId(p.semanticId);
1749
- if (parsed && parsed.type === 'PARAMETER') {
1750
- // Check if parameter's scope matches any scope in the chain
1751
- for (let i = scopePath.length; i >= 0; i--) {
1752
- const searchScopePath = scopePath.slice(0, i);
1753
- // FIXED (REG-309): Handle module-level scope matching for parameters
1754
- if (searchScopePath.length === 0) {
1755
- if (parsed.scopePath.length === 1 && parsed.scopePath[0] === 'global') {
1756
- return true;
1757
- }
1758
- }
1759
- else {
1760
- if (this.scopePathsMatch(parsed.scopePath, searchScopePath)) {
1761
- return true;
1762
- }
1763
- }
1764
- }
1765
- }
1766
- }
1767
- return false;
1768
- }) ?? null;
1769
- }
1770
- /**
1771
- * Check if two scope paths match (REG-309).
1772
- * Handles: ['foo', 'if#0'] vs ['foo', 'if#0']
1773
- */
1774
- scopePathsMatch(a, b) {
1775
- if (a.length !== b.length)
1776
- return false;
1777
- return a.every((item, idx) => item === b[idx]);
1778
- }
1779
- /**
1780
- * Buffer FLOWS_INTO edges for variable reassignments.
1781
- * Handles: x = y, x += y (when x is already declared, not initialization)
1782
- *
1783
- * Edge patterns:
1784
- * - Simple assignment (=): source --FLOWS_INTO--> variable
1785
- * - Compound operators (+=, -=, etc.):
1786
- * - source --FLOWS_INTO--> variable (write new value)
1787
- * - variable --READS_FROM--> variable (self-loop: reads current value before write)
1788
- *
1789
- * REG-309: Uses scope-aware variable lookup via resolveVariableInScope().
1790
- *
1791
- * REG-290: Complete implementation with inline node creation (no continue statements).
1792
- */
1793
- bufferVariableReassignmentEdges(variableReassignments, variableDeclarations, callSites, methodCalls, parameters) {
1794
- // Note: No longer using Map-based cache - scope-aware lookup requires scope chain walk
1795
- // Performance: O(n*m*s) where s = scope depth (typically 2-3), acceptable for correctness
1796
- for (const reassignment of variableReassignments) {
1797
- const { variableName, mutationScopePath, valueType, valueName, valueId, callLine, callColumn, operator, literalValue, expressionType, expressionMetadata, file, line, column } = reassignment;
1798
- // Find target variable node using scope chain resolution (REG-309)
1799
- const scopePath = mutationScopePath ?? [];
1800
- const targetVar = this.resolveVariableInScope(variableName, scopePath, file, variableDeclarations);
1801
- const targetParam = !targetVar ? this.resolveParameterInScope(variableName, scopePath, file, parameters) : null;
1802
- const targetNodeId = targetVar?.id ?? targetParam?.id;
1803
- if (!targetNodeId) {
1804
- // Variable not found - could be external reference
1805
- continue;
1806
- }
1807
- // Resolve source node based on value type
1808
- let sourceNodeId = null;
1809
- // LITERAL: Create node inline (NO CONTINUE STATEMENT)
1810
- if (valueType === 'LITERAL' && valueId) {
1811
- // Create LITERAL node
1812
- this._bufferNode({
1813
- type: 'LITERAL',
1814
- id: valueId,
1815
- value: literalValue,
1816
- file,
1817
- line,
1818
- column
1819
- });
1820
- sourceNodeId = valueId;
1821
- }
1822
- // VARIABLE: Look up existing variable/parameter node using scope chain (REG-309)
1823
- else if (valueType === 'VARIABLE' && valueName) {
1824
- const sourceVar = this.resolveVariableInScope(valueName, scopePath, file, variableDeclarations);
1825
- const sourceParam = !sourceVar ? this.resolveParameterInScope(valueName, scopePath, file, parameters) : null;
1826
- sourceNodeId = sourceVar?.id ?? sourceParam?.id ?? null;
1827
- }
1828
- // CALL_SITE: Look up existing call node
1829
- else if (valueType === 'CALL_SITE' && callLine && callColumn) {
1830
- const callSite = callSites.find(cs => cs.line === callLine && cs.column === callColumn && cs.file === file);
1831
- sourceNodeId = callSite?.id ?? null;
1832
- }
1833
- // METHOD_CALL: Look up existing method call node
1834
- else if (valueType === 'METHOD_CALL' && callLine && callColumn) {
1835
- const methodCall = methodCalls.find(mc => mc.line === callLine && mc.column === callColumn && mc.file === file);
1836
- sourceNodeId = methodCall?.id ?? null;
1837
- }
1838
- // EXPRESSION: Create node inline (NO CONTINUE STATEMENT)
1839
- else if (valueType === 'EXPRESSION' && valueId && expressionType) {
1840
- // Create EXPRESSION node using NodeFactory
1841
- const expressionNode = NodeFactory.createExpressionFromMetadata(expressionType, file, line, column, {
1842
- id: valueId, // ID from JSASTAnalyzer
1843
- object: expressionMetadata?.object,
1844
- property: expressionMetadata?.property,
1845
- computed: expressionMetadata?.computed,
1846
- computedPropertyVar: expressionMetadata?.computedPropertyVar ?? undefined,
1847
- operator: expressionMetadata?.operator
1848
- });
1849
- this._bufferNode(expressionNode);
1850
- sourceNodeId = valueId;
1851
- }
1852
- // Create edges if source found
1853
- if (sourceNodeId && targetNodeId) {
1854
- // For compound operators (operator !== '='), LHS reads its own current value
1855
- // Create READS_FROM self-loop (Linus requirement)
1856
- if (operator !== '=') {
1857
- this._bufferEdge({
1858
- type: 'READS_FROM',
1859
- src: targetNodeId, // Variable reads from...
1860
- dst: targetNodeId // ...itself (self-loop)
1861
- });
1862
- }
1863
- // RHS flows into LHS (write side)
1864
- this._bufferEdge({
1865
- type: 'FLOWS_INTO',
1866
- src: sourceNodeId,
1867
- dst: targetNodeId
1868
- });
1869
- }
1870
- }
1871
- }
1872
- /**
1873
- * Buffer RETURNS edges connecting return expressions to their containing functions.
1874
- *
1875
- * Edge direction: returnExpression --RETURNS--> function
1876
- *
1877
- * This enables tracing data flow through function calls:
1878
- * - Query: "What does formatDate return?"
1879
- * - Answer: Follow RETURNS edges from function to see all possible return values
1880
- */
1881
- bufferReturnEdges(returnStatements, callSites, methodCalls, variableDeclarations, parameters) {
1882
- for (const ret of returnStatements) {
1883
- const { parentFunctionId, returnValueType, file } = ret;
1884
- // Skip if no value returned (bare return;)
1885
- if (returnValueType === 'NONE') {
1886
- continue;
1887
- }
1888
- let sourceNodeId = null;
1889
- switch (returnValueType) {
1890
- case 'LITERAL':
1891
- // Direct reference to literal node
1892
- sourceNodeId = ret.returnValueId ?? null;
1893
- break;
1894
- case 'VARIABLE': {
1895
- // Find variable declaration by name in same file
1896
- const varName = ret.returnValueName;
1897
- if (varName) {
1898
- const sourceVar = variableDeclarations.find(v => v.name === varName && v.file === file);
1899
- if (sourceVar) {
1900
- sourceNodeId = sourceVar.id;
1901
- }
1902
- else {
1903
- // Check parameters
1904
- const sourceParam = parameters.find(p => p.name === varName && p.file === file);
1905
- if (sourceParam) {
1906
- sourceNodeId = sourceParam.id;
1907
- }
1908
- }
1909
- }
1910
- break;
1911
- }
1912
- case 'CALL_SITE': {
1913
- // Find call site by coordinates
1914
- const { returnValueLine, returnValueColumn, returnValueCallName } = ret;
1915
- if (returnValueLine && returnValueColumn) {
1916
- const callSite = callSites.find(cs => cs.line === returnValueLine &&
1917
- cs.column === returnValueColumn &&
1918
- (returnValueCallName ? cs.name === returnValueCallName : true));
1919
- if (callSite) {
1920
- sourceNodeId = callSite.id;
1921
- }
1922
- }
1923
- break;
1924
- }
1925
- case 'METHOD_CALL': {
1926
- // Find method call by coordinates and method name
1927
- const { returnValueLine, returnValueColumn, returnValueCallName } = ret;
1928
- if (returnValueLine && returnValueColumn) {
1929
- const methodCall = methodCalls.find(mc => mc.line === returnValueLine &&
1930
- mc.column === returnValueColumn &&
1931
- mc.file === file &&
1932
- (returnValueCallName ? mc.method === returnValueCallName : true));
1933
- if (methodCall) {
1934
- sourceNodeId = methodCall.id;
1935
- }
1936
- }
1937
- break;
1938
- }
1939
- case 'EXPRESSION': {
1940
- // REG-276: Create EXPRESSION node and DERIVES_FROM edges for return expressions
1941
- const { expressionType, returnValueId, returnValueLine, returnValueColumn, operator, object, property, computed, objectSourceName, leftSourceName, rightSourceName, consequentSourceName, alternateSourceName, expressionSourceNames, unaryArgSourceName } = ret;
1942
- // Skip if no expression ID was generated
1943
- if (!returnValueId) {
1944
- break;
1945
- }
1946
- // Create EXPRESSION node using NodeFactory
1947
- const expressionNode = NodeFactory.createExpressionFromMetadata(expressionType || 'Unknown', file, returnValueLine || ret.line, returnValueColumn || ret.column, {
1948
- id: returnValueId,
1949
- object,
1950
- property,
1951
- computed,
1952
- operator
1953
- });
1954
- this._bufferNode(expressionNode);
1955
- sourceNodeId = returnValueId;
1956
- // Buffer DERIVES_FROM edges based on expression type
1957
- // Helper function to find source variable or parameter
1958
- const findSource = (name) => {
1959
- const variable = variableDeclarations.find(v => v.name === name && v.file === file);
1960
- if (variable)
1961
- return variable.id;
1962
- const param = parameters.find(p => p.name === name && p.file === file);
1963
- if (param)
1964
- return param.id;
1965
- return null;
1966
- };
1967
- // MemberExpression: derives from the object
1968
- if (expressionType === 'MemberExpression' && objectSourceName) {
1969
- const sourceId = findSource(objectSourceName);
1970
- if (sourceId) {
1971
- this._bufferEdge({
1972
- type: 'DERIVES_FROM',
1973
- src: returnValueId,
1974
- dst: sourceId
1975
- });
1976
- }
1977
- }
1978
- // BinaryExpression / LogicalExpression: derives from left and right operands
1979
- if (expressionType === 'BinaryExpression' || expressionType === 'LogicalExpression') {
1980
- if (leftSourceName) {
1981
- const sourceId = findSource(leftSourceName);
1982
- if (sourceId) {
1983
- this._bufferEdge({
1984
- type: 'DERIVES_FROM',
1985
- src: returnValueId,
1986
- dst: sourceId
1987
- });
1988
- }
1989
- }
1990
- if (rightSourceName) {
1991
- const sourceId = findSource(rightSourceName);
1992
- if (sourceId) {
1993
- this._bufferEdge({
1994
- type: 'DERIVES_FROM',
1995
- src: returnValueId,
1996
- dst: sourceId
1997
- });
1998
- }
1999
- }
2000
- }
2001
- // ConditionalExpression: derives from consequent and alternate
2002
- if (expressionType === 'ConditionalExpression') {
2003
- if (consequentSourceName) {
2004
- const sourceId = findSource(consequentSourceName);
2005
- if (sourceId) {
2006
- this._bufferEdge({
2007
- type: 'DERIVES_FROM',
2008
- src: returnValueId,
2009
- dst: sourceId
2010
- });
2011
- }
2012
- }
2013
- if (alternateSourceName) {
2014
- const sourceId = findSource(alternateSourceName);
2015
- if (sourceId) {
2016
- this._bufferEdge({
2017
- type: 'DERIVES_FROM',
2018
- src: returnValueId,
2019
- dst: sourceId
2020
- });
2021
- }
2022
- }
2023
- }
2024
- // UnaryExpression: derives from the argument
2025
- if (expressionType === 'UnaryExpression' && unaryArgSourceName) {
2026
- const sourceId = findSource(unaryArgSourceName);
2027
- if (sourceId) {
2028
- this._bufferEdge({
2029
- type: 'DERIVES_FROM',
2030
- src: returnValueId,
2031
- dst: sourceId
2032
- });
2033
- }
2034
- }
2035
- // TemplateLiteral: derives from all embedded expressions
2036
- if (expressionType === 'TemplateLiteral' && expressionSourceNames && expressionSourceNames.length > 0) {
2037
- for (const sourceName of expressionSourceNames) {
2038
- const sourceId = findSource(sourceName);
2039
- if (sourceId) {
2040
- this._bufferEdge({
2041
- type: 'DERIVES_FROM',
2042
- src: returnValueId,
2043
- dst: sourceId
2044
- });
2045
- }
2046
- }
2047
- }
2048
- break;
2049
- }
2050
- }
2051
- // Create RETURNS edge if we found a source node
2052
- if (sourceNodeId && parentFunctionId) {
2053
- this._bufferEdge({
2054
- type: 'RETURNS',
2055
- src: sourceNodeId,
2056
- dst: parentFunctionId
2057
- });
2058
- }
2059
- }
2060
- }
2061
- /**
2062
- * Buffer YIELDS and DELEGATES_TO edges connecting yield expressions to their generator functions.
2063
- *
2064
- * Edge direction:
2065
- * - For yield: yieldedExpression --YIELDS--> generatorFunction
2066
- * - For yield*: delegatedCall --DELEGATES_TO--> generatorFunction
2067
- *
2068
- * This enables tracing data flow through generator functions:
2069
- * - Query: "What does this generator yield?"
2070
- * - Answer: Follow YIELDS edges from function to see all possible yielded values
2071
- * - Query: "What generators does this delegate to?"
2072
- * - Answer: Follow DELEGATES_TO edges from function
2073
- *
2074
- * REG-270: Generator yield tracking
2075
- */
2076
- bufferYieldEdges(yieldExpressions, callSites, methodCalls, variableDeclarations, parameters) {
2077
- for (const yld of yieldExpressions) {
2078
- const { parentFunctionId, yieldValueType, file, isDelegate } = yld;
2079
- // Skip if no value yielded (bare yield;)
2080
- if (yieldValueType === 'NONE') {
2081
- continue;
2082
- }
2083
- let sourceNodeId = null;
2084
- switch (yieldValueType) {
2085
- case 'LITERAL':
2086
- // Direct reference to literal node
2087
- sourceNodeId = yld.yieldValueId ?? null;
2088
- break;
2089
- case 'VARIABLE': {
2090
- // Find variable declaration by name in same file
2091
- const varName = yld.yieldValueName;
2092
- if (varName) {
2093
- const sourceVar = variableDeclarations.find(v => v.name === varName && v.file === file);
2094
- if (sourceVar) {
2095
- sourceNodeId = sourceVar.id;
2096
- }
2097
- else {
2098
- // Check parameters
2099
- const sourceParam = parameters.find(p => p.name === varName && p.file === file);
2100
- if (sourceParam) {
2101
- sourceNodeId = sourceParam.id;
2102
- }
2103
- }
2104
- }
2105
- break;
2106
- }
2107
- case 'CALL_SITE': {
2108
- // Find call site by coordinates
2109
- const { yieldValueLine, yieldValueColumn, yieldValueCallName } = yld;
2110
- if (yieldValueLine && yieldValueColumn) {
2111
- const callSite = callSites.find(cs => cs.line === yieldValueLine &&
2112
- cs.column === yieldValueColumn &&
2113
- (yieldValueCallName ? cs.name === yieldValueCallName : true));
2114
- if (callSite) {
2115
- sourceNodeId = callSite.id;
2116
- }
2117
- }
2118
- break;
2119
- }
2120
- case 'METHOD_CALL': {
2121
- // Find method call by coordinates and method name
2122
- const { yieldValueLine, yieldValueColumn, yieldValueCallName } = yld;
2123
- if (yieldValueLine && yieldValueColumn) {
2124
- const methodCall = methodCalls.find(mc => mc.line === yieldValueLine &&
2125
- mc.column === yieldValueColumn &&
2126
- mc.file === file &&
2127
- (yieldValueCallName ? mc.method === yieldValueCallName : true));
2128
- if (methodCall) {
2129
- sourceNodeId = methodCall.id;
2130
- }
2131
- }
2132
- break;
2133
- }
2134
- case 'EXPRESSION': {
2135
- // Create EXPRESSION node and DERIVES_FROM edges for yield expressions
2136
- const { expressionType, yieldValueId, yieldValueLine, yieldValueColumn, operator, object, property, computed, objectSourceName, leftSourceName, rightSourceName, consequentSourceName, alternateSourceName, expressionSourceNames, unaryArgSourceName } = yld;
2137
- // Skip if no expression ID was generated
2138
- if (!yieldValueId) {
2139
- break;
2140
- }
2141
- // Create EXPRESSION node using NodeFactory
2142
- const expressionNode = NodeFactory.createExpressionFromMetadata(expressionType || 'Unknown', file, yieldValueLine || yld.line, yieldValueColumn || yld.column, {
2143
- id: yieldValueId,
2144
- object,
2145
- property,
2146
- computed,
2147
- operator
2148
- });
2149
- this._bufferNode(expressionNode);
2150
- sourceNodeId = yieldValueId;
2151
- // Buffer DERIVES_FROM edges based on expression type
2152
- // Helper function to find source variable or parameter
2153
- const findSource = (name) => {
2154
- const variable = variableDeclarations.find(v => v.name === name && v.file === file);
2155
- if (variable)
2156
- return variable.id;
2157
- const param = parameters.find(p => p.name === name && p.file === file);
2158
- if (param)
2159
- return param.id;
2160
- return null;
2161
- };
2162
- // MemberExpression: derives from the object
2163
- if (expressionType === 'MemberExpression' && objectSourceName) {
2164
- const srcId = findSource(objectSourceName);
2165
- if (srcId) {
2166
- this._bufferEdge({
2167
- type: 'DERIVES_FROM',
2168
- src: yieldValueId,
2169
- dst: srcId
2170
- });
2171
- }
2172
- }
2173
- // BinaryExpression / LogicalExpression: derives from left and right operands
2174
- if (expressionType === 'BinaryExpression' || expressionType === 'LogicalExpression') {
2175
- if (leftSourceName) {
2176
- const srcId = findSource(leftSourceName);
2177
- if (srcId) {
2178
- this._bufferEdge({
2179
- type: 'DERIVES_FROM',
2180
- src: yieldValueId,
2181
- dst: srcId
2182
- });
2183
- }
2184
- }
2185
- if (rightSourceName) {
2186
- const srcId = findSource(rightSourceName);
2187
- if (srcId) {
2188
- this._bufferEdge({
2189
- type: 'DERIVES_FROM',
2190
- src: yieldValueId,
2191
- dst: srcId
2192
- });
2193
- }
2194
- }
2195
- }
2196
- // ConditionalExpression: derives from consequent and alternate
2197
- if (expressionType === 'ConditionalExpression') {
2198
- if (consequentSourceName) {
2199
- const srcId = findSource(consequentSourceName);
2200
- if (srcId) {
2201
- this._bufferEdge({
2202
- type: 'DERIVES_FROM',
2203
- src: yieldValueId,
2204
- dst: srcId
2205
- });
2206
- }
2207
- }
2208
- if (alternateSourceName) {
2209
- const srcId = findSource(alternateSourceName);
2210
- if (srcId) {
2211
- this._bufferEdge({
2212
- type: 'DERIVES_FROM',
2213
- src: yieldValueId,
2214
- dst: srcId
2215
- });
2216
- }
2217
- }
2218
- }
2219
- // UnaryExpression: derives from the argument
2220
- if (expressionType === 'UnaryExpression' && unaryArgSourceName) {
2221
- const srcId = findSource(unaryArgSourceName);
2222
- if (srcId) {
2223
- this._bufferEdge({
2224
- type: 'DERIVES_FROM',
2225
- src: yieldValueId,
2226
- dst: srcId
2227
- });
2228
- }
2229
- }
2230
- // TemplateLiteral: derives from all embedded expressions
2231
- if (expressionType === 'TemplateLiteral' && expressionSourceNames && expressionSourceNames.length > 0) {
2232
- for (const sourceName of expressionSourceNames) {
2233
- const srcId = findSource(sourceName);
2234
- if (srcId) {
2235
- this._bufferEdge({
2236
- type: 'DERIVES_FROM',
2237
- src: yieldValueId,
2238
- dst: srcId
2239
- });
2240
- }
2241
- }
2242
- }
2243
- break;
2244
- }
2245
- }
2246
- // Create YIELDS or DELEGATES_TO edge if we found a source node
2247
- if (sourceNodeId && parentFunctionId) {
2248
- const edgeType = isDelegate ? 'DELEGATES_TO' : 'YIELDS';
2249
- this._bufferEdge({
2250
- type: edgeType,
2251
- src: sourceNodeId,
2252
- dst: parentFunctionId
2253
- });
2254
- }
2255
- }
2256
- }
2257
- /**
2258
- * Buffer UPDATE_EXPRESSION nodes and edges for increment/decrement operations.
2259
- *
2260
- * Handles two target types:
2261
- * - IDENTIFIER: Simple variable (i++, --count)
2262
- * - MEMBER_EXPRESSION: Object property (obj.prop++, arr[i]++, this.count++)
2263
- *
2264
- * Creates:
2265
- * - UPDATE_EXPRESSION node with operator and target metadata
2266
- * - MODIFIES edge: UPDATE_EXPRESSION -> target (VARIABLE, PARAMETER, or CLASS)
2267
- * - READS_FROM self-loop: target -> target (reads current value before update)
2268
- * - CONTAINS edge: SCOPE -> UPDATE_EXPRESSION
2269
- *
2270
- * REG-288: Initial implementation for IDENTIFIER targets
2271
- * REG-312: Extended for MEMBER_EXPRESSION targets
2272
- */
2273
- bufferUpdateExpressionEdges(updateExpressions, variableDeclarations, parameters, classDeclarations) {
2274
- // Build lookup caches: O(n) instead of O(n*m)
2275
- const varLookup = new Map();
2276
- for (const v of variableDeclarations) {
2277
- varLookup.set(`${v.file}:${v.name}`, v);
2278
- }
2279
- const paramLookup = new Map();
2280
- for (const p of parameters) {
2281
- paramLookup.set(`${p.file}:${p.name}`, p);
2282
- }
2283
- for (const update of updateExpressions) {
2284
- if (update.targetType === 'IDENTIFIER') {
2285
- // REG-288: Simple identifier (i++, --count)
2286
- this.bufferIdentifierUpdate(update, varLookup, paramLookup);
2287
- }
2288
- else if (update.targetType === 'MEMBER_EXPRESSION') {
2289
- // REG-312: Member expression (obj.prop++, arr[i]++)
2290
- this.bufferMemberExpressionUpdate(update, varLookup, paramLookup, classDeclarations);
2291
- }
2292
- }
2293
- }
2294
- /**
2295
- * Buffer UPDATE_EXPRESSION node and edges for simple identifier updates (i++, --count)
2296
- * REG-288: Original implementation extracted for clarity
2297
- */
2298
- bufferIdentifierUpdate(update, varLookup, paramLookup) {
2299
- const { variableName, operator, prefix, file, line, column, parentScopeId } = update;
2300
- if (!variableName)
2301
- return;
2302
- // Find target variable node
2303
- const targetVar = varLookup.get(`${file}:${variableName}`);
2304
- const targetParam = !targetVar ? paramLookup.get(`${file}:${variableName}`) : null;
2305
- const targetNodeId = targetVar?.id ?? targetParam?.id;
2306
- if (!targetNodeId) {
2307
- // Variable not found - could be module-level or external reference
2308
- return;
2309
- }
2310
- // Create UPDATE_EXPRESSION node
2311
- const updateId = `${file}:UPDATE_EXPRESSION:${operator}:${line}:${column}`;
2312
- this._bufferNode({
2313
- type: 'UPDATE_EXPRESSION',
2314
- id: updateId,
2315
- name: `${prefix ? operator : ''}${variableName}${prefix ? '' : operator}`,
2316
- targetType: 'IDENTIFIER',
2317
- operator,
2318
- prefix,
2319
- variableName,
2320
- file,
2321
- line,
2322
- column
2323
- });
2324
- // Create READS_FROM self-loop
2325
- this._bufferEdge({
2326
- type: 'READS_FROM',
2327
- src: targetNodeId,
2328
- dst: targetNodeId
2329
- });
2330
- // Create MODIFIES edge
2331
- this._bufferEdge({
2332
- type: 'MODIFIES',
2333
- src: updateId,
2334
- dst: targetNodeId
2335
- });
2336
- // Create CONTAINS edge
2337
- if (parentScopeId) {
2338
- this._bufferEdge({
2339
- type: 'CONTAINS',
2340
- src: parentScopeId,
2341
- dst: updateId
2342
- });
2343
- }
2344
- }
2345
- /**
2346
- * Buffer UPDATE_EXPRESSION node and edges for member expression updates (obj.prop++, arr[i]++)
2347
- * REG-312: New implementation for member expression targets
2348
- *
2349
- * Creates:
2350
- * - UPDATE_EXPRESSION node with member expression metadata
2351
- * - MODIFIES edge: UPDATE_EXPRESSION -> VARIABLE(object) or CLASS (for this.prop++)
2352
- * - READS_FROM self-loop: VARIABLE(object) -> VARIABLE(object)
2353
- * - CONTAINS edge: SCOPE -> UPDATE_EXPRESSION
2354
- */
2355
- bufferMemberExpressionUpdate(update, varLookup, paramLookup, classDeclarations) {
2356
- const { objectName, propertyName, mutationType, computedPropertyVar, enclosingClassName, operator, prefix, file, line, column, parentScopeId } = update;
2357
- if (!objectName || !propertyName)
2358
- return;
2359
- // Find target object node
2360
- let objectNodeId = null;
2361
- if (objectName !== 'this') {
2362
- // Regular object: obj.prop++, arr[i]++
2363
- const targetVar = varLookup.get(`${file}:${objectName}`);
2364
- const targetParam = !targetVar ? paramLookup.get(`${file}:${objectName}`) : null;
2365
- objectNodeId = targetVar?.id ?? targetParam?.id ?? null;
2366
- }
2367
- else {
2368
- // this.prop++ - follow REG-152 pattern from bufferObjectMutationEdges
2369
- if (!enclosingClassName)
2370
- return;
2371
- const fileBasename = basename(file);
2372
- const classDecl = classDeclarations.find(c => c.name === enclosingClassName && c.file === fileBasename);
2373
- objectNodeId = classDecl?.id ?? null;
2374
- }
2375
- if (!objectNodeId) {
2376
- // Object not found - external reference or scope issue
2377
- return;
2378
- }
2379
- // Create UPDATE_EXPRESSION node
2380
- const updateId = `${file}:UPDATE_EXPRESSION:${operator}:${line}:${column}`;
2381
- // Display name: "obj.prop++" or "this.count++" or "arr[i]++"
2382
- const displayName = (() => {
2383
- const opStr = prefix ? operator : '';
2384
- const postOpStr = prefix ? '' : operator;
2385
- if (objectName === 'this') {
2386
- return `${opStr}this.${propertyName}${postOpStr}`;
2387
- }
2388
- if (mutationType === 'computed') {
2389
- const computedPart = computedPropertyVar || '?';
2390
- return `${opStr}${objectName}[${computedPart}]${postOpStr}`;
2391
- }
2392
- return `${opStr}${objectName}.${propertyName}${postOpStr}`;
2393
- })();
2394
- this._bufferNode({
2395
- type: 'UPDATE_EXPRESSION',
2396
- id: updateId,
2397
- name: displayName,
2398
- targetType: 'MEMBER_EXPRESSION',
2399
- operator,
2400
- prefix,
2401
- objectName,
2402
- propertyName,
2403
- mutationType,
2404
- computedPropertyVar,
2405
- enclosingClassName,
2406
- file,
2407
- line,
2408
- column
2409
- });
2410
- // Create READS_FROM self-loop (object reads from itself)
2411
- this._bufferEdge({
2412
- type: 'READS_FROM',
2413
- src: objectNodeId,
2414
- dst: objectNodeId
2415
- });
2416
- // Create MODIFIES edge (UPDATE_EXPRESSION modifies object)
2417
- this._bufferEdge({
2418
- type: 'MODIFIES',
2419
- src: updateId,
2420
- dst: objectNodeId
2421
- });
2422
- // Create CONTAINS edge
2423
- if (parentScopeId) {
2424
- this._bufferEdge({
2425
- type: 'CONTAINS',
2426
- src: parentScopeId,
2427
- dst: updateId
2428
- });
2429
- }
2430
- }
2431
- /**
2432
- * Buffer RESOLVES_TO edges for Promise resolution data flow (REG-334).
2433
- *
2434
- * Links resolve/reject CALL nodes to their parent Promise CONSTRUCTOR_CALL.
2435
- * This enables traceValues to follow Promise data flow:
2436
- *
2437
- * Example:
2438
- * ```
2439
- * const result = new Promise((resolve) => {
2440
- * resolve(42); // CALL[resolve] --RESOLVES_TO--> CONSTRUCTOR_CALL[Promise]
2441
- * });
2442
- * ```
2443
- *
2444
- * The edge direction (CALL -> CONSTRUCTOR_CALL) matches data flow semantics:
2445
- * data flows FROM resolve(value) TO the Promise result.
2446
- */
2447
- bufferPromiseResolutionEdges(promiseResolutions) {
2448
- for (const resolution of promiseResolutions) {
2449
- this._bufferEdge({
2450
- type: 'RESOLVES_TO',
2451
- src: resolution.callId,
2452
- dst: resolution.constructorCallId,
2453
- metadata: {
2454
- isReject: resolution.isReject
2455
- }
2456
- });
2457
- }
2458
- }
2459
- /**
2460
- * Buffer OBJECT_LITERAL nodes to the graph.
2461
- * These are object literals passed as function arguments or nested in other literals.
2462
- */
2463
- bufferObjectLiteralNodes(objectLiterals) {
2464
- for (const obj of objectLiterals) {
2465
- this._bufferNode({
2466
- id: obj.id,
2467
- type: obj.type,
2468
- name: '<object>',
2469
- file: obj.file,
2470
- line: obj.line,
2471
- column: obj.column,
2472
- parentCallId: obj.parentCallId,
2473
- argIndex: obj.argIndex
2474
- });
2475
- }
2476
- }
2477
- /**
2478
- * Buffer ARRAY_LITERAL nodes to the graph.
2479
- * These are array literals passed as function arguments or nested in other literals.
2480
- */
2481
- bufferArrayLiteralNodes(arrayLiterals) {
2482
- for (const arr of arrayLiterals) {
2483
- this._bufferNode({
2484
- id: arr.id,
2485
- type: arr.type,
2486
- name: '<array>',
2487
- file: arr.file,
2488
- line: arr.line,
2489
- column: arr.column,
2490
- parentCallId: arr.parentCallId,
2491
- argIndex: arr.argIndex
2492
- });
2493
- }
2494
- }
2495
- /**
2496
- * Buffer HAS_PROPERTY edges connecting OBJECT_LITERAL nodes to their property values.
2497
- * Creates edges from object literal to its property value nodes (LITERAL, nested OBJECT_LITERAL, ARRAY_LITERAL, etc.)
2498
- *
2499
- * REG-329: Adds scope-aware variable resolution for VARIABLE property values.
2500
- * Uses the same resolveVariableInScope infrastructure as mutation handlers.
2501
- */
2502
- bufferObjectPropertyEdges(objectProperties, variableDeclarations, parameters) {
2503
- for (const prop of objectProperties) {
2504
- // REG-329: Handle VARIABLE value types with scope resolution
2505
- if (prop.valueType === 'VARIABLE' && prop.valueName) {
2506
- const scopePath = prop.valueScopePath ?? [];
2507
- const file = prop.file;
2508
- // Resolve variable using scope chain
2509
- const resolvedVar = this.resolveVariableInScope(prop.valueName, scopePath, file, variableDeclarations);
2510
- const resolvedParam = !resolvedVar
2511
- ? this.resolveParameterInScope(prop.valueName, scopePath, file, parameters)
2512
- : null;
2513
- const resolvedNodeId = resolvedVar?.id ?? resolvedParam?.semanticId ?? resolvedParam?.id;
2514
- if (resolvedNodeId) {
2515
- this._bufferEdge({
2516
- type: 'HAS_PROPERTY',
2517
- src: prop.objectId,
2518
- dst: resolvedNodeId,
2519
- propertyName: prop.propertyName
2520
- });
2521
- }
2522
- continue;
2523
- }
2524
- // Existing logic for non-VARIABLE types
2525
- if (prop.valueNodeId) {
2526
- this._bufferEdge({
2527
- type: 'HAS_PROPERTY',
2528
- src: prop.objectId,
2529
- dst: prop.valueNodeId,
2530
- propertyName: prop.propertyName
2531
- });
2532
- }
2533
- }
2534
- }
2535
- /**
2536
- * Handle CLASS ASSIGNED_FROM edges asynchronously (needs graph queries)
2537
- */
2538
- async createClassAssignmentEdges(variableAssignments, graph) {
2539
- let edgesCreated = 0;
2540
- for (const assignment of variableAssignments) {
2541
- const { variableId, sourceType, className } = assignment;
2542
- if (sourceType === 'CLASS' && className) {
2543
- const parts = variableId.split('#');
2544
- const file = parts.length >= 3 ? parts[2] : null;
2545
- let classNode = null;
2546
- for await (const node of graph.queryNodes({ type: 'CLASS' })) {
2547
- if (node.name === className && (!file || node.file === file)) {
2548
- classNode = node;
2549
- break;
2550
- }
2551
- }
2552
- if (classNode) {
2553
- await graph.addEdge({
2554
- type: 'ASSIGNED_FROM',
2555
- src: variableId,
2556
- dst: classNode.id
2557
- });
2558
- edgesCreated++;
422
+ edgesCreated++;
2559
423
  }
2560
424
  }
2561
425
  }
2562
426
  return edgesCreated;
2563
427
  }
2564
- /**
2565
- * Buffer REJECTS edges for async error tracking (REG-311).
2566
- *
2567
- * Creates edges from FUNCTION nodes to error CLASS nodes they can reject.
2568
- * This enables tracking which async functions can throw which error types:
2569
- *
2570
- * - Promise.reject(new Error()) -> FUNCTION --REJECTS--> CLASS[Error]
2571
- * - reject(new ValidationError()) in executor -> FUNCTION --REJECTS--> CLASS[ValidationError]
2572
- * - throw new AuthError() in async function -> FUNCTION --REJECTS--> CLASS[AuthError]
2573
- *
2574
- * Also stores rejectionPatterns in function metadata for downstream enrichers.
2575
- *
2576
- * @param functions - All function infos from analysis
2577
- * @param rejectionPatterns - Collected rejection patterns from analysis
2578
- */
2579
- bufferRejectionEdges(functions, rejectionPatterns) {
2580
- // Group rejection patterns by functionId for efficient lookup
2581
- const patternsByFunction = new Map();
2582
- for (const pattern of rejectionPatterns) {
2583
- const existing = patternsByFunction.get(pattern.functionId);
2584
- if (existing) {
2585
- existing.push(pattern);
2586
- }
2587
- else {
2588
- patternsByFunction.set(pattern.functionId, [pattern]);
2589
- }
2590
- }
2591
- // Process each function that has rejection patterns
2592
- for (const [functionId, patterns] of patternsByFunction) {
2593
- // Collect unique error class names from this function's rejection patterns
2594
- const errorClassNames = new Set();
2595
- for (const pattern of patterns) {
2596
- if (pattern.errorClassName) {
2597
- errorClassNames.add(pattern.errorClassName);
2598
- }
2599
- }
2600
- // Create REJECTS edges to error class nodes
2601
- // Note: These edges target computed CLASS IDs - they will be dangling
2602
- // if the class isn't declared, but that's expected behavior for
2603
- // built-in classes like Error, TypeError, etc.
2604
- for (const errorClassName of errorClassNames) {
2605
- // Find the function's file to compute the class ID
2606
- const func = functions.find(f => f.id === functionId);
2607
- const file = func?.file ?? '';
2608
- // Compute potential class ID at global scope
2609
- // For built-in errors, this will be a dangling reference (expected)
2610
- const globalContext = { file, scopePath: [] };
2611
- const classId = computeSemanticId('CLASS', errorClassName, globalContext);
2612
- this._bufferEdge({
2613
- type: 'REJECTS',
2614
- src: functionId,
2615
- dst: classId,
2616
- metadata: {
2617
- errorClassName
2618
- }
2619
- });
2620
- }
2621
- // Store rejection patterns in function metadata for downstream enrichers
2622
- // Find and update the function node in the buffer
2623
- for (const node of this._nodeBuffer) {
2624
- if (node.id === functionId) {
2625
- // Store in metadata field for proper persistence and test compatibility
2626
- if (!node.metadata) {
2627
- node.metadata = {};
2628
- }
2629
- node.metadata.rejectionPatterns = patterns.map(p => ({
2630
- rejectionType: p.rejectionType,
2631
- errorClassName: p.errorClassName,
2632
- line: p.line,
2633
- column: p.column,
2634
- sourceVariableName: p.sourceVariableName,
2635
- tracePath: p.tracePath
2636
- }));
2637
- break;
2638
- }
2639
- }
2640
- }
2641
- }
2642
- /**
2643
- * Buffer CATCHES_FROM edges linking catch blocks to error sources (REG-311).
2644
- *
2645
- * Creates edges from CATCH_BLOCK nodes to potential error sources within
2646
- * their corresponding try blocks. This enables tracking which catch blocks
2647
- * can handle which exceptions:
2648
- *
2649
- * - try { await fetch() } catch(e) -> CATCH_BLOCK --CATCHES_FROM--> CALL[fetch]
2650
- * - try { throw new Error() } catch(e) -> CATCH_BLOCK --CATCHES_FROM--> THROW_STATEMENT
2651
- *
2652
- * The sourceType metadata helps distinguish different error source kinds
2653
- * for more precise error flow analysis.
2654
- *
2655
- * @param catchesFromInfos - Collected CATCHES_FROM info from analysis
2656
- */
2657
- bufferCatchesFromEdges(catchesFromInfos) {
2658
- for (const info of catchesFromInfos) {
2659
- this._bufferEdge({
2660
- type: 'CATCHES_FROM',
2661
- src: info.catchBlockId,
2662
- dst: info.sourceId,
2663
- metadata: {
2664
- parameterName: info.parameterName,
2665
- sourceType: info.sourceType,
2666
- sourceLine: info.sourceLine
2667
- }
2668
- });
2669
- }
2670
- }
2671
428
  }
2672
429
  //# sourceMappingURL=GraphBuilder.js.map