@optave/codegraph 3.12.0 → 3.15.0

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 (524) hide show
  1. package/README.md +83 -46
  2. package/dist/ast-analysis/engine.d.ts.map +1 -1
  3. package/dist/ast-analysis/engine.js +38 -40
  4. package/dist/ast-analysis/engine.js.map +1 -1
  5. package/dist/ast-analysis/rules/b2.d.ts +7 -0
  6. package/dist/ast-analysis/rules/b2.d.ts.map +1 -0
  7. package/dist/ast-analysis/rules/b2.js +240 -0
  8. package/dist/ast-analysis/rules/b2.js.map +1 -0
  9. package/dist/ast-analysis/rules/b3.d.ts +6 -0
  10. package/dist/ast-analysis/rules/b3.d.ts.map +1 -0
  11. package/dist/ast-analysis/rules/b3.js +105 -0
  12. package/dist/ast-analysis/rules/b3.js.map +1 -0
  13. package/dist/ast-analysis/rules/b4.d.ts +9 -0
  14. package/dist/ast-analysis/rules/b4.d.ts.map +1 -0
  15. package/dist/ast-analysis/rules/b4.js +361 -0
  16. package/dist/ast-analysis/rules/b4.js.map +1 -0
  17. package/dist/ast-analysis/rules/b5.d.ts +4 -0
  18. package/dist/ast-analysis/rules/b5.d.ts.map +1 -0
  19. package/dist/ast-analysis/rules/b5.js +52 -0
  20. package/dist/ast-analysis/rules/b5.js.map +1 -0
  21. package/dist/ast-analysis/rules/c.d.ts +4 -0
  22. package/dist/ast-analysis/rules/c.d.ts.map +1 -0
  23. package/dist/ast-analysis/rules/c.js +143 -0
  24. package/dist/ast-analysis/rules/c.js.map +1 -0
  25. package/dist/ast-analysis/rules/index.d.ts.map +1 -1
  26. package/dist/ast-analysis/rules/index.js +34 -0
  27. package/dist/ast-analysis/rules/index.js.map +1 -1
  28. package/dist/ast-analysis/rules/javascript.d.ts.map +1 -1
  29. package/dist/ast-analysis/rules/javascript.js +3 -0
  30. package/dist/ast-analysis/rules/javascript.js.map +1 -1
  31. package/dist/ast-analysis/shared.d.ts.map +1 -1
  32. package/dist/ast-analysis/shared.js +2 -0
  33. package/dist/ast-analysis/shared.js.map +1 -1
  34. package/dist/ast-analysis/visitor-utils.d.ts +1 -0
  35. package/dist/ast-analysis/visitor-utils.d.ts.map +1 -1
  36. package/dist/ast-analysis/visitor-utils.js +5 -0
  37. package/dist/ast-analysis/visitor-utils.js.map +1 -1
  38. package/dist/ast-analysis/visitor.d.ts.map +1 -1
  39. package/dist/ast-analysis/visitor.js +60 -47
  40. package/dist/ast-analysis/visitor.js.map +1 -1
  41. package/dist/ast-analysis/visitors/cfg-visitor.d.ts.map +1 -1
  42. package/dist/ast-analysis/visitors/cfg-visitor.js +126 -76
  43. package/dist/ast-analysis/visitors/cfg-visitor.js.map +1 -1
  44. package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
  45. package/dist/ast-analysis/visitors/complexity-visitor.js +27 -15
  46. package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
  47. package/dist/ast-analysis/visitors/dataflow-visitor.d.ts.map +1 -1
  48. package/dist/ast-analysis/visitors/dataflow-visitor.js +54 -21
  49. package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
  50. package/dist/cli/commands/audit.d.ts.map +1 -1
  51. package/dist/cli/commands/audit.js +2 -1
  52. package/dist/cli/commands/audit.js.map +1 -1
  53. package/dist/cli/commands/batch.d.ts.map +1 -1
  54. package/dist/cli/commands/batch.js +1 -0
  55. package/dist/cli/commands/batch.js.map +1 -1
  56. package/dist/cli/commands/build.d.ts.map +1 -1
  57. package/dist/cli/commands/build.js +6 -1
  58. package/dist/cli/commands/build.js.map +1 -1
  59. package/dist/cli/commands/config.d.ts +3 -0
  60. package/dist/cli/commands/config.d.ts.map +1 -0
  61. package/dist/cli/commands/config.js +275 -0
  62. package/dist/cli/commands/config.js.map +1 -0
  63. package/dist/cli/commands/roles.d.ts.map +1 -1
  64. package/dist/cli/commands/roles.js +6 -1
  65. package/dist/cli/commands/roles.js.map +1 -1
  66. package/dist/cli/commands/triage.js +1 -1
  67. package/dist/cli/commands/triage.js.map +1 -1
  68. package/dist/cli/index.d.ts.map +1 -1
  69. package/dist/cli/index.js +10 -0
  70. package/dist/cli/index.js.map +1 -1
  71. package/dist/cli/shared/options.d.ts +2 -1
  72. package/dist/cli/shared/options.d.ts.map +1 -1
  73. package/dist/cli/shared/options.js +11 -1
  74. package/dist/cli/shared/options.js.map +1 -1
  75. package/dist/cli/types.d.ts +2 -0
  76. package/dist/cli/types.d.ts.map +1 -1
  77. package/dist/db/better-sqlite3.d.ts +2 -1
  78. package/dist/db/better-sqlite3.d.ts.map +1 -1
  79. package/dist/db/better-sqlite3.js.map +1 -1
  80. package/dist/db/connection.d.ts +7 -1
  81. package/dist/db/connection.d.ts.map +1 -1
  82. package/dist/db/connection.js +20 -5
  83. package/dist/db/connection.js.map +1 -1
  84. package/dist/db/index.d.ts +1 -1
  85. package/dist/db/index.d.ts.map +1 -1
  86. package/dist/db/index.js +1 -1
  87. package/dist/db/index.js.map +1 -1
  88. package/dist/db/migrations.d.ts.map +1 -1
  89. package/dist/db/migrations.js +69 -1
  90. package/dist/db/migrations.js.map +1 -1
  91. package/dist/db/repository/build-stmts.d.ts.map +1 -1
  92. package/dist/db/repository/build-stmts.js +18 -0
  93. package/dist/db/repository/build-stmts.js.map +1 -1
  94. package/dist/db/repository/dataflow.d.ts +5 -0
  95. package/dist/db/repository/dataflow.d.ts.map +1 -1
  96. package/dist/db/repository/dataflow.js +14 -0
  97. package/dist/db/repository/dataflow.js.map +1 -1
  98. package/dist/db/repository/index.d.ts +1 -1
  99. package/dist/db/repository/index.d.ts.map +1 -1
  100. package/dist/db/repository/index.js +1 -1
  101. package/dist/db/repository/index.js.map +1 -1
  102. package/dist/db/repository/native-repository.d.ts.map +1 -1
  103. package/dist/db/repository/native-repository.js +47 -34
  104. package/dist/db/repository/native-repository.js.map +1 -1
  105. package/dist/domain/analysis/context.d.ts +2 -2
  106. package/dist/domain/analysis/dependencies.d.ts +2 -2
  107. package/dist/domain/analysis/diff-impact.d.ts +2 -2
  108. package/dist/domain/analysis/fn-impact.d.ts +3 -1
  109. package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
  110. package/dist/domain/analysis/fn-impact.js +4 -0
  111. package/dist/domain/analysis/fn-impact.js.map +1 -1
  112. package/dist/domain/analysis/implementations.d.ts +2 -2
  113. package/dist/domain/analysis/module-map.d.ts.map +1 -1
  114. package/dist/domain/analysis/module-map.js +32 -5
  115. package/dist/domain/analysis/module-map.js.map +1 -1
  116. package/dist/domain/analysis/roles.d.ts +7 -1
  117. package/dist/domain/analysis/roles.d.ts.map +1 -1
  118. package/dist/domain/analysis/roles.js +16 -0
  119. package/dist/domain/analysis/roles.js.map +1 -1
  120. package/dist/domain/analysis/symbol-lookup.d.ts +4 -4
  121. package/dist/domain/graph/builder/call-resolver.d.ts +29 -13
  122. package/dist/domain/graph/builder/call-resolver.d.ts.map +1 -1
  123. package/dist/domain/graph/builder/call-resolver.js +125 -205
  124. package/dist/domain/graph/builder/call-resolver.js.map +1 -1
  125. package/dist/domain/graph/builder/cha.d.ts +9 -1
  126. package/dist/domain/graph/builder/cha.d.ts.map +1 -1
  127. package/dist/domain/graph/builder/cha.js +17 -2
  128. package/dist/domain/graph/builder/cha.js.map +1 -1
  129. package/dist/domain/graph/builder/context.d.ts +1 -0
  130. package/dist/domain/graph/builder/context.d.ts.map +1 -1
  131. package/dist/domain/graph/builder/context.js.map +1 -1
  132. package/dist/domain/graph/builder/helpers.d.ts +24 -1
  133. package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
  134. package/dist/domain/graph/builder/helpers.js +174 -65
  135. package/dist/domain/graph/builder/helpers.js.map +1 -1
  136. package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
  137. package/dist/domain/graph/builder/incremental.js +166 -97
  138. package/dist/domain/graph/builder/incremental.js.map +1 -1
  139. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
  140. package/dist/domain/graph/builder/pipeline.js +46 -5
  141. package/dist/domain/graph/builder/pipeline.js.map +1 -1
  142. package/dist/domain/graph/builder/stages/build-edges.d.ts +0 -2
  143. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
  144. package/dist/domain/graph/builder/stages/build-edges.js +554 -538
  145. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
  146. package/dist/domain/graph/builder/stages/collect-files.d.ts.map +1 -1
  147. package/dist/domain/graph/builder/stages/collect-files.js +10 -7
  148. package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
  149. package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
  150. package/dist/domain/graph/builder/stages/detect-changes.js +3 -2
  151. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
  152. package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
  153. package/dist/domain/graph/builder/stages/finalize.js +4 -0
  154. package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
  155. package/dist/domain/graph/builder/stages/native-orchestrator.d.ts.map +1 -1
  156. package/dist/domain/graph/builder/stages/native-orchestrator.js +952 -343
  157. package/dist/domain/graph/builder/stages/native-orchestrator.js.map +1 -1
  158. package/dist/domain/graph/builder/stages/resolve-imports.js +1 -1
  159. package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
  160. package/dist/domain/graph/resolver/points-to.d.ts.map +1 -1
  161. package/dist/domain/graph/resolver/points-to.js +105 -57
  162. package/dist/domain/graph/resolver/points-to.js.map +1 -1
  163. package/dist/domain/graph/resolver/strategy.d.ts +61 -0
  164. package/dist/domain/graph/resolver/strategy.d.ts.map +1 -0
  165. package/dist/domain/graph/resolver/strategy.js +222 -0
  166. package/dist/domain/graph/resolver/strategy.js.map +1 -0
  167. package/dist/domain/graph/watcher.d.ts.map +1 -1
  168. package/dist/domain/graph/watcher.js +16 -9
  169. package/dist/domain/graph/watcher.js.map +1 -1
  170. package/dist/domain/parser.d.ts +16 -5
  171. package/dist/domain/parser.d.ts.map +1 -1
  172. package/dist/domain/parser.js +58 -17
  173. package/dist/domain/parser.js.map +1 -1
  174. package/dist/domain/queries.d.ts +1 -1
  175. package/dist/domain/queries.d.ts.map +1 -1
  176. package/dist/domain/queries.js +1 -1
  177. package/dist/domain/queries.js.map +1 -1
  178. package/dist/domain/wasm-worker-entry.js +13 -2
  179. package/dist/domain/wasm-worker-entry.js.map +1 -1
  180. package/dist/domain/wasm-worker-pool.d.ts.map +1 -1
  181. package/dist/domain/wasm-worker-pool.js +26 -5
  182. package/dist/domain/wasm-worker-pool.js.map +1 -1
  183. package/dist/domain/wasm-worker-protocol.d.ts +8 -0
  184. package/dist/domain/wasm-worker-protocol.d.ts.map +1 -1
  185. package/dist/extractors/cpp.d.ts.map +1 -1
  186. package/dist/extractors/cpp.js +42 -1
  187. package/dist/extractors/cpp.js.map +1 -1
  188. package/dist/extractors/cuda.d.ts.map +1 -1
  189. package/dist/extractors/cuda.js +42 -1
  190. package/dist/extractors/cuda.js.map +1 -1
  191. package/dist/extractors/dart.js +48 -3
  192. package/dist/extractors/dart.js.map +1 -1
  193. package/dist/extractors/groovy.js +62 -3
  194. package/dist/extractors/groovy.js.map +1 -1
  195. package/dist/extractors/helpers.d.ts +15 -2
  196. package/dist/extractors/helpers.d.ts.map +1 -1
  197. package/dist/extractors/helpers.js +45 -1
  198. package/dist/extractors/helpers.js.map +1 -1
  199. package/dist/extractors/java.d.ts.map +1 -1
  200. package/dist/extractors/java.js +85 -8
  201. package/dist/extractors/java.js.map +1 -1
  202. package/dist/extractors/javascript.d.ts.map +1 -1
  203. package/dist/extractors/javascript.js +686 -169
  204. package/dist/extractors/javascript.js.map +1 -1
  205. package/dist/extractors/kotlin.js +58 -3
  206. package/dist/extractors/kotlin.js.map +1 -1
  207. package/dist/extractors/objc.js +25 -2
  208. package/dist/extractors/objc.js.map +1 -1
  209. package/dist/extractors/scala.js +62 -2
  210. package/dist/extractors/scala.js.map +1 -1
  211. package/dist/extractors/swift.js +52 -3
  212. package/dist/extractors/swift.js.map +1 -1
  213. package/dist/features/audit.js +26 -23
  214. package/dist/features/audit.js.map +1 -1
  215. package/dist/features/boundaries.d.ts.map +1 -1
  216. package/dist/features/boundaries.js +12 -9
  217. package/dist/features/boundaries.js.map +1 -1
  218. package/dist/features/cfg.d.ts.map +1 -1
  219. package/dist/features/cfg.js +25 -18
  220. package/dist/features/cfg.js.map +1 -1
  221. package/dist/features/check.d.ts.map +1 -1
  222. package/dist/features/check.js +18 -5
  223. package/dist/features/check.js.map +1 -1
  224. package/dist/features/communities.d.ts +4 -2
  225. package/dist/features/communities.d.ts.map +1 -1
  226. package/dist/features/communities.js +6 -4
  227. package/dist/features/communities.js.map +1 -1
  228. package/dist/features/dataflow.d.ts +60 -0
  229. package/dist/features/dataflow.d.ts.map +1 -1
  230. package/dist/features/dataflow.js +530 -6
  231. package/dist/features/dataflow.js.map +1 -1
  232. package/dist/features/manifesto.d.ts.map +1 -1
  233. package/dist/features/manifesto.js +59 -72
  234. package/dist/features/manifesto.js.map +1 -1
  235. package/dist/features/sequence.d.ts.map +1 -1
  236. package/dist/features/sequence.js +27 -22
  237. package/dist/features/sequence.js.map +1 -1
  238. package/dist/features/snapshot.d.ts.map +1 -1
  239. package/dist/features/snapshot.js +36 -28
  240. package/dist/features/snapshot.js.map +1 -1
  241. package/dist/features/structure-query.d.ts +1 -1
  242. package/dist/features/structure-query.d.ts.map +1 -1
  243. package/dist/features/structure-query.js +6 -6
  244. package/dist/features/structure-query.js.map +1 -1
  245. package/dist/features/structure.d.ts.map +1 -1
  246. package/dist/features/structure.js +150 -62
  247. package/dist/features/structure.js.map +1 -1
  248. package/dist/features/triage.d.ts.map +1 -1
  249. package/dist/features/triage.js +18 -11
  250. package/dist/features/triage.js.map +1 -1
  251. package/dist/graph/algorithms/bfs.d.ts +1 -1
  252. package/dist/graph/algorithms/bfs.d.ts.map +1 -1
  253. package/dist/graph/algorithms/bfs.js +14 -13
  254. package/dist/graph/algorithms/bfs.js.map +1 -1
  255. package/dist/graph/algorithms/tarjan.d.ts.map +1 -1
  256. package/dist/graph/algorithms/tarjan.js +5 -0
  257. package/dist/graph/algorithms/tarjan.js.map +1 -1
  258. package/dist/graph/builders/dependency.js +28 -22
  259. package/dist/graph/builders/dependency.js.map +1 -1
  260. package/dist/graph/classifiers/roles.d.ts +10 -1
  261. package/dist/graph/classifiers/roles.d.ts.map +1 -1
  262. package/dist/graph/classifiers/roles.js +60 -6
  263. package/dist/graph/classifiers/roles.js.map +1 -1
  264. package/dist/index.d.ts +1 -1
  265. package/dist/index.d.ts.map +1 -1
  266. package/dist/index.js +1 -1
  267. package/dist/index.js.map +1 -1
  268. package/dist/infrastructure/config.d.ts +87 -4
  269. package/dist/infrastructure/config.d.ts.map +1 -1
  270. package/dist/infrastructure/config.js +424 -22
  271. package/dist/infrastructure/config.js.map +1 -1
  272. package/dist/infrastructure/registry.d.ts +27 -7
  273. package/dist/infrastructure/registry.d.ts.map +1 -1
  274. package/dist/infrastructure/registry.js +79 -5
  275. package/dist/infrastructure/registry.js.map +1 -1
  276. package/dist/infrastructure/update-check.d.ts.map +1 -1
  277. package/dist/infrastructure/update-check.js +49 -31
  278. package/dist/infrastructure/update-check.js.map +1 -1
  279. package/dist/mcp/server.d.ts +2 -10
  280. package/dist/mcp/server.d.ts.map +1 -1
  281. package/dist/mcp/server.js.map +1 -1
  282. package/dist/mcp/tools/ast-query.d.ts +1 -1
  283. package/dist/mcp/tools/ast-query.d.ts.map +1 -1
  284. package/dist/mcp/tools/audit.d.ts +1 -1
  285. package/dist/mcp/tools/audit.d.ts.map +1 -1
  286. package/dist/mcp/tools/batch-query.d.ts +1 -1
  287. package/dist/mcp/tools/batch-query.d.ts.map +1 -1
  288. package/dist/mcp/tools/branch-compare.d.ts +1 -1
  289. package/dist/mcp/tools/branch-compare.d.ts.map +1 -1
  290. package/dist/mcp/tools/brief.d.ts +1 -1
  291. package/dist/mcp/tools/brief.d.ts.map +1 -1
  292. package/dist/mcp/tools/cfg.d.ts +1 -1
  293. package/dist/mcp/tools/cfg.d.ts.map +1 -1
  294. package/dist/mcp/tools/check.d.ts +1 -1
  295. package/dist/mcp/tools/check.d.ts.map +1 -1
  296. package/dist/mcp/tools/co-changes.d.ts +1 -1
  297. package/dist/mcp/tools/co-changes.d.ts.map +1 -1
  298. package/dist/mcp/tools/code-owners.d.ts +1 -1
  299. package/dist/mcp/tools/code-owners.d.ts.map +1 -1
  300. package/dist/mcp/tools/communities.d.ts +1 -1
  301. package/dist/mcp/tools/communities.d.ts.map +1 -1
  302. package/dist/mcp/tools/complexity.d.ts +1 -1
  303. package/dist/mcp/tools/complexity.d.ts.map +1 -1
  304. package/dist/mcp/tools/context.d.ts +1 -1
  305. package/dist/mcp/tools/context.d.ts.map +1 -1
  306. package/dist/mcp/tools/dataflow.d.ts +1 -1
  307. package/dist/mcp/tools/dataflow.d.ts.map +1 -1
  308. package/dist/mcp/tools/diff-impact.d.ts +1 -1
  309. package/dist/mcp/tools/diff-impact.d.ts.map +1 -1
  310. package/dist/mcp/tools/execution-flow.d.ts +1 -1
  311. package/dist/mcp/tools/execution-flow.d.ts.map +1 -1
  312. package/dist/mcp/tools/export-graph.d.ts +1 -1
  313. package/dist/mcp/tools/export-graph.d.ts.map +1 -1
  314. package/dist/mcp/tools/file-deps.d.ts +1 -1
  315. package/dist/mcp/tools/file-deps.d.ts.map +1 -1
  316. package/dist/mcp/tools/file-exports.d.ts +1 -1
  317. package/dist/mcp/tools/file-exports.d.ts.map +1 -1
  318. package/dist/mcp/tools/find-cycles.d.ts +1 -1
  319. package/dist/mcp/tools/find-cycles.d.ts.map +1 -1
  320. package/dist/mcp/tools/fn-impact.d.ts +1 -1
  321. package/dist/mcp/tools/fn-impact.d.ts.map +1 -1
  322. package/dist/mcp/tools/impact-analysis.d.ts +1 -1
  323. package/dist/mcp/tools/impact-analysis.d.ts.map +1 -1
  324. package/dist/mcp/tools/implementations.d.ts +1 -1
  325. package/dist/mcp/tools/implementations.d.ts.map +1 -1
  326. package/dist/mcp/tools/index.d.ts +2 -5
  327. package/dist/mcp/tools/index.d.ts.map +1 -1
  328. package/dist/mcp/tools/index.js.map +1 -1
  329. package/dist/mcp/tools/interfaces.d.ts +1 -1
  330. package/dist/mcp/tools/interfaces.d.ts.map +1 -1
  331. package/dist/mcp/tools/list-functions.d.ts +1 -1
  332. package/dist/mcp/tools/list-functions.d.ts.map +1 -1
  333. package/dist/mcp/tools/list-repos.d.ts +1 -1
  334. package/dist/mcp/tools/list-repos.d.ts.map +1 -1
  335. package/dist/mcp/tools/module-map.d.ts +1 -1
  336. package/dist/mcp/tools/module-map.d.ts.map +1 -1
  337. package/dist/mcp/tools/node-roles.d.ts +1 -1
  338. package/dist/mcp/tools/node-roles.d.ts.map +1 -1
  339. package/dist/mcp/tools/path.d.ts +1 -1
  340. package/dist/mcp/tools/path.d.ts.map +1 -1
  341. package/dist/mcp/tools/query.d.ts +1 -1
  342. package/dist/mcp/tools/query.d.ts.map +1 -1
  343. package/dist/mcp/tools/semantic-search.d.ts +1 -1
  344. package/dist/mcp/tools/semantic-search.d.ts.map +1 -1
  345. package/dist/mcp/tools/sequence.d.ts +1 -1
  346. package/dist/mcp/tools/sequence.d.ts.map +1 -1
  347. package/dist/mcp/tools/structure.d.ts +1 -1
  348. package/dist/mcp/tools/structure.d.ts.map +1 -1
  349. package/dist/mcp/tools/symbol-children.d.ts +1 -1
  350. package/dist/mcp/tools/symbol-children.d.ts.map +1 -1
  351. package/dist/mcp/tools/triage.d.ts +1 -1
  352. package/dist/mcp/tools/triage.d.ts.map +1 -1
  353. package/dist/mcp/tools/where.d.ts +1 -1
  354. package/dist/mcp/tools/where.d.ts.map +1 -1
  355. package/dist/mcp/types.d.ts +19 -0
  356. package/dist/mcp/types.d.ts.map +1 -0
  357. package/dist/mcp/types.js +6 -0
  358. package/dist/mcp/types.js.map +1 -0
  359. package/dist/presentation/queries-cli/index.d.ts +1 -1
  360. package/dist/presentation/queries-cli/index.d.ts.map +1 -1
  361. package/dist/presentation/queries-cli/index.js +1 -1
  362. package/dist/presentation/queries-cli/index.js.map +1 -1
  363. package/dist/presentation/queries-cli/overview.d.ts +1 -0
  364. package/dist/presentation/queries-cli/overview.d.ts.map +1 -1
  365. package/dist/presentation/queries-cli/overview.js +20 -1
  366. package/dist/presentation/queries-cli/overview.js.map +1 -1
  367. package/dist/presentation/queries-cli.d.ts +1 -1
  368. package/dist/presentation/queries-cli.d.ts.map +1 -1
  369. package/dist/presentation/queries-cli.js +1 -1
  370. package/dist/presentation/queries-cli.js.map +1 -1
  371. package/dist/presentation/structure.d.ts +1 -1
  372. package/dist/presentation/structure.d.ts.map +1 -1
  373. package/dist/presentation/structure.js +2 -2
  374. package/dist/presentation/structure.js.map +1 -1
  375. package/dist/presentation/viewer.d.ts.map +1 -1
  376. package/dist/presentation/viewer.js +45 -32
  377. package/dist/presentation/viewer.js.map +1 -1
  378. package/dist/shared/constants.d.ts +21 -0
  379. package/dist/shared/constants.d.ts.map +1 -1
  380. package/dist/shared/constants.js +25 -0
  381. package/dist/shared/constants.js.map +1 -1
  382. package/dist/shared/normalize.d.ts.map +1 -1
  383. package/dist/shared/normalize.js +12 -22
  384. package/dist/shared/normalize.js.map +1 -1
  385. package/dist/shared/paginate.d.ts +4 -17
  386. package/dist/shared/paginate.d.ts.map +1 -1
  387. package/dist/shared/paginate.js.map +1 -1
  388. package/dist/types.d.ts +113 -1
  389. package/dist/types.d.ts.map +1 -1
  390. package/grammars/tree-sitter-erlang.wasm +0 -0
  391. package/grammars/tree-sitter-gleam.wasm +0 -0
  392. package/package.json +7 -8
  393. package/src/ast-analysis/engine.ts +43 -63
  394. package/src/ast-analysis/rules/b2.ts +263 -0
  395. package/src/ast-analysis/rules/b3.ts +127 -0
  396. package/src/ast-analysis/rules/b4.ts +378 -0
  397. package/src/ast-analysis/rules/b5.ts +65 -0
  398. package/src/ast-analysis/rules/c.ts +157 -0
  399. package/src/ast-analysis/rules/index.ts +34 -0
  400. package/src/ast-analysis/rules/javascript.ts +3 -0
  401. package/src/ast-analysis/shared.ts +2 -0
  402. package/src/ast-analysis/visitor-utils.ts +5 -0
  403. package/src/ast-analysis/visitor.ts +82 -52
  404. package/src/ast-analysis/visitors/cfg-visitor.ts +198 -84
  405. package/src/ast-analysis/visitors/complexity-visitor.ts +44 -16
  406. package/src/ast-analysis/visitors/dataflow-visitor.ts +68 -29
  407. package/src/cli/commands/audit.ts +2 -1
  408. package/src/cli/commands/batch.ts +1 -0
  409. package/src/cli/commands/build.ts +6 -1
  410. package/src/cli/commands/config.ts +353 -0
  411. package/src/cli/commands/roles.ts +6 -1
  412. package/src/cli/commands/triage.ts +1 -1
  413. package/src/cli/index.ts +10 -0
  414. package/src/cli/shared/options.ts +11 -1
  415. package/src/cli/types.ts +2 -0
  416. package/src/db/better-sqlite3.ts +5 -4
  417. package/src/db/connection.ts +23 -5
  418. package/src/db/index.ts +1 -0
  419. package/src/db/migrations.ts +69 -1
  420. package/src/db/repository/build-stmts.ts +30 -0
  421. package/src/db/repository/dataflow.ts +16 -0
  422. package/src/db/repository/index.ts +1 -1
  423. package/src/db/repository/native-repository.ts +56 -40
  424. package/src/domain/analysis/fn-impact.ts +4 -0
  425. package/src/domain/analysis/module-map.ts +38 -6
  426. package/src/domain/analysis/roles.ts +23 -0
  427. package/src/domain/graph/builder/call-resolver.ts +156 -218
  428. package/src/domain/graph/builder/cha.ts +18 -1
  429. package/src/domain/graph/builder/context.ts +1 -0
  430. package/src/domain/graph/builder/helpers.ts +205 -67
  431. package/src/domain/graph/builder/incremental.ts +249 -119
  432. package/src/domain/graph/builder/pipeline.ts +59 -6
  433. package/src/domain/graph/builder/stages/build-edges.ts +783 -652
  434. package/src/domain/graph/builder/stages/collect-files.ts +12 -6
  435. package/src/domain/graph/builder/stages/detect-changes.ts +4 -2
  436. package/src/domain/graph/builder/stages/finalize.ts +4 -0
  437. package/src/domain/graph/builder/stages/native-orchestrator.ts +1214 -398
  438. package/src/domain/graph/builder/stages/resolve-imports.ts +1 -1
  439. package/src/domain/graph/resolver/points-to.ts +182 -59
  440. package/src/domain/graph/resolver/strategy.ts +265 -0
  441. package/src/domain/graph/watcher.ts +19 -9
  442. package/src/domain/parser.ts +57 -16
  443. package/src/domain/queries.ts +1 -1
  444. package/src/domain/wasm-worker-entry.ts +13 -2
  445. package/src/domain/wasm-worker-pool.ts +29 -4
  446. package/src/domain/wasm-worker-protocol.ts +5 -0
  447. package/src/extractors/cpp.ts +44 -1
  448. package/src/extractors/cuda.ts +44 -1
  449. package/src/extractors/dart.ts +48 -3
  450. package/src/extractors/groovy.ts +62 -2
  451. package/src/extractors/helpers.ts +48 -2
  452. package/src/extractors/java.ts +88 -8
  453. package/src/extractors/javascript.ts +693 -167
  454. package/src/extractors/kotlin.ts +57 -3
  455. package/src/extractors/objc.ts +25 -1
  456. package/src/extractors/scala.ts +63 -1
  457. package/src/extractors/swift.ts +46 -3
  458. package/src/features/audit.ts +43 -34
  459. package/src/features/boundaries.ts +17 -9
  460. package/src/features/cfg.ts +31 -22
  461. package/src/features/check.ts +21 -5
  462. package/src/features/communities.ts +28 -19
  463. package/src/features/dataflow.ts +755 -6
  464. package/src/features/manifesto.ts +76 -75
  465. package/src/features/sequence.ts +29 -23
  466. package/src/features/snapshot.ts +36 -25
  467. package/src/features/structure-query.ts +7 -7
  468. package/src/features/structure.ts +185 -55
  469. package/src/features/triage.ts +28 -15
  470. package/src/graph/algorithms/bfs.ts +13 -12
  471. package/src/graph/algorithms/tarjan.ts +5 -0
  472. package/src/graph/builders/dependency.ts +35 -23
  473. package/src/graph/classifiers/roles.ts +74 -7
  474. package/src/index.ts +5 -1
  475. package/src/infrastructure/config.ts +511 -23
  476. package/src/infrastructure/registry.ts +117 -12
  477. package/src/infrastructure/update-check.ts +55 -33
  478. package/src/mcp/server.ts +2 -8
  479. package/src/mcp/tools/ast-query.ts +1 -1
  480. package/src/mcp/tools/audit.ts +1 -1
  481. package/src/mcp/tools/batch-query.ts +1 -1
  482. package/src/mcp/tools/branch-compare.ts +1 -1
  483. package/src/mcp/tools/brief.ts +1 -1
  484. package/src/mcp/tools/cfg.ts +1 -1
  485. package/src/mcp/tools/check.ts +1 -1
  486. package/src/mcp/tools/co-changes.ts +1 -1
  487. package/src/mcp/tools/code-owners.ts +1 -1
  488. package/src/mcp/tools/communities.ts +1 -1
  489. package/src/mcp/tools/complexity.ts +1 -1
  490. package/src/mcp/tools/context.ts +1 -1
  491. package/src/mcp/tools/dataflow.ts +1 -1
  492. package/src/mcp/tools/diff-impact.ts +1 -1
  493. package/src/mcp/tools/execution-flow.ts +1 -1
  494. package/src/mcp/tools/export-graph.ts +1 -1
  495. package/src/mcp/tools/file-deps.ts +1 -1
  496. package/src/mcp/tools/file-exports.ts +1 -1
  497. package/src/mcp/tools/find-cycles.ts +1 -1
  498. package/src/mcp/tools/fn-impact.ts +1 -1
  499. package/src/mcp/tools/impact-analysis.ts +1 -1
  500. package/src/mcp/tools/implementations.ts +1 -1
  501. package/src/mcp/tools/index.ts +2 -5
  502. package/src/mcp/tools/interfaces.ts +1 -1
  503. package/src/mcp/tools/list-functions.ts +1 -1
  504. package/src/mcp/tools/list-repos.ts +1 -1
  505. package/src/mcp/tools/module-map.ts +1 -1
  506. package/src/mcp/tools/node-roles.ts +1 -1
  507. package/src/mcp/tools/path.ts +1 -1
  508. package/src/mcp/tools/query.ts +1 -1
  509. package/src/mcp/tools/semantic-search.ts +1 -1
  510. package/src/mcp/tools/sequence.ts +1 -1
  511. package/src/mcp/tools/structure.ts +1 -1
  512. package/src/mcp/tools/symbol-children.ts +1 -1
  513. package/src/mcp/tools/triage.ts +1 -1
  514. package/src/mcp/tools/where.ts +1 -1
  515. package/src/mcp/types.ts +21 -0
  516. package/src/presentation/queries-cli/index.ts +1 -1
  517. package/src/presentation/queries-cli/overview.ts +35 -1
  518. package/src/presentation/queries-cli.ts +1 -0
  519. package/src/presentation/structure.ts +3 -3
  520. package/src/presentation/viewer.ts +98 -87
  521. package/src/shared/constants.ts +26 -0
  522. package/src/shared/normalize.ts +13 -22
  523. package/src/shared/paginate.ts +4 -18
  524. package/src/types.ts +127 -1
@@ -6,6 +6,7 @@ import type {
6
6
  CallAssignment,
7
7
  ClassRelation,
8
8
  Definition,
9
+ DynamicKind,
9
10
  Export,
10
11
  ExtractorOutput,
11
12
  FnRefBinding,
@@ -96,6 +97,13 @@ const BUILTIN_GLOBALS: Set<string> = new Set([
96
97
  const MAX_PROPAGATION_DEPTH = 3;
97
98
  /** Confidence penalty applied per propagation hop (1.0 → 0.9 → 0.8 → 0.7). */
98
99
  export const PROPAGATION_HOP_PENALTY = 0.1;
100
+ /**
101
+ * Confidence score for a return type inferred from `return new Constructor()` with no
102
+ * explicit TypeScript annotation. Registered as `analysis.typeInferenceConfidence` in
103
+ * `src/infrastructure/config.ts` DEFAULTS — kept in sync manually until config is
104
+ * threaded through to `extractSymbols`.
105
+ */
106
+ const INFERRED_RETURN_TYPE_CONFIDENCE = 0.85;
99
107
 
100
108
  /**
101
109
  * Extract symbols from a JS/TS parsed AST.
@@ -169,7 +177,19 @@ function handleClassCapture(
169
177
 
170
178
  /** Handle method_definition capture. */
171
179
  function handleMethodCapture(c: Record<string, TreeSitterNode>, definitions: Definition[]): void {
172
- const methName = c.meth_name!.text;
180
+ const methNameNode = c.meth_name!;
181
+ let methName: string;
182
+ if (methNameNode.type === 'computed_property_name') {
183
+ // Extract the inner string literal from `['methodName']` or `["methodName"]`.
184
+ // Non-string computed keys (e.g. `[Symbol.iterator]`) cannot be resolved at
185
+ // dot-notation call sites, so skip them entirely.
186
+ const inner = methNameNode.child(1); // child(0)='[', child(1)=string, child(2)=']'
187
+ if (!inner || (inner.type !== 'string' && inner.type !== 'string_fragment')) return;
188
+ methName = inner.text.replace(/^['"]|['"]$/g, '');
189
+ if (!methName) return;
190
+ } else {
191
+ methName = methNameNode.text;
192
+ }
173
193
  const parentClass = findParentClass(c.meth_node!);
174
194
  const fullName = parentClass ? `${parentClass}.${methName}` : methName;
175
195
  const methChildren = extractParameters(c.meth_node!);
@@ -292,12 +312,14 @@ function dispatchQueryMatch(
292
312
  } else if (c.exp_node) {
293
313
  handleExportCapture(c, exps, imports);
294
314
  } else if (c.callfn_node) {
295
- calls.push({
296
- name: c.callfn_name!.text,
297
- line: nodeStartLine(c.callfn_node),
298
- });
315
+ // Route through extractCallInfo so special identifier calls (eval) get classified.
316
+ const callfnInfo = extractCallInfo(c.callfn_name!, c.callfn_node);
317
+ if (callfnInfo) calls.push(callfnInfo);
299
318
  calls.push(...extractCallbackReferenceCalls(c.callfn_node));
300
319
  } else if (c.callmem_node) {
320
+ // extractCallInfo → extractMemberExprCallInfo applies the plain-identifier guard for
321
+ // .call/.apply/.bind: when the object is a bare identifier (e.g. `fn.call(ctx)`),
322
+ // the call is emitted as static (no dynamic flag), matching the walk path and native engine.
301
323
  const callInfo = extractCallInfo(c.callmem_fn!, c.callmem_node);
302
324
  if (callInfo) calls.push(callInfo);
303
325
  const cbDef = extractCallbackDefinition(c.callmem_node, c.callmem_fn);
@@ -308,10 +330,20 @@ function dispatchQueryMatch(
308
330
  if (callInfo) calls.push(callInfo);
309
331
  calls.push(...extractCallbackReferenceCalls(c.callsub_node));
310
332
  } else if (c.newfn_node) {
311
- calls.push({
312
- name: c.newfn_name!.text,
313
- line: nodeStartLine(c.newfn_node),
314
- });
333
+ if (c.newfn_name!.text === 'Function') {
334
+ // new Function(body) — dynamic code execution; classify as eval kind
335
+ calls.push({
336
+ name: '<dynamic:eval>',
337
+ line: nodeStartLine(c.newfn_node),
338
+ dynamic: true,
339
+ dynamicKind: 'eval',
340
+ });
341
+ } else {
342
+ calls.push({
343
+ name: c.newfn_name!.text,
344
+ line: nodeStartLine(c.newfn_node),
345
+ });
346
+ }
315
347
  } else if (c.newmem_node) {
316
348
  const callInfo = extractCallInfo(c.newmem_fn!, c.newmem_node);
317
349
  if (callInfo) calls.push(callInfo);
@@ -370,8 +402,11 @@ function extractSymbolsQuery(tree: TreeSitterTree, query: TreeSitterQuery): Extr
370
402
  arrayCallbackBindings,
371
403
  });
372
404
 
373
- // Extract definitions from destructured bindings (query patterns don't match object_pattern)
374
- extractDestructuredBindingsWalk(tree.rootNode, definitions);
405
+ // Extract definitions from destructured bindings (query patterns don't match object_pattern).
406
+ // Also collects CJS require bindings (const { X } = require('…')) into a separate list so
407
+ // importedNames can classify them as import artifacts without creating DB edges (#1661).
408
+ const cjsRequireBindings: Array<{ names: string[]; source: string }> = [];
409
+ extractDestructuredBindingsWalk(tree.rootNode, definitions, cjsRequireBindings);
375
410
 
376
411
  // Everything without bespoke traversal semantics is collected in ONE pass:
377
412
  // dynamic import() calls, prototype-method definitions, param bindings,
@@ -414,6 +449,7 @@ function extractSymbolsQuery(tree: TreeSitterTree, query: TreeSitterQuery): Extr
414
449
  thisCallBindings,
415
450
  newExpressions,
416
451
  ...(definePropertyReceivers.size > 0 ? { definePropertyReceivers } : {}),
452
+ ...(cjsRequireBindings.length > 0 ? { cjsRequireBindings } : {}),
417
453
  };
418
454
  }
419
455
 
@@ -462,6 +498,7 @@ function extractConstantsWalk(node: TreeSitterNode, definitions: Definition[]):
462
498
  }
463
499
 
464
500
  extractConstDeclarators(declNode, definitions);
501
+ extractLetVarObjLiteralDeclarators(declNode, definitions);
465
502
 
466
503
  // Recurse into non-function, non-export-statement children (blocks, if-statements, etc.)
467
504
  if (child.type !== 'export_statement') {
@@ -478,8 +515,15 @@ function extractConstantsWalk(node: TreeSitterNode, definitions: Definition[]):
478
515
  /**
479
516
  * Walk the AST to find destructured const bindings (query patterns don't match object_pattern).
480
517
  * e.g. `const { handleToken, checkPermissions } = initAuth(config)`
518
+ *
519
+ * When `cjsRequireBindings` is provided, also records `const { X } = require('./path')` patterns
520
+ * so the edge builder can classify X as an import artifact rather than a local definition (#1661).
481
521
  */
482
- function extractDestructuredBindingsWalk(node: TreeSitterNode, definitions: Definition[]): void {
522
+ function extractDestructuredBindingsWalk(
523
+ node: TreeSitterNode,
524
+ definitions: Definition[],
525
+ cjsRequireBindings?: Array<{ names: string[]; source: string }>,
526
+ ): void {
483
527
  for (let i = 0; i < node.childCount; i++) {
484
528
  const child = node.child(i);
485
529
  if (!child) continue;
@@ -507,12 +551,58 @@ function extractDestructuredBindingsWalk(node: TreeSitterNode, definitions: Defi
507
551
  nodeEndLine(declNode),
508
552
  definitions,
509
553
  );
554
+ // Record CJS require bindings so importedNames can classify these names
555
+ // as import artifacts, preventing false local-definition blocking (#1661).
556
+ if (cjsRequireBindings) {
557
+ const valueN = declarator.childForFieldName('value');
558
+ if (valueN?.type === 'call_expression') {
559
+ const fn = valueN.childForFieldName('function');
560
+ if (fn?.text === 'require') {
561
+ const args = valueN.childForFieldName('arguments');
562
+ const strArg = args && findChild(args, 'string');
563
+ if (strArg) {
564
+ const modPath = strArg.text.replace(/['"]/g, '');
565
+ const names: string[] = [];
566
+ for (let k = 0; k < nameN.childCount; k++) {
567
+ const prop = nameN.child(k);
568
+ if (!prop) continue;
569
+ if (
570
+ prop.type === 'shorthand_property_identifier_pattern' ||
571
+ prop.type === 'shorthand_property_identifier'
572
+ ) {
573
+ names.push(prop.text);
574
+ } else if (prop.type === 'pair_pattern' || prop.type === 'pair') {
575
+ const val = prop.childForFieldName('value');
576
+ if (
577
+ val?.type === 'identifier' ||
578
+ val?.type === 'shorthand_property_identifier_pattern'
579
+ ) {
580
+ names.push(val.text);
581
+ }
582
+ }
583
+ }
584
+ if (names.length > 0) {
585
+ cjsRequireBindings.push({ names, source: modPath });
586
+ }
587
+ }
588
+ }
589
+ }
590
+ }
591
+ } else if (nameN && nameN.type === 'array_pattern') {
592
+ // `const [x, y] = ...` — emit a single constant node whose name is the
593
+ // full array pattern text (e.g. `[x, y]`), matching native engine behaviour.
594
+ definitions.push({
595
+ name: nameN.text,
596
+ kind: 'constant',
597
+ line: nodeStartLine(declNode),
598
+ endLine: nodeEndLine(declNode),
599
+ });
510
600
  }
511
601
  }
512
602
  }
513
603
 
514
604
  if (child.type !== 'export_statement') {
515
- extractDestructuredBindingsWalk(child, definitions);
605
+ extractDestructuredBindingsWalk(child, definitions, cjsRequireBindings);
516
606
  }
517
607
  }
518
608
  }
@@ -557,6 +647,34 @@ function extractConstDeclarators(declNode: TreeSitterNode, definitions: Definiti
557
647
  }
558
648
  }
559
649
 
650
+ /**
651
+ * Extract qualified method definitions from `let`/`var` object-literal declarations.
652
+ * Mirrors `match_js_objlit_qualified_method_defs` in `javascript.rs`, which emits
653
+ * qualified definitions for `method_definition` (all declaration kinds) and
654
+ * `pair+arrow/function` (`let`/`var` only, since `const` is already handled by
655
+ * `extractConstDeclarators` → `extractObjectLiteralFunctions`).
656
+ *
657
+ * Called from extractConstantsWalk which already provides the function-scope guard.
658
+ * `var q1 = { m1() {} }` → emits Definition { name: 'q1.m1', kind: 'function' }
659
+ */
660
+ function extractLetVarObjLiteralDeclarators(
661
+ declNode: TreeSitterNode,
662
+ definitions: Definition[],
663
+ ): void {
664
+ const t = declNode.type;
665
+ if (t !== 'lexical_declaration' && t !== 'variable_declaration') return;
666
+ if (declNode.text.startsWith('const ')) return; // handled by extractConstDeclarators
667
+
668
+ for (let j = 0; j < declNode.childCount; j++) {
669
+ const declarator = declNode.child(j);
670
+ if (declarator?.type !== 'variable_declarator') continue;
671
+ const nameN = declarator.childForFieldName('name');
672
+ const valueN = declarator.childForFieldName('value');
673
+ if (nameN?.type !== 'identifier' || !valueN || valueN.type !== 'object') continue;
674
+ extractObjectLiteralFunctions(valueN, nameN.text, definitions);
675
+ }
676
+ }
677
+
560
678
  /**
561
679
  * Recursive walk to find dynamic import() calls.
562
680
  * Query patterns match call_expression with identifier/member_expression/subscript_expression
@@ -749,6 +867,9 @@ function walkJavaScriptNode(node: TreeSitterNode, ctx: ExtractorOutput): void {
749
867
  case 'enum_declaration':
750
868
  handleEnumDecl(node, ctx);
751
869
  break;
870
+ case 'decorator':
871
+ handleDecorator(node, ctx.calls);
872
+ break;
752
873
  case 'call_expression':
753
874
  handleCallExpr(node, ctx);
754
875
  break;
@@ -816,8 +937,20 @@ function handleClassDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
816
937
  function handleMethodDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
817
938
  const nameNode = node.childForFieldName('name');
818
939
  if (nameNode) {
940
+ let methName: string;
941
+ if (nameNode.type === 'computed_property_name') {
942
+ // Extract the inner string literal from `['methodName']` or `["methodName"]`.
943
+ // Non-string computed keys (e.g. `[Symbol.iterator]`) cannot be resolved at
944
+ // dot-notation call sites, so skip them entirely.
945
+ const inner = nameNode.child(1); // child(0)='[', child(1)=string, child(2)=']'
946
+ if (!inner || (inner.type !== 'string' && inner.type !== 'string_fragment')) return;
947
+ methName = inner.text.replace(/^['"]|['"]$/g, '');
948
+ if (!methName) return;
949
+ } else {
950
+ methName = nameNode.text;
951
+ }
819
952
  const parentClass = findParentClass(node);
820
- const fullName = parentClass ? `${parentClass}.${nameNode.text}` : nameNode.text;
953
+ const fullName = parentClass ? `${parentClass}.${methName}` : methName;
821
954
  const methChildren = extractParameters(node);
822
955
  const methVis = extractVisibility(node);
823
956
  ctx.definitions.push({
@@ -1003,6 +1136,18 @@ function handleVariableDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
1003
1136
  if (valueN.type === 'object') {
1004
1137
  extractObjectLiteralFunctions(valueN, nameN.text, ctx.definitions);
1005
1138
  }
1139
+ } else if (
1140
+ !isConst &&
1141
+ nameN.type === 'identifier' &&
1142
+ valueN.type === 'object' &&
1143
+ !hasFunctionScopeAncestor(node)
1144
+ ) {
1145
+ // `let`/`var` object literals: extract qualified method definitions so that
1146
+ // `obj.method()` calls resolve correctly. Mirrors Rust match_js_objlit_qualified_method_defs
1147
+ // which emits method_definition qualified names for ALL declaration kinds and
1148
+ // pair+arrow/function for let/var only (const is already handled above).
1149
+ // Scope guard prevents local object properties from polluting the global index.
1150
+ extractObjectLiteralFunctions(valueN, nameN.text, ctx.definitions);
1006
1151
  } else if (isConst && nameN.type === 'object_pattern' && !hasFunctionScopeAncestor(node)) {
1007
1152
  // Destructured bindings: const { handleToken, checkPermissions } = initAuth(...)
1008
1153
  // Each destructured property becomes a function definition so it can be
@@ -1017,6 +1162,50 @@ function handleVariableDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
1017
1162
  nodeEndLine(node),
1018
1163
  ctx.definitions,
1019
1164
  );
1165
+ // Record CJS require bindings for import-artifact classification (#1661).
1166
+ if (valueN?.type === 'call_expression') {
1167
+ const fn = valueN.childForFieldName('function');
1168
+ if (fn?.text === 'require') {
1169
+ const args = valueN.childForFieldName('arguments');
1170
+ const strArg = args && findChild(args, 'string');
1171
+ if (strArg) {
1172
+ const modPath = strArg.text.replace(/['"]/g, '');
1173
+ const names: string[] = [];
1174
+ for (let k = 0; k < nameN.childCount; k++) {
1175
+ const prop = nameN.child(k);
1176
+ if (!prop) continue;
1177
+ if (
1178
+ prop.type === 'shorthand_property_identifier_pattern' ||
1179
+ prop.type === 'shorthand_property_identifier'
1180
+ ) {
1181
+ names.push(prop.text);
1182
+ } else if (prop.type === 'pair_pattern' || prop.type === 'pair') {
1183
+ const val = prop.childForFieldName('value');
1184
+ if (
1185
+ val?.type === 'identifier' ||
1186
+ val?.type === 'shorthand_property_identifier_pattern'
1187
+ ) {
1188
+ names.push(val.text);
1189
+ }
1190
+ }
1191
+ }
1192
+ if (names.length > 0) {
1193
+ if (!ctx.cjsRequireBindings) ctx.cjsRequireBindings = [];
1194
+ ctx.cjsRequireBindings.push({ names, source: modPath });
1195
+ }
1196
+ }
1197
+ }
1198
+ }
1199
+ } else if (isConst && nameN.type === 'array_pattern' && !hasFunctionScopeAncestor(node)) {
1200
+ // Array destructuring: `const [x, y] = ...` — emit a single constant node
1201
+ // whose name is the full array pattern text (e.g. `[x, y]`), matching
1202
+ // native engine behaviour. Scope guard mirrors the object_pattern branch above.
1203
+ ctx.definitions.push({
1204
+ name: nameN.text,
1205
+ kind: 'constant',
1206
+ line: nodeStartLine(node),
1207
+ endLine: nodeEndLine(node),
1208
+ });
1020
1209
  }
1021
1210
  }
1022
1211
  }
@@ -1065,8 +1254,19 @@ function extractObjectLiteralFunctions(
1065
1254
  } else if (child.type === 'method_definition') {
1066
1255
  const nameNode = child.childForFieldName('name');
1067
1256
  if (nameNode) {
1257
+ let methodName: string;
1258
+ if (nameNode.type === 'computed_property_name') {
1259
+ // Strip brackets+quotes from `['methodName']` to get a resolvable name.
1260
+ // Skip non-string computed keys (e.g. [Symbol.iterator]).
1261
+ const inner = nameNode.child(1);
1262
+ if (!inner || (inner.type !== 'string' && inner.type !== 'string_fragment')) continue;
1263
+ methodName = inner.text.replace(/^['"]|['"]$/g, '');
1264
+ if (!methodName) continue;
1265
+ } else {
1266
+ methodName = nameNode.text;
1267
+ }
1068
1268
  definitions.push({
1069
- name: `${varName}.${nameNode.text}`,
1269
+ name: `${varName}.${methodName}`,
1070
1270
  kind: 'function',
1071
1271
  line: nodeStartLine(child),
1072
1272
  endLine: nodeEndLine(child),
@@ -1159,13 +1359,54 @@ function handleNewExpr(node: TreeSitterNode, ctx: ExtractorOutput): void {
1159
1359
  const ctor = node.childForFieldName('constructor') || node.child(1);
1160
1360
  if (!ctor) return;
1161
1361
  if (ctor.type === 'identifier') {
1162
- ctx.calls.push({ name: ctor.text, line: nodeStartLine(node) });
1362
+ if (ctor.text === 'Function') {
1363
+ // new Function(body) — dynamic code execution; undecidable static target
1364
+ ctx.calls.push({
1365
+ name: '<dynamic:eval>',
1366
+ line: nodeStartLine(node),
1367
+ dynamic: true,
1368
+ dynamicKind: 'eval' as DynamicKind,
1369
+ });
1370
+ } else {
1371
+ ctx.calls.push({ name: ctor.text, line: nodeStartLine(node) });
1372
+ }
1163
1373
  } else if (ctor.type === 'member_expression') {
1164
1374
  const callInfo = extractCallInfo(ctor, node);
1165
1375
  if (callInfo) ctx.calls.push(callInfo);
1166
1376
  }
1167
1377
  }
1168
1378
 
1379
+ /**
1380
+ * Handle a TypeScript/JS decorator node.
1381
+ *
1382
+ * Only handles bare-identifier and bare-member-expression decorators
1383
+ * (`@Foo`, `@Foo.bar`) since decorated call expressions (`@Foo()`, `@Foo.bar()`)
1384
+ * are already visited as `call_expression` children by the recursive walker.
1385
+ */
1386
+ function handleDecorator(node: TreeSitterNode, calls: Call[]): void {
1387
+ // Decorators wrap their expression; find the first non-@ child
1388
+ for (let i = 0; i < node.childCount; i++) {
1389
+ const child = node.child(i);
1390
+ if (!child || child.type === '@') continue;
1391
+ const t = child.type;
1392
+ if (t === 'identifier') {
1393
+ // @Foo — the identifier is the decorator factory; emit as reflection call
1394
+ calls.push({
1395
+ name: child.text,
1396
+ line: nodeStartLine(node),
1397
+ dynamic: true,
1398
+ dynamicKind: 'reflection',
1399
+ });
1400
+ } else if (t === 'member_expression') {
1401
+ // @Foo.bar — emit as reflection; always mark dynamic since it's decorator dispatch
1402
+ const callInfo = extractCallInfo(child, node);
1403
+ if (callInfo) calls.push({ ...callInfo, dynamic: true, dynamicKind: 'reflection' });
1404
+ }
1405
+ // call_expression / other — handled by the recursive walker automatically
1406
+ break;
1407
+ }
1408
+ }
1409
+
1169
1410
  /** Handle a dynamic import() call expression and add to imports if static. */
1170
1411
  function handleDynamicImportCall(node: TreeSitterNode, imports: Import[]): void {
1171
1412
  const args = node.childForFieldName('arguments') || findChild(node, 'arguments');
@@ -1538,8 +1779,8 @@ function storeReturnType(
1538
1779
  const inferred = findReturnNewExprType(body);
1539
1780
  if (inferred) {
1540
1781
  const existing = returnTypeMap.get(fnName);
1541
- if (!existing || 0.85 > existing.confidence)
1542
- returnTypeMap.set(fnName, { type: inferred, confidence: 0.85 });
1782
+ if (!existing || INFERRED_RETURN_TYPE_CONFIDENCE > existing.confidence)
1783
+ returnTypeMap.set(fnName, { type: inferred, confidence: INFERRED_RETURN_TYPE_CONFIDENCE });
1543
1784
  }
1544
1785
  }
1545
1786
  }
@@ -1813,9 +2054,23 @@ function runContextCollectorWalk(rootNode: TreeSitterNode, out: ContextCollector
1813
2054
  // Qualify with the enclosing class name so the PTS key matches
1814
2055
  // callerName from findCaller (which uses def.name = 'ClassName.method').
1815
2056
  const enclosingClass = classStack.length > 0 ? classStack[classStack.length - 1] : null;
1816
- const qualifiedName = enclosingClass ? `${enclosingClass}.${nameNode.text}` : nameNode.text;
1817
- funcStack.push(qualifiedName);
1818
- pushedFunc = true;
2057
+ let rawName: string;
2058
+ if (nameNode.type === 'computed_property_name') {
2059
+ const inner = nameNode.child(1);
2060
+ if (!inner || (inner.type !== 'string' && inner.type !== 'string_fragment')) {
2061
+ // Non-string computed key — skip adding to funcStack (no resolvable name).
2062
+ rawName = '';
2063
+ } else {
2064
+ rawName = inner.text.replace(/^['"]|['"]$/g, '');
2065
+ }
2066
+ } else {
2067
+ rawName = nameNode.text;
2068
+ }
2069
+ if (rawName) {
2070
+ const qualifiedName = enclosingClass ? `${enclosingClass}.${rawName}` : rawName;
2071
+ funcStack.push(qualifiedName);
2072
+ pushedFunc = true;
2073
+ }
1819
2074
  }
1820
2075
  } else if (t === 'variable_declarator') {
1821
2076
  // `const process = (arr) => { ... }` — arrow/expression functions assigned
@@ -1866,6 +2121,8 @@ function runContextCollectorWalk(rootNode: TreeSitterNode, out: ContextCollector
1866
2121
  collectCollectionWrapBinding(node, out.fnRefBindings);
1867
2122
  } else if (t === 'required_parameter' || t === 'optional_parameter') {
1868
2123
  handleParamTypeMap(node, out.typeMap);
2124
+ } else if (t === 'public_field_definition' || t === 'field_definition') {
2125
+ handleFieldDefTypeMap(node, out.typeMap, typeMapClass);
1869
2126
  } else if (t === 'assignment_expression') {
1870
2127
  handlePropWriteTypeMap(node, out.typeMap, typeMapClass);
1871
2128
  } else if (t === 'call_expression') {
@@ -1897,7 +2154,190 @@ function runContextCollectorWalk(rootNode: TreeSitterNode, out: ContextCollector
1897
2154
  walk(rootNode, 0, null, null);
1898
2155
  }
1899
2156
 
1900
- /** Extract type info from a variable_declarator: type annotation, constructor, or factory. */
2157
+ /**
2158
+ * Record function-reference bindings from a variable_declarator's value node.
2159
+ *
2160
+ * Captures three patterns (Phase 8.3):
2161
+ * - `const fn = handler` (identifier alias)
2162
+ * - `const fn = obj.method` (member_expression alias)
2163
+ * - `const f = fn.bind(ctx)` (bind creates a bound alias)
2164
+ *
2165
+ * Must be called before any type-analysis early returns so every declarator
2166
+ * contributes to fnRefBindings regardless of whether it has a type annotation.
2167
+ */
2168
+ function collectFnRefBindings(
2169
+ lhsName: string,
2170
+ valueN: TreeSitterNode,
2171
+ fnRefBindings: FnRefBinding[],
2172
+ ): void {
2173
+ if (valueN.type === 'identifier' && !BUILTIN_GLOBALS.has(valueN.text)) {
2174
+ fnRefBindings.push({ lhs: lhsName, rhs: valueN.text });
2175
+ return;
2176
+ }
2177
+ if (valueN.type === 'member_expression') {
2178
+ const prop = valueN.childForFieldName('property');
2179
+ const obj = valueN.childForFieldName('object');
2180
+ // Guard: only static property access (property_identifier or identifier), not
2181
+ // computed subscript expressions like obj[expr] where prop.text would be the
2182
+ // full expression rather than a simple name — those can never match pts keys.
2183
+ if (
2184
+ prop &&
2185
+ (prop.type === 'property_identifier' || prop.type === 'identifier') &&
2186
+ obj?.type === 'identifier' &&
2187
+ !BUILTIN_GLOBALS.has(obj.text)
2188
+ ) {
2189
+ fnRefBindings.push({ lhs: lhsName, rhs: prop.text, rhsReceiver: obj.text });
2190
+ }
2191
+ return;
2192
+ }
2193
+ if (valueN.type === 'call_expression') {
2194
+ // `const f = fn.bind(ctx)` — bind returns a bound copy of fn; track f → fn so
2195
+ // pts(f) ⊇ pts(fn) and subsequent `f(args)` calls resolve to fn.
2196
+ // Note: only flat-identifier binds (fn.bind) are tracked here; method-receiver
2197
+ // binds like `obj.method.bind(ctx)` are not captured (boundFn must be an identifier).
2198
+ const callFn = valueN.childForFieldName('function');
2199
+ if (callFn?.type === 'member_expression') {
2200
+ const bindProp = callFn.childForFieldName('property');
2201
+ if (bindProp?.text === 'bind') {
2202
+ const boundFn = callFn.childForFieldName('object');
2203
+ if (boundFn?.type === 'identifier' && !BUILTIN_GLOBALS.has(boundFn.text)) {
2204
+ fnRefBindings.push({ lhs: lhsName, rhs: boundFn.text });
2205
+ }
2206
+ }
2207
+ }
2208
+ }
2209
+ }
2210
+
2211
+ /**
2212
+ * Handle the `call_expression` branch of variable_declarator type-map seeding.
2213
+ *
2214
+ * Processes three sub-cases in priority order:
2215
+ * 1. Object.create({ ... }) — seeds composite pts keys from the prototype object (Phase 8.3e)
2216
+ * 2. Inter-procedural return-type propagation via returnTypeMap (Phase 8.2)
2217
+ * 3. Factory method heuristic: `const x = Foo.create()` → type Foo at confidence 0.7
2218
+ */
2219
+ function handleCallExprTypeMap(
2220
+ lhsName: string,
2221
+ valueN: TreeSitterNode,
2222
+ typeMap: Map<string, TypeMapEntry>,
2223
+ returnTypeMap: Map<string, TypeMapEntry> | undefined,
2224
+ callAssignments: CallAssignment[] | undefined,
2225
+ ): void {
2226
+ const createFn = valueN.childForFieldName('function');
2227
+ // Phase 8.3e: Object.create({ f1, f2 }) — seed composite pts keys obj.f1 → f1, etc.
2228
+ if (createFn?.type === 'member_expression') {
2229
+ const createObj = createFn.childForFieldName('object');
2230
+ const createProp = createFn.childForFieldName('property');
2231
+ if (createObj?.text === 'Object' && createProp?.text === 'create') {
2232
+ const createArgs = valueN.childForFieldName('arguments') || findChild(valueN, 'arguments');
2233
+ if (createArgs) {
2234
+ let proto: TreeSitterNode | null = null;
2235
+ for (let i = 0; i < createArgs.childCount; i++) {
2236
+ const n = createArgs.child(i);
2237
+ if (n && n.type !== '(' && n.type !== ')' && n.type !== ',') {
2238
+ proto = n;
2239
+ break;
2240
+ }
2241
+ }
2242
+ if (proto?.type === 'object') {
2243
+ seedProtoProperties(lhsName, proto, typeMap);
2244
+ }
2245
+ }
2246
+ return;
2247
+ }
2248
+ }
2249
+ // Phase 8.2: inter-procedural propagation — try to resolve return type from
2250
+ // the local returnTypeMap before falling back to factory heuristics.
2251
+ if (returnTypeMap) {
2252
+ const result = resolveCallExprReturnType(valueN, typeMap, returnTypeMap, 0);
2253
+ if (result) {
2254
+ setTypeMapEntry(typeMap, lhsName, result.type, result.confidence);
2255
+ return;
2256
+ }
2257
+ }
2258
+ // Record for cross-file resolution in build-edges.ts (imported functions)
2259
+ if (callAssignments) {
2260
+ recordCallAssignment(valueN, lhsName, typeMap, callAssignments);
2261
+ }
2262
+ // Factory method heuristic: const x = Foo.create() → type Foo, confidence 0.7
2263
+ if (createFn?.type === 'member_expression') {
2264
+ const obj = createFn.childForFieldName('object');
2265
+ if (obj?.type === 'identifier') {
2266
+ const objName = obj.text;
2267
+ if (objName[0] && objName[0] !== objName[0].toLowerCase() && !BUILTIN_GLOBALS.has(objName)) {
2268
+ setTypeMapEntry(typeMap, lhsName, objName, 0.7);
2269
+ }
2270
+ }
2271
+ }
2272
+ }
2273
+
2274
+ /**
2275
+ * Seed composite pts keys from a module-level object literal assignment (Phase 8.3f).
2276
+ *
2277
+ * `const obj = { baz: () => {} }` → typeMap['obj.baz'] = 'obj.baz'
2278
+ * `const obj = { baz }` (shorthand) → typeMap['obj.baz'] = 'baz' (bare identifier target)
2279
+ * `const obj = { baz: otherFn }` → typeMap['obj.baz'] = 'otherFn' (identifier alias)
2280
+ * `const obj = { baz() {} }` (method shorthand) → typeMap['obj.baz'] = 'obj.baz'
2281
+ *
2282
+ * For function/arrow values, the value is the qualified name ('obj.baz') because
2283
+ * extractObjectLiteralFunctions registers definitions under that qualified name to avoid
2284
+ * polluting the global index with bare property names like 'init', 'run', or 'render'.
2285
+ * Enables accessor this-dispatch: when typeMap['getter:this'] = 'obj',
2286
+ * resolving this.baz() inside getter → typeMap['obj.baz'] → 'obj.baz' → lookup.byName('obj.baz').
2287
+ *
2288
+ * Scope guard: caller must ensure `node` is not inside a function body
2289
+ * (mirrors Rust handle_var_decl's find_parent_of_types check — function-scoped
2290
+ * `const localObj = { fn: ... }` must not shadow a module-level `const obj`).
2291
+ */
2292
+ function handleObjectLiteralTypeMap(
2293
+ lhsName: string,
2294
+ valueN: TreeSitterNode,
2295
+ typeMap: Map<string, TypeMapEntry>,
2296
+ ): void {
2297
+ for (let i = 0; i < valueN.childCount; i++) {
2298
+ const child = valueN.child(i);
2299
+ if (!child) continue;
2300
+ if (child.type === 'shorthand_property_identifier') {
2301
+ setTypeMapEntry(typeMap, `${lhsName}.${child.text}`, child.text, 0.85);
2302
+ } else if (child.type === 'pair') {
2303
+ const keyNode = child.childForFieldName('key');
2304
+ const valNode = child.childForFieldName('value');
2305
+ if (!keyNode || !valNode) continue;
2306
+ const keyName =
2307
+ keyNode.type === 'string' ? keyNode.text.replace(/^['"]|['"]$/g, '') : keyNode.text;
2308
+ if (!keyName) continue;
2309
+ const qualifiedKey = `${lhsName}.${keyName}`;
2310
+ if (
2311
+ valNode.type === 'arrow_function' ||
2312
+ valNode.type === 'function_expression' ||
2313
+ valNode.type === 'function'
2314
+ ) {
2315
+ // Store the qualified name so the resolver finds the qualified definition.
2316
+ setTypeMapEntry(typeMap, qualifiedKey, qualifiedKey, 0.85);
2317
+ } else if (valNode.type === 'identifier') {
2318
+ setTypeMapEntry(typeMap, qualifiedKey, valNode.text, 0.85);
2319
+ }
2320
+ } else if (child.type === 'method_definition') {
2321
+ // Method shorthand: `const obj = { baz() {} }` → typeMap['obj.baz'] = 'obj.baz'
2322
+ // extractObjectLiteralFunctions registers a definition under the qualified name;
2323
+ // seed the matching typeMap entry so the two-step accessor dispatch finds it.
2324
+ const nameNode = child.childForFieldName('name');
2325
+ if (!nameNode) continue;
2326
+ setTypeMapEntry(typeMap, `${lhsName}.${nameNode.text}`, `${lhsName}.${nameNode.text}`, 0.85);
2327
+ }
2328
+ }
2329
+ }
2330
+
2331
+ /**
2332
+ * Extract type info from a variable_declarator: type annotation, constructor, or factory.
2333
+ *
2334
+ * Orchestrates four concerns in priority order:
2335
+ * 1. fnRefBindings — always collected first (before any early return)
2336
+ * 2. new_expression — constructor wins over annotation (runtime type is authoritative)
2337
+ * 3. type_annotation — confidence 0.9 for static analysis
2338
+ * 4. call_expression / object literal — delegated to handleCallExprTypeMap /
2339
+ * handleObjectLiteralTypeMap
2340
+ */
1901
2341
  function handleVarDeclaratorTypeMap(
1902
2342
  node: TreeSitterNode,
1903
2343
  typeMap: Map<string, TypeMapEntry>,
@@ -1911,48 +2351,12 @@ function handleVarDeclaratorTypeMap(
1911
2351
  const typeAnno = findChild(node, 'type_annotation');
1912
2352
  const valueN = node.childForFieldName('value');
1913
2353
 
1914
- // Phase 8.3: record function-reference bindings before any type-analysis early returns.
1915
- // Captures `const fn = handler` (identifier) and `const fn = obj.method` (member_expression).
1916
- // Also handles `const f = fn.bind(ctx)` — bind returns a new function aliasing fn.
2354
+ // 1. fnRefBindings must run before any early return so every declarator contributes.
1917
2355
  if (fnRefBindings && valueN) {
1918
- if (valueN.type === 'identifier' && !BUILTIN_GLOBALS.has(valueN.text)) {
1919
- fnRefBindings.push({ lhs: nameN.text, rhs: valueN.text });
1920
- } else if (valueN.type === 'member_expression') {
1921
- const prop = valueN.childForFieldName('property');
1922
- const obj = valueN.childForFieldName('object');
1923
- // Guard: only static property access (property_identifier or identifier), not
1924
- // computed subscript expressions like obj[expr] where prop.text would be the
1925
- // full expression rather than a simple name — those can never match pts keys.
1926
- if (
1927
- prop &&
1928
- (prop.type === 'property_identifier' || prop.type === 'identifier') &&
1929
- obj?.type === 'identifier' &&
1930
- !BUILTIN_GLOBALS.has(obj.text)
1931
- ) {
1932
- fnRefBindings.push({ lhs: nameN.text, rhs: prop.text, rhsReceiver: obj.text });
1933
- }
1934
- } else if (valueN.type === 'call_expression') {
1935
- // `const f = fn.bind(ctx)` — bind returns a bound copy of fn; track f → fn so
1936
- // pts(f) ⊇ pts(fn) and subsequent `f(args)` calls resolve to fn.
1937
- // Note: only flat-identifier binds (fn.bind) are tracked here; method-receiver
1938
- // binds like `obj.method.bind(ctx)` are not captured (boundFn must be an identifier).
1939
- const callFn = valueN.childForFieldName('function');
1940
- if (callFn?.type === 'member_expression') {
1941
- const bindProp = callFn.childForFieldName('property');
1942
- if (bindProp?.text === 'bind') {
1943
- const boundFn = callFn.childForFieldName('object');
1944
- if (boundFn?.type === 'identifier' && !BUILTIN_GLOBALS.has(boundFn.text)) {
1945
- fnRefBindings.push({ lhs: nameN.text, rhs: boundFn.text });
1946
- }
1947
- }
1948
- }
1949
- }
2356
+ collectFnRefBindings(nameN.text, valueN, fnRefBindings);
1950
2357
  }
1951
2358
 
1952
- // Constructor on the same declaration wins over annotation: the runtime type is
1953
- // what matters for call resolution (e.g. `const x: Base = new Derived()` should
1954
- // resolve `x.render()` to `Derived.render`, not `Base.render`).
1955
- // When no constructor is present, annotation still takes precedence over factory.
2359
+ // 2. Constructor wins over annotation: `const x: Base = new Derived()` resolves to Derived.
1956
2360
  if (valueN?.type === 'new_expression') {
1957
2361
  const ctorType = extractNewExprTypeName(valueN);
1958
2362
  if (ctorType) {
@@ -1961,7 +2365,7 @@ function handleVarDeclaratorTypeMap(
1961
2365
  }
1962
2366
  }
1963
2367
 
1964
- // Type annotation: const x: Foo = … → confidence 0.9
2368
+ // 3. Type annotation confidence 0.9.
1965
2369
  if (typeAnno) {
1966
2370
  const typeName = extractSimpleTypeName(typeAnno);
1967
2371
  if (typeName) {
@@ -1973,108 +2377,15 @@ function handleVarDeclaratorTypeMap(
1973
2377
  if (!valueN) return;
1974
2378
  if (valueN.type === 'new_expression') return;
1975
2379
 
2380
+ // 4a. call_expression — Object.create / return-type propagation / factory heuristic.
1976
2381
  if (valueN.type === 'call_expression') {
1977
- // Phase 8.3e: Object.create({ f1, f2 }) — seed composite pts keys obj.f1 → f1, etc.
1978
- const createFn = valueN.childForFieldName('function');
1979
- if (createFn?.type === 'member_expression') {
1980
- const createObj = createFn.childForFieldName('object');
1981
- const createProp = createFn.childForFieldName('property');
1982
- if (createObj?.text === 'Object' && createProp?.text === 'create') {
1983
- const createArgs = valueN.childForFieldName('arguments') || findChild(valueN, 'arguments');
1984
- if (createArgs) {
1985
- let proto: TreeSitterNode | null = null;
1986
- for (let i = 0; i < createArgs.childCount; i++) {
1987
- const n = createArgs.child(i);
1988
- if (n && n.type !== '(' && n.type !== ')' && n.type !== ',') {
1989
- proto = n;
1990
- break;
1991
- }
1992
- }
1993
- if (proto?.type === 'object') {
1994
- seedProtoProperties(nameN.text, proto, typeMap);
1995
- }
1996
- }
1997
- return;
1998
- }
1999
- }
2000
- // Phase 8.2: inter-procedural propagation — try to resolve return type from
2001
- // the local returnTypeMap before falling back to factory heuristics.
2002
- if (returnTypeMap) {
2003
- const result = resolveCallExprReturnType(valueN, typeMap, returnTypeMap, 0);
2004
- if (result) {
2005
- setTypeMapEntry(typeMap, nameN.text, result.type, result.confidence);
2006
- return;
2007
- }
2008
- }
2009
- // Record for cross-file resolution in build-edges.ts (imported functions)
2010
- if (callAssignments) {
2011
- recordCallAssignment(valueN, nameN.text, typeMap, callAssignments);
2012
- }
2013
- // Factory method heuristic: const x = Foo.create() → type Foo, confidence 0.7
2014
- const fn = valueN.childForFieldName('function');
2015
- if (fn?.type === 'member_expression') {
2016
- const obj = fn.childForFieldName('object');
2017
- if (obj?.type === 'identifier') {
2018
- const objName = obj.text;
2019
- if (
2020
- objName[0] &&
2021
- objName[0] !== objName[0].toLowerCase() &&
2022
- !BUILTIN_GLOBALS.has(objName)
2023
- ) {
2024
- setTypeMapEntry(typeMap, nameN.text, objName, 0.7);
2025
- }
2026
- }
2027
- }
2382
+ handleCallExprTypeMap(nameN.text, valueN, typeMap, returnTypeMap, callAssignments);
2383
+ return;
2028
2384
  }
2029
2385
 
2030
- // Phase 8.3f: seed composite pts keys for object literal properties.
2031
- // `const obj = { baz: () => {} }` → typeMap['obj.baz'] = 'obj.baz'
2032
- // `const obj = { baz }` (shorthand) → typeMap['obj.baz'] = 'baz' (bare identifier target)
2033
- // `const obj = { baz: otherFn }` → typeMap['obj.baz'] = 'otherFn' (identifier alias)
2034
- //
2035
- // For function/arrow values, the value is the qualified name ('obj.baz') because
2036
- // extractObjectLiteralFunctions now registers definitions under that qualified name to avoid
2037
- // polluting the global index with bare property names like 'init', 'run', or 'render'.
2038
- // Enables accessor this-dispatch: when typeMap['getter:this'] = 'obj',
2039
- // resolving this.baz() inside getter → typeMap['obj.baz'] → 'obj.baz' → lookup.byName('obj.baz').
2040
- //
2041
- // Scope guard: mirrors Rust handle_var_decl's find_parent_of_types check — skip object literals
2042
- // inside function bodies so function-scoped `const localObj = { fn: ... }` never seeds
2043
- // the typeMap (which would shadow a module-level `const obj` with the same property names).
2386
+ // 4b. Object literal — seed composite pts keys for module-level const objects.
2044
2387
  if (valueN.type === 'object' && !hasFunctionScopeAncestor(node)) {
2045
- for (let i = 0; i < valueN.childCount; i++) {
2046
- const child = valueN.child(i);
2047
- if (!child) continue;
2048
- if (child.type === 'shorthand_property_identifier') {
2049
- setTypeMapEntry(typeMap, `${nameN.text}.${child.text}`, child.text, 0.85);
2050
- } else if (child.type === 'pair') {
2051
- const keyNode = child.childForFieldName('key');
2052
- const valNode = child.childForFieldName('value');
2053
- if (!keyNode || !valNode) continue;
2054
- const keyName =
2055
- keyNode.type === 'string' ? keyNode.text.replace(/^['"]|['"]$/g, '') : keyNode.text;
2056
- if (!keyName) continue;
2057
- const qualifiedKey = `${nameN.text}.${keyName}`;
2058
- if (
2059
- valNode.type === 'arrow_function' ||
2060
- valNode.type === 'function_expression' ||
2061
- valNode.type === 'function'
2062
- ) {
2063
- // Store the qualified name so the resolver finds the qualified definition.
2064
- setTypeMapEntry(typeMap, qualifiedKey, qualifiedKey, 0.85);
2065
- } else if (valNode.type === 'identifier') {
2066
- setTypeMapEntry(typeMap, qualifiedKey, valNode.text, 0.85);
2067
- }
2068
- } else if (child.type === 'method_definition') {
2069
- // Method shorthand: `const obj = { baz() {} }` → typeMap['obj.baz'] = 'obj.baz'
2070
- // extractObjectLiteralFunctions registers a definition under the qualified name;
2071
- // seed the matching typeMap entry so the two-step accessor dispatch finds it.
2072
- const nameNode = child.childForFieldName('name');
2073
- if (!nameNode) continue;
2074
- const qualifiedKey = `${nameN.text}.${nameNode.text}`;
2075
- setTypeMapEntry(typeMap, qualifiedKey, qualifiedKey, 0.85);
2076
- }
2077
- }
2388
+ handleObjectLiteralTypeMap(nameN.text, valueN, typeMap);
2078
2389
  }
2079
2390
  }
2080
2391
 
@@ -2090,6 +2401,55 @@ function handleParamTypeMap(node: TreeSitterNode, typeMap: Map<string, TypeMapEn
2090
2401
  }
2091
2402
  }
2092
2403
 
2404
+ /**
2405
+ * Extract type info from a class field declaration: `private repo: Repository<User>`.
2406
+ *
2407
+ * Seeds a class-scoped key `ClassName.field` (confidence 0.9) as the primary entry
2408
+ * so that two classes with identically-named fields don't overwrite each other's
2409
+ * typeMap entry (issue #1458). The resolver's `CallerClass.X` fallback (call-resolver.ts
2410
+ * line 110) looks up exactly this key.
2411
+ *
2412
+ * Bare `field` and `this.field` keys are kept at lower confidence (0.6) as fallbacks
2413
+ * for single-class files where the resolver may not have a callerClass context.
2414
+ *
2415
+ * Mirrors the field_definition branch of match_js_type_map in
2416
+ * crates/codegraph-core/src/extractors/javascript.rs.
2417
+ */
2418
+ function handleFieldDefTypeMap(
2419
+ node: TreeSitterNode,
2420
+ typeMap: Map<string, TypeMapEntry>,
2421
+ currentClass: string | null,
2422
+ ): void {
2423
+ const nameNode =
2424
+ node.childForFieldName('name') ||
2425
+ node.childForFieldName('property') ||
2426
+ findChild(node, 'property_identifier');
2427
+ if (!nameNode) return;
2428
+ const kind = nameNode.type;
2429
+ if (
2430
+ kind !== 'property_identifier' &&
2431
+ kind !== 'identifier' &&
2432
+ kind !== 'private_property_identifier'
2433
+ )
2434
+ return;
2435
+ const typeAnno = findChild(node, 'type_annotation');
2436
+ if (!typeAnno) return;
2437
+ const typeName = extractSimpleTypeName(typeAnno);
2438
+ if (!typeName) return;
2439
+ if (currentClass) {
2440
+ // Primary: class-scoped key prevents cross-class collision (issue #1458).
2441
+ setTypeMapEntry(typeMap, `${currentClass}.${nameNode.text}`, typeName, 0.9);
2442
+ // Fallback: bare keys at lower confidence for single-class files or when
2443
+ // the resolver does not have a callerClass in scope.
2444
+ setTypeMapEntry(typeMap, nameNode.text, typeName, 0.6);
2445
+ setTypeMapEntry(typeMap, `this.${nameNode.text}`, typeName, 0.6);
2446
+ } else {
2447
+ // No enclosing class declaration (e.g. class expression) — use bare keys only.
2448
+ setTypeMapEntry(typeMap, nameNode.text, typeName, 0.9);
2449
+ setTypeMapEntry(typeMap, `this.${nameNode.text}`, typeName, 0.9);
2450
+ }
2451
+ }
2452
+
2093
2453
  /**
2094
2454
  * Phase 8.3d: seed the pts map from object property writes.
2095
2455
  *
@@ -2618,6 +2978,28 @@ function extractReceiverName(objNode: TreeSitterNode | null): string | undefined
2618
2978
  function extractCallInfo(fn: TreeSitterNode, callNode: TreeSitterNode): Call | null {
2619
2979
  const fnType = fn.type;
2620
2980
  if (fnType === 'identifier') {
2981
+ if (fn.text === 'eval') {
2982
+ // eval(code) — dynamic code execution; capture first arg if it's a string literal
2983
+ const args = callNode.childForFieldName('arguments') || findChild(callNode, 'arguments');
2984
+ let keyExpr: string | undefined;
2985
+ if (args) {
2986
+ for (let i = 0; i < args.childCount; i++) {
2987
+ const child = args.child(i);
2988
+ if (!child) continue;
2989
+ const t = child.type;
2990
+ if (t === '(' || t === ')' || t === ',') continue;
2991
+ if (t === 'string' || t === 'template_string') keyExpr = child.text;
2992
+ break;
2993
+ }
2994
+ }
2995
+ return {
2996
+ name: '<dynamic:eval>',
2997
+ line: nodeStartLine(callNode),
2998
+ dynamic: true,
2999
+ dynamicKind: 'eval',
3000
+ keyExpr,
3001
+ };
3002
+ }
2621
3003
  return { name: fn.text, line: nodeStartLine(callNode) };
2622
3004
  }
2623
3005
  if (fnType === 'member_expression') {
@@ -2629,6 +3011,45 @@ function extractCallInfo(fn: TreeSitterNode, callNode: TreeSitterNode): Call | n
2629
3011
  return null;
2630
3012
  }
2631
3013
 
3014
+ /** Return the first non-punctuation argument node from a call_expression. */
3015
+ function getFirstCallArg(callNode: TreeSitterNode): TreeSitterNode | null {
3016
+ const args = callNode.childForFieldName('arguments') || findChild(callNode, 'arguments');
3017
+ if (!args) return null;
3018
+ for (let i = 0; i < args.childCount; i++) {
3019
+ const child = args.child(i);
3020
+ if (!child) continue;
3021
+ const t = child.type;
3022
+ if (t === '(' || t === ')' || t === ',') continue;
3023
+ return child;
3024
+ }
3025
+ return null;
3026
+ }
3027
+
3028
+ /** Extract the logical callee from a Reflect.apply/call/construct first-arg. */
3029
+ function extractReflectCalleeFromArg(firstArg: TreeSitterNode | null, callLine: number): Call {
3030
+ if (firstArg?.type === 'identifier') {
3031
+ return { name: firstArg.text, line: callLine, dynamic: true, dynamicKind: 'reflection' };
3032
+ }
3033
+ if (firstArg?.type === 'member_expression') {
3034
+ const innerProp = firstArg.childForFieldName('property');
3035
+ if (innerProp?.type === 'identifier') {
3036
+ return {
3037
+ name: innerProp.text,
3038
+ line: callLine,
3039
+ dynamic: true,
3040
+ dynamicKind: 'reflection',
3041
+ receiver: extractReceiverName(firstArg.childForFieldName('object')),
3042
+ };
3043
+ }
3044
+ }
3045
+ return {
3046
+ name: '<dynamic:unresolved>',
3047
+ line: callLine,
3048
+ dynamic: true,
3049
+ dynamicKind: 'unresolved-dynamic',
3050
+ };
3051
+ }
3052
+
2632
3053
  /** Extract call info from a member_expression function node (obj.method()). */
2633
3054
  function extractMemberExprCallInfo(fn: TreeSitterNode, callNode: TreeSitterNode): Call | null {
2634
3055
  const obj = fn.childForFieldName('object');
@@ -2637,23 +3058,101 @@ function extractMemberExprCallInfo(fn: TreeSitterNode, callNode: TreeSitterNode)
2637
3058
 
2638
3059
  const callLine = nodeStartLine(callNode);
2639
3060
  const propText = prop.text;
3061
+ const isReflect = obj?.type === 'identifier' && obj.text === 'Reflect';
2640
3062
 
2641
- // .call()/.apply()/.bind()dynamic invocation
3063
+ // Reflect.apply(fn, thisArg, args) — extract the first arg as callee
3064
+ // Note: Reflect.call does not exist in the ECMAScript spec (only Reflect.apply, construct, get, etc.)
3065
+ if (isReflect && propText === 'apply') {
3066
+ return extractReflectCalleeFromArg(getFirstCallArg(callNode), callLine);
3067
+ }
3068
+
3069
+ // Reflect.construct(Target, args) — extract the constructor as the callee
3070
+ if (isReflect && propText === 'construct') {
3071
+ return extractReflectCalleeFromArg(getFirstCallArg(callNode), callLine);
3072
+ }
3073
+
3074
+ // Reflect.get(target, prop) — property access via reflection
3075
+ if (isReflect && propText === 'get') {
3076
+ const args = callNode.childForFieldName('arguments') || findChild(callNode, 'arguments');
3077
+ if (args) {
3078
+ let argIdx = 0;
3079
+ let firstArg: TreeSitterNode | null = null;
3080
+ let secondArg: TreeSitterNode | null = null;
3081
+ for (let i = 0; i < args.childCount; i++) {
3082
+ const child = args.child(i);
3083
+ if (!child) continue;
3084
+ const t = child.type;
3085
+ if (t === '(' || t === ')' || t === ',') continue;
3086
+ if (argIdx === 0) firstArg = child;
3087
+ else if (argIdx === 1) secondArg = child;
3088
+ argIdx++;
3089
+ }
3090
+ if (secondArg) {
3091
+ const receiver = firstArg ? extractReceiverName(firstArg) : undefined;
3092
+ const st = secondArg.type;
3093
+ if (st === 'string' || st === 'string_fragment') {
3094
+ const propName = secondArg.text.replace(/['"]/g, '');
3095
+ if (propName) {
3096
+ return {
3097
+ name: propName,
3098
+ line: callLine,
3099
+ dynamic: true,
3100
+ dynamicKind: 'computed-literal',
3101
+ keyExpr: secondArg.text,
3102
+ receiver,
3103
+ };
3104
+ }
3105
+ }
3106
+ if (st === 'identifier') {
3107
+ return {
3108
+ name: '<dynamic:computed-key>',
3109
+ line: callLine,
3110
+ dynamic: true,
3111
+ dynamicKind: 'computed-key',
3112
+ keyExpr: secondArg.text,
3113
+ receiver,
3114
+ };
3115
+ }
3116
+ }
3117
+ }
3118
+ return {
3119
+ name: '<dynamic:unresolved>',
3120
+ line: callLine,
3121
+ dynamic: true,
3122
+ dynamicKind: 'unresolved-dynamic',
3123
+ };
3124
+ }
3125
+
3126
+ // .call()/.apply()/.bind() — this-rebinding; the wrapped function is the real callee.
3127
+ // When the object is a plain identifier (e.g. `f.call({})`), the target is statically
3128
+ // known so we emit a static call (no dynamic flag). This keeps parity with the native
3129
+ // Rust engine, which also resolves these as dyn=0, and prevents the dynZeroEdgeRows
3130
+ // upgrade path in emitDirectCallEdgesForCall from wrongly converting a dyn=0 edge
3131
+ // (emitted by a prior direct `f()` call) to dyn=1.
3132
+ // When the object is a member_expression (e.g. `obj.method.call({})`), we still mark
3133
+ // it dynamic/reflection because the inner callee requires a second resolution hop.
2642
3134
  if (propText === 'call' || propText === 'apply' || propText === 'bind') {
2643
- if (obj && obj.type === 'identifier') return { name: obj.text, line: callLine, dynamic: true };
3135
+ if (obj && obj.type === 'identifier') return { name: obj.text, line: callLine };
2644
3136
  if (obj && obj.type === 'member_expression') {
2645
3137
  const innerProp = obj.childForFieldName('property');
2646
- if (innerProp) return { name: innerProp.text, line: callLine, dynamic: true };
3138
+ if (innerProp)
3139
+ return { name: innerProp.text, line: callLine, dynamic: true, dynamicKind: 'reflection' };
2647
3140
  }
2648
3141
  }
2649
3142
 
2650
- // Computed property: obj["method"]()
3143
+ // Computed string property: obj["method"]() — target is a literal; resolvable
2651
3144
  const propType = prop.type;
2652
3145
  if (propType === 'string' || propType === 'string_fragment') {
2653
3146
  const methodName = propText.replace(/['"]/g, '');
2654
3147
  if (methodName) {
2655
3148
  const receiver = extractReceiverName(obj);
2656
- return { name: methodName, line: callLine, dynamic: true, receiver };
3149
+ return {
3150
+ name: methodName,
3151
+ line: callLine,
3152
+ dynamic: true,
3153
+ dynamicKind: 'computed-literal',
3154
+ receiver,
3155
+ };
2657
3156
  }
2658
3157
  }
2659
3158
 
@@ -2661,7 +3160,7 @@ function extractMemberExprCallInfo(fn: TreeSitterNode, callNode: TreeSitterNode)
2661
3160
  return { name: propText, line: callLine, receiver };
2662
3161
  }
2663
3162
 
2664
- /** Extract call info from a subscript_expression function node (obj["method"]()). */
3163
+ /** Extract call info from a subscript_expression function node (obj[key]()). */
2665
3164
  function extractSubscriptCallInfo(fn: TreeSitterNode, callNode: TreeSitterNode): Call | null {
2666
3165
  const obj = fn.childForFieldName('object');
2667
3166
  const index = fn.childForFieldName('index');
@@ -2676,11 +3175,32 @@ function extractSubscriptCallInfo(fn: TreeSitterNode, callNode: TreeSitterNode):
2676
3175
  name: methodName,
2677
3176
  line: nodeStartLine(callNode),
2678
3177
  dynamic: true,
3178
+ dynamicKind: 'computed-literal',
2679
3179
  receiver,
2680
3180
  };
2681
3181
  }
2682
3182
  }
2683
- return null;
3183
+
3184
+ // obj[variable]() — key is a variable; may be resolvable via pts (RES-1), else flagged
3185
+ if (indexType === 'identifier') {
3186
+ const receiver = extractReceiverName(obj);
3187
+ return {
3188
+ name: '<dynamic:computed-key>',
3189
+ line: nodeStartLine(callNode),
3190
+ dynamic: true,
3191
+ dynamicKind: 'computed-key',
3192
+ keyExpr: index.text,
3193
+ receiver,
3194
+ };
3195
+ }
3196
+
3197
+ // Any other index expression (binary, call, template with ${}…) — not statically resolvable
3198
+ return {
3199
+ name: '<dynamic:unresolved>',
3200
+ line: nodeStartLine(callNode),
3201
+ dynamic: true,
3202
+ dynamicKind: 'unresolved-dynamic',
3203
+ };
2684
3204
  }
2685
3205
 
2686
3206
  /**
@@ -2999,6 +3519,10 @@ function runCollectorWalk(rootNode: TreeSitterNode, targets: CollectorWalkTarget
2999
3519
  if (name) targets.newExpressions.push(name);
3000
3520
  break;
3001
3521
  }
3522
+ case 'decorator': {
3523
+ if (targets.calls) handleDecorator(node, targets.calls);
3524
+ break;
3525
+ }
3002
3526
  case 'field_definition':
3003
3527
  case 'public_field_definition':
3004
3528
  if (targets.classMemberDefs) handleFieldDef(node, targets.classMemberDefs);
@@ -3308,11 +3832,13 @@ function emitPrototypeMethod(
3308
3832
  ): void {
3309
3833
  const fullName = `${className}.${methodName}`;
3310
3834
  if (rhs.type === 'function_expression' || rhs.type === 'arrow_function') {
3835
+ const params = extractParameters(rhs);
3311
3836
  definitions.push({
3312
3837
  name: fullName,
3313
3838
  kind: 'method',
3314
3839
  line: nodeStartLine(rhs),
3315
3840
  endLine: nodeEndLine(rhs),
3841
+ children: params.length > 0 ? params : undefined,
3316
3842
  });
3317
3843
  } else if (rhs.type === 'identifier' && !BUILTIN_GLOBALS.has(rhs.text)) {
3318
3844
  // Prototype alias: `A.prototype.t = f` → typeMap['A.t'] = { type: 'f' }