@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,63 +1,36 @@
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
5
 
6
- import { basename } from 'path';
7
6
  import type { GraphBackend, NodeRecord } from '@grafema/types';
8
- import { ImportNode } from '../../../core/nodes/ImportNode.js';
9
- import { InterfaceNode, type InterfaceNodeRecord } from '../../../core/nodes/InterfaceNode.js';
10
- import { EnumNode } from '../../../core/nodes/EnumNode.js';
11
- import { DecoratorNode } from '../../../core/nodes/DecoratorNode.js';
12
- import { NetworkRequestNode } from '../../../core/nodes/NetworkRequestNode.js';
13
- import { NodeFactory } from '../../../core/NodeFactory.js';
14
- import { computeSemanticId, parseSemanticId } from '../../../core/SemanticId.js';
7
+ import { brandNodeInternal } from '../../../core/brandNodeInternal.js';
8
+ import { parseSemanticId } from '../../../core/SemanticId.js';
15
9
  import type {
16
10
  ModuleNode,
17
11
  FunctionInfo,
18
12
  ParameterInfo,
19
- ScopeInfo,
20
- BranchInfo,
21
- CaseInfo,
22
- LoopInfo,
23
13
  VariableDeclarationInfo,
24
- CallSiteInfo,
25
- MethodCallInfo,
26
- MethodCallbackInfo,
27
- EventListenerInfo,
28
- ClassInstantiationInfo,
29
- ClassDeclarationInfo,
30
- CallArgumentInfo,
31
- ImportInfo,
32
- ExportInfo,
33
- HttpRequestInfo,
34
- LiteralInfo,
35
14
  VariableAssignmentInfo,
36
- InterfaceDeclarationInfo,
37
- TypeAliasInfo,
38
- EnumDeclarationInfo,
39
- DecoratorInfo,
40
- ArrayMutationInfo,
41
- ObjectMutationInfo,
42
- VariableReassignmentInfo,
43
- UpdateExpressionInfo,
44
- ReturnStatementInfo,
45
- YieldExpressionInfo,
46
- ObjectLiteralInfo,
47
- ObjectPropertyInfo,
48
- ArrayLiteralInfo,
49
- TryBlockInfo,
50
- CatchBlockInfo,
51
- FinallyBlockInfo,
52
- PromiseResolutionInfo,
53
- RejectionPatternInfo,
54
- CatchesFromInfo,
55
15
  PropertyAccessInfo,
56
16
  ASTCollections,
57
17
  GraphNode,
58
18
  GraphEdge,
59
19
  BuildResult,
60
20
  } from './types.js';
21
+ import type { BuilderContext } from './builders/types.js';
22
+ import {
23
+ CoreBuilder,
24
+ ControlFlowBuilder,
25
+ AssignmentBuilder,
26
+ CallFlowBuilder,
27
+ MutationBuilder,
28
+ UpdateExpressionBuilder,
29
+ ReturnBuilder,
30
+ YieldBuilder,
31
+ TypeSystemBuilder,
32
+ ModuleRuntimeBuilder,
33
+ } from './builders/index.js';
61
34
 
62
35
  export class GraphBuilder {
63
36
  // Track singleton nodes to avoid duplicates (net:stdio, net:request, etc.)
@@ -67,6 +40,49 @@ export class GraphBuilder {
67
40
  private _nodeBuffer: GraphNode[] = [];
68
41
  private _edgeBuffer: GraphEdge[] = [];
69
42
 
43
+ // Domain builders
44
+ private readonly _coreBuilder: CoreBuilder;
45
+ private readonly _controlFlowBuilder: ControlFlowBuilder;
46
+ private readonly _assignmentBuilder: AssignmentBuilder;
47
+ private readonly _callFlowBuilder: CallFlowBuilder;
48
+ private readonly _mutationBuilder: MutationBuilder;
49
+ private readonly _updateExpressionBuilder: UpdateExpressionBuilder;
50
+ private readonly _returnBuilder: ReturnBuilder;
51
+ private readonly _yieldBuilder: YieldBuilder;
52
+ private readonly _typeSystemBuilder: TypeSystemBuilder;
53
+ private readonly _moduleRuntimeBuilder: ModuleRuntimeBuilder;
54
+
55
+ constructor() {
56
+ const ctx = this._createContext();
57
+ this._coreBuilder = new CoreBuilder(ctx);
58
+ this._controlFlowBuilder = new ControlFlowBuilder(ctx);
59
+ this._assignmentBuilder = new AssignmentBuilder(ctx);
60
+ this._callFlowBuilder = new CallFlowBuilder(ctx);
61
+ this._mutationBuilder = new MutationBuilder(ctx);
62
+ this._updateExpressionBuilder = new UpdateExpressionBuilder(ctx);
63
+ this._returnBuilder = new ReturnBuilder(ctx);
64
+ this._yieldBuilder = new YieldBuilder(ctx);
65
+ this._typeSystemBuilder = new TypeSystemBuilder(ctx);
66
+ this._moduleRuntimeBuilder = new ModuleRuntimeBuilder(ctx);
67
+ }
68
+
69
+ private _createContext(): BuilderContext {
70
+ return {
71
+ bufferNode: (node) => this._bufferNode(node),
72
+ bufferEdge: (edge) => this._bufferEdge(edge),
73
+ isCreated: (key) => this._createdSingletons.has(key),
74
+ markCreated: (key) => { this._createdSingletons.add(key); },
75
+ findBufferedNode: (id) => this._nodeBuffer.find(n => n.id === id),
76
+ findFunctionByName: (functions, name, file, callScopeId) =>
77
+ this.findFunctionByName(functions, name, file, callScopeId),
78
+ resolveVariableInScope: (name, scopePath, file, variables) =>
79
+ this.resolveVariableInScope(name, scopePath, file, variables),
80
+ resolveParameterInScope: (name, scopePath, file, parameters) =>
81
+ this.resolveParameterInScope(name, scopePath, file, parameters),
82
+ scopePathsMatch: (a, b) => this.scopePathsMatch(a, b),
83
+ };
84
+ }
85
+
70
86
  /**
71
87
  * Buffer a node for batched writing
72
88
  */
@@ -86,8 +102,9 @@ export class GraphBuilder {
86
102
  */
87
103
  private async _flushNodes(graph: GraphBackend): Promise<number> {
88
104
  if (this._nodeBuffer.length > 0) {
89
- // Cast to unknown first since GraphNode is more permissive than NodeRecord
90
- await graph.addNodes(this._nodeBuffer as unknown as NodeRecord[]);
105
+ // Brand nodes before flushing - they're validated by builders
106
+ const brandedNodes = this._nodeBuffer.map(node => brandNodeInternal(node as unknown as NodeRecord));
107
+ await graph.addNodes(brandedNodes);
91
108
  const count = this._nodeBuffer.length;
92
109
  this._nodeBuffer = [];
93
110
  return count;
@@ -113,62 +130,24 @@ export class GraphBuilder {
113
130
  * Создаёт ноды и рёбра в графе (BATCHED VERSION)
114
131
  */
115
132
  async build(module: ModuleNode, graph: GraphBackend, projectPath: string, data: ASTCollections): Promise<BuildResult> {
133
+ // Phase 1 node buffering + post-flush fields only; builders receive `data` directly
116
134
  const {
117
135
  functions,
118
136
  parameters = [],
119
137
  scopes,
120
- // Branching
121
138
  branches = [],
122
139
  cases = [],
123
- // Control flow (loops)
124
140
  loops = [],
125
- // Control flow (try/catch/finally) - Phase 4
126
141
  tryBlocks = [],
127
142
  catchBlocks = [],
128
143
  finallyBlocks = [],
129
144
  variableDeclarations,
130
145
  callSites,
131
- methodCalls = [],
132
- eventListeners = [],
133
- classInstantiations = [],
134
146
  constructorCalls = [],
135
- classDeclarations = [],
136
- methodCallbacks = [],
137
- callArguments = [],
138
- imports = [],
139
- exports = [],
140
- httpRequests = [],
141
- literals = [],
147
+ // Post-flush fields
142
148
  variableAssignments = [],
143
- // TypeScript-specific collections
144
- interfaces = [],
145
- typeAliases = [],
146
- enums = [],
147
- decorators = [],
148
- // Array mutation tracking for FLOWS_INTO edges
149
- arrayMutations = [],
150
- // Object mutation tracking for FLOWS_INTO edges
151
- objectMutations = [],
152
- // Variable reassignment tracking for FLOWS_INTO edges (REG-290)
153
- variableReassignments = [],
154
- // Update expression tracking for UPDATE_EXPRESSION nodes and MODIFIES edges (REG-288, REG-312)
155
- updateExpressions = [],
156
- // Return statement tracking for RETURNS edges
157
- returnStatements = [],
158
- // Yield expression tracking for YIELDS/DELEGATES_TO edges (REG-270)
159
- yieldExpressions = [],
160
- // Promise resolution tracking for RESOLVES_TO edges (REG-334)
161
- promiseResolutions = [],
162
- // Object/Array literal tracking
163
- objectLiterals = [],
164
- objectProperties = [],
165
- arrayLiterals = [],
166
- // REG-311: Rejection pattern tracking for async error analysis
167
- rejectionPatterns = [],
168
- // REG-311: CATCHES_FROM tracking for catch parameter error sources
169
- catchesFromInfos = [],
170
- // Property access tracking for PROPERTY_ACCESS nodes (REG-395)
171
- propertyAccesses = []
149
+ propertyAccesses = [],
150
+ hasTopLevelAwait = false
172
151
  } = data;
173
152
 
174
153
  // Reset buffers for this build
@@ -176,9 +155,24 @@ export class GraphBuilder {
176
155
  this._edgeBuffer = [];
177
156
 
178
157
  // 1. Buffer all functions (without edges)
158
+ // REG-401: Strip invokesParamIndexes from node data and store in metadata
179
159
  for (const func of functions) {
180
- const { parentScopeId: _parentScopeId, ...funcData } = func;
181
- this._bufferNode(funcData as GraphNode);
160
+ const { parentScopeId: _parentScopeId, invokesParamIndexes: _invokesParamIndexes, invokesParamBindings: _invokesParamBindings, ...funcData } = func;
161
+ const node = funcData as GraphNode;
162
+ if (_invokesParamIndexes && _invokesParamIndexes.length > 0) {
163
+ if (!node.metadata) {
164
+ node.metadata = {};
165
+ }
166
+ (node.metadata as Record<string, unknown>).invokesParamIndexes = _invokesParamIndexes;
167
+ }
168
+ // REG-417: Store property paths for destructured param bindings
169
+ if (_invokesParamBindings && _invokesParamBindings.length > 0) {
170
+ if (!node.metadata) {
171
+ node.metadata = {};
172
+ }
173
+ (node.metadata as Record<string, unknown>).invokesParamBindings = _invokesParamBindings;
174
+ }
175
+ this._bufferNode(node);
182
176
  }
183
177
 
184
178
  // 2. Buffer all SCOPE (without edges)
@@ -269,132 +263,17 @@ export class GraphBuilder {
269
263
  } as GraphNode);
270
264
  }
271
265
 
272
- // 5. Buffer edges for functions
273
- this.bufferFunctionEdges(module, functions);
274
-
275
- // 6. Buffer edges for SCOPE
276
- this.bufferScopeEdges(scopes, variableDeclarations);
277
-
278
- // 6.3. Buffer edges for LOOP (HAS_BODY, ITERATES_OVER, CONTAINS)
279
- this.bufferLoopEdges(loops, scopes, variableDeclarations, parameters);
280
-
281
- // 6.35. Buffer HAS_CONDITION edges for LOOP (REG-280)
282
- this.bufferLoopConditionEdges(loops, callSites);
283
-
284
- // 6.37. Buffer EXPRESSION nodes for loop conditions (REG-280)
285
- this.bufferLoopConditionExpressions(loops);
286
-
287
- // 6.5. Buffer edges for BRANCH (needs callSites for CallExpression discriminant lookup)
288
- // Phase 3 (REG-267): Now includes scopes for if-branches HAS_CONSEQUENT/HAS_ALTERNATE
289
- this.bufferBranchEdges(branches, callSites, scopes);
290
-
291
- // 6.6. Buffer edges for CASE
292
- this.bufferCaseEdges(cases);
293
-
294
- // 6.65. Buffer edges for TRY_BLOCK, CATCH_BLOCK, FINALLY_BLOCK (Phase 4)
295
- this.bufferTryCatchFinallyEdges(tryBlocks, catchBlocks, finallyBlocks);
296
-
297
- // 6.7. Buffer EXPRESSION nodes for switch discriminants (needs callSites for CallExpression)
298
- this.bufferDiscriminantExpressions(branches, callSites);
299
-
300
- // 7. Buffer edges for variables
301
- this.bufferVariableEdges(variableDeclarations);
302
-
303
- // 8. Buffer edges for CALL_SITE
304
- this.bufferCallSiteEdges(callSites, functions);
305
-
306
- // 9. Buffer METHOD_CALL nodes, CONTAINS edges, and USES edges (REG-262)
307
- this.bufferMethodCalls(methodCalls, variableDeclarations, parameters);
308
-
309
- // 9.5. Buffer PROPERTY_ACCESS nodes and CONTAINS edges (REG-395)
310
- this.bufferPropertyAccessNodes(module, propertyAccesses);
311
-
312
- // 10. Buffer net:stdio and WRITES_TO edges for console.log/error
313
- this.bufferStdioNodes(methodCalls);
314
-
315
- // 11. Buffer CLASS nodes for class declarations and CONTAINS edges
316
- this.bufferClassDeclarationNodes(classDeclarations);
317
-
318
- // 12. Buffer CLASS nodes and INSTANCE_OF edges for NewExpression
319
- this.bufferClassNodes(module, classInstantiations, classDeclarations);
320
-
321
- // 13. Buffer PASSES_ARGUMENT edges (METHOD_CALL -> FUNCTION)
322
- this.bufferCallbackEdges(methodCallbacks, functions);
323
-
324
- // 14. Buffer IMPORT nodes
325
- this.bufferImportNodes(module, imports);
326
-
327
- // 15. Buffer EXPORT nodes
328
- this.bufferExportNodes(module, exports);
329
-
330
- // 16. Buffer EVENT_LISTENER nodes and HANDLED_BY edges
331
- this.bufferEventListeners(eventListeners, functions);
332
-
333
- // 17. Buffer HTTP requests
334
- this.bufferHttpRequests(httpRequests, functions);
335
-
336
- // 18. Buffer LITERAL nodes
337
- this.bufferLiterals(literals);
338
-
339
- // 18.5. Buffer OBJECT_LITERAL nodes (moved before bufferArgumentEdges)
340
- this.bufferObjectLiteralNodes(objectLiterals);
341
-
342
- // 18.6. Buffer ARRAY_LITERAL nodes (moved before bufferArgumentEdges)
343
- this.bufferArrayLiteralNodes(arrayLiterals);
344
-
345
- // 18.7. Buffer HAS_PROPERTY edges (OBJECT_LITERAL -> property values)
346
- // REG-329: Pass variableDeclarations and parameters for scope-aware variable resolution
347
- this.bufferObjectPropertyEdges(objectProperties, variableDeclarations, parameters);
348
-
349
- // 19. Buffer ASSIGNED_FROM edges for data flow (some need to create EXPRESSION nodes)
350
- this.bufferAssignmentEdges(variableAssignments, variableDeclarations, callSites, methodCalls, functions, classInstantiations, parameters);
351
-
352
- // 20. Buffer PASSES_ARGUMENT edges (CALL -> argument)
353
- this.bufferArgumentEdges(callArguments, variableDeclarations, functions, callSites, methodCalls);
354
-
355
- // 21. Buffer INTERFACE nodes and EXTENDS edges
356
- this.bufferInterfaceNodes(module, interfaces);
357
-
358
- // 22. Buffer TYPE nodes
359
- this.bufferTypeAliasNodes(module, typeAliases);
360
-
361
- // 23. Buffer ENUM nodes
362
- this.bufferEnumNodes(module, enums);
363
-
364
- // 24. Buffer DECORATOR nodes and DECORATED_BY edges
365
- this.bufferDecoratorNodes(decorators);
366
-
367
- // 25. Buffer IMPLEMENTS edges (CLASS -> INTERFACE)
368
- this.bufferImplementsEdges(classDeclarations, interfaces);
369
-
370
- // 26. Buffer FLOWS_INTO edges for array mutations (push, unshift, splice, indexed assignment)
371
- // REG-392: Pass literals, objectLiterals, arrayLiterals, callSites for non-variable value lookups
372
- this.bufferArrayMutationEdges(arrayMutations, variableDeclarations, parameters, literals, objectLiterals, arrayLiterals, callSites);
373
-
374
- // 27. Buffer FLOWS_INTO edges for object mutations (property assignment, Object.assign)
375
- // REG-152: Now includes classDeclarations for this.prop = value patterns
376
- this.bufferObjectMutationEdges(objectMutations, variableDeclarations, parameters, functions, classDeclarations);
377
-
378
- // 28. Buffer FLOWS_INTO edges for variable reassignments (REG-290)
379
- this.bufferVariableReassignmentEdges(variableReassignments, variableDeclarations, callSites, methodCalls, parameters);
380
-
381
- // 29. Buffer RETURNS edges for return statements
382
- this.bufferReturnEdges(returnStatements, callSites, methodCalls, variableDeclarations, parameters);
383
-
384
- // 30. Buffer UPDATE_EXPRESSION nodes and MODIFIES edges (REG-288, REG-312)
385
- this.bufferUpdateExpressionEdges(updateExpressions, variableDeclarations, parameters, classDeclarations);
386
-
387
- // 31. Buffer RESOLVES_TO edges for Promise data flow (REG-334)
388
- this.bufferPromiseResolutionEdges(promiseResolutions);
389
-
390
- // 32. Buffer YIELDS/DELEGATES_TO edges for generator yields (REG-270)
391
- this.bufferYieldEdges(yieldExpressions, callSites, methodCalls, variableDeclarations, parameters);
392
-
393
- // 33. Buffer REJECTS edges for async error tracking (REG-311)
394
- this.bufferRejectionEdges(functions, rejectionPatterns);
395
-
396
- // 34. Buffer CATCHES_FROM edges linking catch blocks to error sources (REG-311)
397
- this.bufferCatchesFromEdges(catchesFromInfos);
266
+ // Phase 2: Delegate to domain builders
267
+ this._coreBuilder.buffer(module, data);
268
+ this._controlFlowBuilder.buffer(module, data);
269
+ this._callFlowBuilder.buffer(module, data);
270
+ this._assignmentBuilder.buffer(module, data);
271
+ this._mutationBuilder.buffer(module, data);
272
+ this._updateExpressionBuilder.buffer(module, data);
273
+ this._returnBuilder.buffer(module, data);
274
+ this._yieldBuilder.buffer(module, data);
275
+ this._typeSystemBuilder.buffer(module, data);
276
+ this._moduleRuntimeBuilder.buffer(module, data);
398
277
 
399
278
  // FLUSH: Write all nodes first, then edges in single batch calls
400
279
  const nodesCreated = await this._flushNodes(graph);
@@ -403,2915 +282,243 @@ export class GraphBuilder {
403
282
  // Handle async operations for ASSIGNED_FROM with CLASS lookups
404
283
  const classAssignmentEdges = await this.createClassAssignmentEdges(variableAssignments, graph);
405
284
 
406
- return { nodes: nodesCreated, edges: edgesCreated + classAssignmentEdges };
407
- }
408
-
409
- // ============= BUFFERED METHODS (synchronous, no awaits) =============
285
+ // REG-300: Update MODULE node with import.meta metadata
286
+ const importMetaProps = this.collectImportMetaProperties(propertyAccesses);
287
+ await this.updateModuleImportMetaMetadata(module, graph, importMetaProps);
410
288
 
411
- private bufferFunctionEdges(module: ModuleNode, functions: FunctionInfo[]): void {
412
- for (const func of functions) {
413
- const { parentScopeId, ...funcData } = func;
289
+ // REG-297: Update MODULE node with hasTopLevelAwait metadata
290
+ await this.updateModuleTopLevelAwaitMetadata(module, graph, hasTopLevelAwait);
414
291
 
415
- // MODULE -> CONTAINS -> FUNCTION (для функций верхнего уровня)
416
- // или SCOPE -> CONTAINS -> FUNCTION (для вложенных функций)
417
- if (parentScopeId) {
418
- this._bufferEdge({
419
- type: 'CONTAINS',
420
- src: parentScopeId,
421
- dst: funcData.id
422
- });
423
- } else {
424
- this._bufferEdge({
425
- type: 'CONTAINS',
426
- src: module.id,
427
- dst: funcData.id
428
- });
429
- }
430
- }
292
+ return { nodes: nodesCreated, edges: edgesCreated + classAssignmentEdges };
431
293
  }
432
294
 
433
- private bufferScopeEdges(scopes: ScopeInfo[], variableDeclarations: VariableDeclarationInfo[]): void {
434
- for (const scope of scopes) {
435
- const { parentFunctionId, parentScopeId, capturesFrom, ...scopeData } = scope;
295
+ // ============= SHARED UTILITY METHODS =============
436
296
 
437
- // FUNCTION -> HAS_SCOPE -> SCOPE (для function_body)
438
- if (parentFunctionId) {
439
- this._bufferEdge({
440
- type: 'HAS_SCOPE',
441
- src: parentFunctionId,
442
- dst: scopeData.id
443
- });
444
- }
297
+ /**
298
+ * Scope-aware function lookup: when multiple functions share the same name
299
+ * (e.g., inner function shadows outer), prefer the one in the same scope.
300
+ * Falls back to module-level function if no scope match found.
301
+ */
302
+ private findFunctionByName(
303
+ functions: FunctionInfo[],
304
+ name: string | undefined,
305
+ file: string,
306
+ callScopeId: string
307
+ ): FunctionInfo | undefined {
308
+ if (!name) return undefined;
445
309
 
446
- // SCOPE -> CONTAINS -> SCOPE (для вложенных scope, типа if внутри function)
447
- if (parentScopeId) {
448
- this._bufferEdge({
449
- type: 'CONTAINS',
450
- src: parentScopeId,
451
- dst: scopeData.id
452
- });
453
- }
310
+ // Find all functions with matching name in the same file
311
+ const candidates = functions.filter(f => f.name === name && f.file === file);
454
312
 
455
- // CAPTURES - замыкания захватывают переменные из родительского scope
456
- if (capturesFrom && scopeData.scopeType === 'closure') {
457
- const parentVars = variableDeclarations.filter(v => v.parentScopeId === capturesFrom);
458
- for (const parentVar of parentVars) {
459
- this._bufferEdge({
460
- type: 'CAPTURES',
461
- src: scopeData.id,
462
- dst: parentVar.id
463
- });
464
- }
465
- }
313
+ if (candidates.length === 0) {
314
+ // Fallback: try without file constraint (legacy behavior)
315
+ return functions.find(f => f.name === name);
316
+ }
466
317
 
467
- // REG-288: MODIFIES edges removed - now come from UPDATE_EXPRESSION nodes
318
+ if (candidates.length === 1) {
319
+ return candidates[0];
468
320
  }
321
+
322
+ // Multiple candidates: prefer same scope, then module-level
323
+ const sameScope = candidates.find(f => f.parentScopeId === callScopeId);
324
+ if (sameScope) return sameScope;
325
+
326
+ // Fallback: prefer module-level function (parentScopeId contains MODULE)
327
+ const moduleLevel = candidates.find(f =>
328
+ (f.parentScopeId as string)?.includes(':MODULE:')
329
+ );
330
+ return moduleLevel || candidates[0];
469
331
  }
470
332
 
471
333
  /**
472
- * Buffer LOOP edges (CONTAINS, HAS_BODY, ITERATES_OVER)
473
- *
474
- * Creates edges for:
475
- * - Parent -> CONTAINS -> LOOP
476
- * - LOOP -> HAS_BODY -> body SCOPE
477
- * - LOOP -> ITERATES_OVER -> collection VARIABLE/PARAMETER (for for-in/for-of)
334
+ * Resolve variable by name using scope chain lookup (REG-309).
335
+ * Mirrors JavaScript lexical scoping: search current scope, then parent, then grandparent, etc.
478
336
  *
479
- * Scope-aware variable lookup for ITERATES_OVER:
480
- * For for-of/for-in, finds the iterated variable preferring:
481
- * 1. Variables declared before the loop on same or earlier line (closest first)
482
- * 2. Parameters (function arguments)
337
+ * @param name - Variable name
338
+ * @param scopePath - Scope path where reference occurs (from ScopeTracker)
339
+ * @param file - File path
340
+ * @param variables - All variable declarations
341
+ * @returns Variable declaration or null if not found
483
342
  */
484
- private bufferLoopEdges(
485
- loops: LoopInfo[],
486
- scopes: ScopeInfo[],
487
- variableDeclarations: VariableDeclarationInfo[],
488
- parameters: ParameterInfo[]
489
- ): void {
490
- for (const loop of loops) {
491
- // Parent -> CONTAINS -> LOOP
492
- if (loop.parentScopeId) {
493
- this._bufferEdge({
494
- type: 'CONTAINS',
495
- src: loop.parentScopeId,
496
- dst: loop.id
497
- });
498
- }
343
+ private resolveVariableInScope(
344
+ name: string,
345
+ scopePath: string[],
346
+ file: string,
347
+ variables: VariableDeclarationInfo[]
348
+ ): VariableDeclarationInfo | null {
349
+ // Try current scope, then parent, then grandparent, etc.
350
+ for (let i = scopePath.length; i >= 0; i--) {
351
+ const searchScopePath = scopePath.slice(0, i);
499
352
 
500
- // LOOP -> HAS_BODY -> body SCOPE
501
- // Find the body scope by matching parentScopeId to loop.id
502
- const bodyScope = scopes.find(s => s.parentScopeId === loop.id);
503
- if (bodyScope) {
504
- this._bufferEdge({
505
- type: 'HAS_BODY',
506
- src: loop.id,
507
- dst: bodyScope.id
508
- });
509
- }
353
+ const matchingVar = variables.find(v => {
354
+ if (v.name !== name || v.file !== file) return false;
510
355
 
511
- // LOOP -> ITERATES_OVER -> collection VARIABLE/PARAMETER (for for-in/for-of)
512
- if (loop.iteratesOverName && (loop.loopType === 'for-in' || loop.loopType === 'for-of')) {
513
- // For MemberExpression iterables (obj.items), extract base object
514
- const iterableName = loop.iteratesOverName.includes('.')
515
- ? loop.iteratesOverName.split('.')[0]
516
- : loop.iteratesOverName;
517
-
518
- // Scope-aware lookup: prefer parameters over variables
519
- // Parameters are function-local and shadow outer variables
520
- const param = parameters.find(p =>
521
- p.name === iterableName && p.file === loop.file
522
- );
523
-
524
- // Determine iteration type: for-in iterates keys, for-of iterates values
525
- const iterates = loop.loopType === 'for-in' ? 'keys' : 'values';
526
-
527
- if (param) {
528
- // Parameter found - most local binding
529
- this._bufferEdge({
530
- type: 'ITERATES_OVER',
531
- src: loop.id,
532
- dst: param.id,
533
- metadata: { iterates }
534
- });
535
- } else {
536
- // Find variable by name and line proximity (scope-aware heuristic)
537
- // Prefer variables declared before the loop in the same file
538
- const candidateVars = variableDeclarations.filter(v =>
539
- v.name === iterableName &&
540
- v.file === loop.file &&
541
- (v.line ?? 0) <= loop.line // Declared before or on loop line
542
- );
543
-
544
- // Sort by line descending to find closest declaration
545
- candidateVars.sort((a, b) => (b.line ?? 0) - (a.line ?? 0));
546
-
547
- if (candidateVars.length > 0) {
548
- this._bufferEdge({
549
- type: 'ITERATES_OVER',
550
- src: loop.id,
551
- dst: candidateVars[0].id,
552
- metadata: { iterates }
553
- });
356
+ // REG-464: v2 path use scopePath field if available (set by visitors)
357
+ if (v.scopePath) {
358
+ if (searchScopePath.length === 0) {
359
+ return v.scopePath.length === 0;
554
360
  }
361
+ return this.scopePathsMatch(v.scopePath, searchScopePath);
555
362
  }
556
- }
557
-
558
- // REG-282: LOOP (for) -> HAS_INIT -> VARIABLE (let i = 0)
559
- if (loop.loopType === 'for' && loop.initVariableName && loop.initLine) {
560
- // Find the variable declared in the init on this line
561
- const initVar = variableDeclarations.find(v =>
562
- v.name === loop.initVariableName &&
563
- v.file === loop.file &&
564
- v.line === loop.initLine
565
- );
566
- if (initVar) {
567
- this._bufferEdge({
568
- type: 'HAS_INIT',
569
- src: loop.id,
570
- dst: initVar.id
571
- });
572
- }
573
- }
574
363
 
575
- // REG-282: LOOP -> HAS_CONDITION -> EXPRESSION (i < 10 or condition for while/do-while)
576
- if (loop.testExpressionId && loop.testExpressionType) {
577
- // Create EXPRESSION node for the test
578
- this._bufferNode({
579
- id: loop.testExpressionId,
580
- type: 'EXPRESSION',
581
- name: loop.testExpressionType,
582
- file: loop.file,
583
- line: loop.testLine,
584
- column: loop.testColumn,
585
- expressionType: loop.testExpressionType
586
- });
364
+ // v1 fallback: parse semanticId
365
+ // Variable ID IS the semantic ID (when scopeTracker was available during analysis)
366
+ // Format: file->scope1->scope2->TYPE->name
367
+ // Legacy format: VARIABLE#name#file#line:column:counter
587
368
 
588
- this._bufferEdge({
589
- type: 'HAS_CONDITION',
590
- src: loop.id,
591
- dst: loop.testExpressionId
592
- });
593
- }
369
+ // Try parsing as semantic ID
370
+ const parsed = parseSemanticId(v.id);
371
+ // REG-329: Check for both VARIABLE and CONSTANT (const declarations)
372
+ if (parsed && (parsed.type === 'VARIABLE' || parsed.type === 'CONSTANT')) {
373
+ // FIXED (REG-309): Handle module-level scope matching
374
+ // Empty search scope [] should match semantic ID scope ['global']
375
+ if (searchScopePath.length === 0) {
376
+ return parsed.scopePath.length === 1 && parsed.scopePath[0] === 'global';
377
+ }
378
+ // Non-empty scope: exact match
379
+ return this.scopePathsMatch(parsed.scopePath, searchScopePath);
380
+ }
594
381
 
595
- // REG-282: LOOP (for) -> HAS_UPDATE -> EXPRESSION (i++)
596
- if (loop.loopType === 'for' && loop.updateExpressionId && loop.updateExpressionType) {
597
- // Create EXPRESSION node for the update
598
- this._bufferNode({
599
- id: loop.updateExpressionId,
600
- type: 'EXPRESSION',
601
- name: loop.updateExpressionType,
602
- file: loop.file,
603
- line: loop.updateLine,
604
- column: loop.updateColumn,
605
- expressionType: loop.updateExpressionType
606
- });
382
+ // Legacy ID - assume module-level if no semantic ID
383
+ return searchScopePath.length === 0;
384
+ });
607
385
 
608
- this._bufferEdge({
609
- type: 'HAS_UPDATE',
610
- src: loop.id,
611
- dst: loop.updateExpressionId
612
- });
613
- }
386
+ if (matchingVar) return matchingVar;
614
387
  }
388
+
389
+ return null;
615
390
  }
616
391
 
617
392
  /**
618
- * Buffer HAS_CONDITION edges from LOOP to condition EXPRESSION/CALL nodes.
619
- * Also creates EXPRESSION nodes for non-CallExpression conditions.
620
- *
621
- * REG-280: For while/do-while/for loops, creates HAS_CONDITION edge to the
622
- * condition expression. For-in/for-of loops don't have conditions (use ITERATES_OVER).
393
+ * Resolve parameter by name using scope chain lookup (REG-309).
394
+ * Same semantics as resolveVariableInScope but for parameters.
623
395
  *
624
- * For CallExpression conditions, links to existing CALL_SITE node by coordinates.
396
+ * @param name - Parameter name
397
+ * @param scopePath - Scope path where reference occurs (from ScopeTracker)
398
+ * @param file - File path
399
+ * @param parameters - All parameter declarations
400
+ * @returns Parameter declaration or null if not found
625
401
  */
626
- private bufferLoopConditionEdges(loops: LoopInfo[], callSites: CallSiteInfo[]): void {
627
- for (const loop of loops) {
628
- // Skip for-in/for-of loops - they don't have test expressions
629
- if (loop.loopType === 'for-in' || loop.loopType === 'for-of') {
630
- continue;
631
- }
632
-
633
- // Skip if no condition (e.g., infinite for loop: for(;;))
634
- if (!loop.conditionExpressionId) {
635
- continue;
636
- }
402
+ private resolveParameterInScope(
403
+ name: string,
404
+ scopePath: string[],
405
+ file: string,
406
+ parameters: ParameterInfo[]
407
+ ): ParameterInfo | null {
408
+ // Parameters have semanticId field populated (unlike variables which use id field)
409
+ return parameters.find(p => {
410
+ if (p.name !== name || p.file !== file) return false;
637
411
 
638
- // LOOP -> HAS_CONDITION -> EXPRESSION/CALL
639
- let targetId = loop.conditionExpressionId;
640
-
641
- // For CallExpression conditions, look up the actual CALL_SITE by coordinates
642
- // because CALL_SITE uses semantic IDs that don't match the generated ID
643
- if (loop.conditionExpressionType === 'CallExpression' && loop.conditionLine && loop.conditionColumn !== undefined) {
644
- const callSite = callSites.find(cs =>
645
- cs.file === loop.file &&
646
- cs.line === loop.conditionLine &&
647
- cs.column === loop.conditionColumn
648
- );
649
- if (callSite) {
650
- targetId = callSite.id;
412
+ // REG-464: v2 path use scopePath field if available (set by visitors)
413
+ if (p.scopePath) {
414
+ for (let i = scopePath.length; i >= 0; i--) {
415
+ const searchScopePath = scopePath.slice(0, i);
416
+ if (searchScopePath.length === 0) {
417
+ if (p.scopePath.length === 0) return true;
418
+ } else {
419
+ if (this.scopePathsMatch(p.scopePath, searchScopePath)) return true;
420
+ }
651
421
  }
422
+ return false;
652
423
  }
653
424
 
654
- this._bufferEdge({
655
- type: 'HAS_CONDITION',
656
- src: loop.id,
657
- dst: targetId
658
- });
659
- }
660
- }
661
-
662
- /**
663
- * Buffer EXPRESSION nodes for loop condition expressions (non-CallExpression).
664
- * Similar to bufferDiscriminantExpressions but for loops.
665
- *
666
- * REG-280: Creates EXPRESSION nodes for while/do-while/for loop conditions.
667
- * CallExpression conditions use existing CALL_SITE nodes (no EXPRESSION created).
668
- */
669
- private bufferLoopConditionExpressions(loops: LoopInfo[]): void {
670
- for (const loop of loops) {
671
- // Skip for-in/for-of loops - they don't have test expressions
672
- if (loop.loopType === 'for-in' || loop.loopType === 'for-of') {
673
- continue;
674
- }
675
-
676
- if (loop.conditionExpressionId && loop.conditionExpressionType) {
677
- // Skip CallExpression - we link to existing CALL_SITE in bufferLoopConditionEdges
678
- if (loop.conditionExpressionType === 'CallExpression') {
679
- continue;
680
- }
425
+ // v1 fallback: parse semanticId
426
+ if (p.semanticId) {
427
+ const parsed = parseSemanticId(p.semanticId);
428
+ if (parsed && parsed.type === 'PARAMETER') {
429
+ // Check if parameter's scope matches any scope in the chain
430
+ for (let i = scopePath.length; i >= 0; i--) {
431
+ const searchScopePath = scopePath.slice(0, i);
681
432
 
682
- // Only create if it looks like an EXPRESSION ID
683
- if (loop.conditionExpressionId.includes(':EXPRESSION:')) {
684
- this._bufferNode({
685
- id: loop.conditionExpressionId,
686
- type: 'EXPRESSION',
687
- name: loop.conditionExpressionType,
688
- file: loop.file,
689
- line: loop.conditionLine,
690
- column: loop.conditionColumn,
691
- expressionType: loop.conditionExpressionType
692
- });
433
+ // FIXED (REG-309): Handle module-level scope matching for parameters
434
+ if (searchScopePath.length === 0) {
435
+ if (parsed.scopePath.length === 1 && parsed.scopePath[0] === 'global') {
436
+ return true;
437
+ }
438
+ } else {
439
+ if (this.scopePathsMatch(parsed.scopePath, searchScopePath)) {
440
+ return true;
441
+ }
442
+ }
443
+ }
693
444
  }
694
445
  }
695
- }
446
+ return false;
447
+ }) ?? null;
696
448
  }
697
449
 
698
450
  /**
699
- * Buffer BRANCH edges (CONTAINS, HAS_CONDITION, HAS_CONSEQUENT, HAS_ALTERNATE)
700
- *
701
- * REG-275: For CallExpression discriminants (switch(getType())), looks up the
702
- * actual CALL_SITE node by coordinates since the CALL_SITE uses semantic IDs.
703
- *
704
- * Phase 3 (REG-267): For if-branches, creates HAS_CONSEQUENT and HAS_ALTERNATE edges
705
- * pointing to the if-body and else-body SCOPEs.
451
+ * Check if two scope paths match (REG-309).
452
+ * Handles: ['foo', 'if#0'] vs ['foo', 'if#0']
706
453
  */
707
- private bufferBranchEdges(branches: BranchInfo[], callSites: CallSiteInfo[], scopes: ScopeInfo[]): void {
708
- for (const branch of branches) {
709
- // Parent SCOPE -> CONTAINS -> BRANCH
710
- if (branch.parentScopeId) {
711
- this._bufferEdge({
712
- type: 'CONTAINS',
713
- src: branch.parentScopeId,
714
- dst: branch.id
715
- });
716
- }
717
-
718
- // BRANCH -> HAS_CONDITION -> EXPRESSION/CALL (discriminant)
719
- if (branch.discriminantExpressionId) {
720
- let targetId = branch.discriminantExpressionId;
721
-
722
- // For CallExpression discriminants, look up the actual CALL_SITE by coordinates
723
- // because CALL_SITE uses semantic IDs that don't match the generated ID
724
- if (branch.discriminantExpressionType === 'CallExpression' && branch.discriminantLine && branch.discriminantColumn !== undefined) {
725
- const callSite = callSites.find(cs =>
726
- cs.file === branch.file &&
727
- cs.line === branch.discriminantLine &&
728
- cs.column === branch.discriminantColumn
729
- );
730
- if (callSite) {
731
- targetId = callSite.id;
732
- }
733
- }
734
-
735
- this._bufferEdge({
736
- type: 'HAS_CONDITION',
737
- src: branch.id,
738
- dst: targetId
739
- });
740
- }
741
-
742
- // Phase 3: For if-branches, create HAS_CONSEQUENT and HAS_ALTERNATE edges
743
- if (branch.branchType === 'if') {
744
- // Find consequent (if-body) scope - parentScopeId matches branch.id, scopeType is 'if_statement'
745
- const consequentScope = scopes.find(s =>
746
- s.parentScopeId === branch.id && s.scopeType === 'if_statement'
747
- );
748
- if (consequentScope) {
749
- this._bufferEdge({
750
- type: 'HAS_CONSEQUENT',
751
- src: branch.id,
752
- dst: consequentScope.id
753
- });
754
- }
755
-
756
- // Find alternate (else-body) scope - parentScopeId matches branch.id, scopeType is 'else_statement'
757
- const alternateScope = scopes.find(s =>
758
- s.parentScopeId === branch.id && s.scopeType === 'else_statement'
759
- );
760
- if (alternateScope) {
761
- this._bufferEdge({
762
- type: 'HAS_ALTERNATE',
763
- src: branch.id,
764
- dst: alternateScope.id
765
- });
766
- }
767
-
768
- // For else-if chains: if this branch is the alternate of another branch
769
- // This is handled differently - see below
770
- }
454
+ private scopePathsMatch(a: string[], b: string[]): boolean {
455
+ if (a.length !== b.length) return false;
456
+ return a.every((item, idx) => item === b[idx]);
457
+ }
771
458
 
772
- // REG-287: For ternary branches, create HAS_CONSEQUENT and HAS_ALTERNATE edges to expressions
773
- if (branch.branchType === 'ternary') {
774
- if (branch.consequentExpressionId) {
775
- this._bufferEdge({
776
- type: 'HAS_CONSEQUENT',
777
- src: branch.id,
778
- dst: branch.consequentExpressionId
779
- });
780
- }
781
- if (branch.alternateExpressionId) {
782
- this._bufferEdge({
783
- type: 'HAS_ALTERNATE',
784
- src: branch.id,
785
- dst: branch.alternateExpressionId
786
- });
787
- }
788
- }
459
+ // ============= POST-FLUSH METHODS (need graph queries) =============
789
460
 
790
- // Phase 3: For else-if chains, create HAS_ALTERNATE from parent branch to this branch
791
- if (branch.isAlternateOfBranchId) {
792
- this._bufferEdge({
793
- type: 'HAS_ALTERNATE',
794
- src: branch.isAlternateOfBranchId,
795
- dst: branch.id
796
- });
461
+ /**
462
+ * Collect unique import.meta property names from property accesses (REG-300).
463
+ * Returns deduplicated array of property names (e.g., ["url", "env"]).
464
+ */
465
+ private collectImportMetaProperties(propertyAccesses: PropertyAccessInfo[]): string[] {
466
+ const metaProps = new Set<string>();
467
+ for (const propAccess of propertyAccesses) {
468
+ if (propAccess.objectName === 'import.meta') {
469
+ metaProps.add(propAccess.propertyName);
797
470
  }
798
471
  }
472
+ return [...metaProps];
799
473
  }
800
474
 
801
475
  /**
802
- * Buffer CASE edges (HAS_CASE, HAS_DEFAULT)
476
+ * Update MODULE node with import.meta metadata (REG-300).
477
+ * Reads existing MODULE node, adds importMeta property list, re-adds it.
803
478
  */
804
- private bufferCaseEdges(cases: CaseInfo[]): void {
805
- for (const caseInfo of cases) {
806
- // BRANCH -> HAS_CASE or HAS_DEFAULT -> CASE
807
- const edgeType = caseInfo.isDefault ? 'HAS_DEFAULT' : 'HAS_CASE';
808
- this._bufferEdge({
809
- type: edgeType,
810
- src: caseInfo.parentBranchId,
811
- dst: caseInfo.id
812
- });
813
- }
479
+ private async updateModuleImportMetaMetadata(
480
+ module: ModuleNode,
481
+ graph: GraphBackend,
482
+ importMetaProps: string[]
483
+ ): Promise<void> {
484
+ if (importMetaProps.length === 0) return;
485
+
486
+ const existingNode = await graph.getNode(module.id);
487
+ if (!existingNode) return;
488
+
489
+ // Re-add with importMeta at top level — addNode is upsert in RFDB,
490
+ // and backend spreads metadata fields to top level on read
491
+ await graph.addNode({
492
+ ...existingNode,
493
+ importMeta: importMetaProps
494
+ } as unknown as Parameters<GraphBackend['addNode']>[0]);
814
495
  }
815
496
 
816
497
  /**
817
- * Buffer edges for TRY_BLOCK, CATCH_BLOCK, FINALLY_BLOCK nodes (Phase 4)
818
- *
819
- * Creates edges for:
820
- * - Parent -> CONTAINS -> TRY_BLOCK
821
- * - TRY_BLOCK -> HAS_CATCH -> CATCH_BLOCK
822
- * - TRY_BLOCK -> HAS_FINALLY -> FINALLY_BLOCK
498
+ * Update MODULE node with hasTopLevelAwait metadata (REG-297).
499
+ * Reads existing MODULE node, adds hasTopLevelAwait flag, re-adds it.
823
500
  */
824
- private bufferTryCatchFinallyEdges(
825
- tryBlocks: TryBlockInfo[],
826
- catchBlocks: CatchBlockInfo[],
827
- finallyBlocks: FinallyBlockInfo[]
828
- ): void {
829
- // Buffer TRY_BLOCK edges
830
- for (const tryBlock of tryBlocks) {
831
- // Parent -> CONTAINS -> TRY_BLOCK
832
- if (tryBlock.parentScopeId) {
833
- this._bufferEdge({
834
- type: 'CONTAINS',
835
- src: tryBlock.parentScopeId,
836
- dst: tryBlock.id
837
- });
838
- }
839
- }
501
+ private async updateModuleTopLevelAwaitMetadata(
502
+ module: ModuleNode,
503
+ graph: GraphBackend,
504
+ hasTopLevelAwait: boolean
505
+ ): Promise<void> {
506
+ if (!hasTopLevelAwait) return;
840
507
 
841
- // Buffer CATCH_BLOCK edges (HAS_CATCH from TRY_BLOCK)
842
- for (const catchBlock of catchBlocks) {
843
- // TRY_BLOCK -> HAS_CATCH -> CATCH_BLOCK
844
- this._bufferEdge({
845
- type: 'HAS_CATCH',
846
- src: catchBlock.parentTryBlockId,
847
- dst: catchBlock.id
848
- });
849
- }
508
+ const existingNode = await graph.getNode(module.id);
509
+ if (!existingNode) return;
850
510
 
851
- // Buffer FINALLY_BLOCK edges (HAS_FINALLY from TRY_BLOCK)
852
- for (const finallyBlock of finallyBlocks) {
853
- // TRY_BLOCK -> HAS_FINALLY -> FINALLY_BLOCK
854
- this._bufferEdge({
855
- type: 'HAS_FINALLY',
856
- src: finallyBlock.parentTryBlockId,
857
- dst: finallyBlock.id
858
- });
859
- }
511
+ await graph.addNode({
512
+ ...existingNode,
513
+ hasTopLevelAwait: true
514
+ } as unknown as Parameters<GraphBackend['addNode']>[0]);
860
515
  }
861
516
 
862
517
  /**
863
- * Buffer EXPRESSION nodes for switch discriminants
864
- * Uses stored metadata directly instead of parsing from ID (Linus improvement)
865
- *
866
- * REG-275: For CallExpression discriminants, we don't create nodes here since
867
- * bufferBranchEdges links to the existing CALL_SITE node by coordinates.
518
+ * Handle CLASS ASSIGNED_FROM edges asynchronously (needs graph queries)
868
519
  */
869
- private bufferDiscriminantExpressions(branches: BranchInfo[], _callSites: CallSiteInfo[]): void {
870
- for (const branch of branches) {
871
- if (branch.discriminantExpressionId && branch.discriminantExpressionType) {
872
- // Skip CallExpression - we link to existing CALL_SITE in bufferBranchEdges
873
- if (branch.discriminantExpressionType === 'CallExpression') {
874
- continue;
875
- }
876
-
877
- // Only create if it looks like an EXPRESSION ID
878
- if (branch.discriminantExpressionId.includes(':EXPRESSION:')) {
879
- this._bufferNode({
880
- id: branch.discriminantExpressionId,
881
- type: 'EXPRESSION',
882
- name: branch.discriminantExpressionType,
883
- file: branch.file,
884
- line: branch.discriminantLine,
885
- column: branch.discriminantColumn,
886
- expressionType: branch.discriminantExpressionType
887
- });
888
- }
889
- }
890
- }
891
- }
892
-
893
- private bufferVariableEdges(variableDeclarations: VariableDeclarationInfo[]): void {
894
- for (const varDecl of variableDeclarations) {
895
- const { parentScopeId, isClassProperty, ...varData } = varDecl;
896
-
897
- // REG-271: Skip class properties - they get HAS_PROPERTY edges from CLASS, not DECLARES from SCOPE
898
- if (isClassProperty) {
899
- continue;
900
- }
901
-
902
- // SCOPE -> DECLARES -> VARIABLE
903
- this._bufferEdge({
904
- type: 'DECLARES',
905
- src: parentScopeId as string,
906
- dst: varData.id
907
- });
908
- }
909
- }
910
-
911
- private bufferCallSiteEdges(callSites: CallSiteInfo[], functions: FunctionInfo[]): void {
912
- for (const callSite of callSites) {
913
- const { parentScopeId, targetFunctionName, ...callData } = callSite;
914
-
915
- // SCOPE -> CONTAINS -> CALL_SITE
916
- this._bufferEdge({
917
- type: 'CONTAINS',
918
- src: parentScopeId as string,
919
- dst: callData.id
920
- });
921
-
922
- // CALL_SITE -> CALLS -> FUNCTION
923
- const targetFunction = functions.find(f => f.name === targetFunctionName);
924
- if (targetFunction) {
925
- this._bufferEdge({
926
- type: 'CALLS',
927
- src: callData.id,
928
- dst: targetFunction.id
929
- });
930
- }
931
- }
932
- }
933
-
934
- private bufferMethodCalls(
935
- methodCalls: MethodCallInfo[],
936
- variableDeclarations: VariableDeclarationInfo[],
937
- parameters: ParameterInfo[]
938
- ): void {
939
- for (const methodCall of methodCalls) {
940
- // Keep parentScopeId on node for queries
941
- this._bufferNode(methodCall as unknown as GraphNode);
942
-
943
- // SCOPE -> CONTAINS -> METHOD_CALL
944
- this._bufferEdge({
945
- type: 'CONTAINS',
946
- src: methodCall.parentScopeId as string,
947
- dst: methodCall.id
948
- });
949
-
950
- // REG-262: Create USES edge from METHOD_CALL to receiver variable
951
- // Skip 'this' - it's not a variable node
952
- if (methodCall.object && methodCall.object !== 'this') {
953
- // Handle nested member expressions: obj.nested.method() -> use base 'obj'
954
- const receiverName = methodCall.object.includes('.')
955
- ? methodCall.object.split('.')[0]
956
- : methodCall.object;
957
-
958
- // Find receiver variable in current file
959
- const receiverVar = variableDeclarations.find(v =>
960
- v.name === receiverName && v.file === methodCall.file
961
- );
962
-
963
- if (receiverVar) {
964
- this._bufferEdge({
965
- type: 'USES',
966
- src: methodCall.id,
967
- dst: receiverVar.id
968
- });
969
- } else {
970
- // Check parameters (function arguments)
971
- const receiverParam = parameters.find(p =>
972
- p.name === receiverName && p.file === methodCall.file
973
- );
974
-
975
- if (receiverParam) {
976
- this._bufferEdge({
977
- type: 'USES',
978
- src: methodCall.id,
979
- dst: receiverParam.id
980
- });
981
- }
982
- }
983
- }
984
- }
985
- }
986
-
987
- /**
988
- * Buffer PROPERTY_ACCESS nodes and CONTAINS edges (REG-395).
989
- *
990
- * Creates nodes for property reads (obj.prop, a.b.c) and
991
- * CONTAINS edges from the enclosing scope (function or module).
992
- */
993
- private bufferPropertyAccessNodes(module: ModuleNode, propertyAccesses: PropertyAccessInfo[]): void {
994
- for (const propAccess of propertyAccesses) {
995
- // Buffer node with all relevant fields
996
- this._bufferNode({
997
- id: propAccess.id,
998
- type: 'PROPERTY_ACCESS',
999
- name: propAccess.propertyName,
1000
- objectName: propAccess.objectName,
1001
- file: propAccess.file,
1002
- line: propAccess.line,
1003
- column: propAccess.column,
1004
- semanticId: propAccess.semanticId,
1005
- optional: propAccess.optional,
1006
- computed: propAccess.computed
1007
- } as GraphNode);
1008
-
1009
- // SCOPE/FUNCTION/MODULE -> CONTAINS -> PROPERTY_ACCESS
1010
- const containsSrc = propAccess.parentScopeId ?? module.id;
1011
- this._bufferEdge({
1012
- type: 'CONTAINS',
1013
- src: containsSrc,
1014
- dst: propAccess.id
1015
- });
1016
- }
1017
- }
1018
-
1019
- private bufferStdioNodes(methodCalls: MethodCallInfo[]): void {
1020
- const consoleIOMethods = methodCalls.filter(mc =>
1021
- (mc.object === 'console' && (mc.method === 'log' || mc.method === 'error'))
1022
- );
1023
-
1024
- if (consoleIOMethods.length > 0) {
1025
- const stdioNode = NodeFactory.createExternalStdio();
1026
-
1027
- // Buffer net:stdio node only once (singleton)
1028
- if (!this._createdSingletons.has(stdioNode.id)) {
1029
- this._bufferNode(stdioNode as unknown as GraphNode);
1030
- this._createdSingletons.add(stdioNode.id);
1031
- }
1032
-
1033
- // Buffer WRITES_TO edges for console.log/error
1034
- for (const methodCall of consoleIOMethods) {
1035
- this._bufferEdge({
1036
- type: 'WRITES_TO',
1037
- src: methodCall.id,
1038
- dst: stdioNode.id
1039
- });
1040
- }
1041
- }
1042
- }
1043
-
1044
- private bufferClassDeclarationNodes(classDeclarations: ClassDeclarationInfo[]): void {
1045
- for (const classDecl of classDeclarations) {
1046
- const { id, type, name, file, line, column, superClass, methods, properties, staticBlocks } = classDecl;
1047
-
1048
- // Buffer CLASS node
1049
- this._bufferNode({
1050
- id,
1051
- type,
1052
- name,
1053
- file,
1054
- line,
1055
- column,
1056
- superClass
1057
- });
1058
-
1059
- // Buffer CONTAINS edges: CLASS -> METHOD
1060
- for (const methodId of methods) {
1061
- this._bufferEdge({
1062
- type: 'CONTAINS',
1063
- src: id,
1064
- dst: methodId
1065
- });
1066
- }
1067
-
1068
- // REG-271: Buffer HAS_PROPERTY edges: CLASS -> VARIABLE (private fields)
1069
- if (properties) {
1070
- for (const propertyId of properties) {
1071
- this._bufferEdge({
1072
- type: 'HAS_PROPERTY',
1073
- src: id,
1074
- dst: propertyId
1075
- });
1076
- }
1077
- }
1078
-
1079
- // REG-271: Buffer CONTAINS edges: CLASS -> SCOPE (static blocks)
1080
- if (staticBlocks) {
1081
- for (const staticBlockId of staticBlocks) {
1082
- this._bufferEdge({
1083
- type: 'CONTAINS',
1084
- src: id,
1085
- dst: staticBlockId
1086
- });
1087
- }
1088
- }
1089
-
1090
- // If superClass, buffer DERIVES_FROM edge with computed ID
1091
- if (superClass) {
1092
- // Compute superclass ID using semantic ID format
1093
- // Assume superclass is in same file at global scope (most common case)
1094
- // When superclass is in different file, edge will be dangling until that file analyzed
1095
- const globalContext = { file, scopePath: [] as string[] };
1096
- const superClassId = computeSemanticId('CLASS', superClass, globalContext);
1097
-
1098
- this._bufferEdge({
1099
- type: 'DERIVES_FROM',
1100
- src: id,
1101
- dst: superClassId
1102
- });
1103
- }
1104
- }
1105
- }
1106
-
1107
- private bufferClassNodes(module: ModuleNode, classInstantiations: ClassInstantiationInfo[], classDeclarations: ClassDeclarationInfo[]): void {
1108
- // Create lookup map: className → declaration ID
1109
- // Use basename for comparison because CLASS nodes use scopeTracker.file (basename)
1110
- const moduleBasename = basename(module.file);
1111
- const declarationMap = new Map<string, string>();
1112
- for (const decl of classDeclarations) {
1113
- if (decl.file === moduleBasename) {
1114
- declarationMap.set(decl.name, decl.id);
1115
- }
1116
- }
1117
-
1118
- for (const instantiation of classInstantiations) {
1119
- const { variableId, className, line: _line } = instantiation;
1120
-
1121
- let classId = declarationMap.get(className);
1122
-
1123
- if (!classId) {
1124
- // External class - compute semantic ID
1125
- // Use basename to match CLASS node format (scopeTracker uses basename)
1126
- // When class is in different file, edge will be dangling until that file analyzed
1127
- const globalContext = { file: moduleBasename, scopePath: [] as string[] };
1128
- classId = computeSemanticId('CLASS', className, globalContext);
1129
-
1130
- // NO node creation - node will exist when class file analyzed
1131
- }
1132
-
1133
- // Buffer INSTANCE_OF edge
1134
- this._bufferEdge({
1135
- type: 'INSTANCE_OF',
1136
- src: variableId,
1137
- dst: classId
1138
- });
1139
- }
1140
- }
1141
-
1142
- private bufferCallbackEdges(methodCallbacks: MethodCallbackInfo[], functions: FunctionInfo[]): void {
1143
- for (const callback of methodCallbacks) {
1144
- const { methodCallId, callbackLine, callbackColumn } = callback;
1145
-
1146
- const callbackFunction = functions.find(f =>
1147
- f.line === callbackLine && f.column === callbackColumn
1148
- );
1149
-
1150
- if (callbackFunction) {
1151
- this._bufferEdge({
1152
- type: 'HAS_CALLBACK',
1153
- src: methodCallId,
1154
- dst: callbackFunction.id
1155
- });
1156
- }
1157
- }
1158
- }
1159
-
1160
- private bufferImportNodes(module: ModuleNode, imports: ImportInfo[]): void {
1161
- for (const imp of imports) {
1162
- const { source, specifiers, line, column, isDynamic, isResolvable, dynamicPath } = imp;
1163
-
1164
- // REG-273: Handle side-effect-only imports (no specifiers)
1165
- if (specifiers.length === 0) {
1166
- // Side-effect import: import './polyfill.js'
1167
- const importNode = ImportNode.create(
1168
- source, // name = source (no local binding)
1169
- module.file, // file
1170
- line, // line (stored as field, not in ID)
1171
- column || 0, // column
1172
- source, // source module
1173
- {
1174
- imported: '*', // no specific export
1175
- local: source, // source becomes local
1176
- sideEffect: true // mark as side-effect import
1177
- }
1178
- );
1179
-
1180
- this._bufferNode(importNode as unknown as GraphNode);
1181
-
1182
- // MODULE -> CONTAINS -> IMPORT
1183
- this._bufferEdge({
1184
- type: 'CONTAINS',
1185
- src: module.id,
1186
- dst: importNode.id
1187
- });
1188
-
1189
- // Create EXTERNAL_MODULE node for external modules
1190
- const isRelative = source.startsWith('./') || source.startsWith('../');
1191
- if (!isRelative) {
1192
- const externalModule = NodeFactory.createExternalModule(source);
1193
-
1194
- // Avoid duplicate EXTERNAL_MODULE nodes
1195
- if (!this._createdSingletons.has(externalModule.id)) {
1196
- this._bufferNode(externalModule as unknown as GraphNode);
1197
- this._createdSingletons.add(externalModule.id);
1198
- }
1199
-
1200
- this._bufferEdge({
1201
- type: 'IMPORTS',
1202
- src: module.id,
1203
- dst: externalModule.id
1204
- });
1205
- }
1206
- } else {
1207
- // Regular imports with specifiers
1208
- for (const spec of specifiers) {
1209
- // Use ImportNode factory for proper semantic IDs and field population
1210
- const importNode = ImportNode.create(
1211
- spec.local, // name = local binding
1212
- module.file, // file
1213
- line, // line (stored as field, not in ID)
1214
- column || 0, // column
1215
- source, // source module
1216
- {
1217
- imported: spec.imported,
1218
- local: spec.local,
1219
- sideEffect: false, // regular imports are not side-effects
1220
- // importType is auto-detected from imported field
1221
- // Dynamic import fields
1222
- isDynamic,
1223
- isResolvable,
1224
- dynamicPath
1225
- }
1226
- );
1227
-
1228
- this._bufferNode(importNode as unknown as GraphNode);
1229
-
1230
- // MODULE -> CONTAINS -> IMPORT
1231
- this._bufferEdge({
1232
- type: 'CONTAINS',
1233
- src: module.id,
1234
- dst: importNode.id
1235
- });
1236
-
1237
- // Create EXTERNAL_MODULE node for external modules
1238
- const isRelative = source.startsWith('./') || source.startsWith('../');
1239
- if (!isRelative) {
1240
- const externalModule = NodeFactory.createExternalModule(source);
1241
-
1242
- // Avoid duplicate EXTERNAL_MODULE nodes
1243
- if (!this._createdSingletons.has(externalModule.id)) {
1244
- this._bufferNode(externalModule as unknown as GraphNode);
1245
- this._createdSingletons.add(externalModule.id);
1246
- }
1247
-
1248
- this._bufferEdge({
1249
- type: 'IMPORTS',
1250
- src: module.id,
1251
- dst: externalModule.id
1252
- });
1253
- }
1254
- }
1255
- }
1256
- }
1257
- }
1258
-
1259
- private bufferExportNodes(module: ModuleNode, exports: ExportInfo[]): void {
1260
- for (const exp of exports) {
1261
- const { type, line, name, specifiers, source } = exp;
1262
-
1263
- if (type === 'default') {
1264
- const exportNode = NodeFactory.createExport(
1265
- 'default',
1266
- module.file,
1267
- line,
1268
- 0,
1269
- { default: true, exportType: 'default' }
1270
- );
1271
-
1272
- this._bufferNode(exportNode as unknown as GraphNode);
1273
-
1274
- this._bufferEdge({
1275
- type: 'CONTAINS',
1276
- src: module.id,
1277
- dst: exportNode.id
1278
- });
1279
- } else if (type === 'named') {
1280
- if (specifiers) {
1281
- for (const spec of specifiers) {
1282
- const exportNode = NodeFactory.createExport(
1283
- spec.exported,
1284
- module.file,
1285
- line,
1286
- 0,
1287
- {
1288
- local: spec.local,
1289
- source: source,
1290
- exportType: 'named'
1291
- }
1292
- );
1293
-
1294
- this._bufferNode(exportNode as unknown as GraphNode);
1295
-
1296
- this._bufferEdge({
1297
- type: 'CONTAINS',
1298
- src: module.id,
1299
- dst: exportNode.id
1300
- });
1301
- }
1302
- } else if (name) {
1303
- const exportNode = NodeFactory.createExport(
1304
- name,
1305
- module.file,
1306
- line,
1307
- 0,
1308
- { exportType: 'named' }
1309
- );
1310
-
1311
- this._bufferNode(exportNode as unknown as GraphNode);
1312
-
1313
- this._bufferEdge({
1314
- type: 'CONTAINS',
1315
- src: module.id,
1316
- dst: exportNode.id
1317
- });
1318
- }
1319
- } else if (type === 'all') {
1320
- const exportNode = NodeFactory.createExport(
1321
- '*',
1322
- module.file,
1323
- line,
1324
- 0,
1325
- {
1326
- source: source,
1327
- exportType: 'all'
1328
- }
1329
- );
1330
-
1331
- this._bufferNode(exportNode as unknown as GraphNode);
1332
-
1333
- this._bufferEdge({
1334
- type: 'CONTAINS',
1335
- src: module.id,
1336
- dst: exportNode.id
1337
- });
1338
- }
1339
- }
1340
- }
1341
-
1342
- private bufferEventListeners(eventListeners: EventListenerInfo[], functions: FunctionInfo[]): void {
1343
- for (const eventListener of eventListeners) {
1344
- const { parentScopeId, callbackArg, ...listenerData } = eventListener;
1345
-
1346
- this._bufferNode(listenerData as GraphNode);
1347
-
1348
- this._bufferEdge({
1349
- type: 'CONTAINS',
1350
- src: parentScopeId as string,
1351
- dst: listenerData.id
1352
- });
1353
-
1354
- if (callbackArg && callbackArg.type === 'ArrowFunctionExpression') {
1355
- const callbackLine = (callbackArg.loc as { start: { line: number } }).start.line;
1356
- const callbackFunction = functions.find(f =>
1357
- f.line === callbackLine && f.arrowFunction
1358
- );
1359
-
1360
- if (callbackFunction) {
1361
- this._bufferEdge({
1362
- type: 'HANDLED_BY',
1363
- src: listenerData.id,
1364
- dst: callbackFunction.id
1365
- });
1366
- }
1367
- }
1368
- }
1369
- }
1370
-
1371
- private bufferHttpRequests(httpRequests: HttpRequestInfo[], functions: FunctionInfo[]): void {
1372
- if (httpRequests.length > 0) {
1373
- // Create net:request singleton using factory
1374
- const networkNode = NetworkRequestNode.create();
1375
-
1376
- if (!this._createdSingletons.has(networkNode.id)) {
1377
- this._bufferNode(networkNode as unknown as GraphNode);
1378
- this._createdSingletons.add(networkNode.id);
1379
- }
1380
-
1381
- for (const request of httpRequests) {
1382
- const { parentScopeId, ...requestData } = request;
1383
-
1384
- this._bufferNode(requestData as GraphNode);
1385
-
1386
- this._bufferEdge({
1387
- type: 'CALLS',
1388
- src: request.id,
1389
- dst: networkNode.id
1390
- });
1391
-
1392
- if (parentScopeId) {
1393
- const scopeParts = parentScopeId.split(':');
1394
- if (scopeParts.length >= 3 && scopeParts[1] === 'SCOPE') {
1395
- const functionName = scopeParts[2];
1396
- const file = scopeParts[0];
1397
-
1398
- const parentFunction = functions.find(f =>
1399
- f.file === file && f.name === functionName
1400
- );
1401
-
1402
- if (parentFunction) {
1403
- this._bufferEdge({
1404
- type: 'MAKES_REQUEST',
1405
- src: parentFunction.id,
1406
- dst: request.id
1407
- });
1408
- }
1409
- }
1410
- }
1411
- }
1412
- }
1413
- }
1414
-
1415
- private bufferLiterals(literals: LiteralInfo[]): void {
1416
- for (const literal of literals) {
1417
- const { parentCallId: _parentCallId, argIndex: _argIndex, ...literalData } = literal;
1418
- this._bufferNode(literalData as GraphNode);
1419
- }
1420
- }
1421
-
1422
- private bufferAssignmentEdges(
1423
- variableAssignments: VariableAssignmentInfo[],
1424
- variableDeclarations: VariableDeclarationInfo[],
1425
- callSites: CallSiteInfo[],
1426
- methodCalls: MethodCallInfo[],
1427
- functions: FunctionInfo[],
1428
- classInstantiations: ClassInstantiationInfo[],
1429
- parameters: ParameterInfo[]
1430
- ): void {
1431
- for (const assignment of variableAssignments) {
1432
- const {
1433
- variableId,
1434
- sourceId,
1435
- sourceType,
1436
- sourceName,
1437
- sourceLine,
1438
- sourceColumn,
1439
- sourceFile,
1440
- functionName,
1441
- line,
1442
- column,
1443
- className
1444
- } = assignment;
1445
-
1446
- // Skip CLASS sourceType - handled async in createClassAssignmentEdges
1447
- if (sourceType === 'CLASS') {
1448
- continue;
1449
- }
1450
-
1451
- // CONSTRUCTOR_CALL: create ASSIGNED_FROM edge to existing node
1452
- // Note: CONSTRUCTOR_CALL nodes are already created from constructorCalls collection in step 4.5
1453
- if (sourceType === 'CONSTRUCTOR_CALL' && className) {
1454
- const constructorLine = line ?? 0;
1455
- const constructorColumn = column ?? 0;
1456
- const constructorFile = assignment.file ?? '';
1457
-
1458
- // Generate ID matching the one created in NewExpression visitor
1459
- const constructorCallId = NodeFactory.generateConstructorCallId(
1460
- className,
1461
- constructorFile,
1462
- constructorLine,
1463
- constructorColumn
1464
- );
1465
-
1466
- this._bufferEdge({
1467
- type: 'ASSIGNED_FROM',
1468
- src: variableId,
1469
- dst: constructorCallId
1470
- });
1471
- continue;
1472
- }
1473
-
1474
- // Direct LITERAL assignment
1475
- if (sourceId && sourceType !== 'EXPRESSION') {
1476
- this._bufferEdge({
1477
- type: 'ASSIGNED_FROM',
1478
- src: variableId,
1479
- dst: sourceId
1480
- });
1481
- }
1482
- // METHOD_CALL by coordinates
1483
- else if (sourceType === 'METHOD_CALL' && sourceLine && sourceColumn) {
1484
- const methodCall = methodCalls.find(mc =>
1485
- mc.line === sourceLine &&
1486
- mc.column === sourceColumn &&
1487
- mc.file === sourceFile
1488
- );
1489
-
1490
- if (methodCall) {
1491
- this._bufferEdge({
1492
- type: 'ASSIGNED_FROM',
1493
- src: variableId,
1494
- dst: methodCall.id
1495
- });
1496
- }
1497
- }
1498
- // CALL_SITE by coordinates
1499
- else if (sourceType === 'CALL_SITE') {
1500
- const searchLine = sourceLine || assignment.callLine;
1501
- const searchColumn = sourceColumn || assignment.callColumn;
1502
- const searchName = assignment.callName;
1503
-
1504
- if (searchLine && searchColumn) {
1505
- const callSite = callSites.find(cs =>
1506
- cs.line === searchLine &&
1507
- cs.column === searchColumn &&
1508
- (searchName ? cs.name === searchName : true)
1509
- );
1510
-
1511
- if (callSite) {
1512
- this._bufferEdge({
1513
- type: 'ASSIGNED_FROM',
1514
- src: variableId,
1515
- dst: callSite.id
1516
- });
1517
- }
1518
- }
1519
- }
1520
- // VARIABLE by name
1521
- else if (sourceType === 'VARIABLE' && sourceName) {
1522
- // Find the current variable's file by looking it up in variableDeclarations
1523
- // (semantic IDs don't have predictable file positions like old hash-based IDs)
1524
- const currentVar = variableDeclarations.find(v => v.id === variableId);
1525
- const varFile = currentVar?.file ?? null;
1526
- const sourceVariable = variableDeclarations.find(v =>
1527
- v.name === sourceName && v.file === varFile
1528
- );
1529
-
1530
- if (sourceVariable) {
1531
- this._bufferEdge({
1532
- type: 'ASSIGNED_FROM',
1533
- src: variableId,
1534
- dst: sourceVariable.id
1535
- });
1536
- } else {
1537
- const sourceParam = parameters.find(p =>
1538
- p.name === sourceName && p.file === varFile
1539
- );
1540
-
1541
- if (sourceParam) {
1542
- this._bufferEdge({
1543
- type: 'DERIVES_FROM',
1544
- src: variableId,
1545
- dst: sourceParam.id
1546
- });
1547
- }
1548
- }
1549
- }
1550
- // FUNCTION (arrow function assigned to variable)
1551
- else if (sourceType === 'FUNCTION' && functionName && line) {
1552
- const sourceFunction = functions.find(f =>
1553
- f.name === functionName && f.line === line
1554
- );
1555
-
1556
- if (sourceFunction) {
1557
- this._bufferEdge({
1558
- type: 'ASSIGNED_FROM',
1559
- src: variableId,
1560
- dst: sourceFunction.id
1561
- });
1562
- }
1563
- }
1564
- // EXPRESSION node creation using NodeFactory
1565
- else if (sourceType === 'EXPRESSION' && sourceId) {
1566
- const {
1567
- expressionType,
1568
- object,
1569
- property,
1570
- computed,
1571
- computedPropertyVar,
1572
- operator,
1573
- objectSourceName,
1574
- leftSourceName,
1575
- rightSourceName,
1576
- consequentSourceName,
1577
- alternateSourceName,
1578
- file: exprFile,
1579
- line: exprLine,
1580
- column: exprColumn,
1581
- // Destructuring support (REG-201)
1582
- path,
1583
- baseName,
1584
- propertyPath,
1585
- arrayIndex
1586
- } = assignment;
1587
-
1588
- // Create node from upstream metadata using factory
1589
- const expressionNode = NodeFactory.createExpressionFromMetadata(
1590
- expressionType || 'Unknown',
1591
- exprFile || '',
1592
- exprLine || 0,
1593
- exprColumn || 0,
1594
- {
1595
- id: sourceId, // ID from JSASTAnalyzer
1596
- object,
1597
- property,
1598
- computed,
1599
- computedPropertyVar: computedPropertyVar ?? undefined,
1600
- operator,
1601
- // Destructuring support (REG-201)
1602
- path,
1603
- baseName,
1604
- propertyPath,
1605
- arrayIndex
1606
- }
1607
- );
1608
-
1609
- this._bufferNode(expressionNode);
1610
-
1611
- this._bufferEdge({
1612
- type: 'ASSIGNED_FROM',
1613
- src: variableId,
1614
- dst: sourceId
1615
- });
1616
-
1617
- // Buffer DERIVES_FROM edges
1618
- const varParts = variableId.split('#');
1619
- const varFile = varParts.length >= 3 ? varParts[2] : null;
1620
-
1621
- if (expressionType === 'MemberExpression' && objectSourceName) {
1622
- const objectVar = variableDeclarations.find(v =>
1623
- v.name === objectSourceName && (!varFile || v.file === varFile)
1624
- );
1625
- if (objectVar) {
1626
- this._bufferEdge({
1627
- type: 'DERIVES_FROM',
1628
- src: sourceId,
1629
- dst: objectVar.id
1630
- });
1631
- }
1632
- }
1633
- // Call-based source lookup (REG-223)
1634
- else if (expressionType === 'MemberExpression' && assignment.callSourceLine !== undefined) {
1635
- const { callSourceLine, callSourceColumn, callSourceName, callSourceFile } = assignment;
1636
-
1637
- // Try CALL_SITE first (direct function calls)
1638
- const callSite = callSites.find(cs =>
1639
- cs.line === callSourceLine &&
1640
- cs.column === callSourceColumn &&
1641
- (callSourceName ? cs.name === callSourceName : true)
1642
- );
1643
-
1644
- if (callSite) {
1645
- this._bufferEdge({
1646
- type: 'DERIVES_FROM',
1647
- src: sourceId,
1648
- dst: callSite.id
1649
- });
1650
- }
1651
- // Fall back to methodCalls (arr.map(), obj.getConfig())
1652
- else {
1653
- const methodCall = methodCalls.find(mc =>
1654
- mc.line === callSourceLine &&
1655
- mc.column === callSourceColumn &&
1656
- (callSourceName ? mc.name === callSourceName : true)
1657
- );
1658
-
1659
- if (methodCall) {
1660
- this._bufferEdge({
1661
- type: 'DERIVES_FROM',
1662
- src: sourceId,
1663
- dst: methodCall.id
1664
- });
1665
- }
1666
- // Log warning when lookup fails (per Linus review - no silent failures)
1667
- else {
1668
- console.warn(
1669
- `[REG-223] DERIVES_FROM lookup failed for EXPRESSION(${assignment.object}.${assignment.property}) ` +
1670
- `at ${callSourceFile}:${callSourceLine}:${callSourceColumn}. ` +
1671
- `Expected CALL_SITE or methodCall for "${callSourceName}". ` +
1672
- `This indicates a coordinate mismatch or missing call node.`
1673
- );
1674
- }
1675
- }
1676
- }
1677
-
1678
- if ((expressionType === 'BinaryExpression' || expressionType === 'LogicalExpression')) {
1679
- if (leftSourceName) {
1680
- const leftVar = variableDeclarations.find(v =>
1681
- v.name === leftSourceName && (!varFile || v.file === varFile)
1682
- );
1683
- if (leftVar) {
1684
- this._bufferEdge({
1685
- type: 'DERIVES_FROM',
1686
- src: sourceId,
1687
- dst: leftVar.id
1688
- });
1689
- }
1690
- }
1691
- if (rightSourceName) {
1692
- const rightVar = variableDeclarations.find(v =>
1693
- v.name === rightSourceName && (!varFile || v.file === varFile)
1694
- );
1695
- if (rightVar) {
1696
- this._bufferEdge({
1697
- type: 'DERIVES_FROM',
1698
- src: sourceId,
1699
- dst: rightVar.id
1700
- });
1701
- }
1702
- }
1703
- }
1704
-
1705
- if (expressionType === 'ConditionalExpression') {
1706
- if (consequentSourceName) {
1707
- const consequentVar = variableDeclarations.find(v =>
1708
- v.name === consequentSourceName && (!varFile || v.file === varFile)
1709
- );
1710
- if (consequentVar) {
1711
- this._bufferEdge({
1712
- type: 'DERIVES_FROM',
1713
- src: sourceId,
1714
- dst: consequentVar.id
1715
- });
1716
- }
1717
- }
1718
- if (alternateSourceName) {
1719
- const alternateVar = variableDeclarations.find(v =>
1720
- v.name === alternateSourceName && (!varFile || v.file === varFile)
1721
- );
1722
- if (alternateVar) {
1723
- this._bufferEdge({
1724
- type: 'DERIVES_FROM',
1725
- src: sourceId,
1726
- dst: alternateVar.id
1727
- });
1728
- }
1729
- }
1730
- }
1731
-
1732
- if (expressionType === 'TemplateLiteral') {
1733
- const { expressionSourceNames } = assignment;
1734
- if (expressionSourceNames && expressionSourceNames.length > 0) {
1735
- for (const exprSourceName of expressionSourceNames) {
1736
- const sourceVar = variableDeclarations.find(v =>
1737
- v.name === exprSourceName && (!varFile || v.file === varFile)
1738
- );
1739
- if (sourceVar) {
1740
- this._bufferEdge({
1741
- type: 'DERIVES_FROM',
1742
- src: sourceId,
1743
- dst: sourceVar.id
1744
- });
1745
- }
1746
- }
1747
- }
1748
- }
1749
- }
1750
- // DERIVES_FROM_VARIABLE
1751
- else if (sourceType === 'DERIVES_FROM_VARIABLE' && sourceName) {
1752
- const expressionId = variableId;
1753
- const exprParts = expressionId.split('#');
1754
- const exprFile = exprParts.length >= 3 ? exprParts[2] : assignment.file;
1755
-
1756
- const sourceVariable = variableDeclarations.find(v =>
1757
- v.name === sourceName && v.file === exprFile
1758
- );
1759
-
1760
- if (sourceVariable) {
1761
- this._bufferEdge({
1762
- type: 'DERIVES_FROM',
1763
- src: expressionId,
1764
- dst: sourceVariable.id
1765
- });
1766
- } else {
1767
- const sourceParam = parameters.find(p =>
1768
- p.name === sourceName && p.file === exprFile
1769
- );
1770
-
1771
- if (sourceParam) {
1772
- this._bufferEdge({
1773
- type: 'DERIVES_FROM',
1774
- src: expressionId,
1775
- dst: sourceParam.id
1776
- });
1777
- }
1778
- }
1779
- }
1780
- }
1781
- }
1782
-
1783
- private bufferArgumentEdges(
1784
- callArguments: CallArgumentInfo[],
1785
- variableDeclarations: VariableDeclarationInfo[],
1786
- functions: FunctionInfo[],
1787
- callSites: CallSiteInfo[],
1788
- methodCalls: MethodCallInfo[]
1789
- ): void {
1790
- for (const arg of callArguments) {
1791
- const {
1792
- callId,
1793
- argIndex,
1794
- targetType,
1795
- targetId,
1796
- targetName,
1797
- file,
1798
- isSpread,
1799
- functionLine,
1800
- functionColumn,
1801
- nestedCallLine,
1802
- nestedCallColumn
1803
- } = arg;
1804
-
1805
- let targetNodeId = targetId;
1806
-
1807
- if (targetType === 'VARIABLE' && targetName) {
1808
- const varNode = variableDeclarations.find(v =>
1809
- v.name === targetName && v.file === file
1810
- );
1811
- if (varNode) {
1812
- targetNodeId = varNode.id;
1813
- }
1814
- }
1815
- else if (targetType === 'FUNCTION' && functionLine && functionColumn) {
1816
- const funcNode = functions.find(f =>
1817
- f.file === file && f.line === functionLine && f.column === functionColumn
1818
- );
1819
- if (funcNode) {
1820
- targetNodeId = funcNode.id;
1821
- }
1822
- }
1823
- else if (targetType === 'CALL' && nestedCallLine && nestedCallColumn) {
1824
- const nestedCall = callSites.find(c =>
1825
- c.file === file && c.line === nestedCallLine && c.column === nestedCallColumn
1826
- ) || methodCalls.find(c =>
1827
- c.file === file && c.line === nestedCallLine && c.column === nestedCallColumn
1828
- );
1829
- if (nestedCall) {
1830
- targetNodeId = nestedCall.id;
1831
- }
1832
- }
1833
- else if (targetType === 'LITERAL' ||
1834
- targetType === 'OBJECT_LITERAL' ||
1835
- targetType === 'ARRAY_LITERAL') {
1836
- // targetId is already set by CallExpressionVisitor
1837
- targetNodeId = targetId;
1838
- }
1839
-
1840
- if (targetNodeId) {
1841
- const edgeData: GraphEdge = {
1842
- type: 'PASSES_ARGUMENT',
1843
- src: callId,
1844
- dst: targetNodeId,
1845
- metadata: { argIndex }
1846
- };
1847
-
1848
- if (isSpread) {
1849
- edgeData.metadata = { ...edgeData.metadata, isSpread: true };
1850
- }
1851
-
1852
- this._bufferEdge(edgeData);
1853
- }
1854
- }
1855
- }
1856
-
1857
- // ============= TypeScript-specific buffer methods =============
1858
-
1859
- /**
1860
- * Buffer INTERFACE nodes and EXTENDS edges
1861
- *
1862
- * Uses two-pass approach:
1863
- * 1. First pass: create all interface nodes, store in Map
1864
- * 2. Second pass: create EXTENDS edges using stored node IDs
1865
- */
1866
- private bufferInterfaceNodes(module: ModuleNode, interfaces: InterfaceDeclarationInfo[]): void {
1867
- // First pass: create all interface nodes and store them
1868
- const interfaceNodes = new Map<string, InterfaceNodeRecord>();
1869
-
1870
- for (const iface of interfaces) {
1871
- const interfaceNode = InterfaceNode.create(
1872
- iface.name,
1873
- iface.file,
1874
- iface.line,
1875
- iface.column || 0,
1876
- {
1877
- extends: iface.extends,
1878
- properties: iface.properties
1879
- }
1880
- );
1881
- interfaceNodes.set(iface.name, interfaceNode);
1882
- this._bufferNode(interfaceNode as unknown as GraphNode);
1883
-
1884
- // MODULE -> CONTAINS -> INTERFACE
1885
- this._bufferEdge({
1886
- type: 'CONTAINS',
1887
- src: module.id,
1888
- dst: interfaceNode.id
1889
- });
1890
- }
1891
-
1892
- // Second pass: create EXTENDS edges
1893
- for (const iface of interfaces) {
1894
- if (iface.extends && iface.extends.length > 0) {
1895
- const srcNode = interfaceNodes.get(iface.name)!;
1896
-
1897
- for (const parentName of iface.extends) {
1898
- const parentNode = interfaceNodes.get(parentName);
1899
-
1900
- if (parentNode) {
1901
- // Same-file interface
1902
- this._bufferEdge({
1903
- type: 'EXTENDS',
1904
- src: srcNode.id,
1905
- dst: parentNode.id
1906
- });
1907
- } else {
1908
- // External interface - create a reference node
1909
- const externalInterface = NodeFactory.createInterface(
1910
- parentName,
1911
- iface.file,
1912
- iface.line,
1913
- 0,
1914
- { isExternal: true }
1915
- );
1916
- this._bufferNode(externalInterface as unknown as GraphNode);
1917
- this._bufferEdge({
1918
- type: 'EXTENDS',
1919
- src: srcNode.id,
1920
- dst: externalInterface.id
1921
- });
1922
- }
1923
- }
1924
- }
1925
- }
1926
- }
1927
-
1928
- /**
1929
- * Buffer TYPE alias nodes
1930
- */
1931
- private bufferTypeAliasNodes(module: ModuleNode, typeAliases: TypeAliasInfo[]): void {
1932
- for (const typeAlias of typeAliases) {
1933
- // Create TYPE node using factory
1934
- const typeNode = NodeFactory.createType(
1935
- typeAlias.name,
1936
- typeAlias.file,
1937
- typeAlias.line,
1938
- typeAlias.column || 0,
1939
- { aliasOf: typeAlias.aliasOf }
1940
- );
1941
- this._bufferNode(typeNode as unknown as GraphNode);
1942
-
1943
- // MODULE -> CONTAINS -> TYPE
1944
- this._bufferEdge({
1945
- type: 'CONTAINS',
1946
- src: module.id,
1947
- dst: typeNode.id
1948
- });
1949
- }
1950
- }
1951
-
1952
- /**
1953
- * Buffer ENUM nodes
1954
- * Uses EnumNode.create() to ensure consistent ID format (colon separator)
1955
- */
1956
- private bufferEnumNodes(module: ModuleNode, enums: EnumDeclarationInfo[]): void {
1957
- for (const enumDecl of enums) {
1958
- // Use EnumNode.create() to generate proper ID (colon format)
1959
- // Do NOT use enumDecl.id which has legacy # format from TypeScriptVisitor
1960
- const enumNode = EnumNode.create(
1961
- enumDecl.name,
1962
- enumDecl.file,
1963
- enumDecl.line,
1964
- enumDecl.column || 0,
1965
- {
1966
- isConst: enumDecl.isConst || false,
1967
- members: enumDecl.members || []
1968
- }
1969
- );
1970
-
1971
- this._bufferNode(enumNode as unknown as GraphNode);
1972
-
1973
- // MODULE -> CONTAINS -> ENUM
1974
- this._bufferEdge({
1975
- type: 'CONTAINS',
1976
- src: module.id,
1977
- dst: enumNode.id // Use factory-generated ID (colon format)
1978
- });
1979
- }
1980
- }
1981
-
1982
- /**
1983
- * Buffer DECORATOR nodes and DECORATED_BY edges
1984
- */
1985
- private bufferDecoratorNodes(decorators: DecoratorInfo[]): void {
1986
- for (const decorator of decorators) {
1987
- // Create DECORATOR node using factory (generates colon-format ID)
1988
- const decoratorNode = DecoratorNode.create(
1989
- decorator.name,
1990
- decorator.file,
1991
- decorator.line,
1992
- decorator.column || 0,
1993
- decorator.targetId, // Now included in the node!
1994
- decorator.targetType,
1995
- { arguments: decorator.arguments }
1996
- );
1997
-
1998
- this._bufferNode(decoratorNode as unknown as GraphNode);
1999
-
2000
- // TARGET -> DECORATED_BY -> DECORATOR
2001
- this._bufferEdge({
2002
- type: 'DECORATED_BY',
2003
- src: decorator.targetId,
2004
- dst: decoratorNode.id // Use factory-generated ID (colon format)
2005
- });
2006
- }
2007
- }
2008
-
2009
- /**
2010
- * Buffer IMPLEMENTS edges (CLASS -> INTERFACE)
2011
- */
2012
- private bufferImplementsEdges(classDeclarations: ClassDeclarationInfo[], interfaces: InterfaceDeclarationInfo[]): void {
2013
- for (const classDecl of classDeclarations) {
2014
- if (classDecl.implements && classDecl.implements.length > 0) {
2015
- for (const ifaceName of classDecl.implements) {
2016
- // Try to find the interface in the same file
2017
- const iface = interfaces.find(i => i.name === ifaceName);
2018
- if (iface) {
2019
- // Compute interface ID using same formula as InterfaceNode.create()
2020
- // Format: {file}:INTERFACE:{name}:{line}
2021
- const interfaceId = `${iface.file}:INTERFACE:${iface.name}:${iface.line}`;
2022
- this._bufferEdge({
2023
- type: 'IMPLEMENTS',
2024
- src: classDecl.id,
2025
- dst: interfaceId
2026
- });
2027
- } else {
2028
- // External interface - create a reference node
2029
- const externalInterface = NodeFactory.createInterface(
2030
- ifaceName,
2031
- classDecl.file,
2032
- classDecl.line,
2033
- 0,
2034
- { isExternal: true }
2035
- );
2036
- this._bufferNode(externalInterface as unknown as GraphNode);
2037
- this._bufferEdge({
2038
- type: 'IMPLEMENTS',
2039
- src: classDecl.id,
2040
- dst: externalInterface.id
2041
- });
2042
- }
2043
- }
2044
- }
2045
- }
2046
- }
2047
-
2048
- /**
2049
- * Buffer FLOWS_INTO edges for array mutations (push, unshift, splice, indexed assignment)
2050
- * Creates edges from inserted values to the array variable.
2051
- *
2052
- * REG-117: Handles nested mutations like obj.arr.push(item)
2053
- * REG-392: Handles non-variable values (LITERAL, OBJECT_LITERAL, ARRAY_LITERAL, CALL)
2054
- */
2055
- private bufferArrayMutationEdges(
2056
- arrayMutations: ArrayMutationInfo[],
2057
- variableDeclarations: VariableDeclarationInfo[],
2058
- parameters: ParameterInfo[],
2059
- literals: LiteralInfo[],
2060
- objectLiterals: ObjectLiteralInfo[],
2061
- arrayLiterals: ArrayLiteralInfo[],
2062
- callSites: CallSiteInfo[]
2063
- ): void {
2064
- for (const mutation of arrayMutations) {
2065
- const { arrayName, mutationScopePath, mutationMethod, insertedValues, file, isNested, baseObjectName, propertyName } = mutation;
2066
-
2067
- const scopePath = mutationScopePath ?? [];
2068
-
2069
- // REG-117: For nested mutations (obj.arr.push), resolve target node
2070
- let targetNodeId: string | null = null;
2071
- let nestedProperty: string | undefined;
2072
-
2073
- if (isNested && baseObjectName) {
2074
- // Skip 'this.items.push' - 'this' is not a variable node
2075
- if (baseObjectName === 'this') continue;
2076
-
2077
- // Nested mutation: try base object lookup with scope chain (REG-309)
2078
- const baseVar = this.resolveVariableInScope(baseObjectName, scopePath, file, variableDeclarations);
2079
- const baseParam = !baseVar ? this.resolveParameterInScope(baseObjectName, scopePath, file, parameters) : null;
2080
- targetNodeId = baseVar?.id ?? baseParam?.id ?? null;
2081
- nestedProperty = propertyName;
2082
- } else {
2083
- // Direct mutation: arr.push() (REG-309)
2084
- const arrayVar = this.resolveVariableInScope(arrayName, scopePath, file, variableDeclarations);
2085
- const arrayParam = !arrayVar ? this.resolveParameterInScope(arrayName, scopePath, file, parameters) : null;
2086
- targetNodeId = arrayVar?.id ?? arrayParam?.id ?? null;
2087
- }
2088
-
2089
- if (!targetNodeId) continue;
2090
-
2091
- // Create FLOWS_INTO edges for each inserted value
2092
- for (const arg of insertedValues) {
2093
- let sourceNodeId: string | undefined;
2094
-
2095
- if (arg.valueType === 'VARIABLE' && arg.valueName) {
2096
- // Scope-aware lookup for source variable (REG-309)
2097
- const sourceVar = this.resolveVariableInScope(arg.valueName, scopePath, file, variableDeclarations);
2098
- const sourceParam = !sourceVar ? this.resolveParameterInScope(arg.valueName, scopePath, file, parameters) : null;
2099
- sourceNodeId = sourceVar?.id ?? sourceParam?.id;
2100
- } else if (arg.valueNodeId) {
2101
- // REG-392: Direct node ID for indexed assignments (LITERAL, OBJECT_LITERAL, ARRAY_LITERAL)
2102
- sourceNodeId = arg.valueNodeId;
2103
- } else if (arg.valueType === 'LITERAL' && arg.valueLine !== undefined && arg.valueColumn !== undefined) {
2104
- // REG-392: Find LITERAL node by coordinates (push/unshift — nodes created by extractArguments)
2105
- const literalNode = literals.find(l =>
2106
- l.line === arg.valueLine && l.column === arg.valueColumn && l.file === file
2107
- );
2108
- sourceNodeId = literalNode?.id;
2109
- } else if (arg.valueType === 'OBJECT_LITERAL' && arg.valueLine !== undefined && arg.valueColumn !== undefined) {
2110
- // REG-392: Find OBJECT_LITERAL node by coordinates
2111
- const objNode = objectLiterals.find(o =>
2112
- o.line === arg.valueLine && o.column === arg.valueColumn && o.file === file
2113
- );
2114
- sourceNodeId = objNode?.id;
2115
- } else if (arg.valueType === 'ARRAY_LITERAL' && arg.valueLine !== undefined && arg.valueColumn !== undefined) {
2116
- // REG-392: Find ARRAY_LITERAL node by coordinates
2117
- const arrNode = arrayLiterals.find(a =>
2118
- a.line === arg.valueLine && a.column === arg.valueColumn && a.file === file
2119
- );
2120
- sourceNodeId = arrNode?.id;
2121
- } else if (arg.valueType === 'CALL' && arg.callLine !== undefined && arg.callColumn !== undefined) {
2122
- // REG-392: Find CALL_SITE node by coordinates
2123
- const callSite = callSites.find(cs =>
2124
- cs.line === arg.callLine && cs.column === arg.callColumn && cs.file === file
2125
- );
2126
- sourceNodeId = callSite?.id;
2127
- }
2128
-
2129
- if (sourceNodeId) {
2130
- const edgeData: GraphEdge = {
2131
- type: 'FLOWS_INTO',
2132
- src: sourceNodeId,
2133
- dst: targetNodeId,
2134
- mutationMethod,
2135
- argIndex: arg.argIndex
2136
- };
2137
- if (arg.isSpread) {
2138
- edgeData.isSpread = true;
2139
- }
2140
- if (nestedProperty) {
2141
- edgeData.nestedProperty = nestedProperty;
2142
- }
2143
- this._bufferEdge(edgeData);
2144
- }
2145
- }
2146
- }
2147
- }
2148
-
2149
- /**
2150
- * Buffer FLOWS_INTO edges for object mutations (property assignment, Object.assign)
2151
- * Creates edges from source values to the object variable being mutated.
2152
- *
2153
- * REG-152: For 'this.prop = value' patterns inside classes, creates edges
2154
- * to the CLASS node with mutationType: 'this_property'.
2155
- */
2156
- private bufferObjectMutationEdges(
2157
- objectMutations: ObjectMutationInfo[],
2158
- variableDeclarations: VariableDeclarationInfo[],
2159
- parameters: ParameterInfo[],
2160
- functions: FunctionInfo[],
2161
- classDeclarations: ClassDeclarationInfo[]
2162
- ): void {
2163
- for (const mutation of objectMutations) {
2164
- const { objectName, mutationScopePath, propertyName, mutationType, computedPropertyVar, value, file, enclosingClassName } = mutation;
2165
-
2166
- const scopePath = mutationScopePath ?? [];
2167
-
2168
- // Find the target node (object variable, parameter, or class for 'this')
2169
- let objectNodeId: string | null = null;
2170
- let effectiveMutationType: 'property' | 'computed' | 'assign' | 'spread' | 'this_property' = mutationType;
2171
-
2172
- if (objectName !== 'this') {
2173
- // Regular object - find variable, parameter, or function using scope chain (REG-309)
2174
- const objectVar = this.resolveVariableInScope(objectName, scopePath, file, variableDeclarations);
2175
- const objectParam = !objectVar ? this.resolveParameterInScope(objectName, scopePath, file, parameters) : null;
2176
- const objectFunc = !objectVar && !objectParam ? functions.find(f => f.name === objectName && f.file === file) : null;
2177
- objectNodeId = objectVar?.id ?? objectParam?.id ?? objectFunc?.id ?? null;
2178
- if (!objectNodeId) continue;
2179
- } else {
2180
- // REG-152: 'this' mutations - find the CLASS node
2181
- if (!enclosingClassName) continue; // Skip if no class context (e.g., standalone function)
2182
-
2183
- // Compare using basename since classes use scopeTracker.file (basename)
2184
- // but mutations use module.file (full path)
2185
- const fileBasename = basename(file);
2186
- const classDecl = classDeclarations.find(c => c.name === enclosingClassName && c.file === fileBasename);
2187
- objectNodeId = classDecl?.id ?? null;
2188
-
2189
- if (!objectNodeId) continue; // Skip if class not found
2190
-
2191
- // Use special mutation type to distinguish from regular property mutations
2192
- effectiveMutationType = 'this_property';
2193
- }
2194
-
2195
- // Create FLOWS_INTO edge for VARIABLE value type
2196
- if (value.valueType === 'VARIABLE' && value.valueName) {
2197
- // Find the source: can be variable, parameter, or function using scope chain (REG-309)
2198
- const sourceVar = this.resolveVariableInScope(value.valueName, scopePath, file, variableDeclarations);
2199
- const sourceParam = !sourceVar ? this.resolveParameterInScope(value.valueName, scopePath, file, parameters) : null;
2200
- const sourceFunc = !sourceVar && !sourceParam ? functions.find(f => f.name === value.valueName && f.file === file) : null;
2201
- const sourceNodeId = sourceVar?.id ?? sourceParam?.id ?? sourceFunc?.id;
2202
-
2203
- if (sourceNodeId && objectNodeId) {
2204
- const edgeData: GraphEdge = {
2205
- type: 'FLOWS_INTO',
2206
- src: sourceNodeId,
2207
- dst: objectNodeId,
2208
- mutationType: effectiveMutationType,
2209
- propertyName,
2210
- computedPropertyVar // For enrichment phase resolution
2211
- };
2212
- if (value.argIndex !== undefined) {
2213
- edgeData.argIndex = value.argIndex;
2214
- }
2215
- if (value.isSpread) {
2216
- edgeData.isSpread = true;
2217
- }
2218
- this._bufferEdge(edgeData);
2219
- }
2220
- }
2221
- // For literals, object literals, etc. - we just track variable -> object flows for now
2222
- }
2223
- }
2224
-
2225
- /**
2226
- * Resolve variable by name using scope chain lookup (REG-309).
2227
- * Mirrors JavaScript lexical scoping: search current scope, then parent, then grandparent, etc.
2228
- *
2229
- * @param name - Variable name
2230
- * @param scopePath - Scope path where reference occurs (from ScopeTracker)
2231
- * @param file - File path
2232
- * @param variables - All variable declarations
2233
- * @returns Variable declaration or null if not found
2234
- */
2235
- private resolveVariableInScope(
2236
- name: string,
2237
- scopePath: string[],
2238
- file: string,
2239
- variables: VariableDeclarationInfo[]
2240
- ): VariableDeclarationInfo | null {
2241
- // Try current scope, then parent, then grandparent, etc.
2242
- for (let i = scopePath.length; i >= 0; i--) {
2243
- const searchScopePath = scopePath.slice(0, i);
2244
-
2245
- const matchingVar = variables.find(v => {
2246
- if (v.name !== name || v.file !== file) return false;
2247
-
2248
- // Variable ID IS the semantic ID (when scopeTracker was available during analysis)
2249
- // Format: file->scope1->scope2->TYPE->name
2250
- // Legacy format: VARIABLE#name#file#line:column:counter
2251
-
2252
- // Try parsing as semantic ID
2253
- const parsed = parseSemanticId(v.id);
2254
- // REG-329: Check for both VARIABLE and CONSTANT (const declarations)
2255
- if (parsed && (parsed.type === 'VARIABLE' || parsed.type === 'CONSTANT')) {
2256
- // FIXED (REG-309): Handle module-level scope matching
2257
- // Empty search scope [] should match semantic ID scope ['global']
2258
- if (searchScopePath.length === 0) {
2259
- return parsed.scopePath.length === 1 && parsed.scopePath[0] === 'global';
2260
- }
2261
- // Non-empty scope: exact match
2262
- return this.scopePathsMatch(parsed.scopePath, searchScopePath);
2263
- }
2264
-
2265
- // Legacy ID - assume module-level if no semantic ID
2266
- return searchScopePath.length === 0;
2267
- });
2268
-
2269
- if (matchingVar) return matchingVar;
2270
- }
2271
-
2272
- return null;
2273
- }
2274
-
2275
- /**
2276
- * Resolve parameter by name using scope chain lookup (REG-309).
2277
- * Same semantics as resolveVariableInScope but for parameters.
2278
- *
2279
- * @param name - Parameter name
2280
- * @param scopePath - Scope path where reference occurs (from ScopeTracker)
2281
- * @param file - File path
2282
- * @param parameters - All parameter declarations
2283
- * @returns Parameter declaration or null if not found
2284
- */
2285
- private resolveParameterInScope(
2286
- name: string,
2287
- scopePath: string[],
2288
- file: string,
2289
- parameters: ParameterInfo[]
2290
- ): ParameterInfo | null {
2291
- // Parameters have semanticId field populated (unlike variables which use id field)
2292
- return parameters.find(p => {
2293
- if (p.name !== name || p.file !== file) return false;
2294
-
2295
- if (p.semanticId) {
2296
- const parsed = parseSemanticId(p.semanticId);
2297
- if (parsed && parsed.type === 'PARAMETER') {
2298
- // Check if parameter's scope matches any scope in the chain
2299
- for (let i = scopePath.length; i >= 0; i--) {
2300
- const searchScopePath = scopePath.slice(0, i);
2301
-
2302
- // FIXED (REG-309): Handle module-level scope matching for parameters
2303
- if (searchScopePath.length === 0) {
2304
- if (parsed.scopePath.length === 1 && parsed.scopePath[0] === 'global') {
2305
- return true;
2306
- }
2307
- } else {
2308
- if (this.scopePathsMatch(parsed.scopePath, searchScopePath)) {
2309
- return true;
2310
- }
2311
- }
2312
- }
2313
- }
2314
- }
2315
- return false;
2316
- }) ?? null;
2317
- }
2318
-
2319
- /**
2320
- * Check if two scope paths match (REG-309).
2321
- * Handles: ['foo', 'if#0'] vs ['foo', 'if#0']
2322
- */
2323
- private scopePathsMatch(a: string[], b: string[]): boolean {
2324
- if (a.length !== b.length) return false;
2325
- return a.every((item, idx) => item === b[idx]);
2326
- }
2327
-
2328
- /**
2329
- * Buffer FLOWS_INTO edges for variable reassignments.
2330
- * Handles: x = y, x += y (when x is already declared, not initialization)
2331
- *
2332
- * Edge patterns:
2333
- * - Simple assignment (=): source --FLOWS_INTO--> variable
2334
- * - Compound operators (+=, -=, etc.):
2335
- * - source --FLOWS_INTO--> variable (write new value)
2336
- * - variable --READS_FROM--> variable (self-loop: reads current value before write)
2337
- *
2338
- * REG-309: Uses scope-aware variable lookup via resolveVariableInScope().
2339
- *
2340
- * REG-290: Complete implementation with inline node creation (no continue statements).
2341
- */
2342
- private bufferVariableReassignmentEdges(
2343
- variableReassignments: VariableReassignmentInfo[],
2344
- variableDeclarations: VariableDeclarationInfo[],
2345
- callSites: CallSiteInfo[],
2346
- methodCalls: MethodCallInfo[],
2347
- parameters: ParameterInfo[]
2348
- ): void {
2349
- // Note: No longer using Map-based cache - scope-aware lookup requires scope chain walk
2350
- // Performance: O(n*m*s) where s = scope depth (typically 2-3), acceptable for correctness
2351
-
2352
- for (const reassignment of variableReassignments) {
2353
- const {
2354
- variableName,
2355
- mutationScopePath,
2356
- valueType,
2357
- valueName,
2358
- valueId,
2359
- callLine,
2360
- callColumn,
2361
- operator,
2362
- literalValue,
2363
- expressionType,
2364
- expressionMetadata,
2365
- file,
2366
- line,
2367
- column
2368
- } = reassignment;
2369
-
2370
- // Find target variable node using scope chain resolution (REG-309)
2371
- const scopePath = mutationScopePath ?? [];
2372
- const targetVar = this.resolveVariableInScope(variableName, scopePath, file, variableDeclarations);
2373
- const targetParam = !targetVar ? this.resolveParameterInScope(variableName, scopePath, file, parameters) : null;
2374
- const targetNodeId = targetVar?.id ?? targetParam?.id;
2375
-
2376
- if (!targetNodeId) {
2377
- // Variable not found - could be external reference
2378
- continue;
2379
- }
2380
-
2381
- // Resolve source node based on value type
2382
- let sourceNodeId: string | null = null;
2383
-
2384
- // LITERAL: Create node inline (NO CONTINUE STATEMENT)
2385
- if (valueType === 'LITERAL' && valueId) {
2386
- // Create LITERAL node
2387
- this._bufferNode({
2388
- type: 'LITERAL',
2389
- id: valueId,
2390
- value: literalValue,
2391
- file,
2392
- line,
2393
- column
2394
- });
2395
- sourceNodeId = valueId;
2396
- }
2397
- // VARIABLE: Look up existing variable/parameter node using scope chain (REG-309)
2398
- else if (valueType === 'VARIABLE' && valueName) {
2399
- const sourceVar = this.resolveVariableInScope(valueName, scopePath, file, variableDeclarations);
2400
- const sourceParam = !sourceVar ? this.resolveParameterInScope(valueName, scopePath, file, parameters) : null;
2401
- sourceNodeId = sourceVar?.id ?? sourceParam?.id ?? null;
2402
- }
2403
- // CALL_SITE: Look up existing call node
2404
- else if (valueType === 'CALL_SITE' && callLine && callColumn) {
2405
- const callSite = callSites.find(cs =>
2406
- cs.line === callLine && cs.column === callColumn && cs.file === file
2407
- );
2408
- sourceNodeId = callSite?.id ?? null;
2409
- }
2410
- // METHOD_CALL: Look up existing method call node
2411
- else if (valueType === 'METHOD_CALL' && callLine && callColumn) {
2412
- const methodCall = methodCalls.find(mc =>
2413
- mc.line === callLine && mc.column === callColumn && mc.file === file
2414
- );
2415
- sourceNodeId = methodCall?.id ?? null;
2416
- }
2417
- // EXPRESSION: Create node inline (NO CONTINUE STATEMENT)
2418
- else if (valueType === 'EXPRESSION' && valueId && expressionType) {
2419
- // Create EXPRESSION node using NodeFactory
2420
- const expressionNode = NodeFactory.createExpressionFromMetadata(
2421
- expressionType,
2422
- file,
2423
- line,
2424
- column,
2425
- {
2426
- id: valueId, // ID from JSASTAnalyzer
2427
- object: expressionMetadata?.object,
2428
- property: expressionMetadata?.property,
2429
- computed: expressionMetadata?.computed,
2430
- computedPropertyVar: expressionMetadata?.computedPropertyVar ?? undefined,
2431
- operator: expressionMetadata?.operator
2432
- }
2433
- );
2434
-
2435
- this._bufferNode(expressionNode);
2436
- sourceNodeId = valueId;
2437
- }
2438
-
2439
- // Create edges if source found
2440
- if (sourceNodeId && targetNodeId) {
2441
- // For compound operators (operator !== '='), LHS reads its own current value
2442
- // Create READS_FROM self-loop (Linus requirement)
2443
- if (operator !== '=') {
2444
- this._bufferEdge({
2445
- type: 'READS_FROM',
2446
- src: targetNodeId, // Variable reads from...
2447
- dst: targetNodeId // ...itself (self-loop)
2448
- });
2449
- }
2450
-
2451
- // RHS flows into LHS (write side)
2452
- this._bufferEdge({
2453
- type: 'FLOWS_INTO',
2454
- src: sourceNodeId,
2455
- dst: targetNodeId
2456
- });
2457
- }
2458
- }
2459
- }
2460
-
2461
- /**
2462
- * Buffer RETURNS edges connecting return expressions to their containing functions.
2463
- *
2464
- * Edge direction: returnExpression --RETURNS--> function
2465
- *
2466
- * This enables tracing data flow through function calls:
2467
- * - Query: "What does formatDate return?"
2468
- * - Answer: Follow RETURNS edges from function to see all possible return values
2469
- */
2470
- private bufferReturnEdges(
2471
- returnStatements: ReturnStatementInfo[],
2472
- callSites: CallSiteInfo[],
2473
- methodCalls: MethodCallInfo[],
2474
- variableDeclarations: VariableDeclarationInfo[],
2475
- parameters: ParameterInfo[]
2476
- ): void {
2477
- for (const ret of returnStatements) {
2478
- const { parentFunctionId, returnValueType, file } = ret;
2479
-
2480
- // Skip if no value returned (bare return;)
2481
- if (returnValueType === 'NONE') {
2482
- continue;
2483
- }
2484
-
2485
- let sourceNodeId: string | null = null;
2486
-
2487
- switch (returnValueType) {
2488
- case 'LITERAL':
2489
- // Direct reference to literal node
2490
- sourceNodeId = ret.returnValueId ?? null;
2491
- break;
2492
-
2493
- case 'VARIABLE': {
2494
- // Find variable declaration by name in same file
2495
- const varName = ret.returnValueName;
2496
- if (varName) {
2497
- const sourceVar = variableDeclarations.find(v =>
2498
- v.name === varName && v.file === file
2499
- );
2500
- if (sourceVar) {
2501
- sourceNodeId = sourceVar.id;
2502
- } else {
2503
- // Check parameters
2504
- const sourceParam = parameters.find(p =>
2505
- p.name === varName && p.file === file
2506
- );
2507
- if (sourceParam) {
2508
- sourceNodeId = sourceParam.id;
2509
- }
2510
- }
2511
- }
2512
- break;
2513
- }
2514
-
2515
- case 'CALL_SITE': {
2516
- // Find call site by coordinates
2517
- const { returnValueLine, returnValueColumn, returnValueCallName } = ret;
2518
- if (returnValueLine && returnValueColumn) {
2519
- const callSite = callSites.find(cs =>
2520
- cs.line === returnValueLine &&
2521
- cs.column === returnValueColumn &&
2522
- (returnValueCallName ? cs.name === returnValueCallName : true)
2523
- );
2524
- if (callSite) {
2525
- sourceNodeId = callSite.id;
2526
- }
2527
- }
2528
- break;
2529
- }
2530
-
2531
- case 'METHOD_CALL': {
2532
- // Find method call by coordinates and method name
2533
- const { returnValueLine, returnValueColumn, returnValueCallName } = ret;
2534
- if (returnValueLine && returnValueColumn) {
2535
- const methodCall = methodCalls.find(mc =>
2536
- mc.line === returnValueLine &&
2537
- mc.column === returnValueColumn &&
2538
- mc.file === file &&
2539
- (returnValueCallName ? mc.method === returnValueCallName : true)
2540
- );
2541
- if (methodCall) {
2542
- sourceNodeId = methodCall.id;
2543
- }
2544
- }
2545
- break;
2546
- }
2547
-
2548
- case 'EXPRESSION': {
2549
- // REG-276: Create EXPRESSION node and DERIVES_FROM edges for return expressions
2550
- const {
2551
- expressionType,
2552
- returnValueId,
2553
- returnValueLine,
2554
- returnValueColumn,
2555
- operator,
2556
- object,
2557
- property,
2558
- computed,
2559
- objectSourceName,
2560
- leftSourceName,
2561
- rightSourceName,
2562
- consequentSourceName,
2563
- alternateSourceName,
2564
- expressionSourceNames,
2565
- unaryArgSourceName
2566
- } = ret;
2567
-
2568
- // Skip if no expression ID was generated
2569
- if (!returnValueId) {
2570
- break;
2571
- }
2572
-
2573
- // Create EXPRESSION node using NodeFactory
2574
- const expressionNode = NodeFactory.createExpressionFromMetadata(
2575
- expressionType || 'Unknown',
2576
- file,
2577
- returnValueLine || ret.line,
2578
- returnValueColumn || ret.column,
2579
- {
2580
- id: returnValueId,
2581
- object,
2582
- property,
2583
- computed,
2584
- operator
2585
- }
2586
- );
2587
-
2588
- this._bufferNode(expressionNode);
2589
- sourceNodeId = returnValueId;
2590
-
2591
- // Buffer DERIVES_FROM edges based on expression type
2592
- // Helper function to find source variable or parameter
2593
- const findSource = (name: string): string | null => {
2594
- const variable = variableDeclarations.find(v =>
2595
- v.name === name && v.file === file
2596
- );
2597
- if (variable) return variable.id;
2598
-
2599
- const param = parameters.find(p =>
2600
- p.name === name && p.file === file
2601
- );
2602
- if (param) return param.id;
2603
-
2604
- return null;
2605
- };
2606
-
2607
- // MemberExpression: derives from the object
2608
- if (expressionType === 'MemberExpression' && objectSourceName) {
2609
- const sourceId = findSource(objectSourceName);
2610
- if (sourceId) {
2611
- this._bufferEdge({
2612
- type: 'DERIVES_FROM',
2613
- src: returnValueId,
2614
- dst: sourceId
2615
- });
2616
- }
2617
- }
2618
-
2619
- // BinaryExpression / LogicalExpression: derives from left and right operands
2620
- if (expressionType === 'BinaryExpression' || expressionType === 'LogicalExpression') {
2621
- if (leftSourceName) {
2622
- const sourceId = findSource(leftSourceName);
2623
- if (sourceId) {
2624
- this._bufferEdge({
2625
- type: 'DERIVES_FROM',
2626
- src: returnValueId,
2627
- dst: sourceId
2628
- });
2629
- }
2630
- }
2631
- if (rightSourceName) {
2632
- const sourceId = findSource(rightSourceName);
2633
- if (sourceId) {
2634
- this._bufferEdge({
2635
- type: 'DERIVES_FROM',
2636
- src: returnValueId,
2637
- dst: sourceId
2638
- });
2639
- }
2640
- }
2641
- }
2642
-
2643
- // ConditionalExpression: derives from consequent and alternate
2644
- if (expressionType === 'ConditionalExpression') {
2645
- if (consequentSourceName) {
2646
- const sourceId = findSource(consequentSourceName);
2647
- if (sourceId) {
2648
- this._bufferEdge({
2649
- type: 'DERIVES_FROM',
2650
- src: returnValueId,
2651
- dst: sourceId
2652
- });
2653
- }
2654
- }
2655
- if (alternateSourceName) {
2656
- const sourceId = findSource(alternateSourceName);
2657
- if (sourceId) {
2658
- this._bufferEdge({
2659
- type: 'DERIVES_FROM',
2660
- src: returnValueId,
2661
- dst: sourceId
2662
- });
2663
- }
2664
- }
2665
- }
2666
-
2667
- // UnaryExpression: derives from the argument
2668
- if (expressionType === 'UnaryExpression' && unaryArgSourceName) {
2669
- const sourceId = findSource(unaryArgSourceName);
2670
- if (sourceId) {
2671
- this._bufferEdge({
2672
- type: 'DERIVES_FROM',
2673
- src: returnValueId,
2674
- dst: sourceId
2675
- });
2676
- }
2677
- }
2678
-
2679
- // TemplateLiteral: derives from all embedded expressions
2680
- if (expressionType === 'TemplateLiteral' && expressionSourceNames && expressionSourceNames.length > 0) {
2681
- for (const sourceName of expressionSourceNames) {
2682
- const sourceId = findSource(sourceName);
2683
- if (sourceId) {
2684
- this._bufferEdge({
2685
- type: 'DERIVES_FROM',
2686
- src: returnValueId,
2687
- dst: sourceId
2688
- });
2689
- }
2690
- }
2691
- }
2692
-
2693
- break;
2694
- }
2695
- }
2696
-
2697
- // Create RETURNS edge if we found a source node
2698
- if (sourceNodeId && parentFunctionId) {
2699
- this._bufferEdge({
2700
- type: 'RETURNS',
2701
- src: sourceNodeId,
2702
- dst: parentFunctionId
2703
- });
2704
- }
2705
- }
2706
- }
2707
-
2708
- /**
2709
- * Buffer YIELDS and DELEGATES_TO edges connecting yield expressions to their generator functions.
2710
- *
2711
- * Edge direction:
2712
- * - For yield: yieldedExpression --YIELDS--> generatorFunction
2713
- * - For yield*: delegatedCall --DELEGATES_TO--> generatorFunction
2714
- *
2715
- * This enables tracing data flow through generator functions:
2716
- * - Query: "What does this generator yield?"
2717
- * - Answer: Follow YIELDS edges from function to see all possible yielded values
2718
- * - Query: "What generators does this delegate to?"
2719
- * - Answer: Follow DELEGATES_TO edges from function
2720
- *
2721
- * REG-270: Generator yield tracking
2722
- */
2723
- private bufferYieldEdges(
2724
- yieldExpressions: YieldExpressionInfo[],
2725
- callSites: CallSiteInfo[],
2726
- methodCalls: MethodCallInfo[],
2727
- variableDeclarations: VariableDeclarationInfo[],
2728
- parameters: ParameterInfo[]
2729
- ): void {
2730
- for (const yld of yieldExpressions) {
2731
- const { parentFunctionId, yieldValueType, file, isDelegate } = yld;
2732
-
2733
- // Skip if no value yielded (bare yield;)
2734
- if (yieldValueType === 'NONE') {
2735
- continue;
2736
- }
2737
-
2738
- let sourceNodeId: string | null = null;
2739
-
2740
- switch (yieldValueType) {
2741
- case 'LITERAL':
2742
- // Direct reference to literal node
2743
- sourceNodeId = yld.yieldValueId ?? null;
2744
- break;
2745
-
2746
- case 'VARIABLE': {
2747
- // Find variable declaration by name in same file
2748
- const varName = yld.yieldValueName;
2749
- if (varName) {
2750
- const sourceVar = variableDeclarations.find(v =>
2751
- v.name === varName && v.file === file
2752
- );
2753
- if (sourceVar) {
2754
- sourceNodeId = sourceVar.id;
2755
- } else {
2756
- // Check parameters
2757
- const sourceParam = parameters.find(p =>
2758
- p.name === varName && p.file === file
2759
- );
2760
- if (sourceParam) {
2761
- sourceNodeId = sourceParam.id;
2762
- }
2763
- }
2764
- }
2765
- break;
2766
- }
2767
-
2768
- case 'CALL_SITE': {
2769
- // Find call site by coordinates
2770
- const { yieldValueLine, yieldValueColumn, yieldValueCallName } = yld;
2771
- if (yieldValueLine && yieldValueColumn) {
2772
- const callSite = callSites.find(cs =>
2773
- cs.line === yieldValueLine &&
2774
- cs.column === yieldValueColumn &&
2775
- (yieldValueCallName ? cs.name === yieldValueCallName : true)
2776
- );
2777
- if (callSite) {
2778
- sourceNodeId = callSite.id;
2779
- }
2780
- }
2781
- break;
2782
- }
2783
-
2784
- case 'METHOD_CALL': {
2785
- // Find method call by coordinates and method name
2786
- const { yieldValueLine, yieldValueColumn, yieldValueCallName } = yld;
2787
- if (yieldValueLine && yieldValueColumn) {
2788
- const methodCall = methodCalls.find(mc =>
2789
- mc.line === yieldValueLine &&
2790
- mc.column === yieldValueColumn &&
2791
- mc.file === file &&
2792
- (yieldValueCallName ? mc.method === yieldValueCallName : true)
2793
- );
2794
- if (methodCall) {
2795
- sourceNodeId = methodCall.id;
2796
- }
2797
- }
2798
- break;
2799
- }
2800
-
2801
- case 'EXPRESSION': {
2802
- // Create EXPRESSION node and DERIVES_FROM edges for yield expressions
2803
- const {
2804
- expressionType,
2805
- yieldValueId,
2806
- yieldValueLine,
2807
- yieldValueColumn,
2808
- operator,
2809
- object,
2810
- property,
2811
- computed,
2812
- objectSourceName,
2813
- leftSourceName,
2814
- rightSourceName,
2815
- consequentSourceName,
2816
- alternateSourceName,
2817
- expressionSourceNames,
2818
- unaryArgSourceName
2819
- } = yld;
2820
-
2821
- // Skip if no expression ID was generated
2822
- if (!yieldValueId) {
2823
- break;
2824
- }
2825
-
2826
- // Create EXPRESSION node using NodeFactory
2827
- const expressionNode = NodeFactory.createExpressionFromMetadata(
2828
- expressionType || 'Unknown',
2829
- file,
2830
- yieldValueLine || yld.line,
2831
- yieldValueColumn || yld.column,
2832
- {
2833
- id: yieldValueId,
2834
- object,
2835
- property,
2836
- computed,
2837
- operator
2838
- }
2839
- );
2840
-
2841
- this._bufferNode(expressionNode);
2842
- sourceNodeId = yieldValueId;
2843
-
2844
- // Buffer DERIVES_FROM edges based on expression type
2845
- // Helper function to find source variable or parameter
2846
- const findSource = (name: string): string | null => {
2847
- const variable = variableDeclarations.find(v =>
2848
- v.name === name && v.file === file
2849
- );
2850
- if (variable) return variable.id;
2851
-
2852
- const param = parameters.find(p =>
2853
- p.name === name && p.file === file
2854
- );
2855
- if (param) return param.id;
2856
-
2857
- return null;
2858
- };
2859
-
2860
- // MemberExpression: derives from the object
2861
- if (expressionType === 'MemberExpression' && objectSourceName) {
2862
- const srcId = findSource(objectSourceName);
2863
- if (srcId) {
2864
- this._bufferEdge({
2865
- type: 'DERIVES_FROM',
2866
- src: yieldValueId,
2867
- dst: srcId
2868
- });
2869
- }
2870
- }
2871
-
2872
- // BinaryExpression / LogicalExpression: derives from left and right operands
2873
- if (expressionType === 'BinaryExpression' || expressionType === 'LogicalExpression') {
2874
- if (leftSourceName) {
2875
- const srcId = findSource(leftSourceName);
2876
- if (srcId) {
2877
- this._bufferEdge({
2878
- type: 'DERIVES_FROM',
2879
- src: yieldValueId,
2880
- dst: srcId
2881
- });
2882
- }
2883
- }
2884
- if (rightSourceName) {
2885
- const srcId = findSource(rightSourceName);
2886
- if (srcId) {
2887
- this._bufferEdge({
2888
- type: 'DERIVES_FROM',
2889
- src: yieldValueId,
2890
- dst: srcId
2891
- });
2892
- }
2893
- }
2894
- }
2895
-
2896
- // ConditionalExpression: derives from consequent and alternate
2897
- if (expressionType === 'ConditionalExpression') {
2898
- if (consequentSourceName) {
2899
- const srcId = findSource(consequentSourceName);
2900
- if (srcId) {
2901
- this._bufferEdge({
2902
- type: 'DERIVES_FROM',
2903
- src: yieldValueId,
2904
- dst: srcId
2905
- });
2906
- }
2907
- }
2908
- if (alternateSourceName) {
2909
- const srcId = findSource(alternateSourceName);
2910
- if (srcId) {
2911
- this._bufferEdge({
2912
- type: 'DERIVES_FROM',
2913
- src: yieldValueId,
2914
- dst: srcId
2915
- });
2916
- }
2917
- }
2918
- }
2919
-
2920
- // UnaryExpression: derives from the argument
2921
- if (expressionType === 'UnaryExpression' && unaryArgSourceName) {
2922
- const srcId = findSource(unaryArgSourceName);
2923
- if (srcId) {
2924
- this._bufferEdge({
2925
- type: 'DERIVES_FROM',
2926
- src: yieldValueId,
2927
- dst: srcId
2928
- });
2929
- }
2930
- }
2931
-
2932
- // TemplateLiteral: derives from all embedded expressions
2933
- if (expressionType === 'TemplateLiteral' && expressionSourceNames && expressionSourceNames.length > 0) {
2934
- for (const sourceName of expressionSourceNames) {
2935
- const srcId = findSource(sourceName);
2936
- if (srcId) {
2937
- this._bufferEdge({
2938
- type: 'DERIVES_FROM',
2939
- src: yieldValueId,
2940
- dst: srcId
2941
- });
2942
- }
2943
- }
2944
- }
2945
-
2946
- break;
2947
- }
2948
- }
2949
-
2950
- // Create YIELDS or DELEGATES_TO edge if we found a source node
2951
- if (sourceNodeId && parentFunctionId) {
2952
- const edgeType = isDelegate ? 'DELEGATES_TO' : 'YIELDS';
2953
- this._bufferEdge({
2954
- type: edgeType,
2955
- src: sourceNodeId,
2956
- dst: parentFunctionId
2957
- });
2958
- }
2959
- }
2960
- }
2961
-
2962
- /**
2963
- * Buffer UPDATE_EXPRESSION nodes and edges for increment/decrement operations.
2964
- *
2965
- * Handles two target types:
2966
- * - IDENTIFIER: Simple variable (i++, --count)
2967
- * - MEMBER_EXPRESSION: Object property (obj.prop++, arr[i]++, this.count++)
2968
- *
2969
- * Creates:
2970
- * - UPDATE_EXPRESSION node with operator and target metadata
2971
- * - MODIFIES edge: UPDATE_EXPRESSION -> target (VARIABLE, PARAMETER, or CLASS)
2972
- * - READS_FROM self-loop: target -> target (reads current value before update)
2973
- * - CONTAINS edge: SCOPE -> UPDATE_EXPRESSION
2974
- *
2975
- * REG-288: Initial implementation for IDENTIFIER targets
2976
- * REG-312: Extended for MEMBER_EXPRESSION targets
2977
- */
2978
- private bufferUpdateExpressionEdges(
2979
- updateExpressions: UpdateExpressionInfo[],
2980
- variableDeclarations: VariableDeclarationInfo[],
2981
- parameters: ParameterInfo[],
2982
- classDeclarations: ClassDeclarationInfo[]
2983
- ): void {
2984
- // Build lookup caches: O(n) instead of O(n*m)
2985
- const varLookup = new Map<string, VariableDeclarationInfo>();
2986
- for (const v of variableDeclarations) {
2987
- varLookup.set(`${v.file}:${v.name}`, v);
2988
- }
2989
-
2990
- const paramLookup = new Map<string, ParameterInfo>();
2991
- for (const p of parameters) {
2992
- paramLookup.set(`${p.file}:${p.name}`, p);
2993
- }
2994
-
2995
- for (const update of updateExpressions) {
2996
- if (update.targetType === 'IDENTIFIER') {
2997
- // REG-288: Simple identifier (i++, --count)
2998
- this.bufferIdentifierUpdate(update, varLookup, paramLookup);
2999
- } else if (update.targetType === 'MEMBER_EXPRESSION') {
3000
- // REG-312: Member expression (obj.prop++, arr[i]++)
3001
- this.bufferMemberExpressionUpdate(update, varLookup, paramLookup, classDeclarations);
3002
- }
3003
- }
3004
- }
3005
-
3006
- /**
3007
- * Buffer UPDATE_EXPRESSION node and edges for simple identifier updates (i++, --count)
3008
- * REG-288: Original implementation extracted for clarity
3009
- */
3010
- private bufferIdentifierUpdate(
3011
- update: UpdateExpressionInfo,
3012
- varLookup: Map<string, VariableDeclarationInfo>,
3013
- paramLookup: Map<string, ParameterInfo>
3014
- ): void {
3015
- const {
3016
- variableName,
3017
- operator,
3018
- prefix,
3019
- file,
3020
- line,
3021
- column,
3022
- parentScopeId
3023
- } = update;
3024
-
3025
- if (!variableName) return;
3026
-
3027
- // Find target variable node
3028
- const targetVar = varLookup.get(`${file}:${variableName}`);
3029
- const targetParam = !targetVar ? paramLookup.get(`${file}:${variableName}`) : null;
3030
- const targetNodeId = targetVar?.id ?? targetParam?.id;
3031
-
3032
- if (!targetNodeId) {
3033
- // Variable not found - could be module-level or external reference
3034
- return;
3035
- }
3036
-
3037
- // Create UPDATE_EXPRESSION node
3038
- const updateId = `${file}:UPDATE_EXPRESSION:${operator}:${line}:${column}`;
3039
-
3040
- this._bufferNode({
3041
- type: 'UPDATE_EXPRESSION',
3042
- id: updateId,
3043
- name: `${prefix ? operator : ''}${variableName}${prefix ? '' : operator}`,
3044
- targetType: 'IDENTIFIER',
3045
- operator,
3046
- prefix,
3047
- variableName,
3048
- file,
3049
- line,
3050
- column
3051
- } as GraphNode);
3052
-
3053
- // Create READS_FROM self-loop
3054
- this._bufferEdge({
3055
- type: 'READS_FROM',
3056
- src: targetNodeId,
3057
- dst: targetNodeId
3058
- });
3059
-
3060
- // Create MODIFIES edge
3061
- this._bufferEdge({
3062
- type: 'MODIFIES',
3063
- src: updateId,
3064
- dst: targetNodeId
3065
- });
3066
-
3067
- // Create CONTAINS edge
3068
- if (parentScopeId) {
3069
- this._bufferEdge({
3070
- type: 'CONTAINS',
3071
- src: parentScopeId,
3072
- dst: updateId
3073
- });
3074
- }
3075
- }
3076
-
3077
- /**
3078
- * Buffer UPDATE_EXPRESSION node and edges for member expression updates (obj.prop++, arr[i]++)
3079
- * REG-312: New implementation for member expression targets
3080
- *
3081
- * Creates:
3082
- * - UPDATE_EXPRESSION node with member expression metadata
3083
- * - MODIFIES edge: UPDATE_EXPRESSION -> VARIABLE(object) or CLASS (for this.prop++)
3084
- * - READS_FROM self-loop: VARIABLE(object) -> VARIABLE(object)
3085
- * - CONTAINS edge: SCOPE -> UPDATE_EXPRESSION
3086
- */
3087
- private bufferMemberExpressionUpdate(
3088
- update: UpdateExpressionInfo,
3089
- varLookup: Map<string, VariableDeclarationInfo>,
3090
- paramLookup: Map<string, ParameterInfo>,
3091
- classDeclarations: ClassDeclarationInfo[]
3092
- ): void {
3093
- const {
3094
- objectName,
3095
- propertyName,
3096
- mutationType,
3097
- computedPropertyVar,
3098
- enclosingClassName,
3099
- operator,
3100
- prefix,
3101
- file,
3102
- line,
3103
- column,
3104
- parentScopeId
3105
- } = update;
3106
-
3107
- if (!objectName || !propertyName) return;
3108
-
3109
- // Find target object node
3110
- let objectNodeId: string | null = null;
3111
-
3112
- if (objectName !== 'this') {
3113
- // Regular object: obj.prop++, arr[i]++
3114
- const targetVar = varLookup.get(`${file}:${objectName}`);
3115
- const targetParam = !targetVar ? paramLookup.get(`${file}:${objectName}`) : null;
3116
- objectNodeId = targetVar?.id ?? targetParam?.id ?? null;
3117
- } else {
3118
- // this.prop++ - follow REG-152 pattern from bufferObjectMutationEdges
3119
- if (!enclosingClassName) return;
3120
-
3121
- const fileBasename = basename(file);
3122
- const classDecl = classDeclarations.find(c =>
3123
- c.name === enclosingClassName && c.file === fileBasename
3124
- );
3125
- objectNodeId = classDecl?.id ?? null;
3126
- }
3127
-
3128
- if (!objectNodeId) {
3129
- // Object not found - external reference or scope issue
3130
- return;
3131
- }
3132
-
3133
- // Create UPDATE_EXPRESSION node
3134
- const updateId = `${file}:UPDATE_EXPRESSION:${operator}:${line}:${column}`;
3135
-
3136
- // Display name: "obj.prop++" or "this.count++" or "arr[i]++"
3137
- const displayName = (() => {
3138
- const opStr = prefix ? operator : '';
3139
- const postOpStr = prefix ? '' : operator;
3140
-
3141
- if (objectName === 'this') {
3142
- return `${opStr}this.${propertyName}${postOpStr}`;
3143
- }
3144
- if (mutationType === 'computed') {
3145
- const computedPart = computedPropertyVar || '?';
3146
- return `${opStr}${objectName}[${computedPart}]${postOpStr}`;
3147
- }
3148
- return `${opStr}${objectName}.${propertyName}${postOpStr}`;
3149
- })();
3150
-
3151
- this._bufferNode({
3152
- type: 'UPDATE_EXPRESSION',
3153
- id: updateId,
3154
- name: displayName,
3155
- targetType: 'MEMBER_EXPRESSION',
3156
- operator,
3157
- prefix,
3158
- objectName,
3159
- propertyName,
3160
- mutationType,
3161
- computedPropertyVar,
3162
- enclosingClassName,
3163
- file,
3164
- line,
3165
- column
3166
- } as GraphNode);
3167
-
3168
- // Create READS_FROM self-loop (object reads from itself)
3169
- this._bufferEdge({
3170
- type: 'READS_FROM',
3171
- src: objectNodeId,
3172
- dst: objectNodeId
3173
- });
3174
-
3175
- // Create MODIFIES edge (UPDATE_EXPRESSION modifies object)
3176
- this._bufferEdge({
3177
- type: 'MODIFIES',
3178
- src: updateId,
3179
- dst: objectNodeId
3180
- });
3181
-
3182
- // Create CONTAINS edge
3183
- if (parentScopeId) {
3184
- this._bufferEdge({
3185
- type: 'CONTAINS',
3186
- src: parentScopeId,
3187
- dst: updateId
3188
- });
3189
- }
3190
- }
3191
-
3192
- /**
3193
- * Buffer RESOLVES_TO edges for Promise resolution data flow (REG-334).
3194
- *
3195
- * Links resolve/reject CALL nodes to their parent Promise CONSTRUCTOR_CALL.
3196
- * This enables traceValues to follow Promise data flow:
3197
- *
3198
- * Example:
3199
- * ```
3200
- * const result = new Promise((resolve) => {
3201
- * resolve(42); // CALL[resolve] --RESOLVES_TO--> CONSTRUCTOR_CALL[Promise]
3202
- * });
3203
- * ```
3204
- *
3205
- * The edge direction (CALL -> CONSTRUCTOR_CALL) matches data flow semantics:
3206
- * data flows FROM resolve(value) TO the Promise result.
3207
- */
3208
- private bufferPromiseResolutionEdges(promiseResolutions: PromiseResolutionInfo[]): void {
3209
- for (const resolution of promiseResolutions) {
3210
- this._bufferEdge({
3211
- type: 'RESOLVES_TO',
3212
- src: resolution.callId,
3213
- dst: resolution.constructorCallId,
3214
- metadata: {
3215
- isReject: resolution.isReject
3216
- }
3217
- });
3218
- }
3219
- }
3220
-
3221
- /**
3222
- * Buffer OBJECT_LITERAL nodes to the graph.
3223
- * These are object literals passed as function arguments or nested in other literals.
3224
- */
3225
- private bufferObjectLiteralNodes(objectLiterals: ObjectLiteralInfo[]): void {
3226
- for (const obj of objectLiterals) {
3227
- this._bufferNode({
3228
- id: obj.id,
3229
- type: obj.type,
3230
- name: '<object>',
3231
- file: obj.file,
3232
- line: obj.line,
3233
- column: obj.column,
3234
- parentCallId: obj.parentCallId,
3235
- argIndex: obj.argIndex
3236
- } as GraphNode);
3237
- }
3238
- }
3239
-
3240
- /**
3241
- * Buffer ARRAY_LITERAL nodes to the graph.
3242
- * These are array literals passed as function arguments or nested in other literals.
3243
- */
3244
- private bufferArrayLiteralNodes(arrayLiterals: ArrayLiteralInfo[]): void {
3245
- for (const arr of arrayLiterals) {
3246
- this._bufferNode({
3247
- id: arr.id,
3248
- type: arr.type,
3249
- name: '<array>',
3250
- file: arr.file,
3251
- line: arr.line,
3252
- column: arr.column,
3253
- parentCallId: arr.parentCallId,
3254
- argIndex: arr.argIndex
3255
- } as GraphNode);
3256
- }
3257
- }
3258
-
3259
- /**
3260
- * Buffer HAS_PROPERTY edges connecting OBJECT_LITERAL nodes to their property values.
3261
- * Creates edges from object literal to its property value nodes (LITERAL, nested OBJECT_LITERAL, ARRAY_LITERAL, etc.)
3262
- *
3263
- * REG-329: Adds scope-aware variable resolution for VARIABLE property values.
3264
- * Uses the same resolveVariableInScope infrastructure as mutation handlers.
3265
- */
3266
- private bufferObjectPropertyEdges(
3267
- objectProperties: ObjectPropertyInfo[],
3268
- variableDeclarations: VariableDeclarationInfo[],
3269
- parameters: ParameterInfo[]
3270
- ): void {
3271
- for (const prop of objectProperties) {
3272
- // REG-329: Handle VARIABLE value types with scope resolution
3273
- if (prop.valueType === 'VARIABLE' && prop.valueName) {
3274
- const scopePath = prop.valueScopePath ?? [];
3275
- const file = prop.file;
3276
-
3277
- // Resolve variable using scope chain
3278
- const resolvedVar = this.resolveVariableInScope(
3279
- prop.valueName, scopePath, file, variableDeclarations
3280
- );
3281
- const resolvedParam = !resolvedVar
3282
- ? this.resolveParameterInScope(prop.valueName, scopePath, file, parameters)
3283
- : null;
3284
-
3285
- const resolvedNodeId = resolvedVar?.id ?? resolvedParam?.semanticId ?? resolvedParam?.id;
3286
-
3287
- if (resolvedNodeId) {
3288
- this._bufferEdge({
3289
- type: 'HAS_PROPERTY',
3290
- src: prop.objectId,
3291
- dst: resolvedNodeId,
3292
- propertyName: prop.propertyName
3293
- });
3294
- }
3295
- continue;
3296
- }
3297
-
3298
- // Existing logic for non-VARIABLE types
3299
- if (prop.valueNodeId) {
3300
- this._bufferEdge({
3301
- type: 'HAS_PROPERTY',
3302
- src: prop.objectId,
3303
- dst: prop.valueNodeId,
3304
- propertyName: prop.propertyName
3305
- });
3306
- }
3307
- }
3308
- }
3309
-
3310
- /**
3311
- * Handle CLASS ASSIGNED_FROM edges asynchronously (needs graph queries)
3312
- */
3313
- private async createClassAssignmentEdges(variableAssignments: VariableAssignmentInfo[], graph: GraphBackend): Promise<number> {
3314
- let edgesCreated = 0;
520
+ private async createClassAssignmentEdges(variableAssignments: VariableAssignmentInfo[], graph: GraphBackend): Promise<number> {
521
+ let edgesCreated = 0;
3315
522
 
3316
523
  for (const assignment of variableAssignments) {
3317
524
  const { variableId, sourceType, className } = assignment;
@@ -3341,117 +548,4 @@ export class GraphBuilder {
3341
548
 
3342
549
  return edgesCreated;
3343
550
  }
3344
-
3345
- /**
3346
- * Buffer REJECTS edges for async error tracking (REG-311).
3347
- *
3348
- * Creates edges from FUNCTION nodes to error CLASS nodes they can reject.
3349
- * This enables tracking which async functions can throw which error types:
3350
- *
3351
- * - Promise.reject(new Error()) -> FUNCTION --REJECTS--> CLASS[Error]
3352
- * - reject(new ValidationError()) in executor -> FUNCTION --REJECTS--> CLASS[ValidationError]
3353
- * - throw new AuthError() in async function -> FUNCTION --REJECTS--> CLASS[AuthError]
3354
- *
3355
- * Also stores rejectionPatterns in function metadata for downstream enrichers.
3356
- *
3357
- * @param functions - All function infos from analysis
3358
- * @param rejectionPatterns - Collected rejection patterns from analysis
3359
- */
3360
- private bufferRejectionEdges(functions: FunctionInfo[], rejectionPatterns: RejectionPatternInfo[]): void {
3361
- // Group rejection patterns by functionId for efficient lookup
3362
- const patternsByFunction = new Map<string, RejectionPatternInfo[]>();
3363
- for (const pattern of rejectionPatterns) {
3364
- const existing = patternsByFunction.get(pattern.functionId);
3365
- if (existing) {
3366
- existing.push(pattern);
3367
- } else {
3368
- patternsByFunction.set(pattern.functionId, [pattern]);
3369
- }
3370
- }
3371
-
3372
- // Process each function that has rejection patterns
3373
- for (const [functionId, patterns] of patternsByFunction) {
3374
- // Collect unique error class names from this function's rejection patterns
3375
- const errorClassNames = new Set<string>();
3376
- for (const pattern of patterns) {
3377
- if (pattern.errorClassName) {
3378
- errorClassNames.add(pattern.errorClassName);
3379
- }
3380
- }
3381
-
3382
- // Create REJECTS edges to error class nodes
3383
- // Note: These edges target computed CLASS IDs - they will be dangling
3384
- // if the class isn't declared, but that's expected behavior for
3385
- // built-in classes like Error, TypeError, etc.
3386
- for (const errorClassName of errorClassNames) {
3387
- // Find the function's file to compute the class ID
3388
- const func = functions.find(f => f.id === functionId);
3389
- const file = func?.file ?? '';
3390
-
3391
- // Compute potential class ID at global scope
3392
- // For built-in errors, this will be a dangling reference (expected)
3393
- const globalContext = { file, scopePath: [] as string[] };
3394
- const classId = computeSemanticId('CLASS', errorClassName, globalContext);
3395
-
3396
- this._bufferEdge({
3397
- type: 'REJECTS',
3398
- src: functionId,
3399
- dst: classId,
3400
- metadata: {
3401
- errorClassName
3402
- }
3403
- });
3404
- }
3405
-
3406
- // Store rejection patterns in function metadata for downstream enrichers
3407
- // Find and update the function node in the buffer
3408
- for (const node of this._nodeBuffer) {
3409
- if (node.id === functionId) {
3410
- // Store in metadata field for proper persistence and test compatibility
3411
- if (!node.metadata) {
3412
- node.metadata = {};
3413
- }
3414
- (node.metadata as Record<string, unknown>).rejectionPatterns = patterns.map(p => ({
3415
- rejectionType: p.rejectionType,
3416
- errorClassName: p.errorClassName,
3417
- line: p.line,
3418
- column: p.column,
3419
- sourceVariableName: p.sourceVariableName,
3420
- tracePath: p.tracePath
3421
- }));
3422
- break;
3423
- }
3424
- }
3425
- }
3426
- }
3427
-
3428
- /**
3429
- * Buffer CATCHES_FROM edges linking catch blocks to error sources (REG-311).
3430
- *
3431
- * Creates edges from CATCH_BLOCK nodes to potential error sources within
3432
- * their corresponding try blocks. This enables tracking which catch blocks
3433
- * can handle which exceptions:
3434
- *
3435
- * - try { await fetch() } catch(e) -> CATCH_BLOCK --CATCHES_FROM--> CALL[fetch]
3436
- * - try { throw new Error() } catch(e) -> CATCH_BLOCK --CATCHES_FROM--> THROW_STATEMENT
3437
- *
3438
- * The sourceType metadata helps distinguish different error source kinds
3439
- * for more precise error flow analysis.
3440
- *
3441
- * @param catchesFromInfos - Collected CATCHES_FROM info from analysis
3442
- */
3443
- private bufferCatchesFromEdges(catchesFromInfos: CatchesFromInfo[]): void {
3444
- for (const info of catchesFromInfos) {
3445
- this._bufferEdge({
3446
- type: 'CATCHES_FROM',
3447
- src: info.catchBlockId,
3448
- dst: info.sourceId,
3449
- metadata: {
3450
- parameterName: info.parameterName,
3451
- sourceType: info.sourceType,
3452
- sourceLine: info.sourceLine
3453
- }
3454
- });
3455
- }
3456
- }
3457
551
  }