@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
@@ -40,6 +40,7 @@ import {
40
40
  ClassVisitor,
41
41
  CallExpressionVisitor,
42
42
  TypeScriptVisitor,
43
+ PropertyAccessVisitor,
43
44
  type VisitorModule,
44
45
  type VisitorCollections,
45
46
  type TrackVariableAssignmentCallback
@@ -56,6 +57,7 @@ import { computeSemanticId } from '../../core/SemanticId.js';
56
57
  import { ExpressionNode } from '../../core/nodes/ExpressionNode.js';
57
58
  import { ConstructorCallNode } from '../../core/nodes/ConstructorCallNode.js';
58
59
  import { ObjectLiteralNode } from '../../core/nodes/ObjectLiteralNode.js';
60
+ import { ArrayLiteralNode } from '../../core/nodes/ArrayLiteralNode.js';
59
61
  import { NodeFactory } from '../../core/NodeFactory.js';
60
62
  import type { PluginContext, PluginResult, PluginMetadata, GraphBackend } from '@grafema/types';
61
63
  import type {
@@ -97,9 +99,13 @@ import type {
97
99
  ObjectMutationValue,
98
100
  VariableReassignmentInfo,
99
101
  ReturnStatementInfo,
102
+ YieldExpressionInfo,
100
103
  UpdateExpressionInfo,
101
104
  PromiseResolutionInfo,
102
105
  PromiseExecutorContext,
106
+ RejectionPatternInfo,
107
+ CatchesFromInfo,
108
+ PropertyAccessInfo,
103
109
  CounterRef,
104
110
  ProcessedNodes,
105
111
  ASTCollections,
@@ -165,6 +171,11 @@ interface Collections {
165
171
  promiseResolutions: PromiseResolutionInfo[];
166
172
  // Promise executor contexts (REG-334) - keyed by executor function's start:end position
167
173
  promiseExecutorContexts: Map<string, PromiseExecutorContext>;
174
+ // Yield expression tracking for YIELDS/DELEGATES_TO edges (REG-270)
175
+ yieldExpressions: YieldExpressionInfo[];
176
+ // Property access tracking for PROPERTY_ACCESS nodes (REG-395)
177
+ propertyAccesses: PropertyAccessInfo[];
178
+ propertyAccessCounterRef: CounterRef;
168
179
  objectLiteralCounterRef: CounterRef;
169
180
  arrayLiteralCounterRef: CounterRef;
170
181
  ifScopeCounterRef: CounterRef;
@@ -250,7 +261,6 @@ export class JSASTAnalyzer extends Plugin {
250
261
  return {
251
262
  name: 'JSASTAnalyzer',
252
263
  phase: 'ANALYSIS',
253
- priority: 80,
254
264
  creates: {
255
265
  nodes: [
256
266
  'FUNCTION', 'CLASS', 'METHOD', 'VARIABLE', 'CONSTANT', 'SCOPE',
@@ -269,7 +279,16 @@ export class JSASTAnalyzer extends Plugin {
269
279
  'RESOLVES_TO'
270
280
  ]
271
281
  },
272
- dependencies: ['JSModuleIndexer']
282
+ dependencies: ['JSModuleIndexer'],
283
+ fields: [
284
+ { name: 'object', fieldType: 'string', nodeTypes: ['CALL'] },
285
+ { name: 'method', fieldType: 'string', nodeTypes: ['CALL'] },
286
+ { name: 'async', fieldType: 'bool', nodeTypes: ['FUNCTION', 'METHOD'] },
287
+ { name: 'scopeType', fieldType: 'string', nodeTypes: ['SCOPE'] },
288
+ { name: 'importType', fieldType: 'string', nodeTypes: ['IMPORT'] },
289
+ { name: 'exportType', fieldType: 'string', nodeTypes: ['EXPORT'] },
290
+ { name: 'parentScopeId', fieldType: 'id', nodeTypes: ['FUNCTION', 'METHOD', 'SCOPE', 'VARIABLE'] },
291
+ ]
273
292
  };
274
293
  }
275
294
 
@@ -1458,6 +1477,13 @@ export class JSASTAnalyzer extends Plugin {
1458
1477
  const promiseResolutions: PromiseResolutionInfo[] = [];
1459
1478
  // Promise executor contexts (REG-334) - keyed by executor function's start:end position
1460
1479
  const promiseExecutorContexts = new Map<string, PromiseExecutorContext>();
1480
+ // Yield expression tracking for YIELDS/DELEGATES_TO edges (REG-270)
1481
+ const yieldExpressions: YieldExpressionInfo[] = [];
1482
+ // REG-311: Async error tracking
1483
+ const rejectionPatterns: RejectionPatternInfo[] = [];
1484
+ const catchesFromInfos: CatchesFromInfo[] = [];
1485
+ // Property access tracking for PROPERTY_ACCESS nodes (REG-395)
1486
+ const propertyAccesses: PropertyAccessInfo[] = [];
1461
1487
 
1462
1488
  const ifScopeCounterRef: CounterRef = { value: 0 };
1463
1489
  const scopeCounterRef: CounterRef = { value: 0 };
@@ -1471,6 +1497,7 @@ export class JSASTAnalyzer extends Plugin {
1471
1497
  const arrayLiteralCounterRef: CounterRef = { value: 0 };
1472
1498
  const branchCounterRef: CounterRef = { value: 0 };
1473
1499
  const caseCounterRef: CounterRef = { value: 0 };
1500
+ const propertyAccessCounterRef: CounterRef = { value: 0 };
1474
1501
 
1475
1502
  const processedNodes: ProcessedNodes = {
1476
1503
  functions: new Set(),
@@ -1533,6 +1560,14 @@ export class JSASTAnalyzer extends Plugin {
1533
1560
  // Promise resolution tracking (REG-334)
1534
1561
  promiseResolutions,
1535
1562
  promiseExecutorContexts,
1563
+ // Yield expression tracking (REG-270)
1564
+ yieldExpressions,
1565
+ // REG-311: Async error tracking
1566
+ rejectionPatterns,
1567
+ catchesFromInfos,
1568
+ // Property access tracking (REG-395)
1569
+ propertyAccesses,
1570
+ propertyAccessCounterRef,
1536
1571
  objectLiteralCounterRef, arrayLiteralCounterRef,
1537
1572
  ifScopeCounterRef, scopeCounterRef, varDeclCounterRef,
1538
1573
  callSiteCounterRef, functionCounterRef, httpRequestCounterRef,
@@ -1634,7 +1669,7 @@ export class JSASTAnalyzer extends Plugin {
1634
1669
  // === END VARIABLE REASSIGNMENT ===
1635
1670
 
1636
1671
  // Check for indexed array assignment at module level: arr[i] = value
1637
- this.detectIndexedArrayAssignment(assignNode, module, arrayMutations, scopeTracker);
1672
+ this.detectIndexedArrayAssignment(assignNode, module, arrayMutations, scopeTracker, allCollections);
1638
1673
 
1639
1674
  // Check for object property assignment at module level: obj.prop = value
1640
1675
  this.detectObjectPropertyAssignment(assignNode, module, objectMutations, scopeTracker);
@@ -1728,6 +1763,12 @@ export class JSASTAnalyzer extends Plugin {
1728
1763
  traverse(ast, callExpressionVisitor.getHandlers());
1729
1764
  this.profiler.end('traverse_calls');
1730
1765
 
1766
+ // Property access expressions (REG-395)
1767
+ this.profiler.start('traverse_property_access');
1768
+ const propertyAccessVisitor = new PropertyAccessVisitor(module, allCollections, scopeTracker);
1769
+ traverse(ast, propertyAccessVisitor.getHandlers());
1770
+ this.profiler.end('traverse_property_access');
1771
+
1731
1772
  // Module-level NewExpression (constructor calls)
1732
1773
  // This handles top-level code like `const x = new Date()` that's not inside a function
1733
1774
  this.profiler.start('traverse_new');
@@ -1791,7 +1832,9 @@ export class JSASTAnalyzer extends Plugin {
1791
1832
  resolveName,
1792
1833
  rejectName,
1793
1834
  file: module.file,
1794
- line
1835
+ line,
1836
+ // REG-311: Module-level Promise has no creator function
1837
+ creatorFunctionId: undefined
1795
1838
  });
1796
1839
  }
1797
1840
  }
@@ -1897,6 +1940,8 @@ export class JSASTAnalyzer extends Plugin {
1897
1940
  variableReassignments,
1898
1941
  // Return statement tracking
1899
1942
  returnStatements,
1943
+ // Yield expression tracking (REG-270)
1944
+ yieldExpressions,
1900
1945
  // Update expression tracking (REG-288, REG-312)
1901
1946
  updateExpressions,
1902
1947
  // Promise resolution tracking (REG-334)
@@ -1904,7 +1949,16 @@ export class JSASTAnalyzer extends Plugin {
1904
1949
  // Object/Array literal tracking - use allCollections refs as visitors may have created new arrays
1905
1950
  objectLiterals: allCollections.objectLiterals || objectLiterals,
1906
1951
  objectProperties: allCollections.objectProperties || objectProperties,
1907
- arrayLiterals: allCollections.arrayLiterals || arrayLiterals
1952
+ arrayLiterals: allCollections.arrayLiterals || arrayLiterals,
1953
+ // REG-311: Async error tracking
1954
+ rejectionPatterns: Array.isArray(allCollections.rejectionPatterns)
1955
+ ? allCollections.rejectionPatterns as RejectionPatternInfo[]
1956
+ : rejectionPatterns,
1957
+ catchesFromInfos: Array.isArray(allCollections.catchesFromInfos)
1958
+ ? allCollections.catchesFromInfos as CatchesFromInfo[]
1959
+ : catchesFromInfos,
1960
+ // Property access tracking (REG-395)
1961
+ propertyAccesses: allCollections.propertyAccesses || propertyAccesses
1908
1962
  });
1909
1963
  this.profiler.end('graph_build');
1910
1964
 
@@ -2401,7 +2455,7 @@ export class JSASTAnalyzer extends Plugin {
2401
2455
  scopeTracker: ScopeTracker | undefined,
2402
2456
  tryScopeMap: Map<t.TryStatement, TryScopeInfo>,
2403
2457
  scopeIdStack?: string[],
2404
- controlFlowState?: { hasTryCatch: boolean }
2458
+ controlFlowState?: { hasTryCatch: boolean; tryBlockDepth: number }
2405
2459
  ): { enter: (tryPath: NodePath<t.TryStatement>) => void; exit: (tryPath: NodePath<t.TryStatement>) => void } {
2406
2460
  return {
2407
2461
  enter: (tryPath: NodePath<t.TryStatement>) => {
@@ -2410,6 +2464,8 @@ export class JSASTAnalyzer extends Plugin {
2410
2464
  // Phase 6 (REG-267): Mark that this function has try/catch
2411
2465
  if (controlFlowState) {
2412
2466
  controlFlowState.hasTryCatch = true;
2467
+ // REG-311: Increment try block depth for O(1) isInsideTry detection
2468
+ controlFlowState.tryBlockDepth++;
2413
2469
  }
2414
2470
 
2415
2471
  // Determine actual parent - use stack for nested structures, otherwise original parentScopeId
@@ -2549,7 +2605,13 @@ export class JSASTAnalyzer extends Plugin {
2549
2605
  },
2550
2606
  exit: (tryPath: NodePath<t.TryStatement>) => {
2551
2607
  const tryNode = tryPath.node;
2552
- const scopeInfo = tryScopeMap.get(tryNode);
2608
+ const _scopeInfo = tryScopeMap.get(tryNode);
2609
+
2610
+ // REG-311: Only decrement try block depth if we're still in 'try' block
2611
+ // (not transitioned to catch/finally, where we already decremented)
2612
+ if (controlFlowState && _scopeInfo?.currentBlock === 'try') {
2613
+ controlFlowState.tryBlockDepth--;
2614
+ }
2553
2615
 
2554
2616
  // Pop the current scope from stack (could be try, catch, or finally)
2555
2617
  if (scopeIdStack) {
@@ -2584,7 +2646,8 @@ export class JSASTAnalyzer extends Plugin {
2584
2646
  varDeclCounterRef: CounterRef,
2585
2647
  scopeTracker: ScopeTracker | undefined,
2586
2648
  tryScopeMap: Map<t.TryStatement, TryScopeInfo>,
2587
- scopeIdStack?: string[]
2649
+ scopeIdStack?: string[],
2650
+ controlFlowState?: { hasTryCatch: boolean; tryBlockDepth: number }
2588
2651
  ): { enter: (catchPath: NodePath<t.CatchClause>) => void } {
2589
2652
  return {
2590
2653
  enter: (catchPath: NodePath<t.CatchClause>) => {
@@ -2610,6 +2673,12 @@ export class JSASTAnalyzer extends Plugin {
2610
2673
  scopeTracker.enterCountedScope('catch');
2611
2674
  }
2612
2675
 
2676
+ // REG-311: Decrement tryBlockDepth when leaving try block for catch
2677
+ // Calls in catch block should NOT have isInsideTry=true
2678
+ if (controlFlowState) {
2679
+ controlFlowState.tryBlockDepth--;
2680
+ }
2681
+
2613
2682
  scopeInfo.currentBlock = 'catch';
2614
2683
  }
2615
2684
 
@@ -2947,6 +3016,209 @@ export class JSASTAnalyzer extends Plugin {
2947
3016
  return parts.join('.');
2948
3017
  }
2949
3018
 
3019
+ /**
3020
+ * Extract return expression info from an expression node.
3021
+ * Used for both explicit return statements and implicit arrow returns.
3022
+ *
3023
+ * This method consolidates ~450 lines of duplicated expression handling code
3024
+ * from three locations:
3025
+ * 1. Top-level implicit arrow returns (arrow function expression body)
3026
+ * 2. ReturnStatement handler (explicit returns)
3027
+ * 3. Nested arrow function implicit returns
3028
+ *
3029
+ * @param expr - The expression being returned
3030
+ * @param module - Module info for file context
3031
+ * @param literals - Collection to add literal nodes to
3032
+ * @param literalCounterRef - Counter for generating unique literal IDs
3033
+ * @param baseLine - Line number for literal ID generation
3034
+ * @param baseColumn - Column number for literal ID generation
3035
+ * @param literalIdSuffix - 'return' or 'implicit_return'
3036
+ * @returns Partial ReturnStatementInfo with expression-specific fields
3037
+ */
3038
+ private extractReturnExpressionInfo(
3039
+ expr: t.Expression,
3040
+ module: { file: string },
3041
+ literals: LiteralInfo[],
3042
+ literalCounterRef: CounterRef,
3043
+ baseLine: number,
3044
+ baseColumn: number,
3045
+ literalIdSuffix: 'return' | 'implicit_return' | 'yield' = 'return'
3046
+ ): Partial<ReturnStatementInfo> {
3047
+ const exprLine = getLine(expr);
3048
+ const exprColumn = getColumn(expr);
3049
+
3050
+ // Identifier (variable reference)
3051
+ if (t.isIdentifier(expr)) {
3052
+ return {
3053
+ returnValueType: 'VARIABLE',
3054
+ returnValueName: expr.name,
3055
+ };
3056
+ }
3057
+
3058
+ // TemplateLiteral must come BEFORE isLiteral (TemplateLiteral extends Literal)
3059
+ if (t.isTemplateLiteral(expr)) {
3060
+ const sourceNames: string[] = [];
3061
+ for (const embedded of expr.expressions) {
3062
+ if (t.isIdentifier(embedded)) {
3063
+ sourceNames.push(embedded.name);
3064
+ }
3065
+ }
3066
+ return {
3067
+ returnValueType: 'EXPRESSION',
3068
+ expressionType: 'TemplateLiteral',
3069
+ returnValueLine: exprLine,
3070
+ returnValueColumn: exprColumn,
3071
+ returnValueId: NodeFactory.generateExpressionId(
3072
+ 'TemplateLiteral', module.file, exprLine, exprColumn
3073
+ ),
3074
+ ...(sourceNames.length > 0 ? { expressionSourceNames: sourceNames } : {}),
3075
+ };
3076
+ }
3077
+
3078
+ // Literal values (after TemplateLiteral check)
3079
+ if (t.isLiteral(expr)) {
3080
+ const literalId = `LITERAL#${literalIdSuffix}#${module.file}#${baseLine}:${baseColumn}:${literalCounterRef.value++}`;
3081
+ literals.push({
3082
+ id: literalId,
3083
+ type: 'LITERAL',
3084
+ value: ExpressionEvaluator.extractLiteralValue(expr),
3085
+ valueType: typeof ExpressionEvaluator.extractLiteralValue(expr),
3086
+ file: module.file,
3087
+ line: exprLine,
3088
+ column: exprColumn,
3089
+ });
3090
+ return {
3091
+ returnValueType: 'LITERAL',
3092
+ returnValueId: literalId,
3093
+ };
3094
+ }
3095
+
3096
+ // Direct function call: return foo()
3097
+ if (t.isCallExpression(expr) && t.isIdentifier(expr.callee)) {
3098
+ return {
3099
+ returnValueType: 'CALL_SITE',
3100
+ returnValueLine: exprLine,
3101
+ returnValueColumn: exprColumn,
3102
+ returnValueCallName: expr.callee.name,
3103
+ };
3104
+ }
3105
+
3106
+ // Method call: return obj.method()
3107
+ if (t.isCallExpression(expr) && t.isMemberExpression(expr.callee)) {
3108
+ return {
3109
+ returnValueType: 'METHOD_CALL',
3110
+ returnValueLine: exprLine,
3111
+ returnValueColumn: exprColumn,
3112
+ returnValueCallName: t.isIdentifier(expr.callee.property)
3113
+ ? expr.callee.property.name
3114
+ : undefined,
3115
+ };
3116
+ }
3117
+
3118
+ // BinaryExpression: return a + b
3119
+ if (t.isBinaryExpression(expr)) {
3120
+ return {
3121
+ returnValueType: 'EXPRESSION',
3122
+ expressionType: 'BinaryExpression',
3123
+ returnValueLine: exprLine,
3124
+ returnValueColumn: exprColumn,
3125
+ operator: expr.operator,
3126
+ returnValueId: NodeFactory.generateExpressionId(
3127
+ 'BinaryExpression', module.file, exprLine, exprColumn
3128
+ ),
3129
+ leftSourceName: t.isIdentifier(expr.left) ? expr.left.name : undefined,
3130
+ rightSourceName: t.isIdentifier(expr.right) ? expr.right.name : undefined,
3131
+ };
3132
+ }
3133
+
3134
+ // LogicalExpression: return a && b, return a || b
3135
+ if (t.isLogicalExpression(expr)) {
3136
+ return {
3137
+ returnValueType: 'EXPRESSION',
3138
+ expressionType: 'LogicalExpression',
3139
+ returnValueLine: exprLine,
3140
+ returnValueColumn: exprColumn,
3141
+ operator: expr.operator,
3142
+ returnValueId: NodeFactory.generateExpressionId(
3143
+ 'LogicalExpression', module.file, exprLine, exprColumn
3144
+ ),
3145
+ leftSourceName: t.isIdentifier(expr.left) ? expr.left.name : undefined,
3146
+ rightSourceName: t.isIdentifier(expr.right) ? expr.right.name : undefined,
3147
+ };
3148
+ }
3149
+
3150
+ // ConditionalExpression: return condition ? a : b
3151
+ if (t.isConditionalExpression(expr)) {
3152
+ return {
3153
+ returnValueType: 'EXPRESSION',
3154
+ expressionType: 'ConditionalExpression',
3155
+ returnValueLine: exprLine,
3156
+ returnValueColumn: exprColumn,
3157
+ returnValueId: NodeFactory.generateExpressionId(
3158
+ 'ConditionalExpression', module.file, exprLine, exprColumn
3159
+ ),
3160
+ consequentSourceName: t.isIdentifier(expr.consequent) ? expr.consequent.name : undefined,
3161
+ alternateSourceName: t.isIdentifier(expr.alternate) ? expr.alternate.name : undefined,
3162
+ };
3163
+ }
3164
+
3165
+ // UnaryExpression: return !x, return -x
3166
+ if (t.isUnaryExpression(expr)) {
3167
+ return {
3168
+ returnValueType: 'EXPRESSION',
3169
+ expressionType: 'UnaryExpression',
3170
+ returnValueLine: exprLine,
3171
+ returnValueColumn: exprColumn,
3172
+ operator: expr.operator,
3173
+ returnValueId: NodeFactory.generateExpressionId(
3174
+ 'UnaryExpression', module.file, exprLine, exprColumn
3175
+ ),
3176
+ unaryArgSourceName: t.isIdentifier(expr.argument) ? expr.argument.name : undefined,
3177
+ };
3178
+ }
3179
+
3180
+ // MemberExpression (property access): return obj.prop
3181
+ if (t.isMemberExpression(expr)) {
3182
+ return {
3183
+ returnValueType: 'EXPRESSION',
3184
+ expressionType: 'MemberExpression',
3185
+ returnValueLine: exprLine,
3186
+ returnValueColumn: exprColumn,
3187
+ returnValueId: NodeFactory.generateExpressionId(
3188
+ 'MemberExpression', module.file, exprLine, exprColumn
3189
+ ),
3190
+ object: t.isIdentifier(expr.object) ? expr.object.name : undefined,
3191
+ objectSourceName: t.isIdentifier(expr.object) ? expr.object.name : undefined,
3192
+ property: t.isIdentifier(expr.property) ? expr.property.name : undefined,
3193
+ computed: expr.computed,
3194
+ };
3195
+ }
3196
+
3197
+ // NewExpression: return new Foo()
3198
+ if (t.isNewExpression(expr)) {
3199
+ return {
3200
+ returnValueType: 'EXPRESSION',
3201
+ expressionType: 'NewExpression',
3202
+ returnValueLine: exprLine,
3203
+ returnValueColumn: exprColumn,
3204
+ returnValueId: NodeFactory.generateExpressionId(
3205
+ 'NewExpression', module.file, exprLine, exprColumn
3206
+ ),
3207
+ };
3208
+ }
3209
+
3210
+ // Fallback for other expression types
3211
+ return {
3212
+ returnValueType: 'EXPRESSION',
3213
+ expressionType: expr.type,
3214
+ returnValueLine: exprLine,
3215
+ returnValueColumn: exprColumn,
3216
+ returnValueId: NodeFactory.generateExpressionId(
3217
+ expr.type, module.file, exprLine, exprColumn
3218
+ ),
3219
+ };
3220
+ }
3221
+
2950
3222
  /**
2951
3223
  * Factory method to create IfStatement handler.
2952
3224
  * Creates BRANCH node for if statement and SCOPE nodes for if/else bodies.
@@ -3284,7 +3556,7 @@ export class JSASTAnalyzer extends Plugin {
3284
3556
  * Uses ScopeTracker from collections for semantic ID generation.
3285
3557
  */
3286
3558
  analyzeFunctionBody(
3287
- funcPath: NodePath<t.Function>,
3559
+ funcPath: NodePath<t.Function | t.StaticBlock>,
3288
3560
  parentScopeId: string,
3289
3561
  module: VisitorModule,
3290
3562
  collections: VisitorCollections
@@ -3295,11 +3567,11 @@ export class JSASTAnalyzer extends Plugin {
3295
3567
  const variableDeclarations = (collections.variableDeclarations ?? []) as VariableDeclarationInfo[];
3296
3568
  const callSites = (collections.callSites ?? []) as CallSiteInfo[];
3297
3569
  const methodCalls = (collections.methodCalls ?? []) as MethodCallInfo[];
3298
- const eventListeners = (collections.eventListeners ?? []) as EventListenerInfo[];
3299
- const methodCallbacks = (collections.methodCallbacks ?? []) as MethodCallbackInfo[];
3570
+ const _eventListeners = (collections.eventListeners ?? []) as EventListenerInfo[];
3571
+ const _methodCallbacks = (collections.methodCallbacks ?? []) as MethodCallbackInfo[];
3300
3572
  const classInstantiations = (collections.classInstantiations ?? []) as ClassInstantiationInfo[];
3301
3573
  const constructorCalls = (collections.constructorCalls ?? []) as ConstructorCallInfo[];
3302
- const httpRequests = (collections.httpRequests ?? []) as HttpRequestInfo[];
3574
+ const _httpRequests = (collections.httpRequests ?? []) as HttpRequestInfo[];
3303
3575
  const literals = (collections.literals ?? []) as LiteralInfo[];
3304
3576
  const variableAssignments = (collections.variableAssignments ?? []) as VariableAssignmentInfo[];
3305
3577
  const ifScopeCounterRef = (collections.ifScopeCounterRef ?? { value: 0 }) as CounterRef;
@@ -3307,9 +3579,9 @@ export class JSASTAnalyzer extends Plugin {
3307
3579
  const varDeclCounterRef = (collections.varDeclCounterRef ?? { value: 0 }) as CounterRef;
3308
3580
  const callSiteCounterRef = (collections.callSiteCounterRef ?? { value: 0 }) as CounterRef;
3309
3581
  const functionCounterRef = (collections.functionCounterRef ?? { value: 0 }) as CounterRef;
3310
- const httpRequestCounterRef = (collections.httpRequestCounterRef ?? { value: 0 }) as CounterRef;
3582
+ const _httpRequestCounterRef = (collections.httpRequestCounterRef ?? { value: 0 }) as CounterRef;
3311
3583
  const literalCounterRef = (collections.literalCounterRef ?? { value: 0 }) as CounterRef;
3312
- const anonymousFunctionCounterRef = (collections.anonymousFunctionCounterRef ?? { value: 0 }) as CounterRef;
3584
+ const _anonymousFunctionCounterRef = (collections.anonymousFunctionCounterRef ?? { value: 0 }) as CounterRef;
3313
3585
  const scopeTracker = collections.scopeTracker as ScopeTracker | undefined;
3314
3586
  // Object literal tracking (REG-328)
3315
3587
  if (!collections.objectLiterals) {
@@ -3325,7 +3597,12 @@ export class JSASTAnalyzer extends Plugin {
3325
3597
  const objectProperties = collections.objectProperties as ObjectPropertyInfo[];
3326
3598
  const objectLiteralCounterRef = collections.objectLiteralCounterRef as CounterRef;
3327
3599
  const returnStatements = (collections.returnStatements ?? []) as ReturnStatementInfo[];
3328
- const parameters = (collections.parameters ?? []) as ParameterInfo[];
3600
+ // Initialize yieldExpressions if not exist to ensure nested function calls share same array
3601
+ if (!collections.yieldExpressions) {
3602
+ collections.yieldExpressions = [];
3603
+ }
3604
+ const yieldExpressions = collections.yieldExpressions as YieldExpressionInfo[];
3605
+ const _parameters = (collections.parameters ?? []) as ParameterInfo[];
3329
3606
  // Control flow collections (Phase 2: LOOP nodes)
3330
3607
  // Initialize if not exist to ensure nested function calls share same arrays
3331
3608
  if (!collections.loops) {
@@ -3352,9 +3629,9 @@ export class JSASTAnalyzer extends Plugin {
3352
3629
  const parentScopeVariables = new Set<{ name: string; id: string; scopeId: string }>();
3353
3630
 
3354
3631
  const processedCallSites = processedNodes.callSites;
3355
- const processedVarDecls = processedNodes.varDecls;
3632
+ const _processedVarDecls = processedNodes.varDecls;
3356
3633
  const processedMethodCalls = processedNodes.methodCalls;
3357
- const processedEventListeners = processedNodes.eventListeners;
3634
+ const _processedEventListeners = processedNodes.eventListeners;
3358
3635
 
3359
3636
  // Track if/else scope transitions (Phase 3: extended with branchId)
3360
3637
  const ifElseScopeMap = new Map<t.IfStatement, IfElseScopeInfo>();
@@ -3411,6 +3688,16 @@ export class JSASTAnalyzer extends Plugin {
3411
3688
  }
3412
3689
  const promiseResolutions = collections.promiseResolutions as PromiseResolutionInfo[];
3413
3690
 
3691
+ // REG-311: Initialize rejectionPatterns and catchesFromInfos collections
3692
+ if (!collections.rejectionPatterns) {
3693
+ collections.rejectionPatterns = [];
3694
+ }
3695
+ if (!collections.catchesFromInfos) {
3696
+ collections.catchesFromInfos = [];
3697
+ }
3698
+ const rejectionPatterns = collections.rejectionPatterns as RejectionPatternInfo[];
3699
+ const catchesFromInfos = collections.catchesFromInfos as CatchesFromInfo[];
3700
+
3414
3701
  // Dynamic scope ID stack for CONTAINS edges
3415
3702
  // Starts with the function body scope, gets updated as we enter/exit conditional scopes
3416
3703
  const scopeIdStack: string[] = [parentScopeId];
@@ -3418,16 +3705,24 @@ export class JSASTAnalyzer extends Plugin {
3418
3705
 
3419
3706
  // Determine the ID of the function we're analyzing for RETURNS edges
3420
3707
  // Find by matching file/line/column in functions collection (it was just added by the visitor)
3708
+ // REG-271: Skip for StaticBlock (static blocks don't have RETURNS edges or control flow metadata)
3421
3709
  const funcNode = funcPath.node;
3710
+ const functionNode = t.isFunction(funcNode) ? funcNode : null;
3711
+ const functionPath = functionNode ? (funcPath as NodePath<t.Function>) : null;
3422
3712
  const funcLine = getLine(funcNode);
3423
3713
  const funcColumn = getColumn(funcNode);
3424
3714
  let currentFunctionId: string | null = null;
3425
3715
 
3426
- const matchingFunction = functions.find(f =>
3427
- f.file === module.file &&
3428
- f.line === funcLine &&
3429
- (f.column === undefined || f.column === funcColumn)
3430
- );
3716
+ // StaticBlock is not a function - skip function matching for RETURNS edges
3717
+ // For StaticBlock, matchingFunction will be undefined
3718
+ const matchingFunction = funcNode.type !== 'StaticBlock'
3719
+ ? functions.find(f =>
3720
+ f.file === module.file &&
3721
+ f.line === funcLine &&
3722
+ (f.column === undefined || f.column === funcColumn)
3723
+ )
3724
+ : undefined;
3725
+
3431
3726
  if (matchingFunction) {
3432
3727
  currentFunctionId = matchingFunction.id;
3433
3728
  }
@@ -3442,7 +3737,9 @@ export class JSASTAnalyzer extends Plugin {
3442
3737
  hasEarlyReturn: false,
3443
3738
  hasThrow: false,
3444
3739
  returnCount: 0, // Track total return count for early return detection
3445
- totalStatements: 0 // Track if there are statements after returns
3740
+ totalStatements: 0, // Track if there are statements after returns
3741
+ // REG-311: Try block depth counter for O(1) isInsideTry detection
3742
+ tryBlockDepth: 0
3446
3743
  };
3447
3744
 
3448
3745
  // Handle implicit return for THIS arrow function if it has an expression body
@@ -3452,136 +3749,21 @@ export class JSASTAnalyzer extends Plugin {
3452
3749
  const bodyLine = getLine(bodyExpr);
3453
3750
  const bodyColumn = getColumn(bodyExpr);
3454
3751
 
3752
+ // Extract expression-specific info using shared method
3753
+ const exprInfo = this.extractReturnExpressionInfo(
3754
+ bodyExpr, module, literals, literalCounterRef, funcLine, funcColumn, 'implicit_return'
3755
+ );
3756
+
3455
3757
  const returnInfo: ReturnStatementInfo = {
3456
3758
  parentFunctionId: currentFunctionId,
3457
3759
  file: module.file,
3458
3760
  line: bodyLine,
3459
3761
  column: bodyColumn,
3460
3762
  returnValueType: 'NONE',
3461
- isImplicitReturn: true
3763
+ isImplicitReturn: true,
3764
+ ...exprInfo,
3462
3765
  };
3463
3766
 
3464
- // Apply type detection logic for the implicit return
3465
- if (t.isIdentifier(bodyExpr)) {
3466
- returnInfo.returnValueType = 'VARIABLE';
3467
- returnInfo.returnValueName = bodyExpr.name;
3468
- }
3469
- // TemplateLiteral must come BEFORE isLiteral (TemplateLiteral extends Literal)
3470
- else if (t.isTemplateLiteral(bodyExpr)) {
3471
- returnInfo.returnValueType = 'EXPRESSION';
3472
- returnInfo.expressionType = 'TemplateLiteral';
3473
- returnInfo.returnValueLine = getLine(bodyExpr);
3474
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3475
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
3476
- 'TemplateLiteral', module.file, getLine(bodyExpr), getColumn(bodyExpr)
3477
- );
3478
- const sourceNames: string[] = [];
3479
- for (const expr of bodyExpr.expressions) {
3480
- if (t.isIdentifier(expr)) sourceNames.push(expr.name);
3481
- }
3482
- if (sourceNames.length > 0) returnInfo.expressionSourceNames = sourceNames;
3483
- }
3484
- else if (t.isLiteral(bodyExpr)) {
3485
- returnInfo.returnValueType = 'LITERAL';
3486
- const literalId = `LITERAL#implicit_return#${module.file}#${funcLine}:${funcColumn}:${literalCounterRef.value++}`;
3487
- returnInfo.returnValueId = literalId;
3488
- literals.push({
3489
- id: literalId,
3490
- type: 'LITERAL',
3491
- value: ExpressionEvaluator.extractLiteralValue(bodyExpr),
3492
- valueType: typeof ExpressionEvaluator.extractLiteralValue(bodyExpr),
3493
- file: module.file,
3494
- line: bodyLine,
3495
- column: bodyColumn
3496
- });
3497
- }
3498
- else if (t.isCallExpression(bodyExpr) && t.isIdentifier(bodyExpr.callee)) {
3499
- returnInfo.returnValueType = 'CALL_SITE';
3500
- returnInfo.returnValueLine = getLine(bodyExpr);
3501
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3502
- returnInfo.returnValueCallName = bodyExpr.callee.name;
3503
- }
3504
- else if (t.isCallExpression(bodyExpr) && t.isMemberExpression(bodyExpr.callee)) {
3505
- returnInfo.returnValueType = 'METHOD_CALL';
3506
- returnInfo.returnValueLine = getLine(bodyExpr);
3507
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3508
- if (t.isIdentifier(bodyExpr.callee.property)) {
3509
- returnInfo.returnValueCallName = bodyExpr.callee.property.name;
3510
- }
3511
- }
3512
- // REG-276: Detailed EXPRESSION handling for implicit arrow returns
3513
- else if (t.isBinaryExpression(bodyExpr)) {
3514
- returnInfo.returnValueType = 'EXPRESSION';
3515
- returnInfo.expressionType = 'BinaryExpression';
3516
- returnInfo.returnValueLine = getLine(bodyExpr);
3517
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3518
- returnInfo.operator = bodyExpr.operator;
3519
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
3520
- 'BinaryExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr)
3521
- );
3522
- if (t.isIdentifier(bodyExpr.left)) returnInfo.leftSourceName = bodyExpr.left.name;
3523
- if (t.isIdentifier(bodyExpr.right)) returnInfo.rightSourceName = bodyExpr.right.name;
3524
- }
3525
- else if (t.isLogicalExpression(bodyExpr)) {
3526
- returnInfo.returnValueType = 'EXPRESSION';
3527
- returnInfo.expressionType = 'LogicalExpression';
3528
- returnInfo.returnValueLine = getLine(bodyExpr);
3529
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3530
- returnInfo.operator = bodyExpr.operator;
3531
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
3532
- 'LogicalExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr)
3533
- );
3534
- if (t.isIdentifier(bodyExpr.left)) returnInfo.leftSourceName = bodyExpr.left.name;
3535
- if (t.isIdentifier(bodyExpr.right)) returnInfo.rightSourceName = bodyExpr.right.name;
3536
- }
3537
- else if (t.isConditionalExpression(bodyExpr)) {
3538
- returnInfo.returnValueType = 'EXPRESSION';
3539
- returnInfo.expressionType = 'ConditionalExpression';
3540
- returnInfo.returnValueLine = getLine(bodyExpr);
3541
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3542
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
3543
- 'ConditionalExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr)
3544
- );
3545
- if (t.isIdentifier(bodyExpr.consequent)) returnInfo.consequentSourceName = bodyExpr.consequent.name;
3546
- if (t.isIdentifier(bodyExpr.alternate)) returnInfo.alternateSourceName = bodyExpr.alternate.name;
3547
- }
3548
- else if (t.isUnaryExpression(bodyExpr)) {
3549
- returnInfo.returnValueType = 'EXPRESSION';
3550
- returnInfo.expressionType = 'UnaryExpression';
3551
- returnInfo.returnValueLine = getLine(bodyExpr);
3552
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3553
- returnInfo.operator = bodyExpr.operator;
3554
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
3555
- 'UnaryExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr)
3556
- );
3557
- if (t.isIdentifier(bodyExpr.argument)) returnInfo.unaryArgSourceName = bodyExpr.argument.name;
3558
- }
3559
- else if (t.isMemberExpression(bodyExpr)) {
3560
- returnInfo.returnValueType = 'EXPRESSION';
3561
- returnInfo.expressionType = 'MemberExpression';
3562
- returnInfo.returnValueLine = getLine(bodyExpr);
3563
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3564
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
3565
- 'MemberExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr)
3566
- );
3567
- if (t.isIdentifier(bodyExpr.object)) {
3568
- returnInfo.object = bodyExpr.object.name;
3569
- returnInfo.objectSourceName = bodyExpr.object.name;
3570
- }
3571
- if (t.isIdentifier(bodyExpr.property)) returnInfo.property = bodyExpr.property.name;
3572
- returnInfo.computed = bodyExpr.computed;
3573
- }
3574
- else {
3575
- // Fallback: any other expression type
3576
- returnInfo.returnValueType = 'EXPRESSION';
3577
- returnInfo.expressionType = bodyExpr.type;
3578
- returnInfo.returnValueLine = getLine(bodyExpr);
3579
- returnInfo.returnValueColumn = getColumn(bodyExpr);
3580
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
3581
- bodyExpr.type, module.file, getLine(bodyExpr), getColumn(bodyExpr)
3582
- );
3583
- }
3584
-
3585
3767
  returnStatements.push(returnInfo);
3586
3768
  }
3587
3769
 
@@ -3630,7 +3812,7 @@ export class JSASTAnalyzer extends Plugin {
3630
3812
  const arrayMutations = collections.arrayMutations as ArrayMutationInfo[];
3631
3813
 
3632
3814
  // Check for indexed array assignment: arr[i] = value
3633
- this.detectIndexedArrayAssignment(assignNode, module, arrayMutations, scopeTracker);
3815
+ this.detectIndexedArrayAssignment(assignNode, module, arrayMutations, scopeTracker, collections);
3634
3816
 
3635
3817
  // Initialize object mutations collection if not exists
3636
3818
  if (!collections.objectMutations) {
@@ -3695,238 +3877,174 @@ export class JSASTAnalyzer extends Plugin {
3695
3877
 
3696
3878
  const arg = returnNode.argument;
3697
3879
 
3698
- // Determine return value type and extract relevant info
3880
+ // Extract expression-specific info using shared method
3881
+ const exprInfo = this.extractReturnExpressionInfo(
3882
+ arg, module, literals, literalCounterRef, returnLine, returnColumn, 'return'
3883
+ );
3884
+
3699
3885
  const returnInfo: ReturnStatementInfo = {
3700
3886
  parentFunctionId: currentFunctionId,
3701
3887
  file: module.file,
3702
3888
  line: returnLine,
3703
3889
  column: returnColumn,
3704
- returnValueType: 'NONE'
3890
+ returnValueType: 'NONE',
3891
+ ...exprInfo,
3705
3892
  };
3706
3893
 
3707
- // Identifier (variable reference)
3708
- if (t.isIdentifier(arg)) {
3709
- returnInfo.returnValueType = 'VARIABLE';
3710
- returnInfo.returnValueName = arg.name;
3711
- }
3712
- // TemplateLiteral must come BEFORE isLiteral (TemplateLiteral extends Literal)
3713
- else if (t.isTemplateLiteral(arg)) {
3714
- returnInfo.returnValueType = 'EXPRESSION';
3715
- returnInfo.expressionType = 'TemplateLiteral';
3716
- returnInfo.returnValueLine = getLine(arg);
3717
- returnInfo.returnValueColumn = getColumn(arg);
3718
-
3719
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
3720
- 'TemplateLiteral',
3721
- module.file,
3722
- getLine(arg),
3723
- getColumn(arg)
3724
- );
3894
+ returnStatements.push(returnInfo);
3895
+ },
3725
3896
 
3726
- // Extract all embedded expression identifiers
3727
- const sourceNames: string[] = [];
3728
- for (const expr of arg.expressions) {
3729
- if (t.isIdentifier(expr)) {
3730
- sourceNames.push(expr.name);
3731
- }
3732
- }
3733
- if (sourceNames.length > 0) {
3734
- returnInfo.expressionSourceNames = sourceNames;
3735
- }
3736
- }
3737
- // Literal values (after TemplateLiteral check)
3738
- else if (t.isLiteral(arg)) {
3739
- returnInfo.returnValueType = 'LITERAL';
3740
- // Create a LITERAL node ID for this return value
3741
- const literalId = `LITERAL#return#${module.file}#${returnLine}:${returnColumn}:${literalCounterRef.value++}`;
3742
- returnInfo.returnValueId = literalId;
3743
-
3744
- // Also add to literals collection for node creation
3745
- literals.push({
3746
- id: literalId,
3747
- type: 'LITERAL',
3748
- value: ExpressionEvaluator.extractLiteralValue(arg),
3749
- valueType: typeof ExpressionEvaluator.extractLiteralValue(arg),
3750
- file: module.file,
3751
- line: returnLine,
3752
- column: returnColumn
3753
- });
3754
- }
3755
- // Direct function call: return foo()
3756
- else if (t.isCallExpression(arg) && t.isIdentifier(arg.callee)) {
3757
- returnInfo.returnValueType = 'CALL_SITE';
3758
- returnInfo.returnValueLine = getLine(arg);
3759
- returnInfo.returnValueColumn = getColumn(arg);
3760
- returnInfo.returnValueCallName = arg.callee.name;
3761
- }
3762
- // Method call: return obj.method()
3763
- else if (t.isCallExpression(arg) && t.isMemberExpression(arg.callee)) {
3764
- returnInfo.returnValueType = 'METHOD_CALL';
3765
- returnInfo.returnValueLine = getLine(arg);
3766
- returnInfo.returnValueColumn = getColumn(arg);
3767
- // Extract method name for lookup
3768
- if (t.isIdentifier(arg.callee.property)) {
3769
- returnInfo.returnValueCallName = arg.callee.property.name;
3897
+ // Phase 6 (REG-267): Track throw statements for control flow metadata
3898
+ // REG-311: Also detect async_throw rejection patterns
3899
+ ThrowStatement: (throwPath: NodePath<t.ThrowStatement>) => {
3900
+ // Skip if this throw is inside a nested function (not the function we're analyzing)
3901
+ let parent: NodePath | null = throwPath.parentPath;
3902
+ while (parent) {
3903
+ if (t.isFunction(parent.node) && parent.node !== funcNode) {
3904
+ // This throw is inside a nested function - skip it
3905
+ return;
3770
3906
  }
3907
+ parent = parent.parentPath;
3771
3908
  }
3772
- // BinaryExpression: return a + b
3773
- else if (t.isBinaryExpression(arg)) {
3774
- returnInfo.returnValueType = 'EXPRESSION';
3775
- returnInfo.expressionType = 'BinaryExpression';
3776
- returnInfo.returnValueLine = getLine(arg);
3777
- returnInfo.returnValueColumn = getColumn(arg);
3778
- returnInfo.operator = arg.operator;
3779
-
3780
- // Generate stable ID for the EXPRESSION node
3781
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
3782
- 'BinaryExpression',
3783
- module.file,
3784
- getLine(arg),
3785
- getColumn(arg)
3786
- );
3787
3909
 
3788
- // Extract left operand source
3789
- if (t.isIdentifier(arg.left)) {
3790
- returnInfo.leftSourceName = arg.left.name;
3791
- }
3792
- // Extract right operand source
3793
- if (t.isIdentifier(arg.right)) {
3794
- returnInfo.rightSourceName = arg.right.name;
3795
- }
3796
- }
3797
- // LogicalExpression: return a && b, return a || b
3798
- else if (t.isLogicalExpression(arg)) {
3799
- returnInfo.returnValueType = 'EXPRESSION';
3800
- returnInfo.expressionType = 'LogicalExpression';
3801
- returnInfo.returnValueLine = getLine(arg);
3802
- returnInfo.returnValueColumn = getColumn(arg);
3803
- returnInfo.operator = arg.operator;
3804
-
3805
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
3806
- 'LogicalExpression',
3807
- module.file,
3808
- getLine(arg),
3809
- getColumn(arg)
3810
- );
3910
+ controlFlowState.hasThrow = true;
3811
3911
 
3812
- if (t.isIdentifier(arg.left)) {
3813
- returnInfo.leftSourceName = arg.left.name;
3814
- }
3815
- if (t.isIdentifier(arg.right)) {
3816
- returnInfo.rightSourceName = arg.right.name;
3912
+ // REG-311: Track rejection patterns for async functions
3913
+ const isAsyncFunction = functionNode?.async === true;
3914
+ if (isAsyncFunction && currentFunctionId && functionNode && functionPath) {
3915
+ const throwNode = throwPath.node;
3916
+ const arg = throwNode.argument;
3917
+ const throwLine = getLine(throwNode);
3918
+ const throwColumn = getColumn(throwNode);
3919
+
3920
+ // Case 1: throw new Error() or throw new CustomError()
3921
+ if (arg && t.isNewExpression(arg) && t.isIdentifier(arg.callee)) {
3922
+ rejectionPatterns.push({
3923
+ functionId: currentFunctionId,
3924
+ errorClassName: arg.callee.name,
3925
+ rejectionType: 'async_throw',
3926
+ file: module.file,
3927
+ line: throwLine,
3928
+ column: throwColumn
3929
+ });
3817
3930
  }
3818
- }
3819
- // ConditionalExpression: return condition ? a : b
3820
- else if (t.isConditionalExpression(arg)) {
3821
- returnInfo.returnValueType = 'EXPRESSION';
3822
- returnInfo.expressionType = 'ConditionalExpression';
3823
- returnInfo.returnValueLine = getLine(arg);
3824
- returnInfo.returnValueColumn = getColumn(arg);
3825
-
3826
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
3827
- 'ConditionalExpression',
3828
- module.file,
3829
- getLine(arg),
3830
- getColumn(arg)
3831
- );
3931
+ // Case 2: throw identifier - needs micro-trace
3932
+ else if (arg && t.isIdentifier(arg)) {
3933
+ const varName = arg.name;
3832
3934
 
3833
- // Extract consequent (then branch) source
3834
- if (t.isIdentifier(arg.consequent)) {
3835
- returnInfo.consequentSourceName = arg.consequent.name;
3836
- }
3837
- // Extract alternate (else branch) source
3838
- if (t.isIdentifier(arg.alternate)) {
3839
- returnInfo.alternateSourceName = arg.alternate.name;
3935
+ // Check if it's a parameter
3936
+ const isParameter = functionNode.params.some(param =>
3937
+ t.isIdentifier(param) && param.name === varName
3938
+ );
3939
+
3940
+ if (isParameter) {
3941
+ // Parameter forwarding - can't resolve statically
3942
+ rejectionPatterns.push({
3943
+ functionId: currentFunctionId,
3944
+ errorClassName: null,
3945
+ rejectionType: 'variable_parameter',
3946
+ file: module.file,
3947
+ line: throwLine,
3948
+ column: throwColumn,
3949
+ sourceVariableName: varName
3950
+ });
3951
+ } else {
3952
+ // Try micro-trace
3953
+ const { errorClassName, tracePath } = this.microTraceToErrorClass(
3954
+ varName,
3955
+ functionPath,
3956
+ variableDeclarations
3957
+ );
3958
+
3959
+ rejectionPatterns.push({
3960
+ functionId: currentFunctionId,
3961
+ errorClassName,
3962
+ rejectionType: errorClassName ? 'variable_traced' : 'variable_unknown',
3963
+ file: module.file,
3964
+ line: throwLine,
3965
+ column: throwColumn,
3966
+ sourceVariableName: varName,
3967
+ tracePath
3968
+ });
3969
+ }
3840
3970
  }
3841
3971
  }
3842
- // UnaryExpression: return !x, return -x
3843
- else if (t.isUnaryExpression(arg)) {
3844
- returnInfo.returnValueType = 'EXPRESSION';
3845
- returnInfo.expressionType = 'UnaryExpression';
3846
- returnInfo.returnValueLine = getLine(arg);
3847
- returnInfo.returnValueColumn = getColumn(arg);
3848
- returnInfo.operator = arg.operator;
3849
-
3850
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
3851
- 'UnaryExpression',
3852
- module.file,
3853
- getLine(arg),
3854
- getColumn(arg)
3855
- );
3972
+ },
3856
3973
 
3857
- if (t.isIdentifier(arg.argument)) {
3858
- returnInfo.unaryArgSourceName = arg.argument.name;
3859
- }
3974
+ // Handle yield expressions for YIELDS/DELEGATES_TO edges (REG-270)
3975
+ YieldExpression: (yieldPath: NodePath<t.YieldExpression>) => {
3976
+ // Skip if we couldn't determine the function ID
3977
+ if (!currentFunctionId) {
3978
+ return;
3860
3979
  }
3861
- // MemberExpression (property access): return obj.prop
3862
- else if (t.isMemberExpression(arg)) {
3863
- returnInfo.returnValueType = 'EXPRESSION';
3864
- returnInfo.expressionType = 'MemberExpression';
3865
- returnInfo.returnValueLine = getLine(arg);
3866
- returnInfo.returnValueColumn = getColumn(arg);
3867
-
3868
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
3869
- 'MemberExpression',
3870
- module.file,
3871
- getLine(arg),
3872
- getColumn(arg)
3873
- );
3874
3980
 
3875
- // Extract object.property info
3876
- if (t.isIdentifier(arg.object)) {
3877
- returnInfo.object = arg.object.name;
3878
- returnInfo.objectSourceName = arg.object.name;
3981
+ // Skip if this yield is inside a nested function (not the function we're analyzing)
3982
+ // Check if there's a function ancestor BETWEEN us and funcNode
3983
+ let parent: NodePath | null = yieldPath.parentPath;
3984
+ while (parent) {
3985
+ // If we've reached funcNode, we're done checking - this yield belongs to funcNode
3986
+ if (parent.node === funcNode) {
3987
+ break;
3879
3988
  }
3880
- if (t.isIdentifier(arg.property)) {
3881
- returnInfo.property = arg.property.name;
3989
+ if (t.isFunction(parent.node)) {
3990
+ // Found a function between yieldPath and funcNode - this yield is inside a nested function
3991
+ return;
3882
3992
  }
3883
- returnInfo.computed = arg.computed;
3993
+ parent = parent.parentPath;
3884
3994
  }
3885
- // NewExpression: return new Foo()
3886
- else if (t.isNewExpression(arg)) {
3887
- returnInfo.returnValueType = 'EXPRESSION';
3888
- returnInfo.expressionType = 'NewExpression';
3889
- returnInfo.returnValueLine = getLine(arg);
3890
- returnInfo.returnValueColumn = getColumn(arg);
3891
-
3892
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
3893
- 'NewExpression',
3894
- module.file,
3895
- getLine(arg),
3896
- getColumn(arg)
3897
- );
3995
+
3996
+ const yieldNode = yieldPath.node;
3997
+ const yieldLine = getLine(yieldNode);
3998
+ const yieldColumn = getColumn(yieldNode);
3999
+ const isDelegate = yieldNode.delegate ?? false;
4000
+
4001
+ // Handle bare yield; (no value) - only valid for non-delegate yield
4002
+ if (!yieldNode.argument && !isDelegate) {
4003
+ // Skip - no data flow value
4004
+ return;
3898
4005
  }
3899
- // Fallback for other expression types
3900
- else {
3901
- returnInfo.returnValueType = 'EXPRESSION';
3902
- returnInfo.expressionType = arg.type;
3903
- returnInfo.returnValueLine = getLine(arg);
3904
- returnInfo.returnValueColumn = getColumn(arg);
3905
4006
 
3906
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
3907
- arg.type,
3908
- module.file,
3909
- getLine(arg),
3910
- getColumn(arg)
3911
- );
4007
+ // For yield* without argument (syntax error in practice, but handle gracefully)
4008
+ if (!yieldNode.argument) {
4009
+ return;
3912
4010
  }
3913
4011
 
3914
- returnStatements.push(returnInfo);
3915
- },
4012
+ const arg = yieldNode.argument;
3916
4013
 
3917
- // Phase 6 (REG-267): Track throw statements for control flow metadata
3918
- ThrowStatement: (throwPath: NodePath<t.ThrowStatement>) => {
3919
- // Skip if this throw is inside a nested function (not the function we're analyzing)
3920
- let parent: NodePath | null = throwPath.parentPath;
3921
- while (parent) {
3922
- if (t.isFunction(parent.node) && parent.node !== funcNode) {
3923
- // This throw is inside a nested function - skip it
3924
- return;
3925
- }
3926
- parent = parent.parentPath;
3927
- }
4014
+ // Extract expression-specific info using shared method
4015
+ // Note: We reuse extractReturnExpressionInfo since yield values have identical semantics
4016
+ const exprInfo = this.extractReturnExpressionInfo(
4017
+ arg, module, literals, literalCounterRef, yieldLine, yieldColumn, 'yield'
4018
+ );
3928
4019
 
3929
- controlFlowState.hasThrow = true;
4020
+ // Map ReturnStatementInfo fields to YieldExpressionInfo fields
4021
+ const yieldInfo: YieldExpressionInfo = {
4022
+ parentFunctionId: currentFunctionId,
4023
+ file: module.file,
4024
+ line: yieldLine,
4025
+ column: yieldColumn,
4026
+ isDelegate,
4027
+ yieldValueType: exprInfo.returnValueType ?? 'NONE',
4028
+ yieldValueName: exprInfo.returnValueName,
4029
+ yieldValueId: exprInfo.returnValueId,
4030
+ yieldValueLine: exprInfo.returnValueLine,
4031
+ yieldValueColumn: exprInfo.returnValueColumn,
4032
+ yieldValueCallName: exprInfo.returnValueCallName,
4033
+ expressionType: exprInfo.expressionType,
4034
+ operator: exprInfo.operator,
4035
+ leftSourceName: exprInfo.leftSourceName,
4036
+ rightSourceName: exprInfo.rightSourceName,
4037
+ consequentSourceName: exprInfo.consequentSourceName,
4038
+ alternateSourceName: exprInfo.alternateSourceName,
4039
+ object: exprInfo.object,
4040
+ property: exprInfo.property,
4041
+ computed: exprInfo.computed,
4042
+ objectSourceName: exprInfo.objectSourceName,
4043
+ expressionSourceNames: exprInfo.expressionSourceNames,
4044
+ unaryArgSourceName: exprInfo.unaryArgSourceName,
4045
+ };
4046
+
4047
+ yieldExpressions.push(yieldInfo);
3930
4048
  },
3931
4049
 
3932
4050
  ForStatement: this.createLoopScopeHandler('for', 'for-loop', 'for', parentScopeId, module, scopes, loops, scopeCounterRef, loopCounterRef, scopeTracker, scopeIdStack, controlFlowState),
@@ -3959,7 +4077,8 @@ export class JSASTAnalyzer extends Plugin {
3959
4077
  varDeclCounterRef,
3960
4078
  scopeTracker,
3961
4079
  tryScopeMap,
3962
- scopeIdStack
4080
+ scopeIdStack,
4081
+ controlFlowState
3963
4082
  ),
3964
4083
 
3965
4084
  SwitchStatement: (switchPath: NodePath<t.SwitchStatement>) => {
@@ -3973,6 +4092,53 @@ export class JSASTAnalyzer extends Plugin {
3973
4092
  );
3974
4093
  },
3975
4094
 
4095
+ FunctionDeclaration: (funcDeclPath: NodePath<t.FunctionDeclaration>) => {
4096
+ const node = funcDeclPath.node;
4097
+ const funcName = node.id ? node.id.name : this.generateAnonymousName(scopeTracker);
4098
+ // Use semantic ID as primary ID when scopeTracker available
4099
+ const legacyId = `FUNCTION#${funcName}#${module.file}#${getLine(node)}:${getColumn(node)}:${functionCounterRef.value++}`;
4100
+ const functionId = scopeTracker
4101
+ ? computeSemanticId('FUNCTION', funcName, scopeTracker.getContext())
4102
+ : legacyId;
4103
+
4104
+ functions.push({
4105
+ id: functionId,
4106
+ type: 'FUNCTION',
4107
+ name: funcName,
4108
+ file: module.file,
4109
+ line: getLine(node),
4110
+ column: getColumn(node),
4111
+ async: node.async || false,
4112
+ generator: node.generator || false,
4113
+ parentScopeId
4114
+ });
4115
+
4116
+ const nestedScopeId = `SCOPE#${funcName}:body#${module.file}#${getLine(node)}`;
4117
+ const closureSemanticId = this.generateSemanticId('closure', scopeTracker);
4118
+ scopes.push({
4119
+ id: nestedScopeId,
4120
+ type: 'SCOPE',
4121
+ scopeType: 'closure',
4122
+ name: `${funcName}:body`,
4123
+ semanticId: closureSemanticId,
4124
+ conditional: false,
4125
+ file: module.file,
4126
+ line: getLine(node),
4127
+ parentFunctionId: functionId,
4128
+ capturesFrom: parentScopeId
4129
+ });
4130
+
4131
+ // Enter nested function scope for semantic ID generation
4132
+ if (scopeTracker) {
4133
+ scopeTracker.enterScope(funcName, 'function');
4134
+ }
4135
+ this.analyzeFunctionBody(funcDeclPath, nestedScopeId, module, collections);
4136
+ if (scopeTracker) {
4137
+ scopeTracker.exitScope();
4138
+ }
4139
+ funcDeclPath.skip();
4140
+ },
4141
+
3976
4142
  FunctionExpression: (funcPath: NodePath<t.FunctionExpression>) => {
3977
4143
  const node = funcPath.node;
3978
4144
  const funcName = node.id ? node.id.name : this.generateAnonymousName(scopeTracker);
@@ -4084,135 +4250,21 @@ export class JSASTAnalyzer extends Plugin {
4084
4250
  const bodyLine = getLine(bodyExpr);
4085
4251
  const bodyColumn = getColumn(bodyExpr);
4086
4252
 
4253
+ // Extract expression-specific info using shared method
4254
+ const exprInfo = this.extractReturnExpressionInfo(
4255
+ bodyExpr, module, literals, literalCounterRef, line, column, 'implicit_return'
4256
+ );
4257
+
4087
4258
  const returnInfo: ReturnStatementInfo = {
4088
4259
  parentFunctionId: functionId,
4089
4260
  file: module.file,
4090
4261
  line: bodyLine,
4091
4262
  column: bodyColumn,
4092
4263
  returnValueType: 'NONE',
4093
- isImplicitReturn: true
4264
+ isImplicitReturn: true,
4265
+ ...exprInfo,
4094
4266
  };
4095
4267
 
4096
- // Apply same type detection logic as ReturnStatement handler
4097
- if (t.isIdentifier(bodyExpr)) {
4098
- returnInfo.returnValueType = 'VARIABLE';
4099
- returnInfo.returnValueName = bodyExpr.name;
4100
- }
4101
- // TemplateLiteral must come BEFORE isLiteral (TemplateLiteral extends Literal)
4102
- else if (t.isTemplateLiteral(bodyExpr)) {
4103
- returnInfo.returnValueType = 'EXPRESSION';
4104
- returnInfo.expressionType = 'TemplateLiteral';
4105
- returnInfo.returnValueLine = getLine(bodyExpr);
4106
- returnInfo.returnValueColumn = getColumn(bodyExpr);
4107
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
4108
- 'TemplateLiteral', module.file, getLine(bodyExpr), getColumn(bodyExpr)
4109
- );
4110
- const sourceNames: string[] = [];
4111
- for (const expr of bodyExpr.expressions) {
4112
- if (t.isIdentifier(expr)) sourceNames.push(expr.name);
4113
- }
4114
- if (sourceNames.length > 0) returnInfo.expressionSourceNames = sourceNames;
4115
- }
4116
- else if (t.isLiteral(bodyExpr)) {
4117
- returnInfo.returnValueType = 'LITERAL';
4118
- const literalId = `LITERAL#implicit_return#${module.file}#${line}:${column}:${literalCounterRef.value++}`;
4119
- returnInfo.returnValueId = literalId;
4120
- literals.push({
4121
- id: literalId,
4122
- type: 'LITERAL',
4123
- value: ExpressionEvaluator.extractLiteralValue(bodyExpr),
4124
- valueType: typeof ExpressionEvaluator.extractLiteralValue(bodyExpr),
4125
- file: module.file,
4126
- line: bodyLine,
4127
- column: bodyColumn
4128
- });
4129
- }
4130
- else if (t.isCallExpression(bodyExpr) && t.isIdentifier(bodyExpr.callee)) {
4131
- returnInfo.returnValueType = 'CALL_SITE';
4132
- returnInfo.returnValueLine = getLine(bodyExpr);
4133
- returnInfo.returnValueColumn = getColumn(bodyExpr);
4134
- returnInfo.returnValueCallName = bodyExpr.callee.name;
4135
- }
4136
- else if (t.isCallExpression(bodyExpr) && t.isMemberExpression(bodyExpr.callee)) {
4137
- returnInfo.returnValueType = 'METHOD_CALL';
4138
- returnInfo.returnValueLine = getLine(bodyExpr);
4139
- returnInfo.returnValueColumn = getColumn(bodyExpr);
4140
- if (t.isIdentifier(bodyExpr.callee.property)) {
4141
- returnInfo.returnValueCallName = bodyExpr.callee.property.name;
4142
- }
4143
- }
4144
- // REG-276: Detailed EXPRESSION handling for nested implicit arrow returns
4145
- else if (t.isBinaryExpression(bodyExpr)) {
4146
- returnInfo.returnValueType = 'EXPRESSION';
4147
- returnInfo.expressionType = 'BinaryExpression';
4148
- returnInfo.returnValueLine = getLine(bodyExpr);
4149
- returnInfo.returnValueColumn = getColumn(bodyExpr);
4150
- returnInfo.operator = bodyExpr.operator;
4151
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
4152
- 'BinaryExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr)
4153
- );
4154
- if (t.isIdentifier(bodyExpr.left)) returnInfo.leftSourceName = bodyExpr.left.name;
4155
- if (t.isIdentifier(bodyExpr.right)) returnInfo.rightSourceName = bodyExpr.right.name;
4156
- }
4157
- else if (t.isLogicalExpression(bodyExpr)) {
4158
- returnInfo.returnValueType = 'EXPRESSION';
4159
- returnInfo.expressionType = 'LogicalExpression';
4160
- returnInfo.returnValueLine = getLine(bodyExpr);
4161
- returnInfo.returnValueColumn = getColumn(bodyExpr);
4162
- returnInfo.operator = bodyExpr.operator;
4163
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
4164
- 'LogicalExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr)
4165
- );
4166
- if (t.isIdentifier(bodyExpr.left)) returnInfo.leftSourceName = bodyExpr.left.name;
4167
- if (t.isIdentifier(bodyExpr.right)) returnInfo.rightSourceName = bodyExpr.right.name;
4168
- }
4169
- else if (t.isConditionalExpression(bodyExpr)) {
4170
- returnInfo.returnValueType = 'EXPRESSION';
4171
- returnInfo.expressionType = 'ConditionalExpression';
4172
- returnInfo.returnValueLine = getLine(bodyExpr);
4173
- returnInfo.returnValueColumn = getColumn(bodyExpr);
4174
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
4175
- 'ConditionalExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr)
4176
- );
4177
- if (t.isIdentifier(bodyExpr.consequent)) returnInfo.consequentSourceName = bodyExpr.consequent.name;
4178
- if (t.isIdentifier(bodyExpr.alternate)) returnInfo.alternateSourceName = bodyExpr.alternate.name;
4179
- }
4180
- else if (t.isUnaryExpression(bodyExpr)) {
4181
- returnInfo.returnValueType = 'EXPRESSION';
4182
- returnInfo.expressionType = 'UnaryExpression';
4183
- returnInfo.returnValueLine = getLine(bodyExpr);
4184
- returnInfo.returnValueColumn = getColumn(bodyExpr);
4185
- returnInfo.operator = bodyExpr.operator;
4186
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
4187
- 'UnaryExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr)
4188
- );
4189
- if (t.isIdentifier(bodyExpr.argument)) returnInfo.unaryArgSourceName = bodyExpr.argument.name;
4190
- }
4191
- else if (t.isMemberExpression(bodyExpr)) {
4192
- returnInfo.returnValueType = 'EXPRESSION';
4193
- returnInfo.expressionType = 'MemberExpression';
4194
- returnInfo.returnValueLine = getLine(bodyExpr);
4195
- returnInfo.returnValueColumn = getColumn(bodyExpr);
4196
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
4197
- 'MemberExpression', module.file, getLine(bodyExpr), getColumn(bodyExpr)
4198
- );
4199
- if (t.isIdentifier(bodyExpr.object)) {
4200
- returnInfo.object = bodyExpr.object.name;
4201
- returnInfo.objectSourceName = bodyExpr.object.name;
4202
- }
4203
- if (t.isIdentifier(bodyExpr.property)) returnInfo.property = bodyExpr.property.name;
4204
- returnInfo.computed = bodyExpr.computed;
4205
- }
4206
- else {
4207
- returnInfo.returnValueType = 'EXPRESSION';
4208
- returnInfo.expressionType = bodyExpr.type;
4209
- returnInfo.returnValueLine = getLine(bodyExpr);
4210
- returnInfo.returnValueColumn = getColumn(bodyExpr);
4211
- returnInfo.returnValueId = NodeFactory.generateExpressionId(
4212
- bodyExpr.type, module.file, getLine(bodyExpr), getColumn(bodyExpr)
4213
- );
4214
- }
4215
-
4216
4268
  returnStatements.push(returnInfo);
4217
4269
  }
4218
4270
 
@@ -4282,6 +4334,13 @@ export class JSASTAnalyzer extends Plugin {
4282
4334
 
4283
4335
  // Function call expressions
4284
4336
  CallExpression: (callPath: NodePath<t.CallExpression>) => {
4337
+ // REG-311: Detect isAwaited (parent is AwaitExpression)
4338
+ const parent = callPath.parentPath;
4339
+ const isAwaited = parent?.isAwaitExpression() ?? false;
4340
+
4341
+ // REG-311: Detect isInsideTry (O(1) via depth counter)
4342
+ const isInsideTry = controlFlowState.tryBlockDepth > 0;
4343
+
4285
4344
  this.handleCallExpression(
4286
4345
  callPath.node,
4287
4346
  processedCallSites,
@@ -4292,7 +4351,9 @@ export class JSASTAnalyzer extends Plugin {
4292
4351
  callSiteCounterRef,
4293
4352
  scopeTracker,
4294
4353
  getCurrentScopeId(),
4295
- collections
4354
+ collections,
4355
+ isAwaited,
4356
+ isInsideTry
4296
4357
  );
4297
4358
 
4298
4359
  // REG-334: Check for resolve/reject calls inside Promise executors
@@ -4397,6 +4458,165 @@ export class JSASTAnalyzer extends Plugin {
4397
4458
 
4398
4459
  funcParent = funcParent.getFunctionParent();
4399
4460
  }
4461
+
4462
+ // REG-311: Detect executor_reject pattern - reject(new Error()) inside Promise executor
4463
+ // Walk up to find Promise executor context and check if this is reject call with NewExpression arg
4464
+ funcParent = callPath.getFunctionParent();
4465
+ while (funcParent && currentFunctionId) {
4466
+ const funcNode = funcParent.node;
4467
+ const funcKey = `${funcNode.start}:${funcNode.end}`;
4468
+ const context = promiseExecutorContexts.get(funcKey);
4469
+
4470
+ if (context && calleeName === context.rejectName && callNode.arguments.length > 0) {
4471
+ // REG-311: Use the creator function's ID (the function that created the Promise),
4472
+ // not the executor's ID
4473
+ const targetFunctionId = context.creatorFunctionId || currentFunctionId;
4474
+ const arg = callNode.arguments[0];
4475
+ const callLine = getLine(callNode);
4476
+ const callColumn = getColumn(callNode);
4477
+
4478
+ // Case 1: reject(new Error())
4479
+ if (t.isNewExpression(arg) && t.isIdentifier(arg.callee)) {
4480
+ rejectionPatterns.push({
4481
+ functionId: targetFunctionId,
4482
+ errorClassName: arg.callee.name,
4483
+ rejectionType: 'executor_reject',
4484
+ file: module.file,
4485
+ line: callLine,
4486
+ column: callColumn
4487
+ });
4488
+ }
4489
+ // Case 2: reject(err) where err is variable
4490
+ else if (t.isIdentifier(arg)) {
4491
+ const varName = arg.name;
4492
+ // Check if it's a parameter of ANY containing function (executor, outer, etc.)
4493
+ // Walk up the function chain to find if varName is a parameter
4494
+ let isParameter = false;
4495
+ let checkParent: NodePath<t.Node> | null = funcParent;
4496
+ while (checkParent) {
4497
+ if (t.isFunction(checkParent.node)) {
4498
+ if (checkParent.node.params.some(p =>
4499
+ t.isIdentifier(p) && p.name === varName
4500
+ )) {
4501
+ isParameter = true;
4502
+ break;
4503
+ }
4504
+ }
4505
+ checkParent = checkParent.getFunctionParent();
4506
+ }
4507
+
4508
+ if (isParameter) {
4509
+ rejectionPatterns.push({
4510
+ functionId: targetFunctionId,
4511
+ errorClassName: null,
4512
+ rejectionType: 'variable_parameter',
4513
+ file: module.file,
4514
+ line: callLine,
4515
+ column: callColumn,
4516
+ sourceVariableName: varName
4517
+ });
4518
+ } else {
4519
+ // Try micro-trace
4520
+ const { errorClassName, tracePath } = this.microTraceToErrorClass(
4521
+ varName,
4522
+ funcParent as NodePath<t.Function>,
4523
+ variableDeclarations
4524
+ );
4525
+
4526
+ rejectionPatterns.push({
4527
+ functionId: targetFunctionId,
4528
+ errorClassName,
4529
+ rejectionType: errorClassName ? 'variable_traced' : 'variable_unknown',
4530
+ file: module.file,
4531
+ line: callLine,
4532
+ column: callColumn,
4533
+ sourceVariableName: varName,
4534
+ tracePath
4535
+ });
4536
+ }
4537
+ }
4538
+ break;
4539
+ }
4540
+ funcParent = funcParent.getFunctionParent();
4541
+ }
4542
+ }
4543
+
4544
+ // REG-311: Detect Promise.reject(new Error()) pattern
4545
+ if (t.isMemberExpression(callNode.callee) && currentFunctionId) {
4546
+ const memberCallee = callNode.callee;
4547
+ if (t.isIdentifier(memberCallee.object) &&
4548
+ memberCallee.object.name === 'Promise' &&
4549
+ t.isIdentifier(memberCallee.property) &&
4550
+ memberCallee.property.name === 'reject' &&
4551
+ callNode.arguments.length > 0) {
4552
+ const arg = callNode.arguments[0];
4553
+ const callLine = getLine(callNode);
4554
+ const callColumn = getColumn(callNode);
4555
+
4556
+ // Case 1: Promise.reject(new Error())
4557
+ if (t.isNewExpression(arg) && t.isIdentifier(arg.callee)) {
4558
+ rejectionPatterns.push({
4559
+ functionId: currentFunctionId,
4560
+ errorClassName: arg.callee.name,
4561
+ rejectionType: 'promise_reject',
4562
+ file: module.file,
4563
+ line: callLine,
4564
+ column: callColumn
4565
+ });
4566
+ }
4567
+ // Case 2: Promise.reject(err) where err is variable
4568
+ else if (t.isIdentifier(arg)) {
4569
+ const varName = arg.name;
4570
+ // Check if it's a parameter of containing function
4571
+ const isParameter = functionNode
4572
+ ? functionNode.params.some(param => t.isIdentifier(param) && param.name === varName)
4573
+ : false;
4574
+
4575
+ if (isParameter) {
4576
+ rejectionPatterns.push({
4577
+ functionId: currentFunctionId,
4578
+ errorClassName: null,
4579
+ rejectionType: 'variable_parameter',
4580
+ file: module.file,
4581
+ line: callLine,
4582
+ column: callColumn,
4583
+ sourceVariableName: varName
4584
+ });
4585
+ } else {
4586
+ // Try micro-trace
4587
+ if (!functionPath) {
4588
+ rejectionPatterns.push({
4589
+ functionId: currentFunctionId,
4590
+ errorClassName: null,
4591
+ rejectionType: 'variable_unknown',
4592
+ file: module.file,
4593
+ line: callLine,
4594
+ column: callColumn,
4595
+ sourceVariableName: varName,
4596
+ tracePath: [varName]
4597
+ });
4598
+ return;
4599
+ }
4600
+
4601
+ const { errorClassName, tracePath } = this.microTraceToErrorClass(
4602
+ varName,
4603
+ functionPath,
4604
+ variableDeclarations
4605
+ );
4606
+
4607
+ rejectionPatterns.push({
4608
+ functionId: currentFunctionId,
4609
+ errorClassName,
4610
+ rejectionType: errorClassName ? 'variable_traced' : 'variable_unknown',
4611
+ file: module.file,
4612
+ line: callLine,
4613
+ column: callColumn,
4614
+ sourceVariableName: varName,
4615
+ tracePath
4616
+ });
4617
+ }
4618
+ }
4619
+ }
4400
4620
  }
4401
4621
  },
4402
4622
 
@@ -4460,7 +4680,9 @@ export class JSASTAnalyzer extends Plugin {
4460
4680
  resolveName,
4461
4681
  rejectName,
4462
4682
  file: module.file,
4463
- line
4683
+ line,
4684
+ // REG-311: Store the ID of the function that creates the Promise
4685
+ creatorFunctionId: currentFunctionId || undefined
4464
4686
  });
4465
4687
  }
4466
4688
  }
@@ -4535,9 +4757,65 @@ export class JSASTAnalyzer extends Plugin {
4535
4757
  });
4536
4758
  }
4537
4759
  }
4760
+ },
4761
+
4762
+ // Property access expressions (REG-395)
4763
+ // Shared handler for both MemberExpression and OptionalMemberExpression
4764
+ MemberExpression: (memberPath: NodePath<t.MemberExpression>) => {
4765
+ // Initialize collections if needed
4766
+ if (!collections.propertyAccesses) {
4767
+ collections.propertyAccesses = [];
4768
+ }
4769
+ if (!collections.propertyAccessCounterRef) {
4770
+ collections.propertyAccessCounterRef = { value: 0 };
4771
+ }
4772
+
4773
+ PropertyAccessVisitor.extractPropertyAccesses(
4774
+ memberPath,
4775
+ memberPath.node,
4776
+ module,
4777
+ collections.propertyAccesses as PropertyAccessInfo[],
4778
+ collections.propertyAccessCounterRef as CounterRef,
4779
+ scopeTracker,
4780
+ currentFunctionId || getCurrentScopeId()
4781
+ );
4782
+ },
4783
+ // OptionalMemberExpression: obj?.prop (same logic as MemberExpression)
4784
+ OptionalMemberExpression: (memberPath: NodePath) => {
4785
+ // Initialize collections if needed
4786
+ if (!collections.propertyAccesses) {
4787
+ collections.propertyAccesses = [];
4788
+ }
4789
+ if (!collections.propertyAccessCounterRef) {
4790
+ collections.propertyAccessCounterRef = { value: 0 };
4791
+ }
4792
+
4793
+ PropertyAccessVisitor.extractPropertyAccesses(
4794
+ memberPath,
4795
+ memberPath.node as t.MemberExpression,
4796
+ module,
4797
+ collections.propertyAccesses as PropertyAccessInfo[],
4798
+ collections.propertyAccessCounterRef as CounterRef,
4799
+ scopeTracker,
4800
+ currentFunctionId || getCurrentScopeId()
4801
+ );
4538
4802
  }
4539
4803
  });
4540
4804
 
4805
+ // REG-311: Second pass - collect CATCHES_FROM info for try/catch blocks
4806
+ // This links catch blocks to exception sources in their corresponding try blocks
4807
+ if (functionPath) {
4808
+ this.collectCatchesFromInfo(
4809
+ functionPath,
4810
+ catchBlocks,
4811
+ callSites,
4812
+ methodCalls,
4813
+ constructorCalls,
4814
+ catchesFromInfos,
4815
+ module
4816
+ );
4817
+ }
4818
+
4541
4819
  // Phase 6 (REG-267): Attach control flow metadata to the function node
4542
4820
  if (matchingFunction) {
4543
4821
  const cyclomaticComplexity = 1 +
@@ -4546,13 +4824,27 @@ export class JSASTAnalyzer extends Plugin {
4546
4824
  controlFlowState.caseCount +
4547
4825
  controlFlowState.logicalOpCount;
4548
4826
 
4827
+ // REG-311: Collect rejection info for this function
4828
+ const functionRejectionPatterns = rejectionPatterns.filter(p => p.functionId === matchingFunction.id);
4829
+ const canReject = functionRejectionPatterns.length > 0;
4830
+ const hasAsyncThrow = functionRejectionPatterns.some(p => p.rejectionType === 'async_throw');
4831
+ const rejectedBuiltinErrors = [...new Set(
4832
+ functionRejectionPatterns
4833
+ .filter(p => p.errorClassName !== null)
4834
+ .map(p => p.errorClassName!)
4835
+ )];
4836
+
4549
4837
  matchingFunction.controlFlow = {
4550
4838
  hasBranches: controlFlowState.branchCount > 0,
4551
4839
  hasLoops: controlFlowState.loopCount > 0,
4552
4840
  hasTryCatch: controlFlowState.hasTryCatch,
4553
4841
  hasEarlyReturn: controlFlowState.hasEarlyReturn,
4554
4842
  hasThrow: controlFlowState.hasThrow,
4555
- cyclomaticComplexity
4843
+ cyclomaticComplexity,
4844
+ // REG-311: Async error tracking
4845
+ canReject,
4846
+ hasAsyncThrow,
4847
+ rejectedBuiltinErrors: rejectedBuiltinErrors.length > 0 ? rejectedBuiltinErrors : undefined
4556
4848
  };
4557
4849
  }
4558
4850
  }
@@ -4566,6 +4858,7 @@ export class JSASTAnalyzer extends Plugin {
4566
4858
  * - Method calls (MemberExpression callee) → methodCalls collection
4567
4859
  * - Array mutation detection (push, unshift, splice)
4568
4860
  * - Object.assign() detection
4861
+ * - REG-311: isAwaited and isInsideTry metadata on CALL nodes
4569
4862
  *
4570
4863
  * @param callNode - The call expression AST node
4571
4864
  * @param processedCallSites - Set of already processed call site keys to avoid duplicates
@@ -4577,6 +4870,8 @@ export class JSASTAnalyzer extends Plugin {
4577
4870
  * @param scopeTracker - Optional scope tracker for semantic ID generation
4578
4871
  * @param parentScopeId - ID of the parent scope containing this call
4579
4872
  * @param collections - Full collections object for array/object mutations
4873
+ * @param isAwaited - REG-311: true if wrapped in await expression
4874
+ * @param isInsideTry - REG-311: true if inside try block
4580
4875
  */
4581
4876
  private handleCallExpression(
4582
4877
  callNode: t.CallExpression,
@@ -4588,7 +4883,9 @@ export class JSASTAnalyzer extends Plugin {
4588
4883
  callSiteCounterRef: CounterRef,
4589
4884
  scopeTracker: ScopeTracker | undefined,
4590
4885
  parentScopeId: string,
4591
- collections: VisitorCollections
4886
+ collections: VisitorCollections,
4887
+ isAwaited: boolean = false,
4888
+ isInsideTry: boolean = false
4592
4889
  ): void {
4593
4890
  // Handle direct function calls (greet(), main())
4594
4891
  if (callNode.callee.type === 'Identifier') {
@@ -4616,7 +4913,10 @@ export class JSASTAnalyzer extends Plugin {
4616
4913
  line: getLine(callNode),
4617
4914
  column: getColumn(callNode), // REG-223: Add column for coordinate-based lookup
4618
4915
  parentScopeId,
4619
- targetFunctionName: calleeName
4916
+ targetFunctionName: calleeName,
4917
+ // REG-311: Async error tracking metadata
4918
+ isAwaited,
4919
+ isInsideTry
4620
4920
  });
4621
4921
  }
4622
4922
  // Handle method calls (obj.method(), data.process())
@@ -4657,7 +4957,11 @@ export class JSASTAnalyzer extends Plugin {
4657
4957
  file: module.file,
4658
4958
  line: getLine(callNode),
4659
4959
  column: getColumn(callNode),
4660
- parentScopeId
4960
+ parentScopeId,
4961
+ // REG-311: Async error tracking metadata
4962
+ isAwaited,
4963
+ isInsideTry,
4964
+ isMethodCall: true
4661
4965
  });
4662
4966
 
4663
4967
  // Check for array mutation methods (push, unshift, splice)
@@ -4694,6 +4998,7 @@ export class JSASTAnalyzer extends Plugin {
4694
4998
  }
4695
4999
  }
4696
5000
  // REG-117: Nested array mutations like obj.arr.push(item)
5001
+ // REG-395: General nested method calls like a.b.c() or obj.nested.method()
4697
5002
  // object is MemberExpression, property is the method name
4698
5003
  else if (object.type === 'MemberExpression' && property.type === 'Identifier') {
4699
5004
  const nestedMember = object;
@@ -4731,10 +5036,290 @@ export class JSASTAnalyzer extends Plugin {
4731
5036
  );
4732
5037
  }
4733
5038
  }
5039
+
5040
+ // REG-395: Create CALL node for nested method calls like a.b.c()
5041
+ const objectName = CallExpressionVisitor.extractMemberExpressionName(nestedMember as t.MemberExpression);
5042
+ if (objectName) {
5043
+ const nodeKey = `${callNode.start}:${callNode.end}`;
5044
+ if (!processedMethodCalls.has(nodeKey)) {
5045
+ processedMethodCalls.add(nodeKey);
5046
+
5047
+ const fullName = `${objectName}.${methodName}`;
5048
+ const legacyId = `CALL#${fullName}#${module.file}#${getLine(callNode)}:${getColumn(callNode)}:${callSiteCounterRef.value++}`;
5049
+
5050
+ let methodCallId = legacyId;
5051
+ if (scopeTracker) {
5052
+ const discriminator = scopeTracker.getItemCounter(`CALL:${fullName}`);
5053
+ methodCallId = computeSemanticId('CALL', fullName, scopeTracker.getContext(), { discriminator });
5054
+ }
5055
+
5056
+ methodCalls.push({
5057
+ id: methodCallId,
5058
+ type: 'CALL',
5059
+ name: fullName,
5060
+ object: objectName,
5061
+ method: methodName,
5062
+ file: module.file,
5063
+ line: getLine(callNode),
5064
+ column: getColumn(callNode),
5065
+ parentScopeId,
5066
+ isMethodCall: true
5067
+ });
5068
+ }
5069
+ }
4734
5070
  }
4735
5071
  }
4736
5072
  }
4737
5073
 
5074
+ /**
5075
+ * REG-311: Micro-trace - follow variable assignments within function to find error source.
5076
+ * Used to resolve reject(err) or throw err where err is a variable.
5077
+ *
5078
+ * Uses cycle detection via Set<variableName> to avoid infinite loops on circular assignments.
5079
+ *
5080
+ * @param variableName - Name of variable to trace
5081
+ * @param funcPath - NodePath of containing function for AST traversal
5082
+ * @param variableDeclarations - Variable declarations in current scope
5083
+ * @returns Error class name if traced to NewExpression, null otherwise, plus trace path
5084
+ */
5085
+ private microTraceToErrorClass(
5086
+ variableName: string,
5087
+ funcPath: NodePath<t.Function>,
5088
+ _variableDeclarations: VariableDeclarationInfo[]
5089
+ ): { errorClassName: string | null; tracePath: string[] } {
5090
+ const tracePath: string[] = [variableName];
5091
+ const visited = new Set<string>(); // Cycle detection
5092
+ let currentName = variableName;
5093
+
5094
+ const funcBody = funcPath.node.body;
5095
+ if (!t.isBlockStatement(funcBody)) {
5096
+ return { errorClassName: null, tracePath };
5097
+ }
5098
+
5099
+ // Iterate until we find a NewExpression or can't trace further
5100
+ while (!visited.has(currentName)) {
5101
+ visited.add(currentName);
5102
+ let found = false;
5103
+ let foundNewExpression: string | null = null;
5104
+ let nextName: string | null = null;
5105
+
5106
+ // Walk AST to find assignments: currentName = newValue
5107
+ funcPath.traverse({
5108
+ VariableDeclarator: (declPath: NodePath<t.VariableDeclarator>) => {
5109
+ if (found || foundNewExpression) return;
5110
+ if (t.isIdentifier(declPath.node.id) && declPath.node.id.name === currentName) {
5111
+ const init = declPath.node.init;
5112
+ if (init) {
5113
+ // Case 1: const err = new Error()
5114
+ if (t.isNewExpression(init) && t.isIdentifier(init.callee)) {
5115
+ tracePath.push(`new ${init.callee.name}()`);
5116
+ foundNewExpression = init.callee.name;
5117
+ found = true;
5118
+ return;
5119
+ }
5120
+ // Case 2: const err = otherVar (chain)
5121
+ if (t.isIdentifier(init)) {
5122
+ tracePath.push(init.name);
5123
+ nextName = init.name;
5124
+ found = true;
5125
+ return;
5126
+ }
5127
+ }
5128
+ }
5129
+ },
5130
+ AssignmentExpression: (assignPath: NodePath<t.AssignmentExpression>) => {
5131
+ if (found || foundNewExpression) return;
5132
+ const left = assignPath.node.left;
5133
+ const right = assignPath.node.right;
5134
+
5135
+ if (t.isIdentifier(left) && left.name === currentName) {
5136
+ if (t.isNewExpression(right) && t.isIdentifier(right.callee)) {
5137
+ tracePath.push(`new ${right.callee.name}()`);
5138
+ foundNewExpression = right.callee.name;
5139
+ found = true;
5140
+ return;
5141
+ }
5142
+ if (t.isIdentifier(right)) {
5143
+ tracePath.push(right.name);
5144
+ nextName = right.name;
5145
+ found = true;
5146
+ return;
5147
+ }
5148
+ }
5149
+ }
5150
+ });
5151
+
5152
+ // If we found a NewExpression, return the class name
5153
+ if (foundNewExpression) {
5154
+ return { errorClassName: foundNewExpression, tracePath };
5155
+ }
5156
+
5157
+ // If we found another variable to follow, continue
5158
+ if (nextName) {
5159
+ currentName = nextName;
5160
+ continue;
5161
+ }
5162
+
5163
+ // Couldn't trace further
5164
+ break;
5165
+ }
5166
+
5167
+ return { errorClassName: null, tracePath };
5168
+ }
5169
+
5170
+ /**
5171
+ * REG-311: Collect CATCHES_FROM info linking catch blocks to exception sources in try blocks.
5172
+ *
5173
+ * Sources include:
5174
+ * - Awaited calls: await foo() in try block
5175
+ * - Sync calls: foo() in try block (any call can throw)
5176
+ * - Throw statements: throw new Error() in try block
5177
+ * - Constructor calls: new SomeClass() in try block
5178
+ *
5179
+ * @param funcPath - Function path to traverse
5180
+ * @param catchBlocks - Collection of CATCH_BLOCK nodes
5181
+ * @param callSites - Collection of CALL nodes (direct function calls)
5182
+ * @param methodCalls - Collection of CALL nodes (method calls)
5183
+ * @param constructorCalls - Collection of CONSTRUCTOR_CALL nodes
5184
+ * @param catchesFromInfos - Collection to push CatchesFromInfo to
5185
+ * @param module - Module context
5186
+ */
5187
+ private collectCatchesFromInfo(
5188
+ funcPath: NodePath<t.Function>,
5189
+ catchBlocks: CatchBlockInfo[],
5190
+ callSites: CallSiteInfo[],
5191
+ methodCalls: MethodCallInfo[],
5192
+ constructorCalls: ConstructorCallInfo[],
5193
+ catchesFromInfos: CatchesFromInfo[],
5194
+ module: VisitorModule
5195
+ ): void {
5196
+ // Traverse to find TryStatements and collect sources
5197
+ funcPath.traverse({
5198
+ TryStatement: (tryPath: NodePath<t.TryStatement>) => {
5199
+ const tryNode = tryPath.node;
5200
+ const handler = tryNode.handler;
5201
+
5202
+ // Skip if no catch clause
5203
+ if (!handler) return;
5204
+
5205
+ // Find the catch block for this try
5206
+ // Match by line number since we don't have the tryBlockId here
5207
+ const catchLine = getLine(handler);
5208
+ const catchBlock = catchBlocks.find(cb =>
5209
+ cb.file === module.file && cb.line === catchLine
5210
+ );
5211
+
5212
+ if (!catchBlock || !catchBlock.parameterName) return;
5213
+
5214
+ // Traverse only the try block body (not catch or finally)
5215
+ const _tryBody = tryNode.block;
5216
+ const sources: Array<{ id: string; type: CatchesFromInfo['sourceType']; line: number }> = [];
5217
+
5218
+ // Collect sources from try block
5219
+ tryPath.get('block').traverse({
5220
+ // Stop at nested TryStatement - don't collect from inner try blocks
5221
+ TryStatement: (innerPath) => {
5222
+ innerPath.skip(); // Don't traverse into nested try blocks
5223
+ },
5224
+
5225
+ // Stop at function boundaries - don't collect from nested functions
5226
+ Function: (innerFuncPath) => {
5227
+ innerFuncPath.skip();
5228
+ },
5229
+
5230
+ CallExpression: (callPath: NodePath<t.CallExpression>) => {
5231
+ const callNode = callPath.node;
5232
+ const callLine = getLine(callNode);
5233
+ const callColumn = getColumn(callNode);
5234
+
5235
+ // Check if this is an awaited call
5236
+ const parent = callPath.parentPath;
5237
+ const isAwaited = parent?.isAwaitExpression() ?? false;
5238
+
5239
+ // Find the CALL node that matches this CallExpression
5240
+ let sourceId: string | null = null;
5241
+ let sourceType: CatchesFromInfo['sourceType'] = 'sync_call';
5242
+
5243
+ // Check method calls first (includes Promise.reject which is a method call)
5244
+ const matchingMethodCall = methodCalls.find(mc =>
5245
+ mc.file === module.file &&
5246
+ mc.line === callLine &&
5247
+ mc.column === callColumn
5248
+ );
5249
+
5250
+ if (matchingMethodCall) {
5251
+ sourceId = matchingMethodCall.id;
5252
+ sourceType = isAwaited ? 'awaited_call' : 'sync_call';
5253
+ } else {
5254
+ // Check direct function calls
5255
+ const matchingCallSite = callSites.find(cs =>
5256
+ cs.file === module.file &&
5257
+ cs.line === callLine &&
5258
+ cs.column === callColumn
5259
+ );
5260
+
5261
+ if (matchingCallSite) {
5262
+ sourceId = matchingCallSite.id;
5263
+ sourceType = isAwaited ? 'awaited_call' : 'sync_call';
5264
+ }
5265
+ }
5266
+
5267
+ if (sourceId) {
5268
+ sources.push({ id: sourceId, type: sourceType, line: callLine });
5269
+ }
5270
+ },
5271
+
5272
+ ThrowStatement: (throwPath: NodePath<t.ThrowStatement>) => {
5273
+ const throwNode = throwPath.node;
5274
+ const throwLine = getLine(throwNode);
5275
+ const throwColumn = getColumn(throwNode);
5276
+
5277
+ // Create a synthetic ID for the throw statement
5278
+ // We don't have THROW_STATEMENT nodes, so we use line/column as identifier
5279
+ const sourceId = `THROW#${module.file}#${throwLine}:${throwColumn}`;
5280
+
5281
+ sources.push({ id: sourceId, type: 'throw_statement', line: throwLine });
5282
+ },
5283
+
5284
+ NewExpression: (newPath: NodePath<t.NewExpression>) => {
5285
+ // Skip NewExpression that is direct argument of ThrowStatement
5286
+ // In `throw new Error()`, the throw statement is the primary source
5287
+ if (newPath.parentPath?.isThrowStatement()) {
5288
+ return;
5289
+ }
5290
+
5291
+ const newNode = newPath.node;
5292
+ const newLine = getLine(newNode);
5293
+ const newColumn = getColumn(newNode);
5294
+
5295
+ // Find matching constructor call
5296
+ const matchingConstructor = constructorCalls.find(cc =>
5297
+ cc.file === module.file &&
5298
+ cc.line === newLine &&
5299
+ cc.column === newColumn
5300
+ );
5301
+
5302
+ if (matchingConstructor) {
5303
+ sources.push({ id: matchingConstructor.id, type: 'constructor_call', line: newLine });
5304
+ }
5305
+ }
5306
+ });
5307
+
5308
+ // Create CatchesFromInfo for each source
5309
+ for (const source of sources) {
5310
+ catchesFromInfos.push({
5311
+ catchBlockId: catchBlock.id,
5312
+ parameterName: catchBlock.parameterName,
5313
+ sourceId: source.id,
5314
+ sourceType: source.type,
5315
+ file: module.file,
5316
+ sourceLine: source.line
5317
+ });
5318
+ }
5319
+ }
5320
+ });
5321
+ }
5322
+
4738
5323
  /**
4739
5324
  * Detect array mutation calls (push, unshift, splice) inside functions
4740
5325
  * and collect mutation info for FLOWS_INTO edge creation in GraphBuilder
@@ -4832,17 +5417,22 @@ export class JSASTAnalyzer extends Plugin {
4832
5417
 
4833
5418
  /**
4834
5419
  * Detect indexed array assignment: arr[i] = value
4835
- * Creates ArrayMutationInfo for FLOWS_INTO edge generation in GraphBuilder
5420
+ * Creates ArrayMutationInfo for FLOWS_INTO edge generation in GraphBuilder.
5421
+ * For non-variable values (LITERAL, OBJECT_LITERAL, ARRAY_LITERAL), creates
5422
+ * value nodes and sets valueNodeId so GraphBuilder can create FLOWS_INTO edges.
4836
5423
  *
4837
5424
  * @param assignNode - The assignment expression node
4838
5425
  * @param module - Current module being analyzed
4839
5426
  * @param arrayMutations - Collection to push mutation info into
5427
+ * @param scopeTracker - Scope tracker for semantic ID generation
5428
+ * @param collections - Collections for creating value nodes (literals, objectLiterals, etc.)
4840
5429
  */
4841
5430
  private detectIndexedArrayAssignment(
4842
5431
  assignNode: t.AssignmentExpression,
4843
5432
  module: VisitorModule,
4844
5433
  arrayMutations: ArrayMutationInfo[],
4845
- scopeTracker?: ScopeTracker
5434
+ scopeTracker?: ScopeTracker,
5435
+ collections?: VisitorCollections
4846
5436
  ): void {
4847
5437
  // Check for indexed array assignment: arr[i] = value
4848
5438
  if (assignNode.left.type === 'MemberExpression' && assignNode.left.computed) {
@@ -4850,8 +5440,8 @@ export class JSASTAnalyzer extends Plugin {
4850
5440
 
4851
5441
  // Only process NumericLiteral keys - those are clearly array indexed assignments
4852
5442
  // e.g., arr[0] = value, arr[1] = value
4853
- // All other computed keys (StringLiteral, Identifier, expressions) are handled as object mutations
4854
- // This avoids duplicate edge creation for ambiguous cases like obj[key] = value
5443
+ // Other computed keys (Identifier, expressions) are ambiguous (could be array or object)
5444
+ // and are handled by detectObjectPropertyAssignment as computed mutations
4855
5445
  if (memberExpr.property.type !== 'NumericLiteral') {
4856
5446
  return;
4857
5447
  }
@@ -4861,34 +5451,79 @@ export class JSASTAnalyzer extends Plugin {
4861
5451
  const arrayName = memberExpr.object.name;
4862
5452
  const value = assignNode.right;
4863
5453
 
5454
+ // Use defensive loc checks instead of ! assertions
5455
+ const line = assignNode.loc?.start.line ?? 0;
5456
+ const column = assignNode.loc?.start.column ?? 0;
5457
+
4864
5458
  const argInfo: ArrayMutationArgument = {
4865
5459
  argIndex: 0,
4866
5460
  isSpread: false,
4867
5461
  valueType: 'EXPRESSION'
4868
5462
  };
4869
5463
 
4870
- // Determine value type
5464
+ // Determine value type and create value nodes for non-variable types (REG-392)
4871
5465
  const literalValue = ExpressionEvaluator.extractLiteralValue(value);
4872
5466
  if (literalValue !== null) {
4873
5467
  argInfo.valueType = 'LITERAL';
4874
5468
  argInfo.literalValue = literalValue;
5469
+ const valueLine = value.loc?.start.line ?? line;
5470
+ const valueColumn = value.loc?.start.column ?? column;
5471
+ // Create LITERAL node if collections available
5472
+ if (collections?.literals && collections.literalCounterRef) {
5473
+ const literalCounterRef = collections.literalCounterRef as CounterRef;
5474
+ const literalId = `LITERAL#indexed#${module.file}#${valueLine}:${valueColumn}:${literalCounterRef.value++}`;
5475
+ (collections.literals as LiteralInfo[]).push({
5476
+ id: literalId,
5477
+ type: 'LITERAL',
5478
+ value: literalValue,
5479
+ valueType: typeof literalValue,
5480
+ file: module.file,
5481
+ line: valueLine,
5482
+ column: valueColumn,
5483
+ parentCallId: undefined,
5484
+ argIndex: 0
5485
+ } as LiteralInfo);
5486
+ argInfo.valueNodeId = literalId;
5487
+ }
4875
5488
  } else if (value.type === 'Identifier') {
4876
5489
  argInfo.valueType = 'VARIABLE';
4877
5490
  argInfo.valueName = value.name;
4878
5491
  } else if (value.type === 'ObjectExpression') {
4879
5492
  argInfo.valueType = 'OBJECT_LITERAL';
5493
+ const valueLine = value.loc?.start.line ?? line;
5494
+ const valueColumn = value.loc?.start.column ?? column;
5495
+ // Create OBJECT_LITERAL node if collections available
5496
+ if (collections?.objectLiteralCounterRef) {
5497
+ if (!collections.objectLiterals) collections.objectLiterals = [];
5498
+ const objectLiteralCounterRef = collections.objectLiteralCounterRef as CounterRef;
5499
+ const objectNode = ObjectLiteralNode.create(
5500
+ module.file, valueLine, valueColumn,
5501
+ { counter: objectLiteralCounterRef.value++ }
5502
+ );
5503
+ (collections.objectLiterals as ObjectLiteralInfo[]).push(objectNode as unknown as ObjectLiteralInfo);
5504
+ argInfo.valueNodeId = objectNode.id;
5505
+ }
4880
5506
  } else if (value.type === 'ArrayExpression') {
4881
5507
  argInfo.valueType = 'ARRAY_LITERAL';
5508
+ const valueLine = value.loc?.start.line ?? line;
5509
+ const valueColumn = value.loc?.start.column ?? column;
5510
+ // Create ARRAY_LITERAL node if collections available
5511
+ if (collections?.arrayLiteralCounterRef) {
5512
+ if (!collections.arrayLiterals) collections.arrayLiterals = [];
5513
+ const arrayLiteralCounterRef = collections.arrayLiteralCounterRef as CounterRef;
5514
+ const arrayNode = ArrayLiteralNode.create(
5515
+ module.file, valueLine, valueColumn,
5516
+ { counter: arrayLiteralCounterRef.value++ }
5517
+ );
5518
+ (collections.arrayLiterals as ArrayLiteralInfo[]).push(arrayNode as unknown as ArrayLiteralInfo);
5519
+ argInfo.valueNodeId = arrayNode.id;
5520
+ }
4882
5521
  } else if (value.type === 'CallExpression') {
4883
5522
  argInfo.valueType = 'CALL';
4884
5523
  argInfo.callLine = value.loc?.start.line;
4885
5524
  argInfo.callColumn = value.loc?.start.column;
4886
5525
  }
4887
5526
 
4888
- // Use defensive loc checks instead of ! assertions
4889
- const line = assignNode.loc?.start.line ?? 0;
4890
- const column = assignNode.loc?.start.column ?? 0;
4891
-
4892
5527
  // Capture scope path for scope-aware lookup (REG-309)
4893
5528
  const scopePath = scopeTracker?.getContext().scopePath ?? [];
4894
5529