@grafema/core 0.2.4-beta → 0.2.5-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (557) hide show
  1. package/dist/Orchestrator.d.ts +37 -0
  2. package/dist/Orchestrator.d.ts.map +1 -1
  3. package/dist/Orchestrator.js +322 -35
  4. package/dist/Orchestrator.js.map +1 -0
  5. package/dist/api/GraphAPI.d.ts +1 -1
  6. package/dist/api/GraphAPI.d.ts.map +1 -1
  7. package/dist/api/GraphAPI.js +3 -1
  8. package/dist/api/GraphAPI.js.map +1 -0
  9. package/dist/api/GuaranteeAPI.d.ts.map +1 -1
  10. package/dist/api/GuaranteeAPI.js +4 -2
  11. package/dist/api/GuaranteeAPI.js.map +1 -0
  12. package/dist/config/ConfigLoader.d.ts +66 -0
  13. package/dist/config/ConfigLoader.d.ts.map +1 -1
  14. package/dist/config/ConfigLoader.js +77 -3
  15. package/dist/config/ConfigLoader.js.map +1 -0
  16. package/dist/config/index.d.ts +1 -1
  17. package/dist/config/index.d.ts.map +1 -1
  18. package/dist/config/index.js +2 -1
  19. package/dist/config/index.js.map +1 -0
  20. package/dist/core/ASTWorker.d.ts.map +1 -1
  21. package/dist/core/ASTWorker.js +6 -4
  22. package/dist/core/ASTWorker.js.map +1 -0
  23. package/dist/core/ASTWorkerPool.js +2 -1
  24. package/dist/core/ASTWorkerPool.js.map +1 -0
  25. package/dist/core/AnalysisQueue.js +1 -0
  26. package/dist/core/AnalysisQueue.js.map +1 -0
  27. package/dist/core/CoverageAnalyzer.d.ts.map +1 -1
  28. package/dist/core/CoverageAnalyzer.js +1 -0
  29. package/dist/core/CoverageAnalyzer.js.map +1 -0
  30. package/dist/core/FileExplainer.js +1 -0
  31. package/dist/core/FileExplainer.js.map +1 -0
  32. package/dist/core/FileNodeManager.d.ts.map +1 -1
  33. package/dist/core/FileNodeManager.js +4 -2
  34. package/dist/core/FileNodeManager.js.map +1 -0
  35. package/dist/core/GraphBackend.js +1 -0
  36. package/dist/core/GraphBackend.js.map +1 -0
  37. package/dist/core/GraphFreshnessChecker.js +1 -0
  38. package/dist/core/GraphFreshnessChecker.js.map +1 -0
  39. package/dist/core/GuaranteeManager.js +2 -1
  40. package/dist/core/GuaranteeManager.js.map +1 -0
  41. package/dist/core/HashUtils.js +1 -0
  42. package/dist/core/HashUtils.js.map +1 -0
  43. package/dist/core/IncrementalReanalyzer.d.ts.map +1 -1
  44. package/dist/core/IncrementalReanalyzer.js +7 -3
  45. package/dist/core/IncrementalReanalyzer.js.map +1 -0
  46. package/dist/core/ManifestStore.js +1 -0
  47. package/dist/core/ManifestStore.js.map +1 -0
  48. package/dist/core/NodeFactory.d.ts +54 -34
  49. package/dist/core/NodeFactory.d.ts.map +1 -1
  50. package/dist/core/NodeFactory.js +20 -1
  51. package/dist/core/NodeFactory.js.map +1 -0
  52. package/dist/core/NodeId.js +1 -0
  53. package/dist/core/NodeId.js.map +1 -0
  54. package/dist/core/PriorityQueue.js +1 -0
  55. package/dist/core/PriorityQueue.js.map +1 -0
  56. package/dist/core/Profiler.js +1 -0
  57. package/dist/core/Profiler.js.map +1 -0
  58. package/dist/core/ScopeTracker.js +1 -0
  59. package/dist/core/ScopeTracker.js.map +1 -0
  60. package/dist/core/SemanticId.js +1 -0
  61. package/dist/core/SemanticId.js.map +1 -0
  62. package/dist/core/Task.js +1 -0
  63. package/dist/core/Task.js.map +1 -0
  64. package/dist/core/TaskTypes.js +1 -0
  65. package/dist/core/TaskTypes.js.map +1 -0
  66. package/dist/core/VersionManager.js +1 -0
  67. package/dist/core/VersionManager.js.map +1 -0
  68. package/dist/core/WorkerPool.d.ts.map +1 -1
  69. package/dist/core/WorkerPool.js +3 -1
  70. package/dist/core/WorkerPool.js.map +1 -0
  71. package/dist/core/nodes/ArgumentExpressionNode.js +1 -0
  72. package/dist/core/nodes/ArgumentExpressionNode.js.map +1 -0
  73. package/dist/core/nodes/ArrayLiteralNode.js +1 -0
  74. package/dist/core/nodes/ArrayLiteralNode.js.map +1 -0
  75. package/dist/core/nodes/BranchNode.js +1 -0
  76. package/dist/core/nodes/BranchNode.js.map +1 -0
  77. package/dist/core/nodes/CallSiteNode.js +1 -0
  78. package/dist/core/nodes/CallSiteNode.js.map +1 -0
  79. package/dist/core/nodes/CaseNode.js +1 -0
  80. package/dist/core/nodes/CaseNode.js.map +1 -0
  81. package/dist/core/nodes/ClassNode.js +1 -0
  82. package/dist/core/nodes/ClassNode.js.map +1 -0
  83. package/dist/core/nodes/ConstantNode.js +1 -0
  84. package/dist/core/nodes/ConstantNode.js.map +1 -0
  85. package/dist/core/nodes/ConstructorCallNode.js +1 -0
  86. package/dist/core/nodes/ConstructorCallNode.js.map +1 -0
  87. package/dist/core/nodes/DatabaseQueryNode.js +1 -0
  88. package/dist/core/nodes/DatabaseQueryNode.js.map +1 -0
  89. package/dist/core/nodes/DecoratorNode.js +1 -0
  90. package/dist/core/nodes/DecoratorNode.js.map +1 -0
  91. package/dist/core/nodes/EntrypointNode.js +1 -0
  92. package/dist/core/nodes/EntrypointNode.js.map +1 -0
  93. package/dist/core/nodes/EnumNode.js +1 -0
  94. package/dist/core/nodes/EnumNode.js.map +1 -0
  95. package/dist/core/nodes/EventListenerNode.js +1 -0
  96. package/dist/core/nodes/EventListenerNode.js.map +1 -0
  97. package/dist/core/nodes/ExportNode.js +1 -0
  98. package/dist/core/nodes/ExportNode.js.map +1 -0
  99. package/dist/core/nodes/ExpressionNode.js +1 -0
  100. package/dist/core/nodes/ExpressionNode.js.map +1 -0
  101. package/dist/core/nodes/ExternalModuleNode.js +1 -0
  102. package/dist/core/nodes/ExternalModuleNode.js.map +1 -0
  103. package/dist/core/nodes/ExternalStdioNode.js +1 -0
  104. package/dist/core/nodes/ExternalStdioNode.js.map +1 -0
  105. package/dist/core/nodes/FunctionNode.js +1 -0
  106. package/dist/core/nodes/FunctionNode.js.map +1 -0
  107. package/dist/core/nodes/GuaranteeNode.js +1 -0
  108. package/dist/core/nodes/GuaranteeNode.js.map +1 -0
  109. package/dist/core/nodes/HttpRequestNode.js +1 -0
  110. package/dist/core/nodes/HttpRequestNode.js.map +1 -0
  111. package/dist/core/nodes/ImportNode.js +1 -0
  112. package/dist/core/nodes/ImportNode.js.map +1 -0
  113. package/dist/core/nodes/InterfaceNode.js +1 -0
  114. package/dist/core/nodes/InterfaceNode.js.map +1 -0
  115. package/dist/core/nodes/IssueNode.js +1 -0
  116. package/dist/core/nodes/IssueNode.js.map +1 -0
  117. package/dist/core/nodes/LiteralNode.js +1 -0
  118. package/dist/core/nodes/LiteralNode.js.map +1 -0
  119. package/dist/core/nodes/MethodCallNode.js +1 -0
  120. package/dist/core/nodes/MethodCallNode.js.map +1 -0
  121. package/dist/core/nodes/MethodNode.js +1 -0
  122. package/dist/core/nodes/MethodNode.js.map +1 -0
  123. package/dist/core/nodes/ModuleNode.js +1 -0
  124. package/dist/core/nodes/ModuleNode.js.map +1 -0
  125. package/dist/core/nodes/NetworkRequestNode.js +1 -0
  126. package/dist/core/nodes/NetworkRequestNode.js.map +1 -0
  127. package/dist/core/nodes/NodeKind.d.ts +5 -0
  128. package/dist/core/nodes/NodeKind.d.ts.map +1 -1
  129. package/dist/core/nodes/NodeKind.js +11 -0
  130. package/dist/core/nodes/NodeKind.js.map +1 -0
  131. package/dist/core/nodes/ObjectLiteralNode.js +1 -0
  132. package/dist/core/nodes/ObjectLiteralNode.js.map +1 -0
  133. package/dist/core/nodes/ParameterNode.js +1 -0
  134. package/dist/core/nodes/ParameterNode.js.map +1 -0
  135. package/dist/core/nodes/PluginNode.d.ts +69 -0
  136. package/dist/core/nodes/PluginNode.d.ts.map +1 -0
  137. package/dist/core/nodes/PluginNode.js +106 -0
  138. package/dist/core/nodes/PluginNode.js.map +1 -0
  139. package/dist/core/nodes/ScopeNode.js +1 -0
  140. package/dist/core/nodes/ScopeNode.js.map +1 -0
  141. package/dist/core/nodes/ServiceNode.js +1 -0
  142. package/dist/core/nodes/ServiceNode.js.map +1 -0
  143. package/dist/core/nodes/TypeNode.js +2 -1
  144. package/dist/core/nodes/TypeNode.js.map +1 -0
  145. package/dist/core/nodes/VariableDeclarationNode.js +1 -0
  146. package/dist/core/nodes/VariableDeclarationNode.js.map +1 -0
  147. package/dist/core/nodes/index.d.ts +2 -1
  148. package/dist/core/nodes/index.d.ts.map +1 -1
  149. package/dist/core/nodes/index.js +4 -1
  150. package/dist/core/nodes/index.js.map +1 -0
  151. package/dist/core/toposort.d.ts +38 -0
  152. package/dist/core/toposort.d.ts.map +1 -0
  153. package/dist/core/toposort.js +129 -0
  154. package/dist/core/toposort.js.map +1 -0
  155. package/dist/data/builtins/BuiltinRegistry.js +1 -0
  156. package/dist/data/builtins/BuiltinRegistry.js.map +1 -0
  157. package/dist/data/builtins/definitions.js +1 -0
  158. package/dist/data/builtins/definitions.js.map +1 -0
  159. package/dist/data/builtins/index.js +1 -0
  160. package/dist/data/builtins/index.js.map +1 -0
  161. package/dist/data/builtins/jsGlobals.js +1 -0
  162. package/dist/data/builtins/jsGlobals.js.map +1 -0
  163. package/dist/data/builtins/types.js +1 -0
  164. package/dist/data/builtins/types.js.map +1 -0
  165. package/dist/data/globals/definitions.js +1 -0
  166. package/dist/data/globals/definitions.js.map +1 -0
  167. package/dist/data/globals/index.js +1 -0
  168. package/dist/data/globals/index.js.map +1 -0
  169. package/dist/diagnostics/DiagnosticCollector.d.ts +5 -0
  170. package/dist/diagnostics/DiagnosticCollector.d.ts.map +1 -1
  171. package/dist/diagnostics/DiagnosticCollector.js +4 -0
  172. package/dist/diagnostics/DiagnosticCollector.js.map +1 -0
  173. package/dist/diagnostics/DiagnosticReporter.d.ts +23 -1
  174. package/dist/diagnostics/DiagnosticReporter.d.ts.map +1 -1
  175. package/dist/diagnostics/DiagnosticReporter.js +68 -15
  176. package/dist/diagnostics/DiagnosticReporter.js.map +1 -0
  177. package/dist/diagnostics/DiagnosticWriter.js +1 -0
  178. package/dist/diagnostics/DiagnosticWriter.js.map +1 -0
  179. package/dist/diagnostics/categories.d.ts +57 -0
  180. package/dist/diagnostics/categories.d.ts.map +1 -0
  181. package/dist/diagnostics/categories.js +71 -0
  182. package/dist/diagnostics/categories.js.map +1 -0
  183. package/dist/diagnostics/index.d.ts +3 -0
  184. package/dist/diagnostics/index.d.ts.map +1 -1
  185. package/dist/diagnostics/index.js +4 -0
  186. package/dist/diagnostics/index.js.map +1 -0
  187. package/dist/errors/GrafemaError.d.ts +39 -0
  188. package/dist/errors/GrafemaError.d.ts.map +1 -1
  189. package/dist/errors/GrafemaError.js +28 -0
  190. package/dist/errors/GrafemaError.js.map +1 -0
  191. package/dist/index.d.ts +21 -10
  192. package/dist/index.d.ts.map +1 -1
  193. package/dist/index.js +19 -7
  194. package/dist/index.js.map +1 -0
  195. package/dist/instructions/index.d.ts +8 -0
  196. package/dist/instructions/index.d.ts.map +1 -0
  197. package/dist/instructions/index.js +20 -0
  198. package/dist/instructions/index.js.map +1 -0
  199. package/dist/instructions/onboarding.md +121 -0
  200. package/dist/logging/Logger.d.ts +53 -3
  201. package/dist/logging/Logger.d.ts.map +1 -1
  202. package/dist/logging/Logger.js +144 -4
  203. package/dist/logging/Logger.js.map +1 -0
  204. package/dist/plugins/Plugin.js +1 -0
  205. package/dist/plugins/Plugin.js.map +1 -0
  206. package/dist/plugins/analysis/DatabaseAnalyzer.d.ts.map +1 -1
  207. package/dist/plugins/analysis/DatabaseAnalyzer.js +20 -14
  208. package/dist/plugins/analysis/DatabaseAnalyzer.js.map +1 -0
  209. package/dist/plugins/analysis/ExpressAnalyzer.d.ts.map +1 -1
  210. package/dist/plugins/analysis/ExpressAnalyzer.js +23 -16
  211. package/dist/plugins/analysis/ExpressAnalyzer.js.map +1 -0
  212. package/dist/plugins/analysis/ExpressResponseAnalyzer.d.ts +2 -1
  213. package/dist/plugins/analysis/ExpressResponseAnalyzer.d.ts.map +1 -1
  214. package/dist/plugins/analysis/ExpressResponseAnalyzer.js +53 -76
  215. package/dist/plugins/analysis/ExpressResponseAnalyzer.js.map +1 -0
  216. package/dist/plugins/analysis/ExpressRouteAnalyzer.d.ts.map +1 -1
  217. package/dist/plugins/analysis/ExpressRouteAnalyzer.js +47 -37
  218. package/dist/plugins/analysis/ExpressRouteAnalyzer.js.map +1 -0
  219. package/dist/plugins/analysis/FetchAnalyzer.d.ts +8 -14
  220. package/dist/plugins/analysis/FetchAnalyzer.d.ts.map +1 -1
  221. package/dist/plugins/analysis/FetchAnalyzer.js +144 -97
  222. package/dist/plugins/analysis/FetchAnalyzer.js.map +1 -0
  223. package/dist/plugins/analysis/IncrementalAnalysisPlugin.d.ts.map +1 -1
  224. package/dist/plugins/analysis/IncrementalAnalysisPlugin.js +3 -5
  225. package/dist/plugins/analysis/IncrementalAnalysisPlugin.js.map +1 -0
  226. package/dist/plugins/analysis/JSASTAnalyzer.d.ts +59 -2
  227. package/dist/plugins/analysis/JSASTAnalyzer.d.ts.map +1 -1
  228. package/dist/plugins/analysis/JSASTAnalyzer.js +926 -422
  229. package/dist/plugins/analysis/JSASTAnalyzer.js.map +1 -0
  230. package/dist/plugins/analysis/ReactAnalyzer.d.ts.map +1 -1
  231. package/dist/plugins/analysis/ReactAnalyzer.js +24 -19
  232. package/dist/plugins/analysis/ReactAnalyzer.js.map +1 -0
  233. package/dist/plugins/analysis/RustAnalyzer.d.ts.map +1 -1
  234. package/dist/plugins/analysis/RustAnalyzer.js +39 -26
  235. package/dist/plugins/analysis/RustAnalyzer.js.map +1 -0
  236. package/dist/plugins/analysis/SQLiteAnalyzer.d.ts.map +1 -1
  237. package/dist/plugins/analysis/SQLiteAnalyzer.js +14 -7
  238. package/dist/plugins/analysis/SQLiteAnalyzer.js.map +1 -0
  239. package/dist/plugins/analysis/ServiceLayerAnalyzer.d.ts.map +1 -1
  240. package/dist/plugins/analysis/ServiceLayerAnalyzer.js +33 -28
  241. package/dist/plugins/analysis/ServiceLayerAnalyzer.js.map +1 -0
  242. package/dist/plugins/analysis/SocketIOAnalyzer.d.ts.map +1 -1
  243. package/dist/plugins/analysis/SocketIOAnalyzer.js +24 -14
  244. package/dist/plugins/analysis/SocketIOAnalyzer.js.map +1 -0
  245. package/dist/plugins/analysis/SystemDbAnalyzer.d.ts.map +1 -1
  246. package/dist/plugins/analysis/SystemDbAnalyzer.js +19 -11
  247. package/dist/plugins/analysis/SystemDbAnalyzer.js.map +1 -0
  248. package/dist/plugins/analysis/ast/ConditionParser.js +1 -0
  249. package/dist/plugins/analysis/ast/ConditionParser.js.map +1 -0
  250. package/dist/plugins/analysis/ast/ExpressionEvaluator.d.ts.map +1 -1
  251. package/dist/plugins/analysis/ast/ExpressionEvaluator.js +1 -0
  252. package/dist/plugins/analysis/ast/ExpressionEvaluator.js.map +1 -0
  253. package/dist/plugins/analysis/ast/GraphBuilder.d.ts +58 -6
  254. package/dist/plugins/analysis/ast/GraphBuilder.d.ts.map +1 -1
  255. package/dist/plugins/analysis/ast/GraphBuilder.js +440 -56
  256. package/dist/plugins/analysis/ast/GraphBuilder.js.map +1 -0
  257. package/dist/plugins/analysis/ast/IdGenerator.js +1 -0
  258. package/dist/plugins/analysis/ast/IdGenerator.js.map +1 -0
  259. package/dist/plugins/analysis/ast/OxcAdapter.js +1 -0
  260. package/dist/plugins/analysis/ast/OxcAdapter.js.map +1 -0
  261. package/dist/plugins/analysis/ast/types.d.ts +152 -1
  262. package/dist/plugins/analysis/ast/types.d.ts.map +1 -1
  263. package/dist/plugins/analysis/ast/types.js +1 -0
  264. package/dist/plugins/analysis/ast/types.js.map +1 -0
  265. package/dist/plugins/analysis/ast/utils/babelTraverse.d.ts +27 -0
  266. package/dist/plugins/analysis/ast/utils/babelTraverse.d.ts.map +1 -0
  267. package/dist/plugins/analysis/ast/utils/babelTraverse.js +45 -0
  268. package/dist/plugins/analysis/ast/utils/babelTraverse.js.map +1 -0
  269. package/dist/plugins/analysis/ast/utils/createParameterNodes.d.ts +1 -1
  270. package/dist/plugins/analysis/ast/utils/createParameterNodes.d.ts.map +1 -1
  271. package/dist/plugins/analysis/ast/utils/createParameterNodes.js +1 -0
  272. package/dist/plugins/analysis/ast/utils/createParameterNodes.js.map +1 -0
  273. package/dist/plugins/analysis/ast/utils/index.js +1 -0
  274. package/dist/plugins/analysis/ast/utils/index.js.map +1 -0
  275. package/dist/plugins/analysis/ast/utils/location.js +1 -0
  276. package/dist/plugins/analysis/ast/utils/location.js.map +1 -0
  277. package/dist/plugins/analysis/ast/visitors/ASTVisitor.d.ts +3 -1
  278. package/dist/plugins/analysis/ast/visitors/ASTVisitor.d.ts.map +1 -1
  279. package/dist/plugins/analysis/ast/visitors/ASTVisitor.js +1 -0
  280. package/dist/plugins/analysis/ast/visitors/ASTVisitor.js.map +1 -0
  281. package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts +9 -2
  282. package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts.map +1 -1
  283. package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.js +145 -14
  284. package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.js.map +1 -0
  285. package/dist/plugins/analysis/ast/visitors/ClassVisitor.d.ts +1 -1
  286. package/dist/plugins/analysis/ast/visitors/ClassVisitor.d.ts.map +1 -1
  287. package/dist/plugins/analysis/ast/visitors/ClassVisitor.js +198 -0
  288. package/dist/plugins/analysis/ast/visitors/ClassVisitor.js.map +1 -0
  289. package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts +4 -3
  290. package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts.map +1 -1
  291. package/dist/plugins/analysis/ast/visitors/FunctionVisitor.js +5 -2
  292. package/dist/plugins/analysis/ast/visitors/FunctionVisitor.js.map +1 -0
  293. package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.js +1 -0
  294. package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.js.map +1 -0
  295. package/dist/plugins/analysis/ast/visitors/PropertyAccessVisitor.d.ts +83 -0
  296. package/dist/plugins/analysis/ast/visitors/PropertyAccessVisitor.d.ts.map +1 -0
  297. package/dist/plugins/analysis/ast/visitors/PropertyAccessVisitor.js +258 -0
  298. package/dist/plugins/analysis/ast/visitors/PropertyAccessVisitor.js.map +1 -0
  299. package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.d.ts +1 -1
  300. package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.d.ts.map +1 -1
  301. package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.js +1 -0
  302. package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.js.map +1 -0
  303. package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts +1 -1
  304. package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts.map +1 -1
  305. package/dist/plugins/analysis/ast/visitors/VariableVisitor.js +1 -0
  306. package/dist/plugins/analysis/ast/visitors/VariableVisitor.js.map +1 -0
  307. package/dist/plugins/analysis/ast/visitors/index.d.ts +1 -0
  308. package/dist/plugins/analysis/ast/visitors/index.d.ts.map +1 -1
  309. package/dist/plugins/analysis/ast/visitors/index.js +2 -0
  310. package/dist/plugins/analysis/ast/visitors/index.js.map +1 -0
  311. package/dist/plugins/discovery/DiscoveryPlugin.d.ts +42 -10
  312. package/dist/plugins/discovery/DiscoveryPlugin.d.ts.map +1 -1
  313. package/dist/plugins/discovery/DiscoveryPlugin.js +17 -1
  314. package/dist/plugins/discovery/DiscoveryPlugin.js.map +1 -0
  315. package/dist/plugins/discovery/MonorepoServiceDiscovery.d.ts.map +1 -1
  316. package/dist/plugins/discovery/MonorepoServiceDiscovery.js +3 -2
  317. package/dist/plugins/discovery/MonorepoServiceDiscovery.js.map +1 -0
  318. package/dist/plugins/discovery/SimpleProjectDiscovery.d.ts.map +1 -1
  319. package/dist/plugins/discovery/SimpleProjectDiscovery.js +3 -2
  320. package/dist/plugins/discovery/SimpleProjectDiscovery.js.map +1 -0
  321. package/dist/plugins/discovery/WorkspaceDiscovery.d.ts.map +1 -1
  322. package/dist/plugins/discovery/WorkspaceDiscovery.js +3 -2
  323. package/dist/plugins/discovery/WorkspaceDiscovery.js.map +1 -0
  324. package/dist/plugins/discovery/resolveSourceEntrypoint.js +1 -0
  325. package/dist/plugins/discovery/resolveSourceEntrypoint.js.map +1 -0
  326. package/dist/plugins/discovery/workspaces/detector.js +1 -0
  327. package/dist/plugins/discovery/workspaces/detector.js.map +1 -0
  328. package/dist/plugins/discovery/workspaces/globResolver.js +1 -0
  329. package/dist/plugins/discovery/workspaces/globResolver.js.map +1 -0
  330. package/dist/plugins/discovery/workspaces/index.js +1 -0
  331. package/dist/plugins/discovery/workspaces/index.js.map +1 -0
  332. package/dist/plugins/discovery/workspaces/parsers.js +1 -0
  333. package/dist/plugins/discovery/workspaces/parsers.js.map +1 -0
  334. package/dist/plugins/enrichment/AliasTracker.js +3 -2
  335. package/dist/plugins/enrichment/AliasTracker.js.map +1 -0
  336. package/dist/plugins/enrichment/ArgumentParameterLinker.d.ts.map +1 -1
  337. package/dist/plugins/enrichment/ArgumentParameterLinker.js +1 -1
  338. package/dist/plugins/enrichment/ArgumentParameterLinker.js.map +1 -0
  339. package/dist/plugins/enrichment/ClosureCaptureEnricher.d.ts.map +1 -1
  340. package/dist/plugins/enrichment/ClosureCaptureEnricher.js +1 -1
  341. package/dist/plugins/enrichment/ClosureCaptureEnricher.js.map +1 -0
  342. package/dist/plugins/enrichment/ExpressHandlerLinker.d.ts +21 -0
  343. package/dist/plugins/enrichment/ExpressHandlerLinker.d.ts.map +1 -0
  344. package/dist/plugins/enrichment/ExpressHandlerLinker.js +137 -0
  345. package/dist/plugins/enrichment/ExpressHandlerLinker.js.map +1 -0
  346. package/dist/plugins/enrichment/ExternalCallResolver.d.ts.map +1 -1
  347. package/dist/plugins/enrichment/ExternalCallResolver.js +1 -1
  348. package/dist/plugins/enrichment/ExternalCallResolver.js.map +1 -0
  349. package/dist/plugins/enrichment/FunctionCallResolver.d.ts +5 -0
  350. package/dist/plugins/enrichment/FunctionCallResolver.d.ts.map +1 -1
  351. package/dist/plugins/enrichment/FunctionCallResolver.js +11 -9
  352. package/dist/plugins/enrichment/FunctionCallResolver.js.map +1 -0
  353. package/dist/plugins/enrichment/HTTPConnectionEnricher.d.ts +2 -0
  354. package/dist/plugins/enrichment/HTTPConnectionEnricher.d.ts.map +1 -1
  355. package/dist/plugins/enrichment/HTTPConnectionEnricher.js +51 -13
  356. package/dist/plugins/enrichment/HTTPConnectionEnricher.js.map +1 -0
  357. package/dist/plugins/enrichment/ImportExportLinker.d.ts.map +1 -1
  358. package/dist/plugins/enrichment/ImportExportLinker.js +1 -1
  359. package/dist/plugins/enrichment/ImportExportLinker.js.map +1 -0
  360. package/dist/plugins/enrichment/InstanceOfResolver.js +3 -2
  361. package/dist/plugins/enrichment/InstanceOfResolver.js.map +1 -0
  362. package/dist/plugins/enrichment/MethodCallResolver.d.ts +39 -1
  363. package/dist/plugins/enrichment/MethodCallResolver.d.ts.map +1 -1
  364. package/dist/plugins/enrichment/MethodCallResolver.js +422 -11
  365. package/dist/plugins/enrichment/MethodCallResolver.js.map +1 -0
  366. package/dist/plugins/enrichment/MountPointResolver.d.ts +1 -1
  367. package/dist/plugins/enrichment/MountPointResolver.d.ts.map +1 -1
  368. package/dist/plugins/enrichment/MountPointResolver.js +7 -23
  369. package/dist/plugins/enrichment/MountPointResolver.js.map +1 -0
  370. package/dist/plugins/enrichment/NodejsBuiltinsResolver.d.ts.map +1 -1
  371. package/dist/plugins/enrichment/NodejsBuiltinsResolver.js +2 -2
  372. package/dist/plugins/enrichment/NodejsBuiltinsResolver.js.map +1 -0
  373. package/dist/plugins/enrichment/PrefixEvaluator.d.ts.map +1 -1
  374. package/dist/plugins/enrichment/PrefixEvaluator.js +5 -4
  375. package/dist/plugins/enrichment/PrefixEvaluator.js.map +1 -0
  376. package/dist/plugins/enrichment/RejectionPropagationEnricher.d.ts +30 -0
  377. package/dist/plugins/enrichment/RejectionPropagationEnricher.d.ts.map +1 -0
  378. package/dist/plugins/enrichment/RejectionPropagationEnricher.js +190 -0
  379. package/dist/plugins/enrichment/RejectionPropagationEnricher.js.map +1 -0
  380. package/dist/plugins/enrichment/RustFFIEnricher.d.ts.map +1 -1
  381. package/dist/plugins/enrichment/RustFFIEnricher.js +1 -1
  382. package/dist/plugins/enrichment/RustFFIEnricher.js.map +1 -0
  383. package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts +1 -1
  384. package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts.map +1 -1
  385. package/dist/plugins/enrichment/ValueDomainAnalyzer.js +4 -3
  386. package/dist/plugins/enrichment/ValueDomainAnalyzer.js.map +1 -0
  387. package/dist/plugins/indexing/IncrementalModuleIndexer.d.ts +3 -1
  388. package/dist/plugins/indexing/IncrementalModuleIndexer.d.ts.map +1 -1
  389. package/dist/plugins/indexing/IncrementalModuleIndexer.js +22 -29
  390. package/dist/plugins/indexing/IncrementalModuleIndexer.js.map +1 -0
  391. package/dist/plugins/indexing/JSModuleIndexer.d.ts +3 -1
  392. package/dist/plugins/indexing/JSModuleIndexer.d.ts.map +1 -1
  393. package/dist/plugins/indexing/JSModuleIndexer.js +22 -31
  394. package/dist/plugins/indexing/JSModuleIndexer.js.map +1 -0
  395. package/dist/plugins/indexing/RustModuleIndexer.d.ts.map +1 -1
  396. package/dist/plugins/indexing/RustModuleIndexer.js +11 -5
  397. package/dist/plugins/indexing/RustModuleIndexer.js.map +1 -0
  398. package/dist/plugins/validation/BrokenImportValidator.d.ts.map +1 -1
  399. package/dist/plugins/validation/BrokenImportValidator.js +3 -3
  400. package/dist/plugins/validation/BrokenImportValidator.js.map +1 -0
  401. package/dist/plugins/validation/CallResolverValidator.d.ts.map +1 -1
  402. package/dist/plugins/validation/CallResolverValidator.js +3 -3
  403. package/dist/plugins/validation/CallResolverValidator.js.map +1 -0
  404. package/dist/plugins/validation/DataFlowValidator.js +2 -1
  405. package/dist/plugins/validation/DataFlowValidator.js.map +1 -0
  406. package/dist/plugins/validation/EvalBanValidator.js +2 -1
  407. package/dist/plugins/validation/EvalBanValidator.js.map +1 -0
  408. package/dist/plugins/validation/GraphConnectivityValidator.d.ts.map +1 -1
  409. package/dist/plugins/validation/GraphConnectivityValidator.js +2 -1
  410. package/dist/plugins/validation/GraphConnectivityValidator.js.map +1 -0
  411. package/dist/plugins/validation/SQLInjectionValidator.d.ts.map +1 -1
  412. package/dist/plugins/validation/SQLInjectionValidator.js +4 -2
  413. package/dist/plugins/validation/SQLInjectionValidator.js.map +1 -0
  414. package/dist/plugins/validation/ShadowingDetector.js +2 -1
  415. package/dist/plugins/validation/ShadowingDetector.js.map +1 -0
  416. package/dist/plugins/validation/TypeScriptDeadCodeValidator.d.ts.map +1 -1
  417. package/dist/plugins/validation/TypeScriptDeadCodeValidator.js +3 -3
  418. package/dist/plugins/validation/TypeScriptDeadCodeValidator.js.map +1 -0
  419. package/dist/plugins/vcs/GitPlugin.d.ts.map +1 -1
  420. package/dist/plugins/vcs/GitPlugin.js +13 -6
  421. package/dist/plugins/vcs/GitPlugin.js.map +1 -0
  422. package/dist/plugins/vcs/VCSPlugin.js +1 -0
  423. package/dist/plugins/vcs/VCSPlugin.js.map +1 -0
  424. package/dist/plugins/vcs/index.js +1 -0
  425. package/dist/plugins/vcs/index.js.map +1 -0
  426. package/dist/queries/findCallsInFunction.d.ts +1 -1
  427. package/dist/queries/findCallsInFunction.d.ts.map +1 -1
  428. package/dist/queries/findCallsInFunction.js +3 -2
  429. package/dist/queries/findCallsInFunction.js.map +1 -0
  430. package/dist/queries/findContainingFunction.d.ts +1 -1
  431. package/dist/queries/findContainingFunction.d.ts.map +1 -1
  432. package/dist/queries/findContainingFunction.js +1 -0
  433. package/dist/queries/findContainingFunction.js.map +1 -0
  434. package/dist/queries/index.js +1 -0
  435. package/dist/queries/index.js.map +1 -0
  436. package/dist/queries/traceValues.d.ts.map +1 -1
  437. package/dist/queries/traceValues.js +1 -0
  438. package/dist/queries/traceValues.js.map +1 -0
  439. package/dist/queries/types.js +1 -0
  440. package/dist/queries/types.js.map +1 -0
  441. package/dist/schema/GraphSchemaExtractor.js +1 -0
  442. package/dist/schema/GraphSchemaExtractor.js.map +1 -0
  443. package/dist/schema/InterfaceSchemaExtractor.js +1 -0
  444. package/dist/schema/InterfaceSchemaExtractor.js.map +1 -0
  445. package/dist/schema/index.js +1 -0
  446. package/dist/schema/index.js.map +1 -0
  447. package/dist/storage/backends/RFDBServerBackend.d.ts +25 -1
  448. package/dist/storage/backends/RFDBServerBackend.d.ts.map +1 -1
  449. package/dist/storage/backends/RFDBServerBackend.js +100 -22
  450. package/dist/storage/backends/RFDBServerBackend.js.map +1 -0
  451. package/dist/storage/backends/typeValidation.d.ts.map +1 -1
  452. package/dist/storage/backends/typeValidation.js +3 -0
  453. package/dist/storage/backends/typeValidation.js.map +1 -0
  454. package/dist/utils/findRfdbBinary.js +1 -0
  455. package/dist/utils/findRfdbBinary.js.map +1 -0
  456. package/dist/utils/moduleResolution.d.ts +134 -0
  457. package/dist/utils/moduleResolution.d.ts.map +1 -0
  458. package/dist/utils/moduleResolution.js +164 -0
  459. package/dist/utils/moduleResolution.js.map +1 -0
  460. package/dist/validation/PathValidator.d.ts.map +1 -1
  461. package/dist/validation/PathValidator.js +1 -0
  462. package/dist/validation/PathValidator.js.map +1 -0
  463. package/package.json +4 -3
  464. package/src/Orchestrator.ts +371 -41
  465. package/src/api/GraphAPI.ts +4 -2
  466. package/src/api/GuaranteeAPI.ts +3 -2
  467. package/src/config/ConfigLoader.ts +121 -3
  468. package/src/config/index.ts +7 -1
  469. package/src/core/ASTWorker.ts +8 -20
  470. package/src/core/ASTWorkerPool.ts +1 -1
  471. package/src/core/CoverageAnalyzer.ts +2 -2
  472. package/src/core/FileNodeManager.ts +3 -2
  473. package/src/core/GuaranteeManager.ts +1 -1
  474. package/src/core/IncrementalReanalyzer.ts +6 -3
  475. package/src/core/NodeFactory.ts +34 -1
  476. package/src/core/WorkerPool.ts +2 -1
  477. package/src/core/nodes/NodeKind.ts +11 -0
  478. package/src/core/nodes/PluginNode.ts +144 -0
  479. package/src/core/nodes/TypeNode.ts +1 -1
  480. package/src/core/nodes/index.ts +4 -0
  481. package/src/core/toposort.ts +160 -0
  482. package/src/diagnostics/DiagnosticCollector.ts +8 -1
  483. package/src/diagnostics/DiagnosticReporter.ts +87 -16
  484. package/src/diagnostics/categories.ts +104 -0
  485. package/src/diagnostics/index.ts +14 -0
  486. package/src/errors/GrafemaError.ts +58 -0
  487. package/src/index.ts +53 -9
  488. package/src/instructions/index.ts +21 -0
  489. package/src/instructions/onboarding.md +121 -0
  490. package/src/logging/Logger.ts +155 -4
  491. package/src/plugins/analysis/DatabaseAnalyzer.ts +22 -15
  492. package/src/plugins/analysis/ExpressAnalyzer.ts +30 -18
  493. package/src/plugins/analysis/ExpressResponseAnalyzer.ts +72 -88
  494. package/src/plugins/analysis/ExpressRouteAnalyzer.ts +54 -39
  495. package/src/plugins/analysis/FetchAnalyzer.ts +165 -113
  496. package/src/plugins/analysis/IncrementalAnalysisPlugin.ts +6 -7
  497. package/src/plugins/analysis/JSASTAnalyzer.ts +1122 -487
  498. package/src/plugins/analysis/ReactAnalyzer.ts +27 -20
  499. package/src/plugins/analysis/RustAnalyzer.ts +41 -27
  500. package/src/plugins/analysis/SQLiteAnalyzer.ts +18 -8
  501. package/src/plugins/analysis/ServiceLayerAnalyzer.ts +38 -34
  502. package/src/plugins/analysis/SocketIOAnalyzer.ts +30 -15
  503. package/src/plugins/analysis/SystemDbAnalyzer.ts +24 -13
  504. package/src/plugins/analysis/ast/ExpressionEvaluator.ts +1 -3
  505. package/src/plugins/analysis/ast/GraphBuilder.ts +532 -66
  506. package/src/plugins/analysis/ast/types.ts +200 -2
  507. package/src/plugins/analysis/ast/utils/babelTraverse.ts +74 -0
  508. package/src/plugins/analysis/ast/utils/createParameterNodes.ts +1 -1
  509. package/src/plugins/analysis/ast/visitors/ASTVisitor.ts +7 -2
  510. package/src/plugins/analysis/ast/visitors/CallExpressionVisitor.ts +163 -15
  511. package/src/plugins/analysis/ast/visitors/ClassVisitor.ts +249 -3
  512. package/src/plugins/analysis/ast/visitors/FunctionVisitor.ts +9 -4
  513. package/src/plugins/analysis/ast/visitors/PropertyAccessVisitor.ts +342 -0
  514. package/src/plugins/analysis/ast/visitors/TypeScriptVisitor.ts +2 -3
  515. package/src/plugins/analysis/ast/visitors/VariableVisitor.ts +1 -27
  516. package/src/plugins/analysis/ast/visitors/index.ts +2 -0
  517. package/src/plugins/discovery/DiscoveryPlugin.ts +42 -11
  518. package/src/plugins/discovery/MonorepoServiceDiscovery.ts +2 -2
  519. package/src/plugins/discovery/SimpleProjectDiscovery.ts +2 -2
  520. package/src/plugins/discovery/WorkspaceDiscovery.ts +2 -2
  521. package/src/plugins/discovery/workspaces/globResolver.ts +1 -1
  522. package/src/plugins/enrichment/AliasTracker.ts +2 -2
  523. package/src/plugins/enrichment/ArgumentParameterLinker.ts +0 -1
  524. package/src/plugins/enrichment/ClosureCaptureEnricher.ts +0 -1
  525. package/src/plugins/enrichment/ExpressHandlerLinker.ts +178 -0
  526. package/src/plugins/enrichment/ExternalCallResolver.ts +0 -1
  527. package/src/plugins/enrichment/FunctionCallResolver.ts +10 -15
  528. package/src/plugins/enrichment/HTTPConnectionEnricher.ts +65 -14
  529. package/src/plugins/enrichment/ImportExportLinker.ts +0 -1
  530. package/src/plugins/enrichment/InstanceOfResolver.ts +2 -2
  531. package/src/plugins/enrichment/MethodCallResolver.ts +526 -12
  532. package/src/plugins/enrichment/MountPointResolver.ts +6 -24
  533. package/src/plugins/enrichment/NodejsBuiltinsResolver.ts +1 -2
  534. package/src/plugins/enrichment/PrefixEvaluator.ts +4 -4
  535. package/src/plugins/enrichment/RejectionPropagationEnricher.ts +253 -0
  536. package/src/plugins/enrichment/RustFFIEnricher.ts +0 -1
  537. package/src/plugins/enrichment/ValueDomainAnalyzer.ts +3 -3
  538. package/src/plugins/indexing/IncrementalModuleIndexer.ts +24 -30
  539. package/src/plugins/indexing/JSModuleIndexer.ts +21 -22
  540. package/src/plugins/indexing/RustModuleIndexer.ts +10 -5
  541. package/src/plugins/validation/BrokenImportValidator.ts +2 -3
  542. package/src/plugins/validation/CallResolverValidator.ts +2 -3
  543. package/src/plugins/validation/DataFlowValidator.ts +1 -1
  544. package/src/plugins/validation/EvalBanValidator.ts +1 -1
  545. package/src/plugins/validation/GraphConnectivityValidator.ts +1 -9
  546. package/src/plugins/validation/SQLInjectionValidator.ts +3 -2
  547. package/src/plugins/validation/ShadowingDetector.ts +1 -1
  548. package/src/plugins/validation/TypeScriptDeadCodeValidator.ts +2 -3
  549. package/src/plugins/vcs/GitPlugin.ts +12 -6
  550. package/src/queries/findCallsInFunction.ts +4 -4
  551. package/src/queries/findContainingFunction.ts +1 -1
  552. package/src/queries/traceValues.ts +0 -1
  553. package/src/storage/backends/RFDBServerBackend.ts +115 -25
  554. package/src/storage/backends/typeValidation.ts +2 -0
  555. package/src/utils/moduleResolution.ts +244 -0
  556. package/src/validation/PathValidator.ts +0 -8
  557. package/src/plugins/validation/NodeCreationValidator.ts +0 -554
@@ -22,7 +22,7 @@ function isAnalysisResult(value) {
22
22
  import { Plugin, createSuccessResult, createErrorResult } from '../Plugin.js';
23
23
  import { ExpressionEvaluator } from './ast/ExpressionEvaluator.js';
24
24
  import { GraphBuilder } from './ast/GraphBuilder.js';
25
- import { ImportExportVisitor, VariableVisitor, FunctionVisitor, ClassVisitor, CallExpressionVisitor, TypeScriptVisitor } from './ast/visitors/index.js';
25
+ import { ImportExportVisitor, VariableVisitor, FunctionVisitor, ClassVisitor, CallExpressionVisitor, TypeScriptVisitor, PropertyAccessVisitor } from './ast/visitors/index.js';
26
26
  import { Task } from '../../core/Task.js';
27
27
  import { PriorityQueue } from '../../core/PriorityQueue.js';
28
28
  import { WorkerPool } from '../../core/WorkerPool.js';
@@ -35,6 +35,7 @@ import { computeSemanticId } from '../../core/SemanticId.js';
35
35
  import { ExpressionNode } from '../../core/nodes/ExpressionNode.js';
36
36
  import { ConstructorCallNode } from '../../core/nodes/ConstructorCallNode.js';
37
37
  import { ObjectLiteralNode } from '../../core/nodes/ObjectLiteralNode.js';
38
+ import { ArrayLiteralNode } from '../../core/nodes/ArrayLiteralNode.js';
38
39
  import { NodeFactory } from '../../core/NodeFactory.js';
39
40
  export class JSASTAnalyzer extends Plugin {
40
41
  graphBuilder;
@@ -50,7 +51,6 @@ export class JSASTAnalyzer extends Plugin {
50
51
  return {
51
52
  name: 'JSASTAnalyzer',
52
53
  phase: 'ANALYSIS',
53
- priority: 80,
54
54
  creates: {
55
55
  nodes: [
56
56
  'FUNCTION', 'CLASS', 'METHOD', 'VARIABLE', 'CONSTANT', 'SCOPE',
@@ -69,7 +69,16 @@ export class JSASTAnalyzer extends Plugin {
69
69
  'RESOLVES_TO'
70
70
  ]
71
71
  },
72
- dependencies: ['JSModuleIndexer']
72
+ dependencies: ['JSModuleIndexer'],
73
+ fields: [
74
+ { name: 'object', fieldType: 'string', nodeTypes: ['CALL'] },
75
+ { name: 'method', fieldType: 'string', nodeTypes: ['CALL'] },
76
+ { name: 'async', fieldType: 'bool', nodeTypes: ['FUNCTION', 'METHOD'] },
77
+ { name: 'scopeType', fieldType: 'string', nodeTypes: ['SCOPE'] },
78
+ { name: 'importType', fieldType: 'string', nodeTypes: ['IMPORT'] },
79
+ { name: 'exportType', fieldType: 'string', nodeTypes: ['EXPORT'] },
80
+ { name: 'parentScopeId', fieldType: 'id', nodeTypes: ['FUNCTION', 'METHOD', 'SCOPE', 'VARIABLE'] },
81
+ ]
73
82
  };
74
83
  }
75
84
  /**
@@ -1050,6 +1059,13 @@ export class JSASTAnalyzer extends Plugin {
1050
1059
  const promiseResolutions = [];
1051
1060
  // Promise executor contexts (REG-334) - keyed by executor function's start:end position
1052
1061
  const promiseExecutorContexts = new Map();
1062
+ // Yield expression tracking for YIELDS/DELEGATES_TO edges (REG-270)
1063
+ const yieldExpressions = [];
1064
+ // REG-311: Async error tracking
1065
+ const rejectionPatterns = [];
1066
+ const catchesFromInfos = [];
1067
+ // Property access tracking for PROPERTY_ACCESS nodes (REG-395)
1068
+ const propertyAccesses = [];
1053
1069
  const ifScopeCounterRef = { value: 0 };
1054
1070
  const scopeCounterRef = { value: 0 };
1055
1071
  const varDeclCounterRef = { value: 0 };
@@ -1062,6 +1078,7 @@ export class JSASTAnalyzer extends Plugin {
1062
1078
  const arrayLiteralCounterRef = { value: 0 };
1063
1079
  const branchCounterRef = { value: 0 };
1064
1080
  const caseCounterRef = { value: 0 };
1081
+ const propertyAccessCounterRef = { value: 0 };
1065
1082
  const processedNodes = {
1066
1083
  functions: new Set(),
1067
1084
  classes: new Set(),
@@ -1111,6 +1128,14 @@ export class JSASTAnalyzer extends Plugin {
1111
1128
  // Promise resolution tracking (REG-334)
1112
1129
  promiseResolutions,
1113
1130
  promiseExecutorContexts,
1131
+ // Yield expression tracking (REG-270)
1132
+ yieldExpressions,
1133
+ // REG-311: Async error tracking
1134
+ rejectionPatterns,
1135
+ catchesFromInfos,
1136
+ // Property access tracking (REG-395)
1137
+ propertyAccesses,
1138
+ propertyAccessCounterRef,
1114
1139
  objectLiteralCounterRef, arrayLiteralCounterRef,
1115
1140
  ifScopeCounterRef, scopeCounterRef, varDeclCounterRef,
1116
1141
  callSiteCounterRef, functionCounterRef, httpRequestCounterRef,
@@ -1199,7 +1224,7 @@ export class JSASTAnalyzer extends Plugin {
1199
1224
  }
1200
1225
  // === END VARIABLE REASSIGNMENT ===
1201
1226
  // Check for indexed array assignment at module level: arr[i] = value
1202
- this.detectIndexedArrayAssignment(assignNode, module, arrayMutations, scopeTracker);
1227
+ this.detectIndexedArrayAssignment(assignNode, module, arrayMutations, scopeTracker, allCollections);
1203
1228
  // Check for object property assignment at module level: obj.prop = value
1204
1229
  this.detectObjectPropertyAssignment(assignNode, module, objectMutations, scopeTracker);
1205
1230
  }
@@ -1279,6 +1304,11 @@ export class JSASTAnalyzer extends Plugin {
1279
1304
  const callExpressionVisitor = new CallExpressionVisitor(module, allCollections, scopeTracker);
1280
1305
  traverse(ast, callExpressionVisitor.getHandlers());
1281
1306
  this.profiler.end('traverse_calls');
1307
+ // Property access expressions (REG-395)
1308
+ this.profiler.start('traverse_property_access');
1309
+ const propertyAccessVisitor = new PropertyAccessVisitor(module, allCollections, scopeTracker);
1310
+ traverse(ast, propertyAccessVisitor.getHandlers());
1311
+ this.profiler.end('traverse_property_access');
1282
1312
  // Module-level NewExpression (constructor calls)
1283
1313
  // This handles top-level code like `const x = new Date()` that's not inside a function
1284
1314
  this.profiler.start('traverse_new');
@@ -1336,7 +1366,9 @@ export class JSASTAnalyzer extends Plugin {
1336
1366
  resolveName,
1337
1367
  rejectName,
1338
1368
  file: module.file,
1339
- line
1369
+ line,
1370
+ // REG-311: Module-level Promise has no creator function
1371
+ creatorFunctionId: undefined
1340
1372
  });
1341
1373
  }
1342
1374
  }
@@ -1435,6 +1467,8 @@ export class JSASTAnalyzer extends Plugin {
1435
1467
  variableReassignments,
1436
1468
  // Return statement tracking
1437
1469
  returnStatements,
1470
+ // Yield expression tracking (REG-270)
1471
+ yieldExpressions,
1438
1472
  // Update expression tracking (REG-288, REG-312)
1439
1473
  updateExpressions,
1440
1474
  // Promise resolution tracking (REG-334)
@@ -1442,7 +1476,16 @@ export class JSASTAnalyzer extends Plugin {
1442
1476
  // Object/Array literal tracking - use allCollections refs as visitors may have created new arrays
1443
1477
  objectLiterals: allCollections.objectLiterals || objectLiterals,
1444
1478
  objectProperties: allCollections.objectProperties || objectProperties,
1445
- arrayLiterals: allCollections.arrayLiterals || arrayLiterals
1479
+ arrayLiterals: allCollections.arrayLiterals || arrayLiterals,
1480
+ // REG-311: Async error tracking
1481
+ rejectionPatterns: Array.isArray(allCollections.rejectionPatterns)
1482
+ ? allCollections.rejectionPatterns
1483
+ : rejectionPatterns,
1484
+ catchesFromInfos: Array.isArray(allCollections.catchesFromInfos)
1485
+ ? allCollections.catchesFromInfos
1486
+ : catchesFromInfos,
1487
+ // Property access tracking (REG-395)
1488
+ propertyAccesses: allCollections.propertyAccesses || propertyAccesses
1446
1489
  });
1447
1490
  this.profiler.end('graph_build');
1448
1491
  nodesCreated = result.nodes;
@@ -1830,6 +1873,8 @@ export class JSASTAnalyzer extends Plugin {
1830
1873
  // Phase 6 (REG-267): Mark that this function has try/catch
1831
1874
  if (controlFlowState) {
1832
1875
  controlFlowState.hasTryCatch = true;
1876
+ // REG-311: Increment try block depth for O(1) isInsideTry detection
1877
+ controlFlowState.tryBlockDepth++;
1833
1878
  }
1834
1879
  // Determine actual parent - use stack for nested structures, otherwise original parentScopeId
1835
1880
  const actualParentScopeId = (scopeIdStack && scopeIdStack.length > 0)
@@ -1955,7 +2000,12 @@ export class JSASTAnalyzer extends Plugin {
1955
2000
  },
1956
2001
  exit: (tryPath) => {
1957
2002
  const tryNode = tryPath.node;
1958
- const scopeInfo = tryScopeMap.get(tryNode);
2003
+ const _scopeInfo = tryScopeMap.get(tryNode);
2004
+ // REG-311: Only decrement try block depth if we're still in 'try' block
2005
+ // (not transitioned to catch/finally, where we already decremented)
2006
+ if (controlFlowState && _scopeInfo?.currentBlock === 'try') {
2007
+ controlFlowState.tryBlockDepth--;
2008
+ }
1959
2009
  // Pop the current scope from stack (could be try, catch, or finally)
1960
2010
  if (scopeIdStack) {
1961
2011
  scopeIdStack.pop();
@@ -1980,7 +2030,7 @@ export class JSASTAnalyzer extends Plugin {
1980
2030
  * @param tryScopeMap - Map to track try/catch/finally scope transitions
1981
2031
  * @param scopeIdStack - Stack for tracking current scope ID for CONTAINS edges
1982
2032
  */
1983
- createCatchClauseHandler(module, variableDeclarations, varDeclCounterRef, scopeTracker, tryScopeMap, scopeIdStack) {
2033
+ createCatchClauseHandler(module, variableDeclarations, varDeclCounterRef, scopeTracker, tryScopeMap, scopeIdStack, controlFlowState) {
1984
2034
  return {
1985
2035
  enter: (catchPath) => {
1986
2036
  const catchNode = catchPath.node;
@@ -2002,6 +2052,11 @@ export class JSASTAnalyzer extends Plugin {
2002
2052
  scopeTracker.exitScope();
2003
2053
  scopeTracker.enterCountedScope('catch');
2004
2054
  }
2055
+ // REG-311: Decrement tryBlockDepth when leaving try block for catch
2056
+ // Calls in catch block should NOT have isInsideTry=true
2057
+ if (controlFlowState) {
2058
+ controlFlowState.tryBlockDepth--;
2059
+ }
2005
2060
  scopeInfo.currentBlock = 'catch';
2006
2061
  }
2007
2062
  // Handle catch parameter (e.g., catch (e) or catch ({ message }))
@@ -2311,6 +2366,172 @@ export class JSASTAnalyzer extends Plugin {
2311
2366
  }
2312
2367
  return parts.join('.');
2313
2368
  }
2369
+ /**
2370
+ * Extract return expression info from an expression node.
2371
+ * Used for both explicit return statements and implicit arrow returns.
2372
+ *
2373
+ * This method consolidates ~450 lines of duplicated expression handling code
2374
+ * from three locations:
2375
+ * 1. Top-level implicit arrow returns (arrow function expression body)
2376
+ * 2. ReturnStatement handler (explicit returns)
2377
+ * 3. Nested arrow function implicit returns
2378
+ *
2379
+ * @param expr - The expression being returned
2380
+ * @param module - Module info for file context
2381
+ * @param literals - Collection to add literal nodes to
2382
+ * @param literalCounterRef - Counter for generating unique literal IDs
2383
+ * @param baseLine - Line number for literal ID generation
2384
+ * @param baseColumn - Column number for literal ID generation
2385
+ * @param literalIdSuffix - 'return' or 'implicit_return'
2386
+ * @returns Partial ReturnStatementInfo with expression-specific fields
2387
+ */
2388
+ extractReturnExpressionInfo(expr, module, literals, literalCounterRef, baseLine, baseColumn, literalIdSuffix = 'return') {
2389
+ const exprLine = getLine(expr);
2390
+ const exprColumn = getColumn(expr);
2391
+ // Identifier (variable reference)
2392
+ if (t.isIdentifier(expr)) {
2393
+ return {
2394
+ returnValueType: 'VARIABLE',
2395
+ returnValueName: expr.name,
2396
+ };
2397
+ }
2398
+ // TemplateLiteral must come BEFORE isLiteral (TemplateLiteral extends Literal)
2399
+ if (t.isTemplateLiteral(expr)) {
2400
+ const sourceNames = [];
2401
+ for (const embedded of expr.expressions) {
2402
+ if (t.isIdentifier(embedded)) {
2403
+ sourceNames.push(embedded.name);
2404
+ }
2405
+ }
2406
+ return {
2407
+ returnValueType: 'EXPRESSION',
2408
+ expressionType: 'TemplateLiteral',
2409
+ returnValueLine: exprLine,
2410
+ returnValueColumn: exprColumn,
2411
+ returnValueId: NodeFactory.generateExpressionId('TemplateLiteral', module.file, exprLine, exprColumn),
2412
+ ...(sourceNames.length > 0 ? { expressionSourceNames: sourceNames } : {}),
2413
+ };
2414
+ }
2415
+ // Literal values (after TemplateLiteral check)
2416
+ if (t.isLiteral(expr)) {
2417
+ const literalId = `LITERAL#${literalIdSuffix}#${module.file}#${baseLine}:${baseColumn}:${literalCounterRef.value++}`;
2418
+ literals.push({
2419
+ id: literalId,
2420
+ type: 'LITERAL',
2421
+ value: ExpressionEvaluator.extractLiteralValue(expr),
2422
+ valueType: typeof ExpressionEvaluator.extractLiteralValue(expr),
2423
+ file: module.file,
2424
+ line: exprLine,
2425
+ column: exprColumn,
2426
+ });
2427
+ return {
2428
+ returnValueType: 'LITERAL',
2429
+ returnValueId: literalId,
2430
+ };
2431
+ }
2432
+ // Direct function call: return foo()
2433
+ if (t.isCallExpression(expr) && t.isIdentifier(expr.callee)) {
2434
+ return {
2435
+ returnValueType: 'CALL_SITE',
2436
+ returnValueLine: exprLine,
2437
+ returnValueColumn: exprColumn,
2438
+ returnValueCallName: expr.callee.name,
2439
+ };
2440
+ }
2441
+ // Method call: return obj.method()
2442
+ if (t.isCallExpression(expr) && t.isMemberExpression(expr.callee)) {
2443
+ return {
2444
+ returnValueType: 'METHOD_CALL',
2445
+ returnValueLine: exprLine,
2446
+ returnValueColumn: exprColumn,
2447
+ returnValueCallName: t.isIdentifier(expr.callee.property)
2448
+ ? expr.callee.property.name
2449
+ : undefined,
2450
+ };
2451
+ }
2452
+ // BinaryExpression: return a + b
2453
+ if (t.isBinaryExpression(expr)) {
2454
+ return {
2455
+ returnValueType: 'EXPRESSION',
2456
+ expressionType: 'BinaryExpression',
2457
+ returnValueLine: exprLine,
2458
+ returnValueColumn: exprColumn,
2459
+ operator: expr.operator,
2460
+ returnValueId: NodeFactory.generateExpressionId('BinaryExpression', module.file, exprLine, exprColumn),
2461
+ leftSourceName: t.isIdentifier(expr.left) ? expr.left.name : undefined,
2462
+ rightSourceName: t.isIdentifier(expr.right) ? expr.right.name : undefined,
2463
+ };
2464
+ }
2465
+ // LogicalExpression: return a && b, return a || b
2466
+ if (t.isLogicalExpression(expr)) {
2467
+ return {
2468
+ returnValueType: 'EXPRESSION',
2469
+ expressionType: 'LogicalExpression',
2470
+ returnValueLine: exprLine,
2471
+ returnValueColumn: exprColumn,
2472
+ operator: expr.operator,
2473
+ returnValueId: NodeFactory.generateExpressionId('LogicalExpression', module.file, exprLine, exprColumn),
2474
+ leftSourceName: t.isIdentifier(expr.left) ? expr.left.name : undefined,
2475
+ rightSourceName: t.isIdentifier(expr.right) ? expr.right.name : undefined,
2476
+ };
2477
+ }
2478
+ // ConditionalExpression: return condition ? a : b
2479
+ if (t.isConditionalExpression(expr)) {
2480
+ return {
2481
+ returnValueType: 'EXPRESSION',
2482
+ expressionType: 'ConditionalExpression',
2483
+ returnValueLine: exprLine,
2484
+ returnValueColumn: exprColumn,
2485
+ returnValueId: NodeFactory.generateExpressionId('ConditionalExpression', module.file, exprLine, exprColumn),
2486
+ consequentSourceName: t.isIdentifier(expr.consequent) ? expr.consequent.name : undefined,
2487
+ alternateSourceName: t.isIdentifier(expr.alternate) ? expr.alternate.name : undefined,
2488
+ };
2489
+ }
2490
+ // UnaryExpression: return !x, return -x
2491
+ if (t.isUnaryExpression(expr)) {
2492
+ return {
2493
+ returnValueType: 'EXPRESSION',
2494
+ expressionType: 'UnaryExpression',
2495
+ returnValueLine: exprLine,
2496
+ returnValueColumn: exprColumn,
2497
+ operator: expr.operator,
2498
+ returnValueId: NodeFactory.generateExpressionId('UnaryExpression', module.file, exprLine, exprColumn),
2499
+ unaryArgSourceName: t.isIdentifier(expr.argument) ? expr.argument.name : undefined,
2500
+ };
2501
+ }
2502
+ // MemberExpression (property access): return obj.prop
2503
+ if (t.isMemberExpression(expr)) {
2504
+ return {
2505
+ returnValueType: 'EXPRESSION',
2506
+ expressionType: 'MemberExpression',
2507
+ returnValueLine: exprLine,
2508
+ returnValueColumn: exprColumn,
2509
+ returnValueId: NodeFactory.generateExpressionId('MemberExpression', module.file, exprLine, exprColumn),
2510
+ object: t.isIdentifier(expr.object) ? expr.object.name : undefined,
2511
+ objectSourceName: t.isIdentifier(expr.object) ? expr.object.name : undefined,
2512
+ property: t.isIdentifier(expr.property) ? expr.property.name : undefined,
2513
+ computed: expr.computed,
2514
+ };
2515
+ }
2516
+ // NewExpression: return new Foo()
2517
+ if (t.isNewExpression(expr)) {
2518
+ return {
2519
+ returnValueType: 'EXPRESSION',
2520
+ expressionType: 'NewExpression',
2521
+ returnValueLine: exprLine,
2522
+ returnValueColumn: exprColumn,
2523
+ returnValueId: NodeFactory.generateExpressionId('NewExpression', module.file, exprLine, exprColumn),
2524
+ };
2525
+ }
2526
+ // Fallback for other expression types
2527
+ return {
2528
+ returnValueType: 'EXPRESSION',
2529
+ expressionType: expr.type,
2530
+ returnValueLine: exprLine,
2531
+ returnValueColumn: exprColumn,
2532
+ returnValueId: NodeFactory.generateExpressionId(expr.type, module.file, exprLine, exprColumn),
2533
+ };
2534
+ }
2314
2535
  /**
2315
2536
  * Factory method to create IfStatement handler.
2316
2537
  * Creates BRANCH node for if statement and SCOPE nodes for if/else bodies.
@@ -2587,11 +2808,11 @@ export class JSASTAnalyzer extends Plugin {
2587
2808
  const variableDeclarations = (collections.variableDeclarations ?? []);
2588
2809
  const callSites = (collections.callSites ?? []);
2589
2810
  const methodCalls = (collections.methodCalls ?? []);
2590
- const eventListeners = (collections.eventListeners ?? []);
2591
- const methodCallbacks = (collections.methodCallbacks ?? []);
2811
+ const _eventListeners = (collections.eventListeners ?? []);
2812
+ const _methodCallbacks = (collections.methodCallbacks ?? []);
2592
2813
  const classInstantiations = (collections.classInstantiations ?? []);
2593
2814
  const constructorCalls = (collections.constructorCalls ?? []);
2594
- const httpRequests = (collections.httpRequests ?? []);
2815
+ const _httpRequests = (collections.httpRequests ?? []);
2595
2816
  const literals = (collections.literals ?? []);
2596
2817
  const variableAssignments = (collections.variableAssignments ?? []);
2597
2818
  const ifScopeCounterRef = (collections.ifScopeCounterRef ?? { value: 0 });
@@ -2599,9 +2820,9 @@ export class JSASTAnalyzer extends Plugin {
2599
2820
  const varDeclCounterRef = (collections.varDeclCounterRef ?? { value: 0 });
2600
2821
  const callSiteCounterRef = (collections.callSiteCounterRef ?? { value: 0 });
2601
2822
  const functionCounterRef = (collections.functionCounterRef ?? { value: 0 });
2602
- const httpRequestCounterRef = (collections.httpRequestCounterRef ?? { value: 0 });
2823
+ const _httpRequestCounterRef = (collections.httpRequestCounterRef ?? { value: 0 });
2603
2824
  const literalCounterRef = (collections.literalCounterRef ?? { value: 0 });
2604
- const anonymousFunctionCounterRef = (collections.anonymousFunctionCounterRef ?? { value: 0 });
2825
+ const _anonymousFunctionCounterRef = (collections.anonymousFunctionCounterRef ?? { value: 0 });
2605
2826
  const scopeTracker = collections.scopeTracker;
2606
2827
  // Object literal tracking (REG-328)
2607
2828
  if (!collections.objectLiterals) {
@@ -2617,7 +2838,12 @@ export class JSASTAnalyzer extends Plugin {
2617
2838
  const objectProperties = collections.objectProperties;
2618
2839
  const objectLiteralCounterRef = collections.objectLiteralCounterRef;
2619
2840
  const returnStatements = (collections.returnStatements ?? []);
2620
- const parameters = (collections.parameters ?? []);
2841
+ // Initialize yieldExpressions if not exist to ensure nested function calls share same array
2842
+ if (!collections.yieldExpressions) {
2843
+ collections.yieldExpressions = [];
2844
+ }
2845
+ const yieldExpressions = collections.yieldExpressions;
2846
+ const _parameters = (collections.parameters ?? []);
2621
2847
  // Control flow collections (Phase 2: LOOP nodes)
2622
2848
  // Initialize if not exist to ensure nested function calls share same arrays
2623
2849
  if (!collections.loops) {
@@ -2642,9 +2868,9 @@ export class JSASTAnalyzer extends Plugin {
2642
2868
  };
2643
2869
  const parentScopeVariables = new Set();
2644
2870
  const processedCallSites = processedNodes.callSites;
2645
- const processedVarDecls = processedNodes.varDecls;
2871
+ const _processedVarDecls = processedNodes.varDecls;
2646
2872
  const processedMethodCalls = processedNodes.methodCalls;
2647
- const processedEventListeners = processedNodes.eventListeners;
2873
+ const _processedEventListeners = processedNodes.eventListeners;
2648
2874
  // Track if/else scope transitions (Phase 3: extended with branchId)
2649
2875
  const ifElseScopeMap = new Map();
2650
2876
  // Ensure branches and branchCounterRef are initialized (used by IfStatement and SwitchStatement)
@@ -2694,19 +2920,35 @@ export class JSASTAnalyzer extends Plugin {
2694
2920
  collections.promiseResolutions = [];
2695
2921
  }
2696
2922
  const promiseResolutions = collections.promiseResolutions;
2923
+ // REG-311: Initialize rejectionPatterns and catchesFromInfos collections
2924
+ if (!collections.rejectionPatterns) {
2925
+ collections.rejectionPatterns = [];
2926
+ }
2927
+ if (!collections.catchesFromInfos) {
2928
+ collections.catchesFromInfos = [];
2929
+ }
2930
+ const rejectionPatterns = collections.rejectionPatterns;
2931
+ const catchesFromInfos = collections.catchesFromInfos;
2697
2932
  // Dynamic scope ID stack for CONTAINS edges
2698
2933
  // Starts with the function body scope, gets updated as we enter/exit conditional scopes
2699
2934
  const scopeIdStack = [parentScopeId];
2700
2935
  const getCurrentScopeId = () => scopeIdStack[scopeIdStack.length - 1];
2701
2936
  // Determine the ID of the function we're analyzing for RETURNS edges
2702
2937
  // Find by matching file/line/column in functions collection (it was just added by the visitor)
2938
+ // REG-271: Skip for StaticBlock (static blocks don't have RETURNS edges or control flow metadata)
2703
2939
  const funcNode = funcPath.node;
2940
+ const functionNode = t.isFunction(funcNode) ? funcNode : null;
2941
+ const functionPath = functionNode ? funcPath : null;
2704
2942
  const funcLine = getLine(funcNode);
2705
2943
  const funcColumn = getColumn(funcNode);
2706
2944
  let currentFunctionId = null;
2707
- const matchingFunction = functions.find(f => f.file === module.file &&
2708
- f.line === funcLine &&
2709
- (f.column === undefined || f.column === funcColumn));
2945
+ // StaticBlock is not a function - skip function matching for RETURNS edges
2946
+ // For StaticBlock, matchingFunction will be undefined
2947
+ const matchingFunction = funcNode.type !== 'StaticBlock'
2948
+ ? functions.find(f => f.file === module.file &&
2949
+ f.line === funcLine &&
2950
+ (f.column === undefined || f.column === funcColumn))
2951
+ : undefined;
2710
2952
  if (matchingFunction) {
2711
2953
  currentFunctionId = matchingFunction.id;
2712
2954
  }
@@ -2720,7 +2962,9 @@ export class JSASTAnalyzer extends Plugin {
2720
2962
  hasEarlyReturn: false,
2721
2963
  hasThrow: false,
2722
2964
  returnCount: 0, // Track total return count for early return detection
2723
- totalStatements: 0 // Track if there are statements after returns
2965
+ totalStatements: 0, // Track if there are statements after returns
2966
+ // REG-311: Try block depth counter for O(1) isInsideTry detection
2967
+ tryBlockDepth: 0
2724
2968
  };
2725
2969
  // Handle implicit return for THIS arrow function if it has an expression body
2726
2970
  // e.g., `const double = x => x * 2;` - the function we're analyzing IS an arrow with expression body
@@ -2728,130 +2972,17 @@ export class JSASTAnalyzer extends Plugin {
2728
2972
  const bodyExpr = funcNode.body;
2729
2973
  const bodyLine = getLine(bodyExpr);
2730
2974
  const bodyColumn = getColumn(bodyExpr);
2975
+ // Extract expression-specific info using shared method
2976
+ const exprInfo = this.extractReturnExpressionInfo(bodyExpr, module, literals, literalCounterRef, funcLine, funcColumn, 'implicit_return');
2731
2977
  const returnInfo = {
2732
2978
  parentFunctionId: currentFunctionId,
2733
2979
  file: module.file,
2734
2980
  line: bodyLine,
2735
2981
  column: bodyColumn,
2736
2982
  returnValueType: 'NONE',
2737
- isImplicitReturn: true
2983
+ isImplicitReturn: true,
2984
+ ...exprInfo,
2738
2985
  };
2739
- // Apply type detection logic for the implicit return
2740
- if (t.isIdentifier(bodyExpr)) {
2741
- returnInfo.returnValueType = 'VARIABLE';
2742
- returnInfo.returnValueName = bodyExpr.name;
2743
- }
2744
- // TemplateLiteral must come BEFORE isLiteral (TemplateLiteral extends Literal)
2745
- else if (t.isTemplateLiteral(bodyExpr)) {
2746
- returnInfo.returnValueType = 'EXPRESSION';
2747
- returnInfo.expressionType = 'TemplateLiteral';
2748
- returnInfo.returnValueLine = getLine(bodyExpr);
2749
- returnInfo.returnValueColumn = getColumn(bodyExpr);
2750
- returnInfo.returnValueId = NodeFactory.generateExpressionId('TemplateLiteral', module.file, getLine(bodyExpr), getColumn(bodyExpr));
2751
- const sourceNames = [];
2752
- for (const expr of bodyExpr.expressions) {
2753
- if (t.isIdentifier(expr))
2754
- sourceNames.push(expr.name);
2755
- }
2756
- if (sourceNames.length > 0)
2757
- returnInfo.expressionSourceNames = sourceNames;
2758
- }
2759
- else if (t.isLiteral(bodyExpr)) {
2760
- returnInfo.returnValueType = 'LITERAL';
2761
- const literalId = `LITERAL#implicit_return#${module.file}#${funcLine}:${funcColumn}:${literalCounterRef.value++}`;
2762
- returnInfo.returnValueId = literalId;
2763
- literals.push({
2764
- id: literalId,
2765
- type: 'LITERAL',
2766
- value: ExpressionEvaluator.extractLiteralValue(bodyExpr),
2767
- valueType: typeof ExpressionEvaluator.extractLiteralValue(bodyExpr),
2768
- file: module.file,
2769
- line: bodyLine,
2770
- column: bodyColumn
2771
- });
2772
- }
2773
- else if (t.isCallExpression(bodyExpr) && t.isIdentifier(bodyExpr.callee)) {
2774
- returnInfo.returnValueType = 'CALL_SITE';
2775
- returnInfo.returnValueLine = getLine(bodyExpr);
2776
- returnInfo.returnValueColumn = getColumn(bodyExpr);
2777
- returnInfo.returnValueCallName = bodyExpr.callee.name;
2778
- }
2779
- else if (t.isCallExpression(bodyExpr) && t.isMemberExpression(bodyExpr.callee)) {
2780
- returnInfo.returnValueType = 'METHOD_CALL';
2781
- returnInfo.returnValueLine = getLine(bodyExpr);
2782
- returnInfo.returnValueColumn = getColumn(bodyExpr);
2783
- if (t.isIdentifier(bodyExpr.callee.property)) {
2784
- returnInfo.returnValueCallName = bodyExpr.callee.property.name;
2785
- }
2786
- }
2787
- // REG-276: Detailed EXPRESSION handling for implicit arrow returns
2788
- else if (t.isBinaryExpression(bodyExpr)) {
2789
- returnInfo.returnValueType = 'EXPRESSION';
2790
- returnInfo.expressionType = 'BinaryExpression';
2791
- returnInfo.returnValueLine = getLine(bodyExpr);
2792
- returnInfo.returnValueColumn = getColumn(bodyExpr);
2793
- returnInfo.operator = bodyExpr.operator;
2794
- returnInfo.returnValueId = NodeFactory.generateExpressionId('BinaryExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr));
2795
- if (t.isIdentifier(bodyExpr.left))
2796
- returnInfo.leftSourceName = bodyExpr.left.name;
2797
- if (t.isIdentifier(bodyExpr.right))
2798
- returnInfo.rightSourceName = bodyExpr.right.name;
2799
- }
2800
- else if (t.isLogicalExpression(bodyExpr)) {
2801
- returnInfo.returnValueType = 'EXPRESSION';
2802
- returnInfo.expressionType = 'LogicalExpression';
2803
- returnInfo.returnValueLine = getLine(bodyExpr);
2804
- returnInfo.returnValueColumn = getColumn(bodyExpr);
2805
- returnInfo.operator = bodyExpr.operator;
2806
- returnInfo.returnValueId = NodeFactory.generateExpressionId('LogicalExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr));
2807
- if (t.isIdentifier(bodyExpr.left))
2808
- returnInfo.leftSourceName = bodyExpr.left.name;
2809
- if (t.isIdentifier(bodyExpr.right))
2810
- returnInfo.rightSourceName = bodyExpr.right.name;
2811
- }
2812
- else if (t.isConditionalExpression(bodyExpr)) {
2813
- returnInfo.returnValueType = 'EXPRESSION';
2814
- returnInfo.expressionType = 'ConditionalExpression';
2815
- returnInfo.returnValueLine = getLine(bodyExpr);
2816
- returnInfo.returnValueColumn = getColumn(bodyExpr);
2817
- returnInfo.returnValueId = NodeFactory.generateExpressionId('ConditionalExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr));
2818
- if (t.isIdentifier(bodyExpr.consequent))
2819
- returnInfo.consequentSourceName = bodyExpr.consequent.name;
2820
- if (t.isIdentifier(bodyExpr.alternate))
2821
- returnInfo.alternateSourceName = bodyExpr.alternate.name;
2822
- }
2823
- else if (t.isUnaryExpression(bodyExpr)) {
2824
- returnInfo.returnValueType = 'EXPRESSION';
2825
- returnInfo.expressionType = 'UnaryExpression';
2826
- returnInfo.returnValueLine = getLine(bodyExpr);
2827
- returnInfo.returnValueColumn = getColumn(bodyExpr);
2828
- returnInfo.operator = bodyExpr.operator;
2829
- returnInfo.returnValueId = NodeFactory.generateExpressionId('UnaryExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr));
2830
- if (t.isIdentifier(bodyExpr.argument))
2831
- returnInfo.unaryArgSourceName = bodyExpr.argument.name;
2832
- }
2833
- else if (t.isMemberExpression(bodyExpr)) {
2834
- returnInfo.returnValueType = 'EXPRESSION';
2835
- returnInfo.expressionType = 'MemberExpression';
2836
- returnInfo.returnValueLine = getLine(bodyExpr);
2837
- returnInfo.returnValueColumn = getColumn(bodyExpr);
2838
- returnInfo.returnValueId = NodeFactory.generateExpressionId('MemberExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr));
2839
- if (t.isIdentifier(bodyExpr.object)) {
2840
- returnInfo.object = bodyExpr.object.name;
2841
- returnInfo.objectSourceName = bodyExpr.object.name;
2842
- }
2843
- if (t.isIdentifier(bodyExpr.property))
2844
- returnInfo.property = bodyExpr.property.name;
2845
- returnInfo.computed = bodyExpr.computed;
2846
- }
2847
- else {
2848
- // Fallback: any other expression type
2849
- returnInfo.returnValueType = 'EXPRESSION';
2850
- returnInfo.expressionType = bodyExpr.type;
2851
- returnInfo.returnValueLine = getLine(bodyExpr);
2852
- returnInfo.returnValueColumn = getColumn(bodyExpr);
2853
- returnInfo.returnValueId = NodeFactory.generateExpressionId(bodyExpr.type, module.file, getLine(bodyExpr), getColumn(bodyExpr));
2854
- }
2855
2986
  returnStatements.push(returnInfo);
2856
2987
  }
2857
2988
  funcPath.traverse({
@@ -2879,7 +3010,7 @@ export class JSASTAnalyzer extends Plugin {
2879
3010
  }
2880
3011
  const arrayMutations = collections.arrayMutations;
2881
3012
  // Check for indexed array assignment: arr[i] = value
2882
- this.detectIndexedArrayAssignment(assignNode, module, arrayMutations, scopeTracker);
3013
+ this.detectIndexedArrayAssignment(assignNode, module, arrayMutations, scopeTracker, collections);
2883
3014
  // Initialize object mutations collection if not exists
2884
3015
  if (!collections.objectMutations) {
2885
3016
  collections.objectMutations = [];
@@ -2934,168 +3065,20 @@ export class JSASTAnalyzer extends Plugin {
2934
3065
  return;
2935
3066
  }
2936
3067
  const arg = returnNode.argument;
2937
- // Determine return value type and extract relevant info
3068
+ // Extract expression-specific info using shared method
3069
+ const exprInfo = this.extractReturnExpressionInfo(arg, module, literals, literalCounterRef, returnLine, returnColumn, 'return');
2938
3070
  const returnInfo = {
2939
3071
  parentFunctionId: currentFunctionId,
2940
3072
  file: module.file,
2941
3073
  line: returnLine,
2942
3074
  column: returnColumn,
2943
- returnValueType: 'NONE'
3075
+ returnValueType: 'NONE',
3076
+ ...exprInfo,
2944
3077
  };
2945
- // Identifier (variable reference)
2946
- if (t.isIdentifier(arg)) {
2947
- returnInfo.returnValueType = 'VARIABLE';
2948
- returnInfo.returnValueName = arg.name;
2949
- }
2950
- // TemplateLiteral must come BEFORE isLiteral (TemplateLiteral extends Literal)
2951
- else if (t.isTemplateLiteral(arg)) {
2952
- returnInfo.returnValueType = 'EXPRESSION';
2953
- returnInfo.expressionType = 'TemplateLiteral';
2954
- returnInfo.returnValueLine = getLine(arg);
2955
- returnInfo.returnValueColumn = getColumn(arg);
2956
- returnInfo.returnValueId = NodeFactory.generateExpressionId('TemplateLiteral', module.file, getLine(arg), getColumn(arg));
2957
- // Extract all embedded expression identifiers
2958
- const sourceNames = [];
2959
- for (const expr of arg.expressions) {
2960
- if (t.isIdentifier(expr)) {
2961
- sourceNames.push(expr.name);
2962
- }
2963
- }
2964
- if (sourceNames.length > 0) {
2965
- returnInfo.expressionSourceNames = sourceNames;
2966
- }
2967
- }
2968
- // Literal values (after TemplateLiteral check)
2969
- else if (t.isLiteral(arg)) {
2970
- returnInfo.returnValueType = 'LITERAL';
2971
- // Create a LITERAL node ID for this return value
2972
- const literalId = `LITERAL#return#${module.file}#${returnLine}:${returnColumn}:${literalCounterRef.value++}`;
2973
- returnInfo.returnValueId = literalId;
2974
- // Also add to literals collection for node creation
2975
- literals.push({
2976
- id: literalId,
2977
- type: 'LITERAL',
2978
- value: ExpressionEvaluator.extractLiteralValue(arg),
2979
- valueType: typeof ExpressionEvaluator.extractLiteralValue(arg),
2980
- file: module.file,
2981
- line: returnLine,
2982
- column: returnColumn
2983
- });
2984
- }
2985
- // Direct function call: return foo()
2986
- else if (t.isCallExpression(arg) && t.isIdentifier(arg.callee)) {
2987
- returnInfo.returnValueType = 'CALL_SITE';
2988
- returnInfo.returnValueLine = getLine(arg);
2989
- returnInfo.returnValueColumn = getColumn(arg);
2990
- returnInfo.returnValueCallName = arg.callee.name;
2991
- }
2992
- // Method call: return obj.method()
2993
- else if (t.isCallExpression(arg) && t.isMemberExpression(arg.callee)) {
2994
- returnInfo.returnValueType = 'METHOD_CALL';
2995
- returnInfo.returnValueLine = getLine(arg);
2996
- returnInfo.returnValueColumn = getColumn(arg);
2997
- // Extract method name for lookup
2998
- if (t.isIdentifier(arg.callee.property)) {
2999
- returnInfo.returnValueCallName = arg.callee.property.name;
3000
- }
3001
- }
3002
- // BinaryExpression: return a + b
3003
- else if (t.isBinaryExpression(arg)) {
3004
- returnInfo.returnValueType = 'EXPRESSION';
3005
- returnInfo.expressionType = 'BinaryExpression';
3006
- returnInfo.returnValueLine = getLine(arg);
3007
- returnInfo.returnValueColumn = getColumn(arg);
3008
- returnInfo.operator = arg.operator;
3009
- // Generate stable ID for the EXPRESSION node
3010
- returnInfo.returnValueId = NodeFactory.generateExpressionId('BinaryExpression', module.file, getLine(arg), getColumn(arg));
3011
- // Extract left operand source
3012
- if (t.isIdentifier(arg.left)) {
3013
- returnInfo.leftSourceName = arg.left.name;
3014
- }
3015
- // Extract right operand source
3016
- if (t.isIdentifier(arg.right)) {
3017
- returnInfo.rightSourceName = arg.right.name;
3018
- }
3019
- }
3020
- // LogicalExpression: return a && b, return a || b
3021
- else if (t.isLogicalExpression(arg)) {
3022
- returnInfo.returnValueType = 'EXPRESSION';
3023
- returnInfo.expressionType = 'LogicalExpression';
3024
- returnInfo.returnValueLine = getLine(arg);
3025
- returnInfo.returnValueColumn = getColumn(arg);
3026
- returnInfo.operator = arg.operator;
3027
- returnInfo.returnValueId = NodeFactory.generateExpressionId('LogicalExpression', module.file, getLine(arg), getColumn(arg));
3028
- if (t.isIdentifier(arg.left)) {
3029
- returnInfo.leftSourceName = arg.left.name;
3030
- }
3031
- if (t.isIdentifier(arg.right)) {
3032
- returnInfo.rightSourceName = arg.right.name;
3033
- }
3034
- }
3035
- // ConditionalExpression: return condition ? a : b
3036
- else if (t.isConditionalExpression(arg)) {
3037
- returnInfo.returnValueType = 'EXPRESSION';
3038
- returnInfo.expressionType = 'ConditionalExpression';
3039
- returnInfo.returnValueLine = getLine(arg);
3040
- returnInfo.returnValueColumn = getColumn(arg);
3041
- returnInfo.returnValueId = NodeFactory.generateExpressionId('ConditionalExpression', module.file, getLine(arg), getColumn(arg));
3042
- // Extract consequent (then branch) source
3043
- if (t.isIdentifier(arg.consequent)) {
3044
- returnInfo.consequentSourceName = arg.consequent.name;
3045
- }
3046
- // Extract alternate (else branch) source
3047
- if (t.isIdentifier(arg.alternate)) {
3048
- returnInfo.alternateSourceName = arg.alternate.name;
3049
- }
3050
- }
3051
- // UnaryExpression: return !x, return -x
3052
- else if (t.isUnaryExpression(arg)) {
3053
- returnInfo.returnValueType = 'EXPRESSION';
3054
- returnInfo.expressionType = 'UnaryExpression';
3055
- returnInfo.returnValueLine = getLine(arg);
3056
- returnInfo.returnValueColumn = getColumn(arg);
3057
- returnInfo.operator = arg.operator;
3058
- returnInfo.returnValueId = NodeFactory.generateExpressionId('UnaryExpression', module.file, getLine(arg), getColumn(arg));
3059
- if (t.isIdentifier(arg.argument)) {
3060
- returnInfo.unaryArgSourceName = arg.argument.name;
3061
- }
3062
- }
3063
- // MemberExpression (property access): return obj.prop
3064
- else if (t.isMemberExpression(arg)) {
3065
- returnInfo.returnValueType = 'EXPRESSION';
3066
- returnInfo.expressionType = 'MemberExpression';
3067
- returnInfo.returnValueLine = getLine(arg);
3068
- returnInfo.returnValueColumn = getColumn(arg);
3069
- returnInfo.returnValueId = NodeFactory.generateExpressionId('MemberExpression', module.file, getLine(arg), getColumn(arg));
3070
- // Extract object.property info
3071
- if (t.isIdentifier(arg.object)) {
3072
- returnInfo.object = arg.object.name;
3073
- returnInfo.objectSourceName = arg.object.name;
3074
- }
3075
- if (t.isIdentifier(arg.property)) {
3076
- returnInfo.property = arg.property.name;
3077
- }
3078
- returnInfo.computed = arg.computed;
3079
- }
3080
- // NewExpression: return new Foo()
3081
- else if (t.isNewExpression(arg)) {
3082
- returnInfo.returnValueType = 'EXPRESSION';
3083
- returnInfo.expressionType = 'NewExpression';
3084
- returnInfo.returnValueLine = getLine(arg);
3085
- returnInfo.returnValueColumn = getColumn(arg);
3086
- returnInfo.returnValueId = NodeFactory.generateExpressionId('NewExpression', module.file, getLine(arg), getColumn(arg));
3087
- }
3088
- // Fallback for other expression types
3089
- else {
3090
- returnInfo.returnValueType = 'EXPRESSION';
3091
- returnInfo.expressionType = arg.type;
3092
- returnInfo.returnValueLine = getLine(arg);
3093
- returnInfo.returnValueColumn = getColumn(arg);
3094
- returnInfo.returnValueId = NodeFactory.generateExpressionId(arg.type, module.file, getLine(arg), getColumn(arg));
3095
- }
3096
3078
  returnStatements.push(returnInfo);
3097
3079
  },
3098
3080
  // Phase 6 (REG-267): Track throw statements for control flow metadata
3081
+ // REG-311: Also detect async_throw rejection patterns
3099
3082
  ThrowStatement: (throwPath) => {
3100
3083
  // Skip if this throw is inside a nested function (not the function we're analyzing)
3101
3084
  let parent = throwPath.parentPath;
@@ -3107,6 +3090,122 @@ export class JSASTAnalyzer extends Plugin {
3107
3090
  parent = parent.parentPath;
3108
3091
  }
3109
3092
  controlFlowState.hasThrow = true;
3093
+ // REG-311: Track rejection patterns for async functions
3094
+ const isAsyncFunction = functionNode?.async === true;
3095
+ if (isAsyncFunction && currentFunctionId && functionNode && functionPath) {
3096
+ const throwNode = throwPath.node;
3097
+ const arg = throwNode.argument;
3098
+ const throwLine = getLine(throwNode);
3099
+ const throwColumn = getColumn(throwNode);
3100
+ // Case 1: throw new Error() or throw new CustomError()
3101
+ if (arg && t.isNewExpression(arg) && t.isIdentifier(arg.callee)) {
3102
+ rejectionPatterns.push({
3103
+ functionId: currentFunctionId,
3104
+ errorClassName: arg.callee.name,
3105
+ rejectionType: 'async_throw',
3106
+ file: module.file,
3107
+ line: throwLine,
3108
+ column: throwColumn
3109
+ });
3110
+ }
3111
+ // Case 2: throw identifier - needs micro-trace
3112
+ else if (arg && t.isIdentifier(arg)) {
3113
+ const varName = arg.name;
3114
+ // Check if it's a parameter
3115
+ const isParameter = functionNode.params.some(param => t.isIdentifier(param) && param.name === varName);
3116
+ if (isParameter) {
3117
+ // Parameter forwarding - can't resolve statically
3118
+ rejectionPatterns.push({
3119
+ functionId: currentFunctionId,
3120
+ errorClassName: null,
3121
+ rejectionType: 'variable_parameter',
3122
+ file: module.file,
3123
+ line: throwLine,
3124
+ column: throwColumn,
3125
+ sourceVariableName: varName
3126
+ });
3127
+ }
3128
+ else {
3129
+ // Try micro-trace
3130
+ const { errorClassName, tracePath } = this.microTraceToErrorClass(varName, functionPath, variableDeclarations);
3131
+ rejectionPatterns.push({
3132
+ functionId: currentFunctionId,
3133
+ errorClassName,
3134
+ rejectionType: errorClassName ? 'variable_traced' : 'variable_unknown',
3135
+ file: module.file,
3136
+ line: throwLine,
3137
+ column: throwColumn,
3138
+ sourceVariableName: varName,
3139
+ tracePath
3140
+ });
3141
+ }
3142
+ }
3143
+ }
3144
+ },
3145
+ // Handle yield expressions for YIELDS/DELEGATES_TO edges (REG-270)
3146
+ YieldExpression: (yieldPath) => {
3147
+ // Skip if we couldn't determine the function ID
3148
+ if (!currentFunctionId) {
3149
+ return;
3150
+ }
3151
+ // Skip if this yield is inside a nested function (not the function we're analyzing)
3152
+ // Check if there's a function ancestor BETWEEN us and funcNode
3153
+ let parent = yieldPath.parentPath;
3154
+ while (parent) {
3155
+ // If we've reached funcNode, we're done checking - this yield belongs to funcNode
3156
+ if (parent.node === funcNode) {
3157
+ break;
3158
+ }
3159
+ if (t.isFunction(parent.node)) {
3160
+ // Found a function between yieldPath and funcNode - this yield is inside a nested function
3161
+ return;
3162
+ }
3163
+ parent = parent.parentPath;
3164
+ }
3165
+ const yieldNode = yieldPath.node;
3166
+ const yieldLine = getLine(yieldNode);
3167
+ const yieldColumn = getColumn(yieldNode);
3168
+ const isDelegate = yieldNode.delegate ?? false;
3169
+ // Handle bare yield; (no value) - only valid for non-delegate yield
3170
+ if (!yieldNode.argument && !isDelegate) {
3171
+ // Skip - no data flow value
3172
+ return;
3173
+ }
3174
+ // For yield* without argument (syntax error in practice, but handle gracefully)
3175
+ if (!yieldNode.argument) {
3176
+ return;
3177
+ }
3178
+ const arg = yieldNode.argument;
3179
+ // Extract expression-specific info using shared method
3180
+ // Note: We reuse extractReturnExpressionInfo since yield values have identical semantics
3181
+ const exprInfo = this.extractReturnExpressionInfo(arg, module, literals, literalCounterRef, yieldLine, yieldColumn, 'yield');
3182
+ // Map ReturnStatementInfo fields to YieldExpressionInfo fields
3183
+ const yieldInfo = {
3184
+ parentFunctionId: currentFunctionId,
3185
+ file: module.file,
3186
+ line: yieldLine,
3187
+ column: yieldColumn,
3188
+ isDelegate,
3189
+ yieldValueType: exprInfo.returnValueType ?? 'NONE',
3190
+ yieldValueName: exprInfo.returnValueName,
3191
+ yieldValueId: exprInfo.returnValueId,
3192
+ yieldValueLine: exprInfo.returnValueLine,
3193
+ yieldValueColumn: exprInfo.returnValueColumn,
3194
+ yieldValueCallName: exprInfo.returnValueCallName,
3195
+ expressionType: exprInfo.expressionType,
3196
+ operator: exprInfo.operator,
3197
+ leftSourceName: exprInfo.leftSourceName,
3198
+ rightSourceName: exprInfo.rightSourceName,
3199
+ consequentSourceName: exprInfo.consequentSourceName,
3200
+ alternateSourceName: exprInfo.alternateSourceName,
3201
+ object: exprInfo.object,
3202
+ property: exprInfo.property,
3203
+ computed: exprInfo.computed,
3204
+ objectSourceName: exprInfo.objectSourceName,
3205
+ expressionSourceNames: exprInfo.expressionSourceNames,
3206
+ unaryArgSourceName: exprInfo.unaryArgSourceName,
3207
+ };
3208
+ yieldExpressions.push(yieldInfo);
3110
3209
  },
3111
3210
  ForStatement: this.createLoopScopeHandler('for', 'for-loop', 'for', parentScopeId, module, scopes, loops, scopeCounterRef, loopCounterRef, scopeTracker, scopeIdStack, controlFlowState),
3112
3211
  ForInStatement: this.createLoopScopeHandler('for-in', 'for-in-loop', 'for-in', parentScopeId, module, scopes, loops, scopeCounterRef, loopCounterRef, scopeTracker, scopeIdStack, controlFlowState),
@@ -3115,10 +3214,53 @@ export class JSASTAnalyzer extends Plugin {
3115
3214
  DoWhileStatement: this.createLoopScopeHandler('do-while', 'do-while-loop', 'do-while', parentScopeId, module, scopes, loops, scopeCounterRef, loopCounterRef, scopeTracker, scopeIdStack, controlFlowState),
3116
3215
  // Phase 4 (REG-267): Now creates TRY_BLOCK, CATCH_BLOCK, FINALLY_BLOCK nodes
3117
3216
  TryStatement: this.createTryStatementHandler(parentScopeId, module, scopes, tryBlocks, catchBlocks, finallyBlocks, scopeCounterRef, tryBlockCounterRef, catchBlockCounterRef, finallyBlockCounterRef, scopeTracker, tryScopeMap, scopeIdStack, controlFlowState),
3118
- CatchClause: this.createCatchClauseHandler(module, variableDeclarations, varDeclCounterRef, scopeTracker, tryScopeMap, scopeIdStack),
3217
+ CatchClause: this.createCatchClauseHandler(module, variableDeclarations, varDeclCounterRef, scopeTracker, tryScopeMap, scopeIdStack, controlFlowState),
3119
3218
  SwitchStatement: (switchPath) => {
3120
3219
  this.handleSwitchStatement(switchPath, parentScopeId, module, collections, scopeTracker, controlFlowState);
3121
3220
  },
3221
+ FunctionDeclaration: (funcDeclPath) => {
3222
+ const node = funcDeclPath.node;
3223
+ const funcName = node.id ? node.id.name : this.generateAnonymousName(scopeTracker);
3224
+ // Use semantic ID as primary ID when scopeTracker available
3225
+ const legacyId = `FUNCTION#${funcName}#${module.file}#${getLine(node)}:${getColumn(node)}:${functionCounterRef.value++}`;
3226
+ const functionId = scopeTracker
3227
+ ? computeSemanticId('FUNCTION', funcName, scopeTracker.getContext())
3228
+ : legacyId;
3229
+ functions.push({
3230
+ id: functionId,
3231
+ type: 'FUNCTION',
3232
+ name: funcName,
3233
+ file: module.file,
3234
+ line: getLine(node),
3235
+ column: getColumn(node),
3236
+ async: node.async || false,
3237
+ generator: node.generator || false,
3238
+ parentScopeId
3239
+ });
3240
+ const nestedScopeId = `SCOPE#${funcName}:body#${module.file}#${getLine(node)}`;
3241
+ const closureSemanticId = this.generateSemanticId('closure', scopeTracker);
3242
+ scopes.push({
3243
+ id: nestedScopeId,
3244
+ type: 'SCOPE',
3245
+ scopeType: 'closure',
3246
+ name: `${funcName}:body`,
3247
+ semanticId: closureSemanticId,
3248
+ conditional: false,
3249
+ file: module.file,
3250
+ line: getLine(node),
3251
+ parentFunctionId: functionId,
3252
+ capturesFrom: parentScopeId
3253
+ });
3254
+ // Enter nested function scope for semantic ID generation
3255
+ if (scopeTracker) {
3256
+ scopeTracker.enterScope(funcName, 'function');
3257
+ }
3258
+ this.analyzeFunctionBody(funcDeclPath, nestedScopeId, module, collections);
3259
+ if (scopeTracker) {
3260
+ scopeTracker.exitScope();
3261
+ }
3262
+ funcDeclPath.skip();
3263
+ },
3122
3264
  FunctionExpression: (funcPath) => {
3123
3265
  const node = funcPath.node;
3124
3266
  const funcName = node.id ? node.id.name : this.generateAnonymousName(scopeTracker);
@@ -3222,129 +3364,17 @@ export class JSASTAnalyzer extends Plugin {
3222
3364
  const bodyExpr = node.body;
3223
3365
  const bodyLine = getLine(bodyExpr);
3224
3366
  const bodyColumn = getColumn(bodyExpr);
3367
+ // Extract expression-specific info using shared method
3368
+ const exprInfo = this.extractReturnExpressionInfo(bodyExpr, module, literals, literalCounterRef, line, column, 'implicit_return');
3225
3369
  const returnInfo = {
3226
3370
  parentFunctionId: functionId,
3227
3371
  file: module.file,
3228
3372
  line: bodyLine,
3229
3373
  column: bodyColumn,
3230
3374
  returnValueType: 'NONE',
3231
- isImplicitReturn: true
3375
+ isImplicitReturn: true,
3376
+ ...exprInfo,
3232
3377
  };
3233
- // Apply same type detection logic as ReturnStatement handler
3234
- if (t.isIdentifier(bodyExpr)) {
3235
- returnInfo.returnValueType = 'VARIABLE';
3236
- returnInfo.returnValueName = bodyExpr.name;
3237
- }
3238
- // TemplateLiteral must come BEFORE isLiteral (TemplateLiteral extends Literal)
3239
- else if (t.isTemplateLiteral(bodyExpr)) {
3240
- returnInfo.returnValueType = 'EXPRESSION';
3241
- returnInfo.expressionType = 'TemplateLiteral';
3242
- returnInfo.returnValueLine = getLine(bodyExpr);
3243
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3244
- returnInfo.returnValueId = NodeFactory.generateExpressionId('TemplateLiteral', module.file, getLine(bodyExpr), getColumn(bodyExpr));
3245
- const sourceNames = [];
3246
- for (const expr of bodyExpr.expressions) {
3247
- if (t.isIdentifier(expr))
3248
- sourceNames.push(expr.name);
3249
- }
3250
- if (sourceNames.length > 0)
3251
- returnInfo.expressionSourceNames = sourceNames;
3252
- }
3253
- else if (t.isLiteral(bodyExpr)) {
3254
- returnInfo.returnValueType = 'LITERAL';
3255
- const literalId = `LITERAL#implicit_return#${module.file}#${line}:${column}:${literalCounterRef.value++}`;
3256
- returnInfo.returnValueId = literalId;
3257
- literals.push({
3258
- id: literalId,
3259
- type: 'LITERAL',
3260
- value: ExpressionEvaluator.extractLiteralValue(bodyExpr),
3261
- valueType: typeof ExpressionEvaluator.extractLiteralValue(bodyExpr),
3262
- file: module.file,
3263
- line: bodyLine,
3264
- column: bodyColumn
3265
- });
3266
- }
3267
- else if (t.isCallExpression(bodyExpr) && t.isIdentifier(bodyExpr.callee)) {
3268
- returnInfo.returnValueType = 'CALL_SITE';
3269
- returnInfo.returnValueLine = getLine(bodyExpr);
3270
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3271
- returnInfo.returnValueCallName = bodyExpr.callee.name;
3272
- }
3273
- else if (t.isCallExpression(bodyExpr) && t.isMemberExpression(bodyExpr.callee)) {
3274
- returnInfo.returnValueType = 'METHOD_CALL';
3275
- returnInfo.returnValueLine = getLine(bodyExpr);
3276
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3277
- if (t.isIdentifier(bodyExpr.callee.property)) {
3278
- returnInfo.returnValueCallName = bodyExpr.callee.property.name;
3279
- }
3280
- }
3281
- // REG-276: Detailed EXPRESSION handling for nested implicit arrow returns
3282
- else if (t.isBinaryExpression(bodyExpr)) {
3283
- returnInfo.returnValueType = 'EXPRESSION';
3284
- returnInfo.expressionType = 'BinaryExpression';
3285
- returnInfo.returnValueLine = getLine(bodyExpr);
3286
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3287
- returnInfo.operator = bodyExpr.operator;
3288
- returnInfo.returnValueId = NodeFactory.generateExpressionId('BinaryExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr));
3289
- if (t.isIdentifier(bodyExpr.left))
3290
- returnInfo.leftSourceName = bodyExpr.left.name;
3291
- if (t.isIdentifier(bodyExpr.right))
3292
- returnInfo.rightSourceName = bodyExpr.right.name;
3293
- }
3294
- else if (t.isLogicalExpression(bodyExpr)) {
3295
- returnInfo.returnValueType = 'EXPRESSION';
3296
- returnInfo.expressionType = 'LogicalExpression';
3297
- returnInfo.returnValueLine = getLine(bodyExpr);
3298
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3299
- returnInfo.operator = bodyExpr.operator;
3300
- returnInfo.returnValueId = NodeFactory.generateExpressionId('LogicalExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr));
3301
- if (t.isIdentifier(bodyExpr.left))
3302
- returnInfo.leftSourceName = bodyExpr.left.name;
3303
- if (t.isIdentifier(bodyExpr.right))
3304
- returnInfo.rightSourceName = bodyExpr.right.name;
3305
- }
3306
- else if (t.isConditionalExpression(bodyExpr)) {
3307
- returnInfo.returnValueType = 'EXPRESSION';
3308
- returnInfo.expressionType = 'ConditionalExpression';
3309
- returnInfo.returnValueLine = getLine(bodyExpr);
3310
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3311
- returnInfo.returnValueId = NodeFactory.generateExpressionId('ConditionalExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr));
3312
- if (t.isIdentifier(bodyExpr.consequent))
3313
- returnInfo.consequentSourceName = bodyExpr.consequent.name;
3314
- if (t.isIdentifier(bodyExpr.alternate))
3315
- returnInfo.alternateSourceName = bodyExpr.alternate.name;
3316
- }
3317
- else if (t.isUnaryExpression(bodyExpr)) {
3318
- returnInfo.returnValueType = 'EXPRESSION';
3319
- returnInfo.expressionType = 'UnaryExpression';
3320
- returnInfo.returnValueLine = getLine(bodyExpr);
3321
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3322
- returnInfo.operator = bodyExpr.operator;
3323
- returnInfo.returnValueId = NodeFactory.generateExpressionId('UnaryExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr));
3324
- if (t.isIdentifier(bodyExpr.argument))
3325
- returnInfo.unaryArgSourceName = bodyExpr.argument.name;
3326
- }
3327
- else if (t.isMemberExpression(bodyExpr)) {
3328
- returnInfo.returnValueType = 'EXPRESSION';
3329
- returnInfo.expressionType = 'MemberExpression';
3330
- returnInfo.returnValueLine = getLine(bodyExpr);
3331
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3332
- returnInfo.returnValueId = NodeFactory.generateExpressionId('MemberExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr));
3333
- if (t.isIdentifier(bodyExpr.object)) {
3334
- returnInfo.object = bodyExpr.object.name;
3335
- returnInfo.objectSourceName = bodyExpr.object.name;
3336
- }
3337
- if (t.isIdentifier(bodyExpr.property))
3338
- returnInfo.property = bodyExpr.property.name;
3339
- returnInfo.computed = bodyExpr.computed;
3340
- }
3341
- else {
3342
- returnInfo.returnValueType = 'EXPRESSION';
3343
- returnInfo.expressionType = bodyExpr.type;
3344
- returnInfo.returnValueLine = getLine(bodyExpr);
3345
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3346
- returnInfo.returnValueId = NodeFactory.generateExpressionId(bodyExpr.type, module.file, getLine(bodyExpr), getColumn(bodyExpr));
3347
- }
3348
3378
  returnStatements.push(returnInfo);
3349
3379
  }
3350
3380
  arrowPath.skip();
@@ -3383,7 +3413,12 @@ export class JSASTAnalyzer extends Plugin {
3383
3413
  BlockStatement: this.createBlockStatementHandler(scopeTracker, ifElseScopeMap, tryScopeMap, scopeIdStack),
3384
3414
  // Function call expressions
3385
3415
  CallExpression: (callPath) => {
3386
- this.handleCallExpression(callPath.node, processedCallSites, processedMethodCalls, callSites, methodCalls, module, callSiteCounterRef, scopeTracker, getCurrentScopeId(), collections);
3416
+ // REG-311: Detect isAwaited (parent is AwaitExpression)
3417
+ const parent = callPath.parentPath;
3418
+ const isAwaited = parent?.isAwaitExpression() ?? false;
3419
+ // REG-311: Detect isInsideTry (O(1) via depth counter)
3420
+ const isInsideTry = controlFlowState.tryBlockDepth > 0;
3421
+ this.handleCallExpression(callPath.node, processedCallSites, processedMethodCalls, callSites, methodCalls, module, callSiteCounterRef, scopeTracker, getCurrentScopeId(), collections, isAwaited, isInsideTry);
3387
3422
  // REG-334: Check for resolve/reject calls inside Promise executors
3388
3423
  const callNode = callPath.node;
3389
3424
  if (t.isIdentifier(callNode.callee)) {
@@ -3476,6 +3511,147 @@ export class JSASTAnalyzer extends Plugin {
3476
3511
  }
3477
3512
  funcParent = funcParent.getFunctionParent();
3478
3513
  }
3514
+ // REG-311: Detect executor_reject pattern - reject(new Error()) inside Promise executor
3515
+ // Walk up to find Promise executor context and check if this is reject call with NewExpression arg
3516
+ funcParent = callPath.getFunctionParent();
3517
+ while (funcParent && currentFunctionId) {
3518
+ const funcNode = funcParent.node;
3519
+ const funcKey = `${funcNode.start}:${funcNode.end}`;
3520
+ const context = promiseExecutorContexts.get(funcKey);
3521
+ if (context && calleeName === context.rejectName && callNode.arguments.length > 0) {
3522
+ // REG-311: Use the creator function's ID (the function that created the Promise),
3523
+ // not the executor's ID
3524
+ const targetFunctionId = context.creatorFunctionId || currentFunctionId;
3525
+ const arg = callNode.arguments[0];
3526
+ const callLine = getLine(callNode);
3527
+ const callColumn = getColumn(callNode);
3528
+ // Case 1: reject(new Error())
3529
+ if (t.isNewExpression(arg) && t.isIdentifier(arg.callee)) {
3530
+ rejectionPatterns.push({
3531
+ functionId: targetFunctionId,
3532
+ errorClassName: arg.callee.name,
3533
+ rejectionType: 'executor_reject',
3534
+ file: module.file,
3535
+ line: callLine,
3536
+ column: callColumn
3537
+ });
3538
+ }
3539
+ // Case 2: reject(err) where err is variable
3540
+ else if (t.isIdentifier(arg)) {
3541
+ const varName = arg.name;
3542
+ // Check if it's a parameter of ANY containing function (executor, outer, etc.)
3543
+ // Walk up the function chain to find if varName is a parameter
3544
+ let isParameter = false;
3545
+ let checkParent = funcParent;
3546
+ while (checkParent) {
3547
+ if (t.isFunction(checkParent.node)) {
3548
+ if (checkParent.node.params.some(p => t.isIdentifier(p) && p.name === varName)) {
3549
+ isParameter = true;
3550
+ break;
3551
+ }
3552
+ }
3553
+ checkParent = checkParent.getFunctionParent();
3554
+ }
3555
+ if (isParameter) {
3556
+ rejectionPatterns.push({
3557
+ functionId: targetFunctionId,
3558
+ errorClassName: null,
3559
+ rejectionType: 'variable_parameter',
3560
+ file: module.file,
3561
+ line: callLine,
3562
+ column: callColumn,
3563
+ sourceVariableName: varName
3564
+ });
3565
+ }
3566
+ else {
3567
+ // Try micro-trace
3568
+ const { errorClassName, tracePath } = this.microTraceToErrorClass(varName, funcParent, variableDeclarations);
3569
+ rejectionPatterns.push({
3570
+ functionId: targetFunctionId,
3571
+ errorClassName,
3572
+ rejectionType: errorClassName ? 'variable_traced' : 'variable_unknown',
3573
+ file: module.file,
3574
+ line: callLine,
3575
+ column: callColumn,
3576
+ sourceVariableName: varName,
3577
+ tracePath
3578
+ });
3579
+ }
3580
+ }
3581
+ break;
3582
+ }
3583
+ funcParent = funcParent.getFunctionParent();
3584
+ }
3585
+ }
3586
+ // REG-311: Detect Promise.reject(new Error()) pattern
3587
+ if (t.isMemberExpression(callNode.callee) && currentFunctionId) {
3588
+ const memberCallee = callNode.callee;
3589
+ if (t.isIdentifier(memberCallee.object) &&
3590
+ memberCallee.object.name === 'Promise' &&
3591
+ t.isIdentifier(memberCallee.property) &&
3592
+ memberCallee.property.name === 'reject' &&
3593
+ callNode.arguments.length > 0) {
3594
+ const arg = callNode.arguments[0];
3595
+ const callLine = getLine(callNode);
3596
+ const callColumn = getColumn(callNode);
3597
+ // Case 1: Promise.reject(new Error())
3598
+ if (t.isNewExpression(arg) && t.isIdentifier(arg.callee)) {
3599
+ rejectionPatterns.push({
3600
+ functionId: currentFunctionId,
3601
+ errorClassName: arg.callee.name,
3602
+ rejectionType: 'promise_reject',
3603
+ file: module.file,
3604
+ line: callLine,
3605
+ column: callColumn
3606
+ });
3607
+ }
3608
+ // Case 2: Promise.reject(err) where err is variable
3609
+ else if (t.isIdentifier(arg)) {
3610
+ const varName = arg.name;
3611
+ // Check if it's a parameter of containing function
3612
+ const isParameter = functionNode
3613
+ ? functionNode.params.some(param => t.isIdentifier(param) && param.name === varName)
3614
+ : false;
3615
+ if (isParameter) {
3616
+ rejectionPatterns.push({
3617
+ functionId: currentFunctionId,
3618
+ errorClassName: null,
3619
+ rejectionType: 'variable_parameter',
3620
+ file: module.file,
3621
+ line: callLine,
3622
+ column: callColumn,
3623
+ sourceVariableName: varName
3624
+ });
3625
+ }
3626
+ else {
3627
+ // Try micro-trace
3628
+ if (!functionPath) {
3629
+ rejectionPatterns.push({
3630
+ functionId: currentFunctionId,
3631
+ errorClassName: null,
3632
+ rejectionType: 'variable_unknown',
3633
+ file: module.file,
3634
+ line: callLine,
3635
+ column: callColumn,
3636
+ sourceVariableName: varName,
3637
+ tracePath: [varName]
3638
+ });
3639
+ return;
3640
+ }
3641
+ const { errorClassName, tracePath } = this.microTraceToErrorClass(varName, functionPath, variableDeclarations);
3642
+ rejectionPatterns.push({
3643
+ functionId: currentFunctionId,
3644
+ errorClassName,
3645
+ rejectionType: errorClassName ? 'variable_traced' : 'variable_unknown',
3646
+ file: module.file,
3647
+ line: callLine,
3648
+ column: callColumn,
3649
+ sourceVariableName: varName,
3650
+ tracePath
3651
+ });
3652
+ }
3653
+ }
3654
+ }
3479
3655
  }
3480
3656
  },
3481
3657
  // NewExpression (constructor calls)
@@ -3531,7 +3707,9 @@ export class JSASTAnalyzer extends Plugin {
3531
3707
  resolveName,
3532
3708
  rejectName,
3533
3709
  file: module.file,
3534
- line
3710
+ line,
3711
+ // REG-311: Store the ID of the function that creates the Promise
3712
+ creatorFunctionId: currentFunctionId || undefined
3535
3713
  });
3536
3714
  }
3537
3715
  }
@@ -3597,8 +3775,36 @@ export class JSASTAnalyzer extends Plugin {
3597
3775
  });
3598
3776
  }
3599
3777
  }
3778
+ },
3779
+ // Property access expressions (REG-395)
3780
+ // Shared handler for both MemberExpression and OptionalMemberExpression
3781
+ MemberExpression: (memberPath) => {
3782
+ // Initialize collections if needed
3783
+ if (!collections.propertyAccesses) {
3784
+ collections.propertyAccesses = [];
3785
+ }
3786
+ if (!collections.propertyAccessCounterRef) {
3787
+ collections.propertyAccessCounterRef = { value: 0 };
3788
+ }
3789
+ PropertyAccessVisitor.extractPropertyAccesses(memberPath, memberPath.node, module, collections.propertyAccesses, collections.propertyAccessCounterRef, scopeTracker, currentFunctionId || getCurrentScopeId());
3790
+ },
3791
+ // OptionalMemberExpression: obj?.prop (same logic as MemberExpression)
3792
+ OptionalMemberExpression: (memberPath) => {
3793
+ // Initialize collections if needed
3794
+ if (!collections.propertyAccesses) {
3795
+ collections.propertyAccesses = [];
3796
+ }
3797
+ if (!collections.propertyAccessCounterRef) {
3798
+ collections.propertyAccessCounterRef = { value: 0 };
3799
+ }
3800
+ PropertyAccessVisitor.extractPropertyAccesses(memberPath, memberPath.node, module, collections.propertyAccesses, collections.propertyAccessCounterRef, scopeTracker, currentFunctionId || getCurrentScopeId());
3600
3801
  }
3601
3802
  });
3803
+ // REG-311: Second pass - collect CATCHES_FROM info for try/catch blocks
3804
+ // This links catch blocks to exception sources in their corresponding try blocks
3805
+ if (functionPath) {
3806
+ this.collectCatchesFromInfo(functionPath, catchBlocks, callSites, methodCalls, constructorCalls, catchesFromInfos, module);
3807
+ }
3602
3808
  // Phase 6 (REG-267): Attach control flow metadata to the function node
3603
3809
  if (matchingFunction) {
3604
3810
  const cyclomaticComplexity = 1 +
@@ -3606,13 +3812,24 @@ export class JSASTAnalyzer extends Plugin {
3606
3812
  controlFlowState.loopCount +
3607
3813
  controlFlowState.caseCount +
3608
3814
  controlFlowState.logicalOpCount;
3815
+ // REG-311: Collect rejection info for this function
3816
+ const functionRejectionPatterns = rejectionPatterns.filter(p => p.functionId === matchingFunction.id);
3817
+ const canReject = functionRejectionPatterns.length > 0;
3818
+ const hasAsyncThrow = functionRejectionPatterns.some(p => p.rejectionType === 'async_throw');
3819
+ const rejectedBuiltinErrors = [...new Set(functionRejectionPatterns
3820
+ .filter(p => p.errorClassName !== null)
3821
+ .map(p => p.errorClassName))];
3609
3822
  matchingFunction.controlFlow = {
3610
3823
  hasBranches: controlFlowState.branchCount > 0,
3611
3824
  hasLoops: controlFlowState.loopCount > 0,
3612
3825
  hasTryCatch: controlFlowState.hasTryCatch,
3613
3826
  hasEarlyReturn: controlFlowState.hasEarlyReturn,
3614
3827
  hasThrow: controlFlowState.hasThrow,
3615
- cyclomaticComplexity
3828
+ cyclomaticComplexity,
3829
+ // REG-311: Async error tracking
3830
+ canReject,
3831
+ hasAsyncThrow,
3832
+ rejectedBuiltinErrors: rejectedBuiltinErrors.length > 0 ? rejectedBuiltinErrors : undefined
3616
3833
  };
3617
3834
  }
3618
3835
  }
@@ -3625,6 +3842,7 @@ export class JSASTAnalyzer extends Plugin {
3625
3842
  * - Method calls (MemberExpression callee) → methodCalls collection
3626
3843
  * - Array mutation detection (push, unshift, splice)
3627
3844
  * - Object.assign() detection
3845
+ * - REG-311: isAwaited and isInsideTry metadata on CALL nodes
3628
3846
  *
3629
3847
  * @param callNode - The call expression AST node
3630
3848
  * @param processedCallSites - Set of already processed call site keys to avoid duplicates
@@ -3636,8 +3854,10 @@ export class JSASTAnalyzer extends Plugin {
3636
3854
  * @param scopeTracker - Optional scope tracker for semantic ID generation
3637
3855
  * @param parentScopeId - ID of the parent scope containing this call
3638
3856
  * @param collections - Full collections object for array/object mutations
3857
+ * @param isAwaited - REG-311: true if wrapped in await expression
3858
+ * @param isInsideTry - REG-311: true if inside try block
3639
3859
  */
3640
- handleCallExpression(callNode, processedCallSites, processedMethodCalls, callSites, methodCalls, module, callSiteCounterRef, scopeTracker, parentScopeId, collections) {
3860
+ handleCallExpression(callNode, processedCallSites, processedMethodCalls, callSites, methodCalls, module, callSiteCounterRef, scopeTracker, parentScopeId, collections, isAwaited = false, isInsideTry = false) {
3641
3861
  // Handle direct function calls (greet(), main())
3642
3862
  if (callNode.callee.type === 'Identifier') {
3643
3863
  const nodeKey = `${callNode.start}:${callNode.end}`;
@@ -3661,7 +3881,10 @@ export class JSASTAnalyzer extends Plugin {
3661
3881
  line: getLine(callNode),
3662
3882
  column: getColumn(callNode), // REG-223: Add column for coordinate-based lookup
3663
3883
  parentScopeId,
3664
- targetFunctionName: calleeName
3884
+ targetFunctionName: calleeName,
3885
+ // REG-311: Async error tracking metadata
3886
+ isAwaited,
3887
+ isInsideTry
3665
3888
  });
3666
3889
  }
3667
3890
  // Handle method calls (obj.method(), data.process())
@@ -3697,7 +3920,11 @@ export class JSASTAnalyzer extends Plugin {
3697
3920
  file: module.file,
3698
3921
  line: getLine(callNode),
3699
3922
  column: getColumn(callNode),
3700
- parentScopeId
3923
+ parentScopeId,
3924
+ // REG-311: Async error tracking metadata
3925
+ isAwaited,
3926
+ isInsideTry,
3927
+ isMethodCall: true
3701
3928
  });
3702
3929
  // Check for array mutation methods (push, unshift, splice)
3703
3930
  const ARRAY_MUTATION_METHODS = ['push', 'unshift', 'splice'];
@@ -3720,6 +3947,7 @@ export class JSASTAnalyzer extends Plugin {
3720
3947
  }
3721
3948
  }
3722
3949
  // REG-117: Nested array mutations like obj.arr.push(item)
3950
+ // REG-395: General nested method calls like a.b.c() or obj.nested.method()
3723
3951
  // object is MemberExpression, property is the method name
3724
3952
  else if (object.type === 'MemberExpression' && property.type === 'Identifier') {
3725
3953
  const nestedMember = object;
@@ -3745,8 +3973,238 @@ export class JSASTAnalyzer extends Plugin {
3745
3973
  baseObjectName, propertyName);
3746
3974
  }
3747
3975
  }
3976
+ // REG-395: Create CALL node for nested method calls like a.b.c()
3977
+ const objectName = CallExpressionVisitor.extractMemberExpressionName(nestedMember);
3978
+ if (objectName) {
3979
+ const nodeKey = `${callNode.start}:${callNode.end}`;
3980
+ if (!processedMethodCalls.has(nodeKey)) {
3981
+ processedMethodCalls.add(nodeKey);
3982
+ const fullName = `${objectName}.${methodName}`;
3983
+ const legacyId = `CALL#${fullName}#${module.file}#${getLine(callNode)}:${getColumn(callNode)}:${callSiteCounterRef.value++}`;
3984
+ let methodCallId = legacyId;
3985
+ if (scopeTracker) {
3986
+ const discriminator = scopeTracker.getItemCounter(`CALL:${fullName}`);
3987
+ methodCallId = computeSemanticId('CALL', fullName, scopeTracker.getContext(), { discriminator });
3988
+ }
3989
+ methodCalls.push({
3990
+ id: methodCallId,
3991
+ type: 'CALL',
3992
+ name: fullName,
3993
+ object: objectName,
3994
+ method: methodName,
3995
+ file: module.file,
3996
+ line: getLine(callNode),
3997
+ column: getColumn(callNode),
3998
+ parentScopeId,
3999
+ isMethodCall: true
4000
+ });
4001
+ }
4002
+ }
4003
+ }
4004
+ }
4005
+ }
4006
+ /**
4007
+ * REG-311: Micro-trace - follow variable assignments within function to find error source.
4008
+ * Used to resolve reject(err) or throw err where err is a variable.
4009
+ *
4010
+ * Uses cycle detection via Set<variableName> to avoid infinite loops on circular assignments.
4011
+ *
4012
+ * @param variableName - Name of variable to trace
4013
+ * @param funcPath - NodePath of containing function for AST traversal
4014
+ * @param variableDeclarations - Variable declarations in current scope
4015
+ * @returns Error class name if traced to NewExpression, null otherwise, plus trace path
4016
+ */
4017
+ microTraceToErrorClass(variableName, funcPath, _variableDeclarations) {
4018
+ const tracePath = [variableName];
4019
+ const visited = new Set(); // Cycle detection
4020
+ let currentName = variableName;
4021
+ const funcBody = funcPath.node.body;
4022
+ if (!t.isBlockStatement(funcBody)) {
4023
+ return { errorClassName: null, tracePath };
4024
+ }
4025
+ // Iterate until we find a NewExpression or can't trace further
4026
+ while (!visited.has(currentName)) {
4027
+ visited.add(currentName);
4028
+ let found = false;
4029
+ let foundNewExpression = null;
4030
+ let nextName = null;
4031
+ // Walk AST to find assignments: currentName = newValue
4032
+ funcPath.traverse({
4033
+ VariableDeclarator: (declPath) => {
4034
+ if (found || foundNewExpression)
4035
+ return;
4036
+ if (t.isIdentifier(declPath.node.id) && declPath.node.id.name === currentName) {
4037
+ const init = declPath.node.init;
4038
+ if (init) {
4039
+ // Case 1: const err = new Error()
4040
+ if (t.isNewExpression(init) && t.isIdentifier(init.callee)) {
4041
+ tracePath.push(`new ${init.callee.name}()`);
4042
+ foundNewExpression = init.callee.name;
4043
+ found = true;
4044
+ return;
4045
+ }
4046
+ // Case 2: const err = otherVar (chain)
4047
+ if (t.isIdentifier(init)) {
4048
+ tracePath.push(init.name);
4049
+ nextName = init.name;
4050
+ found = true;
4051
+ return;
4052
+ }
4053
+ }
4054
+ }
4055
+ },
4056
+ AssignmentExpression: (assignPath) => {
4057
+ if (found || foundNewExpression)
4058
+ return;
4059
+ const left = assignPath.node.left;
4060
+ const right = assignPath.node.right;
4061
+ if (t.isIdentifier(left) && left.name === currentName) {
4062
+ if (t.isNewExpression(right) && t.isIdentifier(right.callee)) {
4063
+ tracePath.push(`new ${right.callee.name}()`);
4064
+ foundNewExpression = right.callee.name;
4065
+ found = true;
4066
+ return;
4067
+ }
4068
+ if (t.isIdentifier(right)) {
4069
+ tracePath.push(right.name);
4070
+ nextName = right.name;
4071
+ found = true;
4072
+ return;
4073
+ }
4074
+ }
4075
+ }
4076
+ });
4077
+ // If we found a NewExpression, return the class name
4078
+ if (foundNewExpression) {
4079
+ return { errorClassName: foundNewExpression, tracePath };
3748
4080
  }
4081
+ // If we found another variable to follow, continue
4082
+ if (nextName) {
4083
+ currentName = nextName;
4084
+ continue;
4085
+ }
4086
+ // Couldn't trace further
4087
+ break;
3749
4088
  }
4089
+ return { errorClassName: null, tracePath };
4090
+ }
4091
+ /**
4092
+ * REG-311: Collect CATCHES_FROM info linking catch blocks to exception sources in try blocks.
4093
+ *
4094
+ * Sources include:
4095
+ * - Awaited calls: await foo() in try block
4096
+ * - Sync calls: foo() in try block (any call can throw)
4097
+ * - Throw statements: throw new Error() in try block
4098
+ * - Constructor calls: new SomeClass() in try block
4099
+ *
4100
+ * @param funcPath - Function path to traverse
4101
+ * @param catchBlocks - Collection of CATCH_BLOCK nodes
4102
+ * @param callSites - Collection of CALL nodes (direct function calls)
4103
+ * @param methodCalls - Collection of CALL nodes (method calls)
4104
+ * @param constructorCalls - Collection of CONSTRUCTOR_CALL nodes
4105
+ * @param catchesFromInfos - Collection to push CatchesFromInfo to
4106
+ * @param module - Module context
4107
+ */
4108
+ collectCatchesFromInfo(funcPath, catchBlocks, callSites, methodCalls, constructorCalls, catchesFromInfos, module) {
4109
+ // Traverse to find TryStatements and collect sources
4110
+ funcPath.traverse({
4111
+ TryStatement: (tryPath) => {
4112
+ const tryNode = tryPath.node;
4113
+ const handler = tryNode.handler;
4114
+ // Skip if no catch clause
4115
+ if (!handler)
4116
+ return;
4117
+ // Find the catch block for this try
4118
+ // Match by line number since we don't have the tryBlockId here
4119
+ const catchLine = getLine(handler);
4120
+ const catchBlock = catchBlocks.find(cb => cb.file === module.file && cb.line === catchLine);
4121
+ if (!catchBlock || !catchBlock.parameterName)
4122
+ return;
4123
+ // Traverse only the try block body (not catch or finally)
4124
+ const _tryBody = tryNode.block;
4125
+ const sources = [];
4126
+ // Collect sources from try block
4127
+ tryPath.get('block').traverse({
4128
+ // Stop at nested TryStatement - don't collect from inner try blocks
4129
+ TryStatement: (innerPath) => {
4130
+ innerPath.skip(); // Don't traverse into nested try blocks
4131
+ },
4132
+ // Stop at function boundaries - don't collect from nested functions
4133
+ Function: (innerFuncPath) => {
4134
+ innerFuncPath.skip();
4135
+ },
4136
+ CallExpression: (callPath) => {
4137
+ const callNode = callPath.node;
4138
+ const callLine = getLine(callNode);
4139
+ const callColumn = getColumn(callNode);
4140
+ // Check if this is an awaited call
4141
+ const parent = callPath.parentPath;
4142
+ const isAwaited = parent?.isAwaitExpression() ?? false;
4143
+ // Find the CALL node that matches this CallExpression
4144
+ let sourceId = null;
4145
+ let sourceType = 'sync_call';
4146
+ // Check method calls first (includes Promise.reject which is a method call)
4147
+ const matchingMethodCall = methodCalls.find(mc => mc.file === module.file &&
4148
+ mc.line === callLine &&
4149
+ mc.column === callColumn);
4150
+ if (matchingMethodCall) {
4151
+ sourceId = matchingMethodCall.id;
4152
+ sourceType = isAwaited ? 'awaited_call' : 'sync_call';
4153
+ }
4154
+ else {
4155
+ // Check direct function calls
4156
+ const matchingCallSite = callSites.find(cs => cs.file === module.file &&
4157
+ cs.line === callLine &&
4158
+ cs.column === callColumn);
4159
+ if (matchingCallSite) {
4160
+ sourceId = matchingCallSite.id;
4161
+ sourceType = isAwaited ? 'awaited_call' : 'sync_call';
4162
+ }
4163
+ }
4164
+ if (sourceId) {
4165
+ sources.push({ id: sourceId, type: sourceType, line: callLine });
4166
+ }
4167
+ },
4168
+ ThrowStatement: (throwPath) => {
4169
+ const throwNode = throwPath.node;
4170
+ const throwLine = getLine(throwNode);
4171
+ const throwColumn = getColumn(throwNode);
4172
+ // Create a synthetic ID for the throw statement
4173
+ // We don't have THROW_STATEMENT nodes, so we use line/column as identifier
4174
+ const sourceId = `THROW#${module.file}#${throwLine}:${throwColumn}`;
4175
+ sources.push({ id: sourceId, type: 'throw_statement', line: throwLine });
4176
+ },
4177
+ NewExpression: (newPath) => {
4178
+ // Skip NewExpression that is direct argument of ThrowStatement
4179
+ // In `throw new Error()`, the throw statement is the primary source
4180
+ if (newPath.parentPath?.isThrowStatement()) {
4181
+ return;
4182
+ }
4183
+ const newNode = newPath.node;
4184
+ const newLine = getLine(newNode);
4185
+ const newColumn = getColumn(newNode);
4186
+ // Find matching constructor call
4187
+ const matchingConstructor = constructorCalls.find(cc => cc.file === module.file &&
4188
+ cc.line === newLine &&
4189
+ cc.column === newColumn);
4190
+ if (matchingConstructor) {
4191
+ sources.push({ id: matchingConstructor.id, type: 'constructor_call', line: newLine });
4192
+ }
4193
+ }
4194
+ });
4195
+ // Create CatchesFromInfo for each source
4196
+ for (const source of sources) {
4197
+ catchesFromInfos.push({
4198
+ catchBlockId: catchBlock.id,
4199
+ parameterName: catchBlock.parameterName,
4200
+ sourceId: source.id,
4201
+ sourceType: source.type,
4202
+ file: module.file,
4203
+ sourceLine: source.line
4204
+ });
4205
+ }
4206
+ }
4207
+ });
3750
4208
  }
3751
4209
  /**
3752
4210
  * Detect array mutation calls (push, unshift, splice) inside functions
@@ -3831,20 +4289,24 @@ export class JSASTAnalyzer extends Plugin {
3831
4289
  }
3832
4290
  /**
3833
4291
  * Detect indexed array assignment: arr[i] = value
3834
- * Creates ArrayMutationInfo for FLOWS_INTO edge generation in GraphBuilder
4292
+ * Creates ArrayMutationInfo for FLOWS_INTO edge generation in GraphBuilder.
4293
+ * For non-variable values (LITERAL, OBJECT_LITERAL, ARRAY_LITERAL), creates
4294
+ * value nodes and sets valueNodeId so GraphBuilder can create FLOWS_INTO edges.
3835
4295
  *
3836
4296
  * @param assignNode - The assignment expression node
3837
4297
  * @param module - Current module being analyzed
3838
4298
  * @param arrayMutations - Collection to push mutation info into
4299
+ * @param scopeTracker - Scope tracker for semantic ID generation
4300
+ * @param collections - Collections for creating value nodes (literals, objectLiterals, etc.)
3839
4301
  */
3840
- detectIndexedArrayAssignment(assignNode, module, arrayMutations, scopeTracker) {
4302
+ detectIndexedArrayAssignment(assignNode, module, arrayMutations, scopeTracker, collections) {
3841
4303
  // Check for indexed array assignment: arr[i] = value
3842
4304
  if (assignNode.left.type === 'MemberExpression' && assignNode.left.computed) {
3843
4305
  const memberExpr = assignNode.left;
3844
4306
  // Only process NumericLiteral keys - those are clearly array indexed assignments
3845
4307
  // e.g., arr[0] = value, arr[1] = value
3846
- // All other computed keys (StringLiteral, Identifier, expressions) are handled as object mutations
3847
- // This avoids duplicate edge creation for ambiguous cases like obj[key] = value
4308
+ // Other computed keys (Identifier, expressions) are ambiguous (could be array or object)
4309
+ // and are handled by detectObjectPropertyAssignment as computed mutations
3848
4310
  if (memberExpr.property.type !== 'NumericLiteral') {
3849
4311
  return;
3850
4312
  }
@@ -3852,16 +4314,38 @@ export class JSASTAnalyzer extends Plugin {
3852
4314
  if (memberExpr.object.type === 'Identifier') {
3853
4315
  const arrayName = memberExpr.object.name;
3854
4316
  const value = assignNode.right;
4317
+ // Use defensive loc checks instead of ! assertions
4318
+ const line = assignNode.loc?.start.line ?? 0;
4319
+ const column = assignNode.loc?.start.column ?? 0;
3855
4320
  const argInfo = {
3856
4321
  argIndex: 0,
3857
4322
  isSpread: false,
3858
4323
  valueType: 'EXPRESSION'
3859
4324
  };
3860
- // Determine value type
4325
+ // Determine value type and create value nodes for non-variable types (REG-392)
3861
4326
  const literalValue = ExpressionEvaluator.extractLiteralValue(value);
3862
4327
  if (literalValue !== null) {
3863
4328
  argInfo.valueType = 'LITERAL';
3864
4329
  argInfo.literalValue = literalValue;
4330
+ const valueLine = value.loc?.start.line ?? line;
4331
+ const valueColumn = value.loc?.start.column ?? column;
4332
+ // Create LITERAL node if collections available
4333
+ if (collections?.literals && collections.literalCounterRef) {
4334
+ const literalCounterRef = collections.literalCounterRef;
4335
+ const literalId = `LITERAL#indexed#${module.file}#${valueLine}:${valueColumn}:${literalCounterRef.value++}`;
4336
+ collections.literals.push({
4337
+ id: literalId,
4338
+ type: 'LITERAL',
4339
+ value: literalValue,
4340
+ valueType: typeof literalValue,
4341
+ file: module.file,
4342
+ line: valueLine,
4343
+ column: valueColumn,
4344
+ parentCallId: undefined,
4345
+ argIndex: 0
4346
+ });
4347
+ argInfo.valueNodeId = literalId;
4348
+ }
3865
4349
  }
3866
4350
  else if (value.type === 'Identifier') {
3867
4351
  argInfo.valueType = 'VARIABLE';
@@ -3869,18 +4353,37 @@ export class JSASTAnalyzer extends Plugin {
3869
4353
  }
3870
4354
  else if (value.type === 'ObjectExpression') {
3871
4355
  argInfo.valueType = 'OBJECT_LITERAL';
4356
+ const valueLine = value.loc?.start.line ?? line;
4357
+ const valueColumn = value.loc?.start.column ?? column;
4358
+ // Create OBJECT_LITERAL node if collections available
4359
+ if (collections?.objectLiteralCounterRef) {
4360
+ if (!collections.objectLiterals)
4361
+ collections.objectLiterals = [];
4362
+ const objectLiteralCounterRef = collections.objectLiteralCounterRef;
4363
+ const objectNode = ObjectLiteralNode.create(module.file, valueLine, valueColumn, { counter: objectLiteralCounterRef.value++ });
4364
+ collections.objectLiterals.push(objectNode);
4365
+ argInfo.valueNodeId = objectNode.id;
4366
+ }
3872
4367
  }
3873
4368
  else if (value.type === 'ArrayExpression') {
3874
4369
  argInfo.valueType = 'ARRAY_LITERAL';
4370
+ const valueLine = value.loc?.start.line ?? line;
4371
+ const valueColumn = value.loc?.start.column ?? column;
4372
+ // Create ARRAY_LITERAL node if collections available
4373
+ if (collections?.arrayLiteralCounterRef) {
4374
+ if (!collections.arrayLiterals)
4375
+ collections.arrayLiterals = [];
4376
+ const arrayLiteralCounterRef = collections.arrayLiteralCounterRef;
4377
+ const arrayNode = ArrayLiteralNode.create(module.file, valueLine, valueColumn, { counter: arrayLiteralCounterRef.value++ });
4378
+ collections.arrayLiterals.push(arrayNode);
4379
+ argInfo.valueNodeId = arrayNode.id;
4380
+ }
3875
4381
  }
3876
4382
  else if (value.type === 'CallExpression') {
3877
4383
  argInfo.valueType = 'CALL';
3878
4384
  argInfo.callLine = value.loc?.start.line;
3879
4385
  argInfo.callColumn = value.loc?.start.column;
3880
4386
  }
3881
- // Use defensive loc checks instead of ! assertions
3882
- const line = assignNode.loc?.start.line ?? 0;
3883
- const column = assignNode.loc?.start.column ?? 0;
3884
4387
  // Capture scope path for scope-aware lookup (REG-309)
3885
4388
  const scopePath = scopeTracker?.getContext().scopePath ?? [];
3886
4389
  arrayMutations.push({
@@ -4303,3 +4806,4 @@ export class JSASTAnalyzer extends Plugin {
4303
4806
  }
4304
4807
  }
4305
4808
  }
4809
+ //# sourceMappingURL=JSASTAnalyzer.js.map