@selvakumaresra/specship 0.1.3 → 0.4.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 (718) hide show
  1. package/README.md +2 -2
  2. package/commands/ss-design-implement.md +84 -0
  3. package/commands/ss-design-loop.md +125 -0
  4. package/commands/{cg-drifted.md → ss-drifted.md} +2 -2
  5. package/commands/{cg-fix.md → ss-fix.md} +1 -1
  6. package/commands/{cg-implement.md → ss-implement.md} +1 -1
  7. package/commands/ss-spec-author.md +43 -0
  8. package/commands/ss-spec-review.md +48 -0
  9. package/dist/bin/node-version-check.d.ts +37 -0
  10. package/dist/bin/node-version-check.d.ts.map +1 -0
  11. package/dist/bin/node-version-check.js +79 -0
  12. package/dist/bin/node-version-check.js.map +1 -0
  13. package/dist/bin/specship.d.ts +25 -0
  14. package/dist/bin/specship.d.ts.map +1 -0
  15. package/dist/bin/specship.js +2085 -0
  16. package/dist/bin/specship.js.map +1 -0
  17. package/dist/bin/uninstall.d.ts +13 -0
  18. package/dist/bin/uninstall.d.ts.map +1 -0
  19. package/dist/bin/uninstall.js +35 -0
  20. package/dist/bin/uninstall.js.map +1 -0
  21. package/dist/context/formatter.d.ts +30 -0
  22. package/dist/context/formatter.d.ts.map +1 -0
  23. package/dist/context/formatter.js +263 -0
  24. package/dist/context/formatter.js.map +1 -0
  25. package/dist/context/index.d.ts +119 -0
  26. package/dist/context/index.d.ts.map +1 -0
  27. package/dist/context/index.js +1289 -0
  28. package/dist/context/index.js.map +1 -0
  29. package/dist/context/markers.d.ts +19 -0
  30. package/dist/context/markers.d.ts.map +1 -0
  31. package/dist/context/markers.js +22 -0
  32. package/dist/context/markers.js.map +1 -0
  33. package/dist/db/index.d.ts +103 -0
  34. package/dist/db/index.d.ts.map +1 -0
  35. package/dist/db/index.js +279 -0
  36. package/dist/db/index.js.map +1 -0
  37. package/dist/db/migrations.d.ts +44 -0
  38. package/dist/db/migrations.d.ts.map +1 -0
  39. package/dist/db/migrations.js +462 -0
  40. package/dist/db/migrations.js.map +1 -0
  41. package/dist/db/queries.d.ts +357 -0
  42. package/dist/db/queries.d.ts.map +1 -0
  43. package/dist/db/queries.js +1504 -0
  44. package/dist/db/queries.js.map +1 -0
  45. package/dist/db/schema.sql +419 -0
  46. package/dist/db/spec-queries.d.ts +101 -0
  47. package/dist/db/spec-queries.d.ts.map +1 -0
  48. package/dist/db/spec-queries.js +675 -0
  49. package/dist/db/spec-queries.js.map +1 -0
  50. package/dist/db/sqlite-adapter.d.ts +65 -0
  51. package/dist/db/sqlite-adapter.d.ts.map +1 -0
  52. package/dist/db/sqlite-adapter.js +214 -0
  53. package/dist/db/sqlite-adapter.js.map +1 -0
  54. package/dist/designer/artifact-store.js +54 -0
  55. package/dist/designer/browser.js +141 -0
  56. package/dist/designer/cdp-ensure.js +60 -0
  57. package/dist/designer/cdp-env.js +18 -0
  58. package/dist/designer/cdp-trace.js +599 -0
  59. package/dist/designer/cross-platform.js +74 -0
  60. package/dist/designer/designer-controller.js +1413 -0
  61. package/dist/designer/file-panel.js +39 -0
  62. package/dist/designer/interstitials.js +97 -0
  63. package/dist/designer/oopif-reader.js +176 -0
  64. package/dist/designer/package-meta.js +18 -0
  65. package/dist/designer/preview-host.js +50 -0
  66. package/dist/designer/repo-root.js +31 -0
  67. package/dist/designer/run-state.js +353 -0
  68. package/dist/designer/session-store.js +59 -0
  69. package/dist/designer/ui-anchors.js +651 -0
  70. package/dist/directory.d.ts +67 -0
  71. package/dist/directory.d.ts.map +1 -0
  72. package/dist/directory.js +267 -0
  73. package/dist/directory.js.map +1 -0
  74. package/dist/errors.d.ts +136 -0
  75. package/dist/errors.d.ts.map +1 -0
  76. package/dist/errors.js +219 -0
  77. package/dist/errors.js.map +1 -0
  78. package/dist/extraction/dfm-extractor.d.ts +31 -0
  79. package/dist/extraction/dfm-extractor.d.ts.map +1 -0
  80. package/dist/extraction/dfm-extractor.js +151 -0
  81. package/dist/extraction/dfm-extractor.js.map +1 -0
  82. package/dist/extraction/generated-detection.d.ts +30 -0
  83. package/dist/extraction/generated-detection.d.ts.map +1 -0
  84. package/dist/extraction/generated-detection.js +80 -0
  85. package/dist/extraction/generated-detection.js.map +1 -0
  86. package/dist/extraction/grammars.d.ts +100 -0
  87. package/dist/extraction/grammars.d.ts.map +1 -0
  88. package/dist/extraction/grammars.js +426 -0
  89. package/dist/extraction/grammars.js.map +1 -0
  90. package/dist/extraction/index.d.ts +138 -0
  91. package/dist/extraction/index.d.ts.map +1 -0
  92. package/dist/extraction/index.js +1394 -0
  93. package/dist/extraction/index.js.map +1 -0
  94. package/dist/extraction/languages/c-cpp.d.ts +4 -0
  95. package/dist/extraction/languages/c-cpp.d.ts.map +1 -0
  96. package/dist/extraction/languages/c-cpp.js +171 -0
  97. package/dist/extraction/languages/c-cpp.js.map +1 -0
  98. package/dist/extraction/languages/csharp.d.ts +3 -0
  99. package/dist/extraction/languages/csharp.d.ts.map +1 -0
  100. package/dist/extraction/languages/csharp.js +73 -0
  101. package/dist/extraction/languages/csharp.js.map +1 -0
  102. package/dist/extraction/languages/dart.d.ts +3 -0
  103. package/dist/extraction/languages/dart.d.ts.map +1 -0
  104. package/dist/extraction/languages/dart.js +192 -0
  105. package/dist/extraction/languages/dart.js.map +1 -0
  106. package/dist/extraction/languages/go.d.ts +3 -0
  107. package/dist/extraction/languages/go.d.ts.map +1 -0
  108. package/dist/extraction/languages/go.js +74 -0
  109. package/dist/extraction/languages/go.js.map +1 -0
  110. package/dist/extraction/languages/index.d.ts +10 -0
  111. package/dist/extraction/languages/index.d.ts.map +1 -0
  112. package/dist/extraction/languages/index.js +51 -0
  113. package/dist/extraction/languages/index.js.map +1 -0
  114. package/dist/extraction/languages/java.d.ts +3 -0
  115. package/dist/extraction/languages/java.d.ts.map +1 -0
  116. package/dist/extraction/languages/java.js +70 -0
  117. package/dist/extraction/languages/java.js.map +1 -0
  118. package/dist/extraction/languages/javascript.d.ts +3 -0
  119. package/dist/extraction/languages/javascript.d.ts.map +1 -0
  120. package/dist/extraction/languages/javascript.js +90 -0
  121. package/dist/extraction/languages/javascript.js.map +1 -0
  122. package/dist/extraction/languages/kotlin.d.ts +3 -0
  123. package/dist/extraction/languages/kotlin.d.ts.map +1 -0
  124. package/dist/extraction/languages/kotlin.js +259 -0
  125. package/dist/extraction/languages/kotlin.js.map +1 -0
  126. package/dist/extraction/languages/lua.d.ts +3 -0
  127. package/dist/extraction/languages/lua.d.ts.map +1 -0
  128. package/dist/extraction/languages/lua.js +150 -0
  129. package/dist/extraction/languages/lua.js.map +1 -0
  130. package/dist/extraction/languages/luau.d.ts +3 -0
  131. package/dist/extraction/languages/luau.d.ts.map +1 -0
  132. package/dist/extraction/languages/luau.js +37 -0
  133. package/dist/extraction/languages/luau.js.map +1 -0
  134. package/dist/extraction/languages/objc.d.ts +3 -0
  135. package/dist/extraction/languages/objc.d.ts.map +1 -0
  136. package/dist/extraction/languages/objc.js +133 -0
  137. package/dist/extraction/languages/objc.js.map +1 -0
  138. package/dist/extraction/languages/pascal.d.ts +3 -0
  139. package/dist/extraction/languages/pascal.d.ts.map +1 -0
  140. package/dist/extraction/languages/pascal.js +66 -0
  141. package/dist/extraction/languages/pascal.js.map +1 -0
  142. package/dist/extraction/languages/php.d.ts +3 -0
  143. package/dist/extraction/languages/php.d.ts.map +1 -0
  144. package/dist/extraction/languages/php.js +107 -0
  145. package/dist/extraction/languages/php.js.map +1 -0
  146. package/dist/extraction/languages/python.d.ts +3 -0
  147. package/dist/extraction/languages/python.d.ts.map +1 -0
  148. package/dist/extraction/languages/python.js +56 -0
  149. package/dist/extraction/languages/python.js.map +1 -0
  150. package/dist/extraction/languages/ruby.d.ts +3 -0
  151. package/dist/extraction/languages/ruby.d.ts.map +1 -0
  152. package/dist/extraction/languages/ruby.js +114 -0
  153. package/dist/extraction/languages/ruby.js.map +1 -0
  154. package/dist/extraction/languages/rust.d.ts +3 -0
  155. package/dist/extraction/languages/rust.d.ts.map +1 -0
  156. package/dist/extraction/languages/rust.js +109 -0
  157. package/dist/extraction/languages/rust.js.map +1 -0
  158. package/dist/extraction/languages/scala.d.ts +3 -0
  159. package/dist/extraction/languages/scala.d.ts.map +1 -0
  160. package/dist/extraction/languages/scala.js +139 -0
  161. package/dist/extraction/languages/scala.js.map +1 -0
  162. package/dist/extraction/languages/swift.d.ts +3 -0
  163. package/dist/extraction/languages/swift.d.ts.map +1 -0
  164. package/dist/extraction/languages/swift.js +91 -0
  165. package/dist/extraction/languages/swift.js.map +1 -0
  166. package/dist/extraction/languages/typescript.d.ts +3 -0
  167. package/dist/extraction/languages/typescript.d.ts.map +1 -0
  168. package/dist/extraction/languages/typescript.js +129 -0
  169. package/dist/extraction/languages/typescript.js.map +1 -0
  170. package/dist/extraction/liquid-extractor.d.ts +52 -0
  171. package/dist/extraction/liquid-extractor.d.ts.map +1 -0
  172. package/dist/extraction/liquid-extractor.js +313 -0
  173. package/dist/extraction/liquid-extractor.js.map +1 -0
  174. package/dist/extraction/mybatis-extractor.d.ts +48 -0
  175. package/dist/extraction/mybatis-extractor.d.ts.map +1 -0
  176. package/dist/extraction/mybatis-extractor.js +198 -0
  177. package/dist/extraction/mybatis-extractor.js.map +1 -0
  178. package/dist/extraction/parse-worker.d.ts +8 -0
  179. package/dist/extraction/parse-worker.d.ts.map +1 -0
  180. package/dist/extraction/parse-worker.js +94 -0
  181. package/dist/extraction/parse-worker.js.map +1 -0
  182. package/dist/extraction/specs/markdown-spec-extractor.d.ts +59 -0
  183. package/dist/extraction/specs/markdown-spec-extractor.d.ts.map +1 -0
  184. package/dist/extraction/specs/markdown-spec-extractor.js +327 -0
  185. package/dist/extraction/specs/markdown-spec-extractor.js.map +1 -0
  186. package/dist/extraction/specs/types.d.ts +39 -0
  187. package/dist/extraction/specs/types.d.ts.map +1 -0
  188. package/dist/extraction/specs/types.js +8 -0
  189. package/dist/extraction/specs/types.js.map +1 -0
  190. package/dist/extraction/svelte-extractor.d.ts +56 -0
  191. package/dist/extraction/svelte-extractor.d.ts.map +1 -0
  192. package/dist/extraction/svelte-extractor.js +272 -0
  193. package/dist/extraction/svelte-extractor.js.map +1 -0
  194. package/dist/extraction/tree-sitter-helpers.d.ts +28 -0
  195. package/dist/extraction/tree-sitter-helpers.d.ts.map +1 -0
  196. package/dist/extraction/tree-sitter-helpers.js +103 -0
  197. package/dist/extraction/tree-sitter-helpers.js.map +1 -0
  198. package/dist/extraction/tree-sitter-types.d.ts +193 -0
  199. package/dist/extraction/tree-sitter-types.d.ts.map +1 -0
  200. package/dist/extraction/tree-sitter-types.js +10 -0
  201. package/dist/extraction/tree-sitter-types.js.map +1 -0
  202. package/dist/extraction/tree-sitter.d.ts +317 -0
  203. package/dist/extraction/tree-sitter.d.ts.map +1 -0
  204. package/dist/extraction/tree-sitter.js +3092 -0
  205. package/dist/extraction/tree-sitter.js.map +1 -0
  206. package/dist/extraction/vue-extractor.d.ts +51 -0
  207. package/dist/extraction/vue-extractor.d.ts.map +1 -0
  208. package/dist/extraction/vue-extractor.js +251 -0
  209. package/dist/extraction/vue-extractor.js.map +1 -0
  210. package/dist/extraction/wasm/tree-sitter-lua.wasm +0 -0
  211. package/dist/extraction/wasm/tree-sitter-luau.wasm +0 -0
  212. package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  213. package/dist/extraction/wasm/tree-sitter-scala.wasm +0 -0
  214. package/dist/extraction/wasm-runtime-flags.d.ts +38 -0
  215. package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -0
  216. package/dist/extraction/wasm-runtime-flags.js +106 -0
  217. package/dist/extraction/wasm-runtime-flags.js.map +1 -0
  218. package/dist/graph/index.d.ts +8 -0
  219. package/dist/graph/index.d.ts.map +1 -0
  220. package/dist/graph/index.js +13 -0
  221. package/dist/graph/index.js.map +1 -0
  222. package/dist/graph/queries.d.ts +106 -0
  223. package/dist/graph/queries.d.ts.map +1 -0
  224. package/dist/graph/queries.js +366 -0
  225. package/dist/graph/queries.js.map +1 -0
  226. package/dist/graph/traversal.d.ts +127 -0
  227. package/dist/graph/traversal.d.ts.map +1 -0
  228. package/dist/graph/traversal.js +531 -0
  229. package/dist/graph/traversal.js.map +1 -0
  230. package/dist/index.d.ts +551 -0
  231. package/dist/index.d.ts.map +1 -0
  232. package/dist/index.js +1165 -0
  233. package/dist/index.js.map +1 -0
  234. package/dist/installer/config-writer.d.ts +28 -0
  235. package/dist/installer/config-writer.d.ts.map +1 -0
  236. package/dist/installer/config-writer.js +91 -0
  237. package/dist/installer/config-writer.js.map +1 -0
  238. package/dist/installer/index.d.ts +92 -0
  239. package/dist/installer/index.d.ts.map +1 -0
  240. package/dist/installer/index.js +416 -0
  241. package/dist/installer/index.js.map +1 -0
  242. package/dist/installer/instructions-template.d.ts +35 -0
  243. package/dist/installer/instructions-template.d.ts.map +1 -0
  244. package/dist/installer/instructions-template.js +51 -0
  245. package/dist/installer/instructions-template.js.map +1 -0
  246. package/dist/installer/targets/claude.d.ts +117 -0
  247. package/dist/installer/targets/claude.d.ts.map +1 -0
  248. package/dist/installer/targets/claude.js +736 -0
  249. package/dist/installer/targets/claude.js.map +1 -0
  250. package/dist/installer/targets/registry.d.ts +19 -0
  251. package/dist/installer/targets/registry.d.ts.map +1 -0
  252. package/dist/installer/targets/registry.js +31 -0
  253. package/dist/installer/targets/registry.js.map +1 -0
  254. package/dist/installer/targets/shared.d.ts +76 -0
  255. package/dist/installer/targets/shared.d.ts.map +1 -0
  256. package/dist/installer/targets/shared.js +256 -0
  257. package/dist/installer/targets/shared.js.map +1 -0
  258. package/dist/installer/targets/types.d.ts +84 -0
  259. package/dist/installer/targets/types.d.ts.map +1 -0
  260. package/dist/installer/targets/types.js +12 -0
  261. package/dist/installer/targets/types.js.map +1 -0
  262. package/dist/isolation/worktree.d.ts +65 -0
  263. package/dist/isolation/worktree.d.ts.map +1 -0
  264. package/dist/isolation/worktree.js +231 -0
  265. package/dist/isolation/worktree.js.map +1 -0
  266. package/dist/mcp/daemon-paths.d.ts +46 -0
  267. package/dist/mcp/daemon-paths.d.ts.map +1 -0
  268. package/dist/mcp/daemon-paths.js +125 -0
  269. package/dist/mcp/daemon-paths.js.map +1 -0
  270. package/dist/mcp/daemon.d.ts +161 -0
  271. package/dist/mcp/daemon.d.ts.map +1 -0
  272. package/dist/mcp/daemon.js +403 -0
  273. package/dist/mcp/daemon.js.map +1 -0
  274. package/dist/mcp/designer-tools.d.ts +33 -0
  275. package/dist/mcp/designer-tools.d.ts.map +1 -0
  276. package/dist/mcp/designer-tools.js +313 -0
  277. package/dist/mcp/designer-tools.js.map +1 -0
  278. package/dist/mcp/engine.d.ts +105 -0
  279. package/dist/mcp/engine.d.ts.map +1 -0
  280. package/dist/mcp/engine.js +270 -0
  281. package/dist/mcp/engine.js.map +1 -0
  282. package/dist/mcp/index.d.ts +112 -0
  283. package/dist/mcp/index.d.ts.map +1 -0
  284. package/dist/mcp/index.js +477 -0
  285. package/dist/mcp/index.js.map +1 -0
  286. package/dist/mcp/proxy.d.ts +81 -0
  287. package/dist/mcp/proxy.d.ts.map +1 -0
  288. package/dist/mcp/proxy.js +510 -0
  289. package/dist/mcp/proxy.js.map +1 -0
  290. package/dist/mcp/server-instructions.d.ts +18 -0
  291. package/dist/mcp/server-instructions.d.ts.map +1 -0
  292. package/dist/mcp/server-instructions.js +77 -0
  293. package/dist/mcp/server-instructions.js.map +1 -0
  294. package/dist/mcp/session.d.ts +77 -0
  295. package/dist/mcp/session.d.ts.map +1 -0
  296. package/dist/mcp/session.js +294 -0
  297. package/dist/mcp/session.js.map +1 -0
  298. package/dist/mcp/spec-tools.d.ts +39 -0
  299. package/dist/mcp/spec-tools.d.ts.map +1 -0
  300. package/dist/mcp/spec-tools.js +326 -0
  301. package/dist/mcp/spec-tools.js.map +1 -0
  302. package/dist/mcp/tools.d.ts +404 -0
  303. package/dist/mcp/tools.d.ts.map +1 -0
  304. package/dist/mcp/tools.js +3087 -0
  305. package/dist/mcp/tools.js.map +1 -0
  306. package/dist/mcp/transport.d.ts +188 -0
  307. package/dist/mcp/transport.d.ts.map +1 -0
  308. package/dist/mcp/transport.js +343 -0
  309. package/dist/mcp/transport.js.map +1 -0
  310. package/dist/mcp/version.d.ts +19 -0
  311. package/dist/mcp/version.d.ts.map +1 -0
  312. package/dist/mcp/version.js +71 -0
  313. package/dist/mcp/version.js.map +1 -0
  314. package/dist/resolution/callback-synthesizer.d.ts +10 -0
  315. package/dist/resolution/callback-synthesizer.d.ts.map +1 -0
  316. package/dist/resolution/callback-synthesizer.js +1300 -0
  317. package/dist/resolution/callback-synthesizer.js.map +1 -0
  318. package/dist/resolution/frameworks/cargo-workspace.d.ts +18 -0
  319. package/dist/resolution/frameworks/cargo-workspace.d.ts.map +1 -0
  320. package/dist/resolution/frameworks/cargo-workspace.js +225 -0
  321. package/dist/resolution/frameworks/cargo-workspace.js.map +1 -0
  322. package/dist/resolution/frameworks/csharp.d.ts +8 -0
  323. package/dist/resolution/frameworks/csharp.d.ts.map +1 -0
  324. package/dist/resolution/frameworks/csharp.js +241 -0
  325. package/dist/resolution/frameworks/csharp.js.map +1 -0
  326. package/dist/resolution/frameworks/drupal.d.ts +51 -0
  327. package/dist/resolution/frameworks/drupal.d.ts.map +1 -0
  328. package/dist/resolution/frameworks/drupal.js +367 -0
  329. package/dist/resolution/frameworks/drupal.js.map +1 -0
  330. package/dist/resolution/frameworks/expo-modules.d.ts +3 -0
  331. package/dist/resolution/frameworks/expo-modules.d.ts.map +1 -0
  332. package/dist/resolution/frameworks/expo-modules.js +143 -0
  333. package/dist/resolution/frameworks/expo-modules.js.map +1 -0
  334. package/dist/resolution/frameworks/express.d.ts +8 -0
  335. package/dist/resolution/frameworks/express.d.ts.map +1 -0
  336. package/dist/resolution/frameworks/express.js +308 -0
  337. package/dist/resolution/frameworks/express.js.map +1 -0
  338. package/dist/resolution/frameworks/fabric.d.ts +3 -0
  339. package/dist/resolution/frameworks/fabric.d.ts.map +1 -0
  340. package/dist/resolution/frameworks/fabric.js +354 -0
  341. package/dist/resolution/frameworks/fabric.js.map +1 -0
  342. package/dist/resolution/frameworks/go.d.ts +8 -0
  343. package/dist/resolution/frameworks/go.d.ts.map +1 -0
  344. package/dist/resolution/frameworks/go.js +161 -0
  345. package/dist/resolution/frameworks/go.js.map +1 -0
  346. package/dist/resolution/frameworks/index.d.ts +48 -0
  347. package/dist/resolution/frameworks/index.d.ts.map +1 -0
  348. package/dist/resolution/frameworks/index.js +161 -0
  349. package/dist/resolution/frameworks/index.js.map +1 -0
  350. package/dist/resolution/frameworks/java.d.ts +8 -0
  351. package/dist/resolution/frameworks/java.d.ts.map +1 -0
  352. package/dist/resolution/frameworks/java.js +504 -0
  353. package/dist/resolution/frameworks/java.js.map +1 -0
  354. package/dist/resolution/frameworks/laravel.d.ts +13 -0
  355. package/dist/resolution/frameworks/laravel.d.ts.map +1 -0
  356. package/dist/resolution/frameworks/laravel.js +257 -0
  357. package/dist/resolution/frameworks/laravel.js.map +1 -0
  358. package/dist/resolution/frameworks/nestjs.d.ts +26 -0
  359. package/dist/resolution/frameworks/nestjs.d.ts.map +1 -0
  360. package/dist/resolution/frameworks/nestjs.js +698 -0
  361. package/dist/resolution/frameworks/nestjs.js.map +1 -0
  362. package/dist/resolution/frameworks/play.d.ts +19 -0
  363. package/dist/resolution/frameworks/play.d.ts.map +1 -0
  364. package/dist/resolution/frameworks/play.js +111 -0
  365. package/dist/resolution/frameworks/play.js.map +1 -0
  366. package/dist/resolution/frameworks/python.d.ts +10 -0
  367. package/dist/resolution/frameworks/python.d.ts.map +1 -0
  368. package/dist/resolution/frameworks/python.js +396 -0
  369. package/dist/resolution/frameworks/python.js.map +1 -0
  370. package/dist/resolution/frameworks/react-native.d.ts +3 -0
  371. package/dist/resolution/frameworks/react-native.d.ts.map +1 -0
  372. package/dist/resolution/frameworks/react-native.js +360 -0
  373. package/dist/resolution/frameworks/react-native.js.map +1 -0
  374. package/dist/resolution/frameworks/react.d.ts +8 -0
  375. package/dist/resolution/frameworks/react.d.ts.map +1 -0
  376. package/dist/resolution/frameworks/react.js +365 -0
  377. package/dist/resolution/frameworks/react.js.map +1 -0
  378. package/dist/resolution/frameworks/ruby.d.ts +8 -0
  379. package/dist/resolution/frameworks/ruby.d.ts.map +1 -0
  380. package/dist/resolution/frameworks/ruby.js +302 -0
  381. package/dist/resolution/frameworks/ruby.js.map +1 -0
  382. package/dist/resolution/frameworks/rust.d.ts +8 -0
  383. package/dist/resolution/frameworks/rust.d.ts.map +1 -0
  384. package/dist/resolution/frameworks/rust.js +304 -0
  385. package/dist/resolution/frameworks/rust.js.map +1 -0
  386. package/dist/resolution/frameworks/svelte.d.ts +9 -0
  387. package/dist/resolution/frameworks/svelte.d.ts.map +1 -0
  388. package/dist/resolution/frameworks/svelte.js +249 -0
  389. package/dist/resolution/frameworks/svelte.js.map +1 -0
  390. package/dist/resolution/frameworks/swift-objc.d.ts +37 -0
  391. package/dist/resolution/frameworks/swift-objc.d.ts.map +1 -0
  392. package/dist/resolution/frameworks/swift-objc.js +252 -0
  393. package/dist/resolution/frameworks/swift-objc.js.map +1 -0
  394. package/dist/resolution/frameworks/swift.d.ts +10 -0
  395. package/dist/resolution/frameworks/swift.d.ts.map +1 -0
  396. package/dist/resolution/frameworks/swift.js +400 -0
  397. package/dist/resolution/frameworks/swift.js.map +1 -0
  398. package/dist/resolution/frameworks/vue.d.ts +9 -0
  399. package/dist/resolution/frameworks/vue.d.ts.map +1 -0
  400. package/dist/resolution/frameworks/vue.js +306 -0
  401. package/dist/resolution/frameworks/vue.js.map +1 -0
  402. package/dist/resolution/go-module.d.ts +26 -0
  403. package/dist/resolution/go-module.d.ts.map +1 -0
  404. package/dist/resolution/go-module.js +78 -0
  405. package/dist/resolution/go-module.js.map +1 -0
  406. package/dist/resolution/import-resolver.d.ts +68 -0
  407. package/dist/resolution/import-resolver.d.ts.map +1 -0
  408. package/dist/resolution/import-resolver.js +1275 -0
  409. package/dist/resolution/import-resolver.js.map +1 -0
  410. package/dist/resolution/index.d.ts +117 -0
  411. package/dist/resolution/index.d.ts.map +1 -0
  412. package/dist/resolution/index.js +895 -0
  413. package/dist/resolution/index.js.map +1 -0
  414. package/dist/resolution/lru-cache.d.ts +24 -0
  415. package/dist/resolution/lru-cache.d.ts.map +1 -0
  416. package/dist/resolution/lru-cache.js +62 -0
  417. package/dist/resolution/lru-cache.js.map +1 -0
  418. package/dist/resolution/name-matcher.d.ts +32 -0
  419. package/dist/resolution/name-matcher.d.ts.map +1 -0
  420. package/dist/resolution/name-matcher.js +596 -0
  421. package/dist/resolution/name-matcher.js.map +1 -0
  422. package/dist/resolution/path-aliases.d.ts +68 -0
  423. package/dist/resolution/path-aliases.d.ts.map +1 -0
  424. package/dist/resolution/path-aliases.js +238 -0
  425. package/dist/resolution/path-aliases.js.map +1 -0
  426. package/dist/resolution/spec-link-resolver.d.ts +103 -0
  427. package/dist/resolution/spec-link-resolver.d.ts.map +1 -0
  428. package/dist/resolution/spec-link-resolver.js +259 -0
  429. package/dist/resolution/spec-link-resolver.js.map +1 -0
  430. package/dist/resolution/strip-comments.d.ts +27 -0
  431. package/dist/resolution/strip-comments.d.ts.map +1 -0
  432. package/dist/resolution/strip-comments.js +441 -0
  433. package/dist/resolution/strip-comments.js.map +1 -0
  434. package/dist/resolution/swift-objc-bridge.d.ts +134 -0
  435. package/dist/resolution/swift-objc-bridge.d.ts.map +1 -0
  436. package/dist/resolution/swift-objc-bridge.js +256 -0
  437. package/dist/resolution/swift-objc-bridge.js.map +1 -0
  438. package/dist/resolution/types.d.ts +216 -0
  439. package/dist/resolution/types.d.ts.map +1 -0
  440. package/dist/resolution/types.js +8 -0
  441. package/dist/resolution/types.js.map +1 -0
  442. package/dist/resolution/workspace-packages.d.ts +48 -0
  443. package/dist/resolution/workspace-packages.d.ts.map +1 -0
  444. package/dist/resolution/workspace-packages.js +208 -0
  445. package/dist/resolution/workspace-packages.js.map +1 -0
  446. package/dist/search/query-parser.d.ts +57 -0
  447. package/dist/search/query-parser.d.ts.map +1 -0
  448. package/dist/search/query-parser.js +177 -0
  449. package/dist/search/query-parser.js.map +1 -0
  450. package/dist/search/query-utils.d.ts +71 -0
  451. package/dist/search/query-utils.d.ts.map +1 -0
  452. package/dist/search/query-utils.js +380 -0
  453. package/dist/search/query-utils.js.map +1 -0
  454. package/dist/server/cli.js +152 -0
  455. package/dist/server/index.js +12 -0
  456. package/dist/server/ingest/index.js +18 -0
  457. package/dist/server/ingest/ingestor.js +506 -0
  458. package/dist/server/ingest/parser.js +104 -0
  459. package/dist/server/ingest/pricing.js +78 -0
  460. package/dist/server/ingest/types.js +9 -0
  461. package/dist/server/ingest/watcher.js +77 -0
  462. package/dist/server/package.json +3 -0
  463. package/dist/server/project-registry.js +101 -0
  464. package/dist/server/routes/claude.js +868 -0
  465. package/dist/server/routes/graph.js +211 -0
  466. package/dist/server/routes/memory.js +272 -0
  467. package/dist/server/routes/projects.js +197 -0
  468. package/dist/server/routes/spec.js +265 -0
  469. package/dist/server/routes/status.js +112 -0
  470. package/dist/server/routes/workflow.js +212 -0
  471. package/dist/server/server.js +206 -0
  472. package/dist/server/static-handler.js +87 -0
  473. package/dist/sync/git-hooks.d.ts +45 -0
  474. package/dist/sync/git-hooks.d.ts.map +1 -0
  475. package/dist/sync/git-hooks.js +225 -0
  476. package/dist/sync/git-hooks.js.map +1 -0
  477. package/dist/sync/index.d.ts +19 -0
  478. package/dist/sync/index.d.ts.map +1 -0
  479. package/dist/sync/index.js +35 -0
  480. package/dist/sync/index.js.map +1 -0
  481. package/dist/sync/watch-policy.d.ts +48 -0
  482. package/dist/sync/watch-policy.d.ts.map +1 -0
  483. package/dist/sync/watch-policy.js +124 -0
  484. package/dist/sync/watch-policy.js.map +1 -0
  485. package/dist/sync/watcher.d.ts +283 -0
  486. package/dist/sync/watcher.d.ts.map +1 -0
  487. package/dist/sync/watcher.js +606 -0
  488. package/dist/sync/watcher.js.map +1 -0
  489. package/dist/sync/worktree.d.ts +54 -0
  490. package/dist/sync/worktree.d.ts.map +1 -0
  491. package/dist/sync/worktree.js +137 -0
  492. package/dist/sync/worktree.js.map +1 -0
  493. package/dist/types.d.ts +623 -0
  494. package/dist/types.d.ts.map +1 -0
  495. package/dist/types.js +108 -0
  496. package/dist/types.js.map +1 -0
  497. package/dist/ui/glyphs.d.ts +42 -0
  498. package/dist/ui/glyphs.d.ts.map +1 -0
  499. package/dist/ui/glyphs.js +78 -0
  500. package/dist/ui/glyphs.js.map +1 -0
  501. package/dist/ui/shimmer-progress.d.ts +11 -0
  502. package/dist/ui/shimmer-progress.d.ts.map +1 -0
  503. package/dist/ui/shimmer-progress.js +90 -0
  504. package/dist/ui/shimmer-progress.js.map +1 -0
  505. package/dist/ui/shimmer-worker.d.ts +2 -0
  506. package/dist/ui/shimmer-worker.d.ts.map +1 -0
  507. package/dist/ui/shimmer-worker.js +118 -0
  508. package/dist/ui/shimmer-worker.js.map +1 -0
  509. package/dist/ui/types.d.ts +17 -0
  510. package/dist/ui/types.d.ts.map +1 -0
  511. package/dist/ui/types.js +3 -0
  512. package/dist/ui/types.js.map +1 -0
  513. package/dist/utils.d.ts +205 -0
  514. package/dist/utils.d.ts.map +1 -0
  515. package/dist/utils.js +549 -0
  516. package/dist/utils.js.map +1 -0
  517. package/dist/web/chunk-2AJCHB7P.js +1 -0
  518. package/dist/web/chunk-2CPLUFCH.js +2 -0
  519. package/dist/web/chunk-2GBEK2GM.js +1 -0
  520. package/dist/web/chunk-2I7L37NS.js +1 -0
  521. package/dist/web/chunk-2NAWAJB5.js +1 -0
  522. package/dist/web/chunk-2OJBIPE4.js +1 -0
  523. package/dist/web/chunk-2YUJNZ2Y.js +6 -0
  524. package/dist/web/chunk-3E2WB6D5.js +1 -0
  525. package/dist/web/chunk-3EBFYSCH.js +2 -0
  526. package/dist/web/chunk-3QCQ4BXS.js +1 -0
  527. package/dist/web/chunk-42XVAQ6I.js +1 -0
  528. package/dist/web/chunk-45QHGCB4.js +17 -0
  529. package/dist/web/chunk-4IMMPEYM.js +1 -0
  530. package/dist/web/chunk-4TJQJPCZ.js +1 -0
  531. package/dist/web/chunk-4WZIHTPC.js +1 -0
  532. package/dist/web/chunk-4YVSYOSD.js +1 -0
  533. package/dist/web/chunk-5BQIOYKW.js +1 -0
  534. package/dist/web/chunk-5HGWHUJA.js +1 -0
  535. package/dist/web/chunk-5Y244R4G.js +1 -0
  536. package/dist/web/chunk-6RRDPT5Z.js +1 -0
  537. package/dist/web/chunk-6VKB2ZWM.js +1 -0
  538. package/dist/web/chunk-7DMFVTU4.js +1 -0
  539. package/dist/web/chunk-7RNS77UP.js +1 -0
  540. package/dist/web/chunk-7SMPKVEP.js +1 -0
  541. package/dist/web/chunk-A5R3MJMO.js +1 -0
  542. package/dist/web/chunk-ASZ77FMZ.js +1 -0
  543. package/dist/web/chunk-AZJVTPLU.js +1 -0
  544. package/dist/web/chunk-B3YPFY6A.js +1 -0
  545. package/dist/web/chunk-BLBRMCN2.js +1 -0
  546. package/dist/web/chunk-BMIAXD2V.js +2 -0
  547. package/dist/web/chunk-BUXWEHIY.js +1 -0
  548. package/dist/web/chunk-BYZFQSM6.js +1 -0
  549. package/dist/web/chunk-D5OCNEJA.js +2 -0
  550. package/dist/web/chunk-DLQPZWSI.css +1 -0
  551. package/dist/web/chunk-DTRN7FZR.js +1 -0
  552. package/dist/web/chunk-DYRFLPJA.js +1 -0
  553. package/dist/web/chunk-E3J3CXR5.js +1 -0
  554. package/dist/web/chunk-E44X4RH2.js +1 -0
  555. package/dist/web/chunk-E73OX2P7.js +1 -0
  556. package/dist/web/chunk-EAXRKDLV.js +1 -0
  557. package/dist/web/chunk-EBKKDHYI.js +1 -0
  558. package/dist/web/chunk-EE7V7Q5P.js +1 -0
  559. package/dist/web/chunk-EKY2FUHU.js +1 -0
  560. package/dist/web/chunk-EMGMOEVR.js +1 -0
  561. package/dist/web/chunk-EP6XOPXH.js +1 -0
  562. package/dist/web/chunk-ESGDLJOJ.js +1 -0
  563. package/dist/web/chunk-ETJG7NCY.js +1 -0
  564. package/dist/web/chunk-EUUEFEDI.js +1 -0
  565. package/dist/web/chunk-FGNZDHTL.js +11 -0
  566. package/dist/web/chunk-FHZHD2ZG.js +1 -0
  567. package/dist/web/chunk-FIJW2UNJ.js +1 -0
  568. package/dist/web/chunk-FMV5PXRC.js +5 -0
  569. package/dist/web/chunk-G7VZT5KB.js +3 -0
  570. package/dist/web/chunk-GR72OOCN.js +1 -0
  571. package/dist/web/chunk-GRZYXPSO.js +7 -0
  572. package/dist/web/chunk-GWPVKJIY.js +1 -0
  573. package/dist/web/chunk-GYGPS3AN.js +1 -0
  574. package/dist/web/chunk-H7AF7YS4.js +1 -0
  575. package/dist/web/chunk-HDZDQILN.js +1 -0
  576. package/dist/web/chunk-HMK6UO6N.js +1 -0
  577. package/dist/web/chunk-HZA6NEAB.js +1 -0
  578. package/dist/web/chunk-IHEE5NYJ.js +1 -0
  579. package/dist/web/chunk-ISNEBICW.js +1 -0
  580. package/dist/web/chunk-J2GZVLHH.js +1 -0
  581. package/dist/web/chunk-JTFXTIPE.js +903 -0
  582. package/dist/web/chunk-L37MTFSG.js +3 -0
  583. package/dist/web/chunk-LB6JPLX2.js +1 -0
  584. package/dist/web/chunk-LNSVDHCI.js +1 -0
  585. package/dist/web/chunk-LVGIY3SO.js +1 -0
  586. package/dist/web/chunk-LXLHIHEN.js +1 -0
  587. package/dist/web/chunk-MC4DFIHG.js +1 -0
  588. package/dist/web/chunk-MVOMVPYB.js +1 -0
  589. package/dist/web/chunk-N6SS4G6S.js +1 -0
  590. package/dist/web/chunk-NTBJG6SJ.js +1 -0
  591. package/dist/web/chunk-NUDB3Q2Y.js +3 -0
  592. package/dist/web/chunk-NZEZCT65.js +1 -0
  593. package/dist/web/chunk-OXEF5E3E.js +1 -0
  594. package/dist/web/chunk-PDN6QYGJ.js +4 -0
  595. package/dist/web/chunk-PGGJPDJG.js +1 -0
  596. package/dist/web/chunk-PUYSJNJR.js +1 -0
  597. package/dist/web/chunk-Q2RVFS45.js +1 -0
  598. package/dist/web/chunk-Q7L6LLAK.js +1 -0
  599. package/dist/web/chunk-QCMKJIWY.js +1 -0
  600. package/dist/web/chunk-QH6CF3M3.js +1 -0
  601. package/dist/web/chunk-QQ5LD7PI.js +1 -0
  602. package/dist/web/chunk-QR6L3KAC.js +1 -0
  603. package/dist/web/chunk-R2DLK4HO.js +1 -0
  604. package/dist/web/chunk-R5W2MDZN.js +1 -0
  605. package/dist/web/chunk-RD6TVPOT.js +1 -0
  606. package/dist/web/chunk-RKY4EJYJ.js +1 -0
  607. package/dist/web/chunk-RONYWVY7.js +1 -0
  608. package/dist/web/chunk-RXKXYF2C.js +1 -0
  609. package/dist/web/chunk-SBWU7JFC.js +1 -0
  610. package/dist/web/chunk-SEXBRGYK.js +1 -0
  611. package/dist/web/chunk-SHPTC4RL.js +1 -0
  612. package/dist/web/chunk-SUZYBYDW.js +1 -0
  613. package/dist/web/chunk-SWKJRNYY.js +1 -0
  614. package/dist/web/chunk-T66XVKGB.js +1 -0
  615. package/dist/web/chunk-T7AZ65JP.js +1 -0
  616. package/dist/web/chunk-TCZDVOHD.js +1 -0
  617. package/dist/web/chunk-TPTITA3V.js +1 -0
  618. package/dist/web/chunk-TR335633.js +1 -0
  619. package/dist/web/chunk-UBOZGQNK.js +1 -0
  620. package/dist/web/chunk-UR5KDXPX.js +1 -0
  621. package/dist/web/chunk-UR6O2GEH.js +1 -0
  622. package/dist/web/chunk-UTNMGWTP.js +1 -0
  623. package/dist/web/chunk-UYC52MBC.js +1 -0
  624. package/dist/web/chunk-VECWMHJP.js +1 -0
  625. package/dist/web/chunk-VUACT35R.js +3 -0
  626. package/dist/web/chunk-VZI7H4SZ.js +1 -0
  627. package/dist/web/chunk-WAI2JMZP.js +1 -0
  628. package/dist/web/chunk-WB6YHOD4.js +1 -0
  629. package/dist/web/chunk-WBT64AWV.js +1 -0
  630. package/dist/web/chunk-WCKHQIYN.js +1 -0
  631. package/dist/web/chunk-WDU3WICG.js +1 -0
  632. package/dist/web/chunk-WFXJIXZE.js +4 -0
  633. package/dist/web/chunk-WLIMNDS3.js +1 -0
  634. package/dist/web/chunk-WTGYRH3Z.js +298 -0
  635. package/dist/web/chunk-WXTCVDTP.js +1 -0
  636. package/dist/web/chunk-X2HTISHL.js +1 -0
  637. package/dist/web/chunk-XCDHWLVH.js +1 -0
  638. package/dist/web/chunk-Y3H6FFUZ.js +1 -0
  639. package/dist/web/chunk-Y4F5ULGJ.js +1 -0
  640. package/dist/web/chunk-YAMRN47K.js +2 -0
  641. package/dist/web/chunk-YEGKAAEE.js +1 -0
  642. package/dist/web/chunk-YM2KU57F.js +1 -0
  643. package/dist/web/chunk-YRERBP6T.js +1 -0
  644. package/dist/web/chunk-ZLV4VCDG.js +3 -0
  645. package/dist/web/chunk-ZTVI5KFF.js +1 -0
  646. package/dist/web/favicon-16.png +0 -0
  647. package/dist/web/favicon-180.png +0 -0
  648. package/dist/web/favicon-32.png +0 -0
  649. package/dist/web/favicon-512.png +0 -0
  650. package/dist/web/favicon-small.svg +15 -0
  651. package/dist/web/favicon.ico +0 -0
  652. package/dist/web/favicon.svg +20 -0
  653. package/dist/web/index.html +145 -0
  654. package/dist/web/main-ESADRXN2.css +1 -0
  655. package/dist/web/main-R53HA54V.js +1 -0
  656. package/dist/web/media/codicon-LN6W7LCM.ttf +0 -0
  657. package/dist/web/styles-KSOPUVDA.css +1 -0
  658. package/dist/web/sw.js +69 -0
  659. package/dist/workflows/condition-evaluator.d.ts +75 -0
  660. package/dist/workflows/condition-evaluator.d.ts.map +1 -0
  661. package/dist/workflows/condition-evaluator.js +282 -0
  662. package/dist/workflows/condition-evaluator.js.map +1 -0
  663. package/dist/workflows/defaults/claude-design-implement.yaml +336 -0
  664. package/dist/workflows/defaults/index.d.ts +26 -0
  665. package/dist/workflows/defaults/index.d.ts.map +1 -0
  666. package/dist/workflows/defaults/index.js +94 -0
  667. package/dist/workflows/defaults/index.js.map +1 -0
  668. package/dist/workflows/defaults/spec-author.yaml +214 -0
  669. package/dist/workflows/defaults/spec-fix.yaml +110 -0
  670. package/dist/workflows/defaults/spec-implement.yaml +150 -0
  671. package/dist/workflows/defaults/spec-relink.yaml +81 -0
  672. package/dist/workflows/defaults/spec-verify.yaml +51 -0
  673. package/dist/workflows/discovery.d.ts +46 -0
  674. package/dist/workflows/discovery.d.ts.map +1 -0
  675. package/dist/workflows/discovery.js +193 -0
  676. package/dist/workflows/discovery.js.map +1 -0
  677. package/dist/workflows/executor.d.ts +83 -0
  678. package/dist/workflows/executor.d.ts.map +1 -0
  679. package/dist/workflows/executor.js +624 -0
  680. package/dist/workflows/executor.js.map +1 -0
  681. package/dist/workflows/runners/approval.d.ts +18 -0
  682. package/dist/workflows/runners/approval.d.ts.map +1 -0
  683. package/dist/workflows/runners/approval.js +34 -0
  684. package/dist/workflows/runners/approval.js.map +1 -0
  685. package/dist/workflows/runners/bash.d.ts +13 -0
  686. package/dist/workflows/runners/bash.d.ts.map +1 -0
  687. package/dist/workflows/runners/bash.js +143 -0
  688. package/dist/workflows/runners/bash.js.map +1 -0
  689. package/dist/workflows/runners/cancel.d.ts +10 -0
  690. package/dist/workflows/runners/cancel.d.ts.map +1 -0
  691. package/dist/workflows/runners/cancel.js +19 -0
  692. package/dist/workflows/runners/cancel.js.map +1 -0
  693. package/dist/workflows/runners/prompt.d.ts +28 -0
  694. package/dist/workflows/runners/prompt.d.ts.map +1 -0
  695. package/dist/workflows/runners/prompt.js +212 -0
  696. package/dist/workflows/runners/prompt.js.map +1 -0
  697. package/dist/workflows/runners/script.d.ts +17 -0
  698. package/dist/workflows/runners/script.d.ts.map +1 -0
  699. package/dist/workflows/runners/script.js +155 -0
  700. package/dist/workflows/runners/script.js.map +1 -0
  701. package/dist/workflows/runners/types.d.ts +51 -0
  702. package/dist/workflows/runners/types.d.ts.map +1 -0
  703. package/dist/workflows/runners/types.js +13 -0
  704. package/dist/workflows/runners/types.js.map +1 -0
  705. package/dist/workflows/schemas/workflow.d.ts +166 -0
  706. package/dist/workflows/schemas/workflow.d.ts.map +1 -0
  707. package/dist/workflows/schemas/workflow.js +437 -0
  708. package/dist/workflows/schemas/workflow.js.map +1 -0
  709. package/hooks/hooks.json +11 -0
  710. package/package.json +7 -3
  711. package/scripts/offline-install.sh +19 -6
  712. package/selectors.json +41 -0
  713. /package/commands/{cg-explore.md → ss-explore.md} +0 -0
  714. /package/commands/{cg-impact.md → ss-impact.md} +0 -0
  715. /package/commands/{cg-relink.md → ss-relink.md} +0 -0
  716. /package/commands/{cg-spec.md → ss-spec.md} +0 -0
  717. /package/commands/{cg-sync.md → ss-sync.md} +0 -0
  718. /package/commands/{cg-trace.md → ss-trace.md} +0 -0
@@ -0,0 +1,3092 @@
1
+ "use strict";
2
+ /**
3
+ * Tree-sitter Parser Wrapper
4
+ *
5
+ * Handles parsing source code and extracting structural information.
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.TreeSitterExtractor = exports.generateNodeId = void 0;
42
+ exports.extractFromSource = extractFromSource;
43
+ const path = __importStar(require("path"));
44
+ const grammars_1 = require("./grammars");
45
+ const tree_sitter_helpers_1 = require("./tree-sitter-helpers");
46
+ const languages_1 = require("./languages");
47
+ const liquid_extractor_1 = require("./liquid-extractor");
48
+ const svelte_extractor_1 = require("./svelte-extractor");
49
+ const dfm_extractor_1 = require("./dfm-extractor");
50
+ const vue_extractor_1 = require("./vue-extractor");
51
+ const mybatis_extractor_1 = require("./mybatis-extractor");
52
+ const frameworks_1 = require("../resolution/frameworks");
53
+ // Re-export for backward compatibility
54
+ var tree_sitter_helpers_2 = require("./tree-sitter-helpers");
55
+ Object.defineProperty(exports, "generateNodeId", { enumerable: true, get: function () { return tree_sitter_helpers_2.generateNodeId; } });
56
+ /**
57
+ * Extract the name from a node based on language
58
+ */
59
+ function extractName(node, source, extractor) {
60
+ const hookName = extractor.resolveName?.(node, source);
61
+ if (hookName)
62
+ return hookName;
63
+ // Try field name first
64
+ const nameNode = (0, tree_sitter_helpers_1.getChildByField)(node, extractor.nameField);
65
+ if (nameNode) {
66
+ // Unwrap pointer_declarator(s) for C/C++ pointer return types
67
+ let resolved = nameNode;
68
+ while (resolved.type === 'pointer_declarator') {
69
+ const inner = (0, tree_sitter_helpers_1.getChildByField)(resolved, 'declarator') || resolved.namedChild(0);
70
+ if (!inner)
71
+ break;
72
+ resolved = inner;
73
+ }
74
+ // Handle complex declarators (C/C++)
75
+ if (resolved.type === 'function_declarator' || resolved.type === 'declarator') {
76
+ const innerName = (0, tree_sitter_helpers_1.getChildByField)(resolved, 'declarator') || resolved.namedChild(0);
77
+ return innerName ? (0, tree_sitter_helpers_1.getNodeText)(innerName, source) : (0, tree_sitter_helpers_1.getNodeText)(resolved, source);
78
+ }
79
+ // Lua: `function t.f()` / `function t:m()` — the name node is a dot/method
80
+ // index expression; the simple name is the trailing field/method (the table
81
+ // receiver is captured separately via getReceiverType).
82
+ if (resolved.type === 'dot_index_expression') {
83
+ const field = (0, tree_sitter_helpers_1.getChildByField)(resolved, 'field');
84
+ if (field)
85
+ return (0, tree_sitter_helpers_1.getNodeText)(field, source);
86
+ }
87
+ if (resolved.type === 'method_index_expression') {
88
+ const method = (0, tree_sitter_helpers_1.getChildByField)(resolved, 'method');
89
+ if (method)
90
+ return (0, tree_sitter_helpers_1.getNodeText)(method, source);
91
+ }
92
+ return (0, tree_sitter_helpers_1.getNodeText)(resolved, source);
93
+ }
94
+ // For Dart method_signature, look inside inner signature types
95
+ if (node.type === 'method_signature') {
96
+ for (let i = 0; i < node.namedChildCount; i++) {
97
+ const child = node.namedChild(i);
98
+ if (child && (child.type === 'function_signature' ||
99
+ child.type === 'getter_signature' ||
100
+ child.type === 'setter_signature' ||
101
+ child.type === 'constructor_signature' ||
102
+ child.type === 'factory_constructor_signature')) {
103
+ // Find identifier inside the inner signature
104
+ for (let j = 0; j < child.namedChildCount; j++) {
105
+ const inner = child.namedChild(j);
106
+ if (inner?.type === 'identifier') {
107
+ return (0, tree_sitter_helpers_1.getNodeText)(inner, source);
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ // Arrow/function expressions get their name from the parent variable_declarator,
114
+ // not from identifiers in their body. Without this, single-expression arrow
115
+ // functions like `const fn = () => someIdentifier` get named "someIdentifier"
116
+ // instead of "fn", because the fallback below finds the body identifier.
117
+ if (node.type === 'arrow_function' || node.type === 'function_expression') {
118
+ return '<anonymous>';
119
+ }
120
+ // Fall back to first identifier child
121
+ for (let i = 0; i < node.namedChildCount; i++) {
122
+ const child = node.namedChild(i);
123
+ if (child &&
124
+ (child.type === 'identifier' ||
125
+ child.type === 'type_identifier' ||
126
+ child.type === 'simple_identifier' ||
127
+ child.type === 'constant')) {
128
+ return (0, tree_sitter_helpers_1.getNodeText)(child, source);
129
+ }
130
+ }
131
+ return '<anonymous>';
132
+ }
133
+ /**
134
+ * Tree-sitter node kinds that represent constructor invocations
135
+ * (`new Foo()` and friends). Used by extractInstantiation to emit
136
+ * an `instantiates` reference targeting the class name.
137
+ */
138
+ const INSTANTIATION_KINDS = new Set([
139
+ 'new_expression', // typescript / javascript / tsx / jsx
140
+ 'object_creation_expression', // java / c#
141
+ 'instance_creation_expression', // some grammars
142
+ ]);
143
+ /**
144
+ * TreeSitterExtractor - Main extraction class
145
+ */
146
+ class TreeSitterExtractor {
147
+ filePath;
148
+ language;
149
+ source;
150
+ tree = null;
151
+ nodes = [];
152
+ edges = [];
153
+ unresolvedReferences = [];
154
+ errors = [];
155
+ extractor = null;
156
+ nodeStack = []; // Stack of parent node IDs
157
+ methodIndex = null; // lookup key → node ID for Pascal defProc lookup
158
+ constructor(filePath, source, language) {
159
+ this.filePath = filePath;
160
+ this.source = source;
161
+ this.language = language || (0, grammars_1.detectLanguage)(filePath, source);
162
+ this.extractor = languages_1.EXTRACTORS[this.language] || null;
163
+ }
164
+ /**
165
+ * Parse and extract from the source code
166
+ */
167
+ extract() {
168
+ const startTime = Date.now();
169
+ if (!(0, grammars_1.isLanguageSupported)(this.language)) {
170
+ return {
171
+ nodes: [],
172
+ edges: [],
173
+ unresolvedReferences: [],
174
+ errors: [
175
+ {
176
+ message: `Unsupported language: ${this.language}`,
177
+ filePath: this.filePath,
178
+ severity: 'error',
179
+ code: 'unsupported_language',
180
+ },
181
+ ],
182
+ durationMs: Date.now() - startTime,
183
+ };
184
+ }
185
+ const parser = (0, grammars_1.getParser)(this.language);
186
+ if (!parser) {
187
+ return {
188
+ nodes: [],
189
+ edges: [],
190
+ unresolvedReferences: [],
191
+ errors: [
192
+ {
193
+ message: `Failed to get parser for language: ${this.language}`,
194
+ filePath: this.filePath,
195
+ severity: 'error',
196
+ code: 'parser_error',
197
+ },
198
+ ],
199
+ durationMs: Date.now() - startTime,
200
+ };
201
+ }
202
+ try {
203
+ this.tree = parser.parse(this.source) ?? null;
204
+ if (!this.tree) {
205
+ throw new Error('Parser returned null tree');
206
+ }
207
+ // Create file node representing the source file
208
+ const fileNode = {
209
+ id: `file:${this.filePath}`,
210
+ kind: 'file',
211
+ name: path.basename(this.filePath),
212
+ qualifiedName: this.filePath,
213
+ filePath: this.filePath,
214
+ language: this.language,
215
+ startLine: 1,
216
+ endLine: this.source.split('\n').length,
217
+ startColumn: 0,
218
+ endColumn: 0,
219
+ isExported: false,
220
+ updatedAt: Date.now(),
221
+ };
222
+ this.nodes.push(fileNode);
223
+ // Push file node onto stack so top-level declarations get contains edges
224
+ this.nodeStack.push(fileNode.id);
225
+ // File-level package declaration (Kotlin/Java). Creates an implicit
226
+ // `namespace` node wrapping every top-level declaration so their
227
+ // qualifiedName carries the FQN — required for cross-file import
228
+ // resolution on JVM languages where filename ≠ class name.
229
+ const packageNodeId = this.extractFilePackage(this.tree.rootNode);
230
+ if (packageNodeId)
231
+ this.nodeStack.push(packageNodeId);
232
+ this.visitNode(this.tree.rootNode);
233
+ if (packageNodeId)
234
+ this.nodeStack.pop();
235
+ this.nodeStack.pop();
236
+ }
237
+ catch (error) {
238
+ const msg = error instanceof Error ? error.message : String(error);
239
+ // WASM memory errors leave the module in a corrupted state — all subsequent
240
+ // parses would also fail. Re-throw so the worker can detect and crash,
241
+ // forcing a clean restart with a fresh heap.
242
+ if (msg.includes('memory access out of bounds') || msg.includes('out of memory')) {
243
+ throw error;
244
+ }
245
+ this.errors.push({
246
+ message: `Parse error: ${msg}`,
247
+ filePath: this.filePath,
248
+ severity: 'error',
249
+ code: 'parse_error',
250
+ });
251
+ }
252
+ finally {
253
+ // Free tree-sitter WASM memory immediately — trees hold native heap memory
254
+ // invisible to V8's GC that accumulates across thousands of files.
255
+ if (this.tree) {
256
+ this.tree.delete();
257
+ this.tree = null;
258
+ }
259
+ // Release source string to reduce GC pressure
260
+ this.source = '';
261
+ }
262
+ return {
263
+ nodes: this.nodes,
264
+ edges: this.edges,
265
+ unresolvedReferences: this.unresolvedReferences,
266
+ errors: this.errors,
267
+ durationMs: Date.now() - startTime,
268
+ };
269
+ }
270
+ /**
271
+ * Visit a node and extract information
272
+ */
273
+ visitNode(node) {
274
+ if (!this.extractor)
275
+ return;
276
+ const nodeType = node.type;
277
+ let skipChildren = false;
278
+ // Language-specific custom visitor hook
279
+ if (this.extractor.visitNode) {
280
+ const ctx = this.makeExtractorContext();
281
+ const handled = this.extractor.visitNode(node, ctx);
282
+ if (handled)
283
+ return;
284
+ }
285
+ // Pascal-specific AST handling
286
+ if (this.language === 'pascal') {
287
+ skipChildren = this.visitPascalNode(node);
288
+ if (skipChildren)
289
+ return;
290
+ }
291
+ // Check for function declarations
292
+ // For Python/Ruby, function_definition inside a class should be treated as method
293
+ if (this.extractor.functionTypes.includes(nodeType)) {
294
+ if (this.isInsideClassLikeNode() && this.extractor.methodTypes.includes(nodeType)) {
295
+ // Inside a class - treat as method
296
+ this.extractMethod(node);
297
+ skipChildren = true; // extractMethod visits children via visitFunctionBody
298
+ }
299
+ else {
300
+ this.extractFunction(node);
301
+ skipChildren = true; // extractFunction visits children via visitFunctionBody
302
+ }
303
+ }
304
+ // Check for class declarations
305
+ else if (this.extractor.classTypes.includes(nodeType)) {
306
+ // Some languages reuse class_declaration for structs/enums (e.g. Swift)
307
+ const classification = this.extractor.classifyClassNode?.(node) ?? 'class';
308
+ if (classification === 'struct') {
309
+ this.extractStruct(node);
310
+ }
311
+ else if (classification === 'enum') {
312
+ this.extractEnum(node);
313
+ }
314
+ else if (classification === 'interface') {
315
+ this.extractInterface(node);
316
+ }
317
+ else if (classification === 'trait') {
318
+ this.extractClass(node, 'trait');
319
+ }
320
+ else {
321
+ this.extractClass(node);
322
+ }
323
+ skipChildren = true; // extractClass visits body children
324
+ }
325
+ // Extra class node types (e.g. Dart mixin_declaration, extension_declaration)
326
+ else if (this.extractor.extraClassNodeTypes?.includes(nodeType)) {
327
+ this.extractClass(node);
328
+ skipChildren = true;
329
+ }
330
+ // Check for method declarations (only if not already handled by functionTypes)
331
+ else if (this.extractor.methodTypes.includes(nodeType)) {
332
+ this.extractMethod(node);
333
+ skipChildren = true; // extractMethod visits children via visitFunctionBody
334
+ }
335
+ // Check for interface/protocol/trait declarations
336
+ else if (this.extractor.interfaceTypes.includes(nodeType)) {
337
+ this.extractInterface(node);
338
+ skipChildren = true; // extractInterface visits body children
339
+ }
340
+ // Check for struct declarations
341
+ else if (this.extractor.structTypes.includes(nodeType)) {
342
+ this.extractStruct(node);
343
+ skipChildren = true; // extractStruct visits body children
344
+ }
345
+ // Check for enum declarations
346
+ else if (this.extractor.enumTypes.includes(nodeType)) {
347
+ this.extractEnum(node);
348
+ skipChildren = true; // extractEnum visits body children
349
+ }
350
+ // Check for type alias declarations (e.g. `type X = ...` in TypeScript)
351
+ // For Go, type_spec wraps struct/interface definitions — resolveTypeAliasKind
352
+ // detects these and extractTypeAlias creates the correct node kind.
353
+ else if (this.extractor.typeAliasTypes.includes(nodeType)) {
354
+ skipChildren = this.extractTypeAlias(node);
355
+ }
356
+ // Check for class properties (e.g. C# property_declaration)
357
+ else if (this.extractor.propertyTypes?.includes(nodeType) && this.isInsideClassLikeNode()) {
358
+ this.extractProperty(node);
359
+ skipChildren = true;
360
+ }
361
+ // Check for class fields (e.g. Java field_declaration, C# field_declaration)
362
+ else if (this.extractor.fieldTypes?.includes(nodeType) && this.isInsideClassLikeNode()) {
363
+ this.extractField(node);
364
+ skipChildren = true;
365
+ }
366
+ // Check for variable declarations (const, let, var, etc.)
367
+ // Only extract top-level variables (not inside functions/methods)
368
+ else if (this.extractor.variableTypes.includes(nodeType) && !this.isInsideClassLikeNode()) {
369
+ this.extractVariable(node);
370
+ skipChildren = true; // extractVariable handles children
371
+ }
372
+ // `export_statement` itself is not extracted — the walker descends
373
+ // into children, where the inner declaration (lexical_declaration,
374
+ // function_declaration, class_declaration, etc.) is dispatched to
375
+ // its own extractor. `isExported` walks the parent chain, so the
376
+ // exported flag is preserved automatically.
377
+ //
378
+ // Calling extractExportedVariables here AND descending caused every
379
+ // `export const X = ...` to produce two nodes for the same symbol —
380
+ // one kind:'variable' from extractExportedVariables and one
381
+ // kind:'constant' from extractVariable. The dedicated dispatch is
382
+ // the correct one (it picks kind from isConst, captures the
383
+ // initializer signature, and walks type annotations); the
384
+ // export-statement helper was redundant.
385
+ // Check for imports
386
+ else if (this.extractor.importTypes.includes(nodeType)) {
387
+ this.extractImport(node);
388
+ }
389
+ // Check for function calls
390
+ else if (this.extractor.callTypes.includes(nodeType)) {
391
+ this.extractCall(node);
392
+ }
393
+ // `new Foo(...)` / `Foo::new(...)` / object_creation_expression —
394
+ // produce an `instantiates` reference. Children still walked so
395
+ // nested calls inside the constructor args (`new Foo(bar())`) get
396
+ // their own `calls` refs.
397
+ else if (INSTANTIATION_KINDS.has(nodeType)) {
398
+ this.extractInstantiation(node);
399
+ // Java/C# `new T(...) { ... }` — anonymous class with body. Without
400
+ // extracting it as a class node + its methods, the interface→impl
401
+ // synthesizer (Phase 5.5) can't bridge T's abstract methods to the
402
+ // anonymous overrides, and an agent investigating a call through T
403
+ // (`strategy.iterator(...)` where strategy is a Strategy lambda body)
404
+ // has to Read the file to find the actual implementation.
405
+ const anonBody = this.findAnonymousClassBody(node);
406
+ if (anonBody) {
407
+ this.extractAnonymousClass(node, anonBody);
408
+ skipChildren = true;
409
+ }
410
+ }
411
+ // (Decorator handling lives inside the symbol-creating extractors
412
+ // — extractClass / extractFunction / extractProperty — because the
413
+ // decorator node sits BEFORE the symbol in the AST and the walker
414
+ // would otherwise see the wrong nodeStack head.)
415
+ // Rust: `impl Trait for Type { ... }` — creates implements edge from Type to Trait
416
+ else if (nodeType === 'impl_item') {
417
+ this.extractRustImplItem(node);
418
+ }
419
+ // TypeScript interface members: property_signature (`foo: T`, `foo?: T`)
420
+ // and method_signature (`foo(arg: A): R`) both carry type annotations the
421
+ // interface walker would otherwise drop. Extract them as `references`
422
+ // edges from the interface so resolvers can wire callers/impact for
423
+ // types that only appear in interface members.
424
+ else if ((nodeType === 'property_signature' || nodeType === 'method_signature') &&
425
+ this.isInsideClassLikeNode() &&
426
+ this.TYPE_ANNOTATION_LANGUAGES.has(this.language)) {
427
+ const parentId = this.nodeStack[this.nodeStack.length - 1];
428
+ if (parentId) {
429
+ this.extractTypeAnnotations(node, parentId);
430
+ }
431
+ // don't skipChildren — nested signatures still need traversal
432
+ }
433
+ // Visit children (unless the extract method already visited them)
434
+ if (!skipChildren) {
435
+ for (let i = 0; i < node.namedChildCount; i++) {
436
+ const child = node.namedChild(i);
437
+ if (child) {
438
+ this.visitNode(child);
439
+ }
440
+ }
441
+ }
442
+ }
443
+ /**
444
+ * Create a Node object
445
+ */
446
+ createNode(kind, name, node, extra) {
447
+ // Skip nodes with empty/missing names — they are not meaningful symbols
448
+ // and would cause FK violations when edges reference them (see issue #42)
449
+ if (!name) {
450
+ return null;
451
+ }
452
+ const id = (0, tree_sitter_helpers_1.generateNodeId)(this.filePath, kind, name, node.startPosition.row + 1);
453
+ // Some grammars (e.g. Dart) model a function/method body as a *sibling* of
454
+ // the signature node, so the declaration node's own range is just the
455
+ // signature line. Extend endLine to the resolved body when it sits beyond
456
+ // the node so the node spans its body — required for any body-level analysis
457
+ // (callees, the callback synthesizer's body scan, context slices). Guarded to
458
+ // only ever extend: for child-body grammars the body is within range (no-op).
459
+ let endLine = node.endPosition.row + 1;
460
+ if (kind === 'function' || kind === 'method') {
461
+ const body = this.extractor?.resolveBody?.(node, this.extractor.bodyField);
462
+ if (body && body.endPosition.row + 1 > endLine) {
463
+ endLine = body.endPosition.row + 1;
464
+ }
465
+ }
466
+ const newNode = {
467
+ id,
468
+ kind,
469
+ name,
470
+ qualifiedName: this.buildQualifiedName(name),
471
+ filePath: this.filePath,
472
+ language: this.language,
473
+ startLine: node.startPosition.row + 1,
474
+ endLine,
475
+ startColumn: node.startPosition.column,
476
+ endColumn: node.endPosition.column,
477
+ updatedAt: Date.now(),
478
+ ...extra,
479
+ };
480
+ this.nodes.push(newNode);
481
+ // Add containment edge from parent
482
+ if (this.nodeStack.length > 0) {
483
+ const parentId = this.nodeStack[this.nodeStack.length - 1];
484
+ if (parentId) {
485
+ this.edges.push({
486
+ source: parentId,
487
+ target: id,
488
+ kind: 'contains',
489
+ });
490
+ }
491
+ }
492
+ return newNode;
493
+ }
494
+ /**
495
+ * Find first named child whose type is in the given list.
496
+ * Used to locate inner type nodes (e.g. enum_specifier inside a typedef).
497
+ */
498
+ findChildByTypes(node, types) {
499
+ for (let i = 0; i < node.namedChildCount; i++) {
500
+ const child = node.namedChild(i);
501
+ if (child && types.includes(child.type))
502
+ return child;
503
+ }
504
+ return null;
505
+ }
506
+ /**
507
+ * Find a `packageTypes` child under the root, create a `namespace` node
508
+ * for it, and return its id so the caller can scope top-level
509
+ * declarations underneath. Returns null when no package header is
510
+ * present (script files, .kts without a package).
511
+ */
512
+ extractFilePackage(rootNode) {
513
+ const types = this.extractor?.packageTypes;
514
+ if (!types || types.length === 0 || !this.extractor?.extractPackage)
515
+ return null;
516
+ let pkgNode = null;
517
+ for (let i = 0; i < rootNode.namedChildCount; i++) {
518
+ const child = rootNode.namedChild(i);
519
+ if (child && types.includes(child.type)) {
520
+ pkgNode = child;
521
+ break;
522
+ }
523
+ }
524
+ if (!pkgNode)
525
+ return null;
526
+ const pkgName = this.extractor.extractPackage(pkgNode, this.source);
527
+ if (!pkgName)
528
+ return null;
529
+ const ns = this.createNode('namespace', pkgName, pkgNode);
530
+ return ns?.id ?? null;
531
+ }
532
+ /**
533
+ * Build qualified name from node stack
534
+ */
535
+ buildQualifiedName(name) {
536
+ // Build a qualified name from the semantic hierarchy only (no file path).
537
+ // The file path is stored separately in filePath and pollutes FTS if included here.
538
+ const parts = [];
539
+ for (const nodeId of this.nodeStack) {
540
+ const node = this.nodes.find((n) => n.id === nodeId);
541
+ if (node && node.kind !== 'file') {
542
+ parts.push(node.name);
543
+ }
544
+ }
545
+ parts.push(name);
546
+ return parts.join('::');
547
+ }
548
+ /**
549
+ * Build an ExtractorContext for passing to language-specific visitNode hooks.
550
+ */
551
+ makeExtractorContext() {
552
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
553
+ const self = this;
554
+ return {
555
+ createNode: (kind, name, node, extra) => self.createNode(kind, name, node, extra),
556
+ visitNode: (node) => self.visitNode(node),
557
+ visitFunctionBody: (body, functionId) => self.visitFunctionBody(body, functionId),
558
+ addUnresolvedReference: (ref) => self.unresolvedReferences.push(ref),
559
+ pushScope: (nodeId) => self.nodeStack.push(nodeId),
560
+ popScope: () => self.nodeStack.pop(),
561
+ get filePath() { return self.filePath; },
562
+ get source() { return self.source; },
563
+ get nodeStack() { return self.nodeStack; },
564
+ get nodes() { return self.nodes; },
565
+ };
566
+ }
567
+ /**
568
+ * Check if the current node stack indicates we are inside a class-like node
569
+ * (class, struct, interface, trait). File nodes do not count as class-like.
570
+ */
571
+ isInsideClassLikeNode() {
572
+ if (this.nodeStack.length === 0)
573
+ return false;
574
+ const parentId = this.nodeStack[this.nodeStack.length - 1];
575
+ if (!parentId)
576
+ return false;
577
+ const parentNode = this.nodes.find((n) => n.id === parentId);
578
+ if (!parentNode)
579
+ return false;
580
+ return (parentNode.kind === 'class' ||
581
+ parentNode.kind === 'struct' ||
582
+ parentNode.kind === 'interface' ||
583
+ parentNode.kind === 'trait' ||
584
+ parentNode.kind === 'enum' ||
585
+ parentNode.kind === 'module');
586
+ }
587
+ /**
588
+ * Extract a function
589
+ */
590
+ extractFunction(node, nameOverride) {
591
+ if (!this.extractor)
592
+ return;
593
+ // If the language provides getReceiverType and this function has a receiver
594
+ // (e.g., Rust function_item inside an impl block), extract as method instead
595
+ if (this.extractor.getReceiverType?.(node, this.source)) {
596
+ this.extractMethod(node);
597
+ return;
598
+ }
599
+ // nameOverride is supplied only for explicitly-named anonymous functions the
600
+ // caller resolved itself (e.g. arrow values of exported-const object members
601
+ // — SvelteKit actions). Inline-object arrows reached by the general walker
602
+ // get no override, so they still fall through to the <anonymous> skip below.
603
+ let name = nameOverride ?? extractName(node, this.source, this.extractor);
604
+ // For arrow functions and function expressions assigned to variables,
605
+ // resolve the name from the parent variable_declarator.
606
+ // e.g. `export const useAuth = () => { ... }` — the arrow_function node
607
+ // has no `name` field; the name lives on the variable_declarator.
608
+ if (!nameOverride &&
609
+ name === '<anonymous>' &&
610
+ (node.type === 'arrow_function' || node.type === 'function_expression')) {
611
+ const parent = node.parent;
612
+ if (parent?.type === 'variable_declarator') {
613
+ const varName = (0, tree_sitter_helpers_1.getChildByField)(parent, 'name');
614
+ if (varName) {
615
+ name = (0, tree_sitter_helpers_1.getNodeText)(varName, this.source);
616
+ }
617
+ }
618
+ }
619
+ if (name === '<anonymous>') {
620
+ // Don't emit a node for the anonymous wrapper itself, but still visit its
621
+ // body: AMD/RequireJS and CommonJS module wrappers (`define([], function(){…})`,
622
+ // `(function(){…})()`) hold named inner functions and calls that would
623
+ // otherwise be lost — the dispatcher set skipChildren, so nothing else
624
+ // descends into this subtree. (#528)
625
+ const body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
626
+ ?? (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.bodyField);
627
+ if (body) {
628
+ this.visitFunctionBody(body, '');
629
+ }
630
+ return;
631
+ }
632
+ // Check for misparse artifacts (e.g. C++ macros causing "namespace detail" functions)
633
+ // Skip the node but still visit the body for calls and structural nodes
634
+ if (this.extractor.isMisparsedFunction?.(name, node)) {
635
+ const body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
636
+ ?? (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.bodyField);
637
+ if (body) {
638
+ this.visitFunctionBody(body, '');
639
+ }
640
+ return;
641
+ }
642
+ const docstring = (0, tree_sitter_helpers_1.getPrecedingDocstring)(node, this.source);
643
+ const signature = this.extractor.getSignature?.(node, this.source);
644
+ const visibility = this.extractor.getVisibility?.(node);
645
+ const isExported = this.extractor.isExported?.(node, this.source);
646
+ const isAsync = this.extractor.isAsync?.(node);
647
+ const isStatic = this.extractor.isStatic?.(node);
648
+ const funcNode = this.createNode('function', name, node, {
649
+ docstring,
650
+ signature,
651
+ visibility,
652
+ isExported,
653
+ isAsync,
654
+ isStatic,
655
+ });
656
+ if (!funcNode)
657
+ return;
658
+ // Extract type annotations (parameter types and return type)
659
+ this.extractTypeAnnotations(node, funcNode.id);
660
+ // Extract decorators applied to the function (rare in JS/TS but
661
+ // present in Python `@decorator def f():` and Java/Kotlin
662
+ // annotations on free functions).
663
+ this.extractDecoratorsFor(node, funcNode.id);
664
+ // Push to stack and visit body
665
+ this.nodeStack.push(funcNode.id);
666
+ const body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
667
+ ?? (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.bodyField);
668
+ if (body) {
669
+ this.visitFunctionBody(body, funcNode.id);
670
+ }
671
+ this.nodeStack.pop();
672
+ }
673
+ /**
674
+ * Extract a class
675
+ */
676
+ extractClass(node, kind = 'class') {
677
+ if (!this.extractor)
678
+ return;
679
+ const name = extractName(node, this.source, this.extractor);
680
+ const docstring = (0, tree_sitter_helpers_1.getPrecedingDocstring)(node, this.source);
681
+ const visibility = this.extractor.getVisibility?.(node);
682
+ const isExported = this.extractor.isExported?.(node, this.source);
683
+ const classNode = this.createNode(kind, name, node, {
684
+ docstring,
685
+ visibility,
686
+ isExported,
687
+ });
688
+ if (!classNode)
689
+ return;
690
+ // Extract extends/implements
691
+ this.extractInheritance(node, classNode.id);
692
+ // Extract decorators applied to the class (`@Foo class X {}`).
693
+ this.extractDecoratorsFor(node, classNode.id);
694
+ // Push to stack and visit body
695
+ this.nodeStack.push(classNode.id);
696
+ let body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
697
+ ?? (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.bodyField);
698
+ if (!body)
699
+ body = node;
700
+ // Visit all children for methods and properties
701
+ for (let i = 0; i < body.namedChildCount; i++) {
702
+ const child = body.namedChild(i);
703
+ if (child) {
704
+ this.visitNode(child);
705
+ }
706
+ }
707
+ this.nodeStack.pop();
708
+ }
709
+ /**
710
+ * Extract a method
711
+ */
712
+ extractMethod(node) {
713
+ if (!this.extractor)
714
+ return;
715
+ // For languages with receiver types (Go, Rust), include receiver in qualified name
716
+ // so FTS can match "scrapeLoop.run" → qualified_name "...::scrapeLoop::run"
717
+ const receiverType = this.extractor.getReceiverType?.(node, this.source);
718
+ // For most languages, only extract as method if inside a class-like node
719
+ // Languages with methodsAreTopLevel (e.g. Go) always treat them as methods
720
+ // Languages with getReceiverType (e.g. Rust) extract as method when receiver is found
721
+ if (!this.isInsideClassLikeNode() && !this.extractor.methodsAreTopLevel && !receiverType) {
722
+ // Skip method_definition nodes inside object literals (getters/setters/methods
723
+ // in inline objects). These are ephemeral and create noise (e.g., Svelte context
724
+ // objects: `ctx.set({ get view() { ... } })`).
725
+ if (node.parent?.type === 'object' || node.parent?.type === 'object_expression') {
726
+ const body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
727
+ ?? (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.bodyField);
728
+ if (body) {
729
+ this.visitFunctionBody(body, '');
730
+ }
731
+ return;
732
+ }
733
+ // Not inside a class-like node and no receiver type, treat as function
734
+ this.extractFunction(node);
735
+ return;
736
+ }
737
+ const name = extractName(node, this.source, this.extractor);
738
+ // Check for misparse artifacts (e.g. C++ "switch" inside macro-confused class body)
739
+ if (this.extractor.isMisparsedFunction?.(name, node)) {
740
+ const body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
741
+ ?? (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.bodyField);
742
+ if (body) {
743
+ this.visitFunctionBody(body, '');
744
+ }
745
+ return;
746
+ }
747
+ const docstring = (0, tree_sitter_helpers_1.getPrecedingDocstring)(node, this.source);
748
+ const signature = this.extractor.getSignature?.(node, this.source);
749
+ const visibility = this.extractor.getVisibility?.(node);
750
+ const isAsync = this.extractor.isAsync?.(node);
751
+ const isStatic = this.extractor.isStatic?.(node);
752
+ const extraProps = {
753
+ docstring,
754
+ signature,
755
+ visibility,
756
+ isAsync,
757
+ isStatic,
758
+ };
759
+ if (receiverType) {
760
+ extraProps.qualifiedName = `${receiverType}::${name}`;
761
+ }
762
+ const methodNode = this.createNode('method', name, node, extraProps);
763
+ if (!methodNode)
764
+ return;
765
+ // For methods with a receiver type but no class-like parent on the stack
766
+ // (e.g., Rust impl blocks), add a contains edge from the owning struct/trait
767
+ if (receiverType && !this.isInsideClassLikeNode()) {
768
+ const ownerNode = this.nodes.find((n) => n.name === receiverType &&
769
+ n.filePath === this.filePath &&
770
+ (n.kind === 'struct' || n.kind === 'class' || n.kind === 'enum' || n.kind === 'trait'));
771
+ if (ownerNode) {
772
+ this.edges.push({
773
+ source: ownerNode.id,
774
+ target: methodNode.id,
775
+ kind: 'contains',
776
+ });
777
+ }
778
+ }
779
+ // Extract type annotations (parameter types and return type)
780
+ this.extractTypeAnnotations(node, methodNode.id);
781
+ // Extract decorators (`@Get('/list') list() {}`).
782
+ this.extractDecoratorsFor(node, methodNode.id);
783
+ // Push to stack and visit body
784
+ this.nodeStack.push(methodNode.id);
785
+ const body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
786
+ ?? (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.bodyField);
787
+ if (body) {
788
+ this.visitFunctionBody(body, methodNode.id);
789
+ }
790
+ this.nodeStack.pop();
791
+ }
792
+ /**
793
+ * Extract an interface/protocol/trait
794
+ */
795
+ extractInterface(node) {
796
+ if (!this.extractor)
797
+ return;
798
+ const name = extractName(node, this.source, this.extractor);
799
+ const docstring = (0, tree_sitter_helpers_1.getPrecedingDocstring)(node, this.source);
800
+ const isExported = this.extractor.isExported?.(node, this.source);
801
+ const kind = this.extractor.interfaceKind ?? 'interface';
802
+ const interfaceNode = this.createNode(kind, name, node, {
803
+ docstring,
804
+ isExported,
805
+ });
806
+ if (!interfaceNode)
807
+ return;
808
+ // Extract extends (interface inheritance)
809
+ this.extractInheritance(node, interfaceNode.id);
810
+ // Visit body children for interface methods and nested types
811
+ this.nodeStack.push(interfaceNode.id);
812
+ let body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
813
+ ?? (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.bodyField);
814
+ if (!body)
815
+ body = node;
816
+ for (let i = 0; i < body.namedChildCount; i++) {
817
+ const child = body.namedChild(i);
818
+ if (child) {
819
+ this.visitNode(child);
820
+ }
821
+ }
822
+ this.nodeStack.pop();
823
+ }
824
+ /**
825
+ * Extract a struct
826
+ */
827
+ extractStruct(node) {
828
+ if (!this.extractor)
829
+ return;
830
+ // Skip forward declarations and type references (no body = not a definition)
831
+ const body = (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.bodyField);
832
+ if (!body)
833
+ return;
834
+ const name = extractName(node, this.source, this.extractor);
835
+ const docstring = (0, tree_sitter_helpers_1.getPrecedingDocstring)(node, this.source);
836
+ const visibility = this.extractor.getVisibility?.(node);
837
+ const isExported = this.extractor.isExported?.(node, this.source);
838
+ const structNode = this.createNode('struct', name, node, {
839
+ docstring,
840
+ visibility,
841
+ isExported,
842
+ });
843
+ if (!structNode)
844
+ return;
845
+ // Extract inheritance (e.g. Swift: struct HTTPMethod: RawRepresentable)
846
+ this.extractInheritance(node, structNode.id);
847
+ // Push to stack for field extraction
848
+ this.nodeStack.push(structNode.id);
849
+ for (let i = 0; i < body.namedChildCount; i++) {
850
+ const child = body.namedChild(i);
851
+ if (child) {
852
+ this.visitNode(child);
853
+ }
854
+ }
855
+ this.nodeStack.pop();
856
+ }
857
+ /**
858
+ * Extract an enum
859
+ */
860
+ extractEnum(node) {
861
+ if (!this.extractor)
862
+ return;
863
+ // Skip forward declarations and type references (no body = not a definition)
864
+ const body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
865
+ ?? (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.bodyField);
866
+ if (!body)
867
+ return;
868
+ const name = extractName(node, this.source, this.extractor);
869
+ const docstring = (0, tree_sitter_helpers_1.getPrecedingDocstring)(node, this.source);
870
+ const visibility = this.extractor.getVisibility?.(node);
871
+ const isExported = this.extractor.isExported?.(node, this.source);
872
+ const enumNode = this.createNode('enum', name, node, {
873
+ docstring,
874
+ visibility,
875
+ isExported,
876
+ });
877
+ if (!enumNode)
878
+ return;
879
+ // Extract inheritance (e.g. Swift: enum AFError: Error)
880
+ this.extractInheritance(node, enumNode.id);
881
+ // Push to stack and visit body children (enum members, nested types, methods)
882
+ this.nodeStack.push(enumNode.id);
883
+ const memberTypes = this.extractor.enumMemberTypes;
884
+ for (let i = 0; i < body.namedChildCount; i++) {
885
+ const child = body.namedChild(i);
886
+ if (!child)
887
+ continue;
888
+ if (memberTypes?.includes(child.type)) {
889
+ this.extractEnumMembers(child);
890
+ }
891
+ else {
892
+ this.visitNode(child);
893
+ }
894
+ }
895
+ this.nodeStack.pop();
896
+ }
897
+ /**
898
+ * Extract enum member names from an enum member node.
899
+ * Handles multi-case declarations (Swift: `case put, delete`) and single-case patterns.
900
+ */
901
+ extractEnumMembers(node) {
902
+ // Try field-based name first (e.g. Rust enum_variant has a 'name' field)
903
+ const nameNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'name');
904
+ if (nameNode) {
905
+ this.createNode('enum_member', (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source), node);
906
+ return;
907
+ }
908
+ // Check for identifier-like children (Swift: simple_identifier, TS: property_identifier)
909
+ let found = false;
910
+ for (let i = 0; i < node.namedChildCount; i++) {
911
+ const child = node.namedChild(i);
912
+ if (child && (child.type === 'simple_identifier' || child.type === 'identifier' || child.type === 'property_identifier')) {
913
+ this.createNode('enum_member', (0, tree_sitter_helpers_1.getNodeText)(child, this.source), child);
914
+ found = true;
915
+ }
916
+ }
917
+ // If the node itself IS the identifier (e.g. TS property_identifier directly in enum body)
918
+ if (!found && node.namedChildCount === 0) {
919
+ this.createNode('enum_member', (0, tree_sitter_helpers_1.getNodeText)(node, this.source), node);
920
+ }
921
+ }
922
+ /**
923
+ * Extract a class property declaration (e.g. C# `public string Name { get; set; }`).
924
+ * Extracts as 'property' kind node inside the owning class.
925
+ */
926
+ extractProperty(node) {
927
+ if (!this.extractor)
928
+ return;
929
+ const docstring = (0, tree_sitter_helpers_1.getPrecedingDocstring)(node, this.source);
930
+ const visibility = this.extractor.getVisibility?.(node);
931
+ const isStatic = this.extractor.isStatic?.(node) ?? false;
932
+ const hookName = this.extractor.extractPropertyName?.(node, this.source);
933
+ const nameNode = hookName
934
+ ? null
935
+ : (0, tree_sitter_helpers_1.getChildByField)(node, 'name') || node.namedChildren.find(c => c.type === 'identifier');
936
+ const name = hookName ?? (nameNode ? (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source) : null);
937
+ if (!name)
938
+ return;
939
+ // Get property type from the type child (first named child that isn't modifier or identifier)
940
+ const typeNode = node.namedChildren.find(c => c.type !== 'modifier' && c.type !== 'modifiers'
941
+ && c.type !== 'identifier' && c.type !== 'accessor_list'
942
+ && c.type !== 'accessors' && c.type !== 'equals_value_clause');
943
+ const typeText = typeNode ? (0, tree_sitter_helpers_1.getNodeText)(typeNode, this.source) : undefined;
944
+ const signature = typeText ? `${typeText} ${name}` : name;
945
+ const propNode = this.createNode('property', name, node, {
946
+ docstring,
947
+ signature,
948
+ visibility,
949
+ isStatic,
950
+ });
951
+ // `@Inject() private svc: Foo` and similar — capture the
952
+ // decorator->target relationship for class properties too.
953
+ if (propNode) {
954
+ this.extractDecoratorsFor(node, propNode.id);
955
+ // Emit `references` edges from the property to types named in its
956
+ // type annotation (#381). The generic walker handles TS-style
957
+ // `type_annotation` children; the C# branch walks the `type` field.
958
+ this.extractTypeAnnotations(node, propNode.id);
959
+ }
960
+ }
961
+ /**
962
+ * Extract a class field declaration (e.g. Java field_declaration, C# field_declaration).
963
+ * Extracts each declarator as a 'field' kind node inside the owning class.
964
+ */
965
+ extractField(node) {
966
+ if (!this.extractor)
967
+ return;
968
+ const docstring = (0, tree_sitter_helpers_1.getPrecedingDocstring)(node, this.source);
969
+ const visibility = this.extractor.getVisibility?.(node);
970
+ const isStatic = this.extractor.isStatic?.(node) ?? false;
971
+ // Java field_declaration: "private final String name = value;" → variable_declarator(s) are direct children
972
+ // C# field_declaration: wraps in variable_declaration → variable_declarator(s)
973
+ let declarators = node.namedChildren.filter(c => c.type === 'variable_declarator');
974
+ // C#: look inside variable_declaration wrapper
975
+ if (declarators.length === 0) {
976
+ const varDecl = node.namedChildren.find(c => c.type === 'variable_declaration');
977
+ if (varDecl) {
978
+ declarators = varDecl.namedChildren.filter(c => c.type === 'variable_declarator');
979
+ }
980
+ }
981
+ // PHP property_declaration: property_element → variable_name → name
982
+ if (declarators.length === 0) {
983
+ const propElements = node.namedChildren.filter(c => c.type === 'property_element');
984
+ if (propElements.length > 0) {
985
+ // Get type annotation if present (e.g. "string", "int", "?Foo")
986
+ const typeNode = node.namedChildren.find(c => c.type !== 'visibility_modifier' && c.type !== 'static_modifier'
987
+ && c.type !== 'readonly_modifier' && c.type !== 'property_element'
988
+ && c.type !== 'var_modifier');
989
+ const typeText = typeNode ? (0, tree_sitter_helpers_1.getNodeText)(typeNode, this.source) : undefined;
990
+ for (const elem of propElements) {
991
+ const varName = elem.namedChildren.find(c => c.type === 'variable_name');
992
+ const nameNode = varName?.namedChildren.find(c => c.type === 'name');
993
+ if (!nameNode)
994
+ continue;
995
+ const name = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
996
+ const signature = typeText ? `${typeText} $${name}` : `$${name}`;
997
+ this.createNode('field', name, elem, {
998
+ docstring,
999
+ signature,
1000
+ visibility,
1001
+ isStatic,
1002
+ });
1003
+ }
1004
+ return;
1005
+ }
1006
+ }
1007
+ if (declarators.length > 0) {
1008
+ // Get field type from the type child
1009
+ // Java: type is a direct child of field_declaration
1010
+ // C#: type is inside variable_declaration wrapper
1011
+ const varDecl = node.namedChildren.find(c => c.type === 'variable_declaration');
1012
+ const typeSearchNode = varDecl ?? node;
1013
+ const typeNode = typeSearchNode.namedChildren.find(c => c.type !== 'modifiers' && c.type !== 'modifier' && c.type !== 'variable_declarator'
1014
+ && c.type !== 'variable_declaration' && c.type !== 'marker_annotation' && c.type !== 'annotation');
1015
+ const typeText = typeNode ? (0, tree_sitter_helpers_1.getNodeText)(typeNode, this.source) : undefined;
1016
+ for (const decl of declarators) {
1017
+ const nameNode = (0, tree_sitter_helpers_1.getChildByField)(decl, 'name')
1018
+ || decl.namedChildren.find(c => c.type === 'identifier');
1019
+ if (!nameNode)
1020
+ continue;
1021
+ const name = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
1022
+ const signature = typeText ? `${typeText} ${name}` : name;
1023
+ const fieldNode = this.createNode('field', name, decl, {
1024
+ docstring,
1025
+ signature,
1026
+ visibility,
1027
+ isStatic,
1028
+ });
1029
+ // Java/Kotlin annotations / TS field decorators sit on the
1030
+ // outer field_declaration, not on the individual declarator.
1031
+ if (fieldNode) {
1032
+ this.extractDecoratorsFor(node, fieldNode.id);
1033
+ // Same as properties: emit `references` to the field's annotated
1034
+ // type. The outer `field_declaration` is the right scope to
1035
+ // search from — C# carries the `type` inside `variable_declaration`
1036
+ // and the language-aware path in `extractTypeAnnotations` descends
1037
+ // into that wrapper (#381).
1038
+ this.extractTypeAnnotations(node, fieldNode.id);
1039
+ }
1040
+ }
1041
+ }
1042
+ else {
1043
+ // Fallback: try to find an identifier child directly
1044
+ const nameNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'name')
1045
+ || node.namedChildren.find(c => c.type === 'identifier');
1046
+ if (nameNode) {
1047
+ const name = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
1048
+ this.createNode('field', name, node, {
1049
+ docstring,
1050
+ visibility,
1051
+ isStatic,
1052
+ });
1053
+ }
1054
+ }
1055
+ }
1056
+ /**
1057
+ * Extract function-valued properties of an object literal as named function
1058
+ * nodes (named by their property key). Shared by the two object-of-functions
1059
+ * shapes in extractVariable: the object as a direct const value, and the
1060
+ * object returned by a store-initializer call. Handles both `key: () => {}` /
1061
+ * `key: function() {}` pairs and method shorthand `key() {}`.
1062
+ */
1063
+ extractObjectLiteralFunctions(obj) {
1064
+ for (let i = 0; i < obj.namedChildCount; i++) {
1065
+ const member = obj.namedChild(i);
1066
+ if (!member)
1067
+ continue;
1068
+ if (member.type === 'pair') {
1069
+ const key = (0, tree_sitter_helpers_1.getChildByField)(member, 'key');
1070
+ const value = (0, tree_sitter_helpers_1.getChildByField)(member, 'value');
1071
+ if (key && value && (value.type === 'arrow_function' || value.type === 'function_expression')) {
1072
+ this.extractFunction(value, this.objectKeyName(key));
1073
+ }
1074
+ }
1075
+ else if (member.type === 'method_definition') {
1076
+ // Method shorthand: `{ fetchUser() {...} }`. extractMethod deliberately
1077
+ // skips object-literal methods, so route through extractFunction with an
1078
+ // explicit name (method_definition exposes a `body` field, so resolveBody
1079
+ // falls through to it and the node spans the full method).
1080
+ const key = (0, tree_sitter_helpers_1.getChildByField)(member, 'name');
1081
+ if (key)
1082
+ this.extractFunction(member, this.objectKeyName(key));
1083
+ }
1084
+ }
1085
+ }
1086
+ /** Property-key text with surrounding quotes stripped (`'foo'` → `foo`). */
1087
+ objectKeyName(key) {
1088
+ return (0, tree_sitter_helpers_1.getNodeText)(key, this.source).replace(/^['"`]|['"`]$/g, '');
1089
+ }
1090
+ /**
1091
+ * Given a `call_expression` initializer (`create((set, get) => ({...}))`),
1092
+ * find the object literal RETURNED by a function argument — descending through
1093
+ * nested call_expression arguments so middleware wrappers are unwrapped
1094
+ * (`create(persist((set, get) => ({...}), {...}))`, devtools, immer,
1095
+ * subscribeWithSelector). Returns null when no such object is found — the
1096
+ * common case for ordinary call initializers — so this stays cheap and silent
1097
+ * rather than guessing. Keyed purely on AST shape; no library names.
1098
+ */
1099
+ findInitializerReturnedObject(callNode, depth = 0) {
1100
+ if (depth > 4)
1101
+ return null;
1102
+ const args = (0, tree_sitter_helpers_1.getChildByField)(callNode, 'arguments');
1103
+ if (!args)
1104
+ return null;
1105
+ for (let i = 0; i < args.namedChildCount; i++) {
1106
+ const arg = args.namedChild(i);
1107
+ if (!arg)
1108
+ continue;
1109
+ if (arg.type === 'arrow_function' || arg.type === 'function_expression') {
1110
+ const obj = this.functionReturnedObject(arg);
1111
+ if (obj)
1112
+ return obj;
1113
+ }
1114
+ else if (arg.type === 'call_expression') {
1115
+ const obj = this.findInitializerReturnedObject(arg, depth + 1);
1116
+ if (obj)
1117
+ return obj;
1118
+ }
1119
+ }
1120
+ return null;
1121
+ }
1122
+ /**
1123
+ * The object literal a function expression returns — either the `=> ({...})`
1124
+ * arrow form (a parenthesized_expression wrapping an object) or a
1125
+ * `=> { return {...} }` block. Returns null for any other body shape.
1126
+ */
1127
+ functionReturnedObject(fnNode) {
1128
+ const body = (0, tree_sitter_helpers_1.getChildByField)(fnNode, 'body');
1129
+ if (!body)
1130
+ return null;
1131
+ const asObject = (n) => {
1132
+ if (!n)
1133
+ return null;
1134
+ if (n.type === 'object' || n.type === 'object_expression')
1135
+ return n;
1136
+ if (n.type === 'parenthesized_expression') {
1137
+ for (let i = 0; i < n.namedChildCount; i++) {
1138
+ const inner = asObject(n.namedChild(i));
1139
+ if (inner)
1140
+ return inner;
1141
+ }
1142
+ }
1143
+ return null;
1144
+ };
1145
+ // `(set, get) => ({...})` — body is the (parenthesized) object directly.
1146
+ const direct = asObject(body);
1147
+ if (direct)
1148
+ return direct;
1149
+ // `(set, get) => { return {...} }` — scan top-level return statements.
1150
+ if (body.type === 'statement_block') {
1151
+ for (let i = 0; i < body.namedChildCount; i++) {
1152
+ const stmt = body.namedChild(i);
1153
+ if (stmt?.type !== 'return_statement')
1154
+ continue;
1155
+ for (let j = 0; j < stmt.namedChildCount; j++) {
1156
+ const obj = asObject(stmt.namedChild(j));
1157
+ if (obj)
1158
+ return obj;
1159
+ }
1160
+ }
1161
+ }
1162
+ return null;
1163
+ }
1164
+ /**
1165
+ * Extract a variable declaration (const, let, var, etc.)
1166
+ *
1167
+ * Extracts top-level and module-level variable declarations.
1168
+ * Captures the variable name and first 100 chars of initializer in signature for searchability.
1169
+ */
1170
+ extractVariable(node) {
1171
+ if (!this.extractor)
1172
+ return;
1173
+ // Different languages have different variable declaration structures
1174
+ // TypeScript/JavaScript: lexical_declaration contains variable_declarator children
1175
+ // Python: assignment has left (identifier) and right (value)
1176
+ // Go: var_declaration, short_var_declaration, const_declaration
1177
+ const isConst = this.extractor.isConst?.(node) ?? false;
1178
+ const kind = isConst ? 'constant' : 'variable';
1179
+ const docstring = (0, tree_sitter_helpers_1.getPrecedingDocstring)(node, this.source);
1180
+ const isExported = this.extractor.isExported?.(node, this.source) ?? false;
1181
+ // Extract variable declarators based on language
1182
+ if (this.language === 'typescript' || this.language === 'javascript' ||
1183
+ this.language === 'tsx' || this.language === 'jsx') {
1184
+ // Handle lexical_declaration and variable_declaration
1185
+ // These contain one or more variable_declarator children
1186
+ for (let i = 0; i < node.namedChildCount; i++) {
1187
+ const child = node.namedChild(i);
1188
+ if (child?.type === 'variable_declarator') {
1189
+ const nameNode = (0, tree_sitter_helpers_1.getChildByField)(child, 'name');
1190
+ const valueNode = (0, tree_sitter_helpers_1.getChildByField)(child, 'value');
1191
+ if (nameNode) {
1192
+ // Skip destructured patterns (e.g., `let { x, y } = $props()` in Svelte)
1193
+ // These produce ugly multi-line names like "{ class: className }"
1194
+ if (nameNode.type === 'object_pattern' || nameNode.type === 'array_pattern') {
1195
+ continue;
1196
+ }
1197
+ const name = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
1198
+ // Arrow functions / function expressions: extract as function instead of variable
1199
+ if (valueNode && (valueNode.type === 'arrow_function' || valueNode.type === 'function_expression')) {
1200
+ this.extractFunction(valueNode);
1201
+ continue;
1202
+ }
1203
+ // Capture first 100 chars of initializer for context (stored in signature for searchability)
1204
+ const initValue = valueNode ? (0, tree_sitter_helpers_1.getNodeText)(valueNode, this.source).slice(0, 100) : undefined;
1205
+ const initSignature = initValue ? `= ${initValue}${initValue.length >= 100 ? '...' : ''}` : undefined;
1206
+ const varNode = this.createNode(kind, name, child, {
1207
+ docstring,
1208
+ signature: initSignature,
1209
+ isExported,
1210
+ });
1211
+ // Extract type annotation references (e.g., const x: ITextModel = ...)
1212
+ if (varNode) {
1213
+ this.extractVariableTypeAnnotation(child, varNode.id);
1214
+ }
1215
+ // Exported const object-of-functions — extract each function-valued
1216
+ // property as a function named by its key + walk its body so its
1217
+ // calls are captured. Two shapes, both keyed on AST shape (not on any
1218
+ // library name):
1219
+ // `export const actions = { default: async () => {} }` — object is
1220
+ // the DIRECT value (SvelteKit form actions / handler maps / route
1221
+ // tables).
1222
+ // `export const useStore = create((set, get) => ({ fetchUser:
1223
+ // async () => {} }))` — object is RETURNED by an initializer call,
1224
+ // possibly through middleware wrappers (persist/devtools/immer).
1225
+ // Covers Zustand/Redux/Pinia/MobX stores generically. Without
1226
+ // this, store actions exist only as object-literal properties —
1227
+ // never nodes — so `node`/`callers` on `fetchUser` return "not
1228
+ // found" and the agent Reads the store to reconstruct the flow.
1229
+ // Scoped to EXPORTED consts to exclude inline-object noise
1230
+ // (`ctx.set({...})`) the object-method skip deliberately avoids.
1231
+ const objectOfFns = valueNode && (valueNode.type === 'object' || valueNode.type === 'object_expression')
1232
+ ? valueNode
1233
+ : valueNode?.type === 'call_expression'
1234
+ ? this.findInitializerReturnedObject(valueNode)
1235
+ : null;
1236
+ const extractObjectMethods = isExported && !!objectOfFns;
1237
+ // Visit the initializer body for calls — EXCEPT object literals (their
1238
+ // function-valued properties are extracted below) and the store-factory
1239
+ // call whose returned object we extract method-by-method below (walking
1240
+ // the whole call would re-visit those method arrows and mis-attribute
1241
+ // their inner calls to the file/module scope).
1242
+ if (valueNode &&
1243
+ valueNode.type !== 'object' &&
1244
+ valueNode.type !== 'object_expression' &&
1245
+ !(extractObjectMethods && valueNode.type === 'call_expression')) {
1246
+ this.visitFunctionBody(valueNode, '');
1247
+ }
1248
+ if (extractObjectMethods && objectOfFns) {
1249
+ this.extractObjectLiteralFunctions(objectOfFns);
1250
+ }
1251
+ }
1252
+ }
1253
+ }
1254
+ }
1255
+ else if (this.language === 'python' || this.language === 'ruby') {
1256
+ // Python/Ruby assignment: left = right
1257
+ const left = (0, tree_sitter_helpers_1.getChildByField)(node, 'left') || node.namedChild(0);
1258
+ const right = (0, tree_sitter_helpers_1.getChildByField)(node, 'right') || node.namedChild(1);
1259
+ if (left && left.type === 'identifier') {
1260
+ const name = (0, tree_sitter_helpers_1.getNodeText)(left, this.source);
1261
+ // Skip if name starts with lowercase and looks like a function call result
1262
+ // Python constants are usually UPPER_CASE
1263
+ const initValue = right ? (0, tree_sitter_helpers_1.getNodeText)(right, this.source).slice(0, 100) : undefined;
1264
+ const initSignature = initValue ? `= ${initValue}${initValue.length >= 100 ? '...' : ''}` : undefined;
1265
+ this.createNode(kind, name, node, {
1266
+ docstring,
1267
+ signature: initSignature,
1268
+ });
1269
+ }
1270
+ }
1271
+ else if (this.language === 'go') {
1272
+ // Go: var_declaration, short_var_declaration, const_declaration
1273
+ // These can have multiple identifiers on the left
1274
+ const specs = node.namedChildren.filter(c => c.type === 'var_spec' || c.type === 'const_spec');
1275
+ for (const spec of specs) {
1276
+ const nameNode = spec.namedChild(0);
1277
+ if (nameNode && nameNode.type === 'identifier') {
1278
+ const name = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
1279
+ const valueNode = spec.namedChildCount > 1 ? spec.namedChild(spec.namedChildCount - 1) : null;
1280
+ const initValue = valueNode ? (0, tree_sitter_helpers_1.getNodeText)(valueNode, this.source).slice(0, 100) : undefined;
1281
+ const initSignature = initValue ? `= ${initValue}${initValue.length >= 100 ? '...' : ''}` : undefined;
1282
+ this.createNode(node.type === 'const_declaration' ? 'constant' : 'variable', name, spec, {
1283
+ docstring,
1284
+ signature: initSignature,
1285
+ });
1286
+ }
1287
+ }
1288
+ // Handle short_var_declaration (:=)
1289
+ if (node.type === 'short_var_declaration') {
1290
+ const left = (0, tree_sitter_helpers_1.getChildByField)(node, 'left');
1291
+ const right = (0, tree_sitter_helpers_1.getChildByField)(node, 'right');
1292
+ if (left) {
1293
+ // Can be expression_list with multiple identifiers
1294
+ const identifiers = left.type === 'expression_list'
1295
+ ? left.namedChildren.filter(c => c.type === 'identifier')
1296
+ : [left];
1297
+ for (const id of identifiers) {
1298
+ const name = (0, tree_sitter_helpers_1.getNodeText)(id, this.source);
1299
+ const initValue = right ? (0, tree_sitter_helpers_1.getNodeText)(right, this.source).slice(0, 100) : undefined;
1300
+ const initSignature = initValue ? `= ${initValue}${initValue.length >= 100 ? '...' : ''}` : undefined;
1301
+ this.createNode('variable', name, node, {
1302
+ docstring,
1303
+ signature: initSignature,
1304
+ });
1305
+ }
1306
+ }
1307
+ }
1308
+ }
1309
+ else if (this.language === 'lua' || this.language === 'luau') {
1310
+ // Lua/Luau: variable_declaration → assignment_statement → variable_list
1311
+ // (name: identifier...) = expression_list. `local x, y = 1, 2`
1312
+ // declares multiple names; only plain identifiers are locals.
1313
+ const assign = node.namedChildren.find((c) => c.type === 'assignment_statement') ?? node;
1314
+ const varList = assign.namedChildren.find((c) => c.type === 'variable_list');
1315
+ const exprList = assign.namedChildren.find((c) => c.type === 'expression_list');
1316
+ const values = exprList ? exprList.namedChildren : [];
1317
+ const names = varList ? varList.namedChildren.filter((c) => c.type === 'identifier') : [];
1318
+ names.forEach((nameNode, i) => {
1319
+ const name = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
1320
+ if (!name)
1321
+ return;
1322
+ const valueNode = values[i];
1323
+ const initValue = valueNode ? (0, tree_sitter_helpers_1.getNodeText)(valueNode, this.source).slice(0, 100) : undefined;
1324
+ const initSignature = initValue ? `= ${initValue}${initValue.length >= 100 ? '...' : ''}` : undefined;
1325
+ this.createNode(kind, name, nameNode, { docstring, signature: initSignature, isExported });
1326
+ });
1327
+ }
1328
+ else {
1329
+ // Generic fallback for other languages
1330
+ // Try to find identifier children
1331
+ for (let i = 0; i < node.namedChildCount; i++) {
1332
+ const child = node.namedChild(i);
1333
+ if (child?.type === 'identifier' || child?.type === 'variable_declarator') {
1334
+ const name = child.type === 'identifier'
1335
+ ? (0, tree_sitter_helpers_1.getNodeText)(child, this.source)
1336
+ : extractName(child, this.source, this.extractor);
1337
+ if (name && name !== '<anonymous>') {
1338
+ this.createNode(kind, name, child, {
1339
+ docstring,
1340
+ isExported,
1341
+ });
1342
+ }
1343
+ }
1344
+ }
1345
+ }
1346
+ }
1347
+ /**
1348
+ * Extract a type alias (e.g. `export type X = ...` in TypeScript).
1349
+ * For languages like Go, resolveTypeAliasKind detects when the type_spec
1350
+ * wraps a struct or interface definition and creates the correct node kind.
1351
+ * Returns true if children should be skipped (struct/interface handled body visiting).
1352
+ */
1353
+ extractTypeAlias(node) {
1354
+ if (!this.extractor)
1355
+ return false;
1356
+ const name = extractName(node, this.source, this.extractor);
1357
+ if (name === '<anonymous>')
1358
+ return false;
1359
+ const docstring = (0, tree_sitter_helpers_1.getPrecedingDocstring)(node, this.source);
1360
+ const isExported = this.extractor.isExported?.(node, this.source);
1361
+ // Check if this type alias is actually a struct or interface definition
1362
+ // (e.g. Go: `type Foo struct { ... }` is a type_spec wrapping struct_type)
1363
+ const resolvedKind = this.extractor.resolveTypeAliasKind?.(node, this.source);
1364
+ if (resolvedKind === 'struct') {
1365
+ const structNode = this.createNode('struct', name, node, { docstring, isExported });
1366
+ if (!structNode)
1367
+ return true;
1368
+ // Visit body children for field extraction
1369
+ this.nodeStack.push(structNode.id);
1370
+ // Try Go-style 'type' field first, then find inner struct child (C typedef struct)
1371
+ const typeChild = (0, tree_sitter_helpers_1.getChildByField)(node, 'type')
1372
+ || this.findChildByTypes(node, this.extractor.structTypes);
1373
+ if (typeChild) {
1374
+ // Extract struct embedding (e.g. Go: `type DB struct { *Head; Queryable }`)
1375
+ this.extractInheritance(typeChild, structNode.id);
1376
+ const body = (0, tree_sitter_helpers_1.getChildByField)(typeChild, this.extractor.bodyField) || typeChild;
1377
+ for (let i = 0; i < body.namedChildCount; i++) {
1378
+ const child = body.namedChild(i);
1379
+ if (child)
1380
+ this.visitNode(child);
1381
+ }
1382
+ }
1383
+ this.nodeStack.pop();
1384
+ return true;
1385
+ }
1386
+ if (resolvedKind === 'enum') {
1387
+ const enumNode = this.createNode('enum', name, node, { docstring, isExported });
1388
+ if (!enumNode)
1389
+ return true;
1390
+ this.nodeStack.push(enumNode.id);
1391
+ // Find the inner enum type child (e.g. C: typedef enum { ... } name)
1392
+ const innerEnum = this.findChildByTypes(node, this.extractor.enumTypes);
1393
+ if (innerEnum) {
1394
+ this.extractInheritance(innerEnum, enumNode.id);
1395
+ const body = this.extractor.resolveBody?.(innerEnum, this.extractor.bodyField)
1396
+ ?? (0, tree_sitter_helpers_1.getChildByField)(innerEnum, this.extractor.bodyField);
1397
+ if (body) {
1398
+ const memberTypes = this.extractor.enumMemberTypes;
1399
+ for (let i = 0; i < body.namedChildCount; i++) {
1400
+ const child = body.namedChild(i);
1401
+ if (!child)
1402
+ continue;
1403
+ if (memberTypes?.includes(child.type)) {
1404
+ this.extractEnumMembers(child);
1405
+ }
1406
+ else {
1407
+ this.visitNode(child);
1408
+ }
1409
+ }
1410
+ }
1411
+ }
1412
+ this.nodeStack.pop();
1413
+ return true;
1414
+ }
1415
+ if (resolvedKind === 'interface') {
1416
+ const kind = this.extractor.interfaceKind ?? 'interface';
1417
+ const interfaceNode = this.createNode(kind, name, node, { docstring, isExported });
1418
+ if (!interfaceNode)
1419
+ return true;
1420
+ // Extract interface inheritance from the inner type node
1421
+ const typeChild = (0, tree_sitter_helpers_1.getChildByField)(node, 'type');
1422
+ if (typeChild)
1423
+ this.extractInheritance(typeChild, interfaceNode.id);
1424
+ return true;
1425
+ }
1426
+ const typeAliasNode = this.createNode('type_alias', name, node, {
1427
+ docstring,
1428
+ isExported,
1429
+ });
1430
+ // Extract type references from the alias value (e.g., `type X = ITextModel | null`)
1431
+ if (typeAliasNode && this.TYPE_ANNOTATION_LANGUAGES.has(this.language)) {
1432
+ // The value is everything after the `=`, which is typically the last named child
1433
+ // In tree-sitter TS: type_alias_declaration has name + value children
1434
+ const value = (0, tree_sitter_helpers_1.getChildByField)(node, 'value');
1435
+ if (value) {
1436
+ this.extractTypeRefsFromSubtree(value, typeAliasNode.id);
1437
+ // `type X = { foo: T; bar(): T }` — make the members first-class
1438
+ // property/method nodes under the type alias so `recorder.stop()`
1439
+ // can attach the call edge to `RecorderHandle.stop` instead of
1440
+ // an unrelated class method picked by path-proximity (#359).
1441
+ if (this.language === 'typescript' || this.language === 'tsx') {
1442
+ this.extractTsTypeAliasMembers(value, typeAliasNode);
1443
+ }
1444
+ }
1445
+ }
1446
+ return false;
1447
+ }
1448
+ /**
1449
+ * Surface the members of a TypeScript `type X = { ... }` (or intersection
1450
+ * thereof) as `property` / `method` nodes under the type-alias node. Only
1451
+ * walks the immediate object_type / intersection operands so anonymous
1452
+ * nested object types inside generic arguments (`Promise<{ ok: true }>`)
1453
+ * don't produce phantom members.
1454
+ */
1455
+ extractTsTypeAliasMembers(value, typeAliasNode) {
1456
+ const objectTypes = [];
1457
+ if (value.type === 'object_type') {
1458
+ objectTypes.push(value);
1459
+ }
1460
+ else if (value.type === 'intersection_type') {
1461
+ for (let i = 0; i < value.namedChildCount; i++) {
1462
+ const op = value.namedChild(i);
1463
+ if (op && op.type === 'object_type')
1464
+ objectTypes.push(op);
1465
+ }
1466
+ }
1467
+ else {
1468
+ return;
1469
+ }
1470
+ this.nodeStack.push(typeAliasNode.id);
1471
+ for (const objType of objectTypes) {
1472
+ for (let i = 0; i < objType.namedChildCount; i++) {
1473
+ const child = objType.namedChild(i);
1474
+ if (!child)
1475
+ continue;
1476
+ if (child.type !== 'property_signature' && child.type !== 'method_signature')
1477
+ continue;
1478
+ const nameNode = (0, tree_sitter_helpers_1.getChildByField)(child, 'name');
1479
+ const memberName = nameNode ? (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source) : '';
1480
+ if (!memberName)
1481
+ continue;
1482
+ // `foo: () => T` and `foo(): T` are functionally a method on the
1483
+ // type contract. Treat the property_signature with a function-typed
1484
+ // annotation as a method too so call sites can resolve to it.
1485
+ const memberKind = child.type === 'method_signature'
1486
+ ? 'method'
1487
+ : this.isTsFunctionTypedProperty(child) ? 'method' : 'property';
1488
+ const docstring = (0, tree_sitter_helpers_1.getPrecedingDocstring)(child, this.source);
1489
+ const signature = (0, tree_sitter_helpers_1.getNodeText)(child, this.source);
1490
+ this.createNode(memberKind, memberName, child, {
1491
+ docstring,
1492
+ signature,
1493
+ qualifiedName: `${typeAliasNode.name}::${memberName}`,
1494
+ });
1495
+ // Emit `references` edges from the type alias to types named in the
1496
+ // member's signature, matching the interface-member behavior added in
1497
+ // #432. We attach refs to the type-alias parent (consistent with
1498
+ // interface property_signature treatment).
1499
+ this.extractTypeAnnotations(child, typeAliasNode.id);
1500
+ }
1501
+ }
1502
+ this.nodeStack.pop();
1503
+ }
1504
+ /**
1505
+ * `foo: () => T` → property_signature whose type_annotation contains a
1506
+ * `function_type`. Treat that as a method-shaped contract member, since
1507
+ * the call site `obj.foo()` has identical semantics to `bar(): T`.
1508
+ */
1509
+ isTsFunctionTypedProperty(propertySignature) {
1510
+ const typeAnno = (0, tree_sitter_helpers_1.getChildByField)(propertySignature, 'type');
1511
+ if (!typeAnno)
1512
+ return false;
1513
+ for (let i = 0; i < typeAnno.namedChildCount; i++) {
1514
+ const inner = typeAnno.namedChild(i);
1515
+ if (inner && inner.type === 'function_type')
1516
+ return true;
1517
+ }
1518
+ return false;
1519
+ }
1520
+ // extractExportedVariables removed — the walker now descends into
1521
+ // export_statement children and the inner declaration's dedicated
1522
+ // extractor (extractVariable, extractFunction, extractClass, etc.)
1523
+ // handles the symbol with isExported=true via parent-walk in the
1524
+ // language extractor's isExported predicate.
1525
+ /**
1526
+ * Extract an import
1527
+ *
1528
+ * Creates an import node with the full import statement stored in signature for searchability.
1529
+ * Also creates unresolved references for resolution purposes.
1530
+ */
1531
+ extractImport(node) {
1532
+ if (!this.extractor)
1533
+ return;
1534
+ const importText = (0, tree_sitter_helpers_1.getNodeText)(node, this.source).trim();
1535
+ // Try language-specific hook first
1536
+ if (this.extractor.extractImport) {
1537
+ const info = this.extractor.extractImport(node, this.source);
1538
+ if (info) {
1539
+ this.createNode('import', info.moduleName, node, {
1540
+ signature: info.signature,
1541
+ });
1542
+ // Create unresolved reference unless the hook handled it
1543
+ if (!info.handledRefs && info.moduleName && this.nodeStack.length > 0) {
1544
+ const parentId = this.nodeStack[this.nodeStack.length - 1];
1545
+ if (parentId) {
1546
+ this.unresolvedReferences.push({
1547
+ fromNodeId: parentId,
1548
+ referenceName: info.moduleName,
1549
+ referenceKind: 'imports',
1550
+ line: node.startPosition.row + 1,
1551
+ column: node.startPosition.column,
1552
+ });
1553
+ }
1554
+ }
1555
+ return;
1556
+ }
1557
+ // Hook returned null — fall through to multi-import inline handlers only
1558
+ // (hook returning null means "I didn't handle this" for multi-import cases,
1559
+ // NOT "use generic fallback" — the hook already declined)
1560
+ }
1561
+ // Multi-import cases that create multiple nodes (can't be expressed with single-return hook)
1562
+ // Python import_statement: import os, sys (creates one import per module)
1563
+ if (this.language === 'python' && node.type === 'import_statement') {
1564
+ for (let i = 0; i < node.namedChildCount; i++) {
1565
+ const child = node.namedChild(i);
1566
+ if (child?.type === 'dotted_name') {
1567
+ this.createNode('import', (0, tree_sitter_helpers_1.getNodeText)(child, this.source), node, {
1568
+ signature: importText,
1569
+ });
1570
+ }
1571
+ else if (child?.type === 'aliased_import') {
1572
+ const dottedName = child.namedChildren.find(c => c.type === 'dotted_name');
1573
+ if (dottedName) {
1574
+ this.createNode('import', (0, tree_sitter_helpers_1.getNodeText)(dottedName, this.source), node, {
1575
+ signature: importText,
1576
+ });
1577
+ }
1578
+ }
1579
+ }
1580
+ return;
1581
+ }
1582
+ // Go imports: single or grouped (creates one import per spec)
1583
+ if (this.language === 'go') {
1584
+ const parentId = this.nodeStack.length > 0 ? this.nodeStack[this.nodeStack.length - 1] : null;
1585
+ const extractFromSpec = (spec) => {
1586
+ const stringLiteral = spec.namedChildren.find(c => c.type === 'interpreted_string_literal');
1587
+ if (stringLiteral) {
1588
+ const importPath = (0, tree_sitter_helpers_1.getNodeText)(stringLiteral, this.source).replace(/['"]/g, '');
1589
+ if (importPath) {
1590
+ this.createNode('import', importPath, spec, {
1591
+ signature: (0, tree_sitter_helpers_1.getNodeText)(spec, this.source).trim(),
1592
+ });
1593
+ // Create unresolved reference so the resolver can create imports edges
1594
+ if (parentId) {
1595
+ this.unresolvedReferences.push({
1596
+ fromNodeId: parentId,
1597
+ referenceName: importPath,
1598
+ referenceKind: 'imports',
1599
+ line: spec.startPosition.row + 1,
1600
+ column: spec.startPosition.column,
1601
+ });
1602
+ }
1603
+ }
1604
+ }
1605
+ };
1606
+ const importSpecList = node.namedChildren.find(c => c.type === 'import_spec_list');
1607
+ if (importSpecList) {
1608
+ for (const spec of importSpecList.namedChildren.filter(c => c.type === 'import_spec')) {
1609
+ extractFromSpec(spec);
1610
+ }
1611
+ }
1612
+ else {
1613
+ const importSpec = node.namedChildren.find(c => c.type === 'import_spec');
1614
+ if (importSpec) {
1615
+ extractFromSpec(importSpec);
1616
+ }
1617
+ }
1618
+ return;
1619
+ }
1620
+ // PHP grouped imports: use X\{A, B} (creates one import per item)
1621
+ if (this.language === 'php') {
1622
+ const namespacePrefix = node.namedChildren.find(c => c.type === 'namespace_name');
1623
+ const useGroup = node.namedChildren.find(c => c.type === 'namespace_use_group');
1624
+ if (namespacePrefix && useGroup) {
1625
+ const prefix = (0, tree_sitter_helpers_1.getNodeText)(namespacePrefix, this.source);
1626
+ const useClauses = useGroup.namedChildren.filter((c) => c.type === 'namespace_use_group_clause' || c.type === 'namespace_use_clause');
1627
+ for (const clause of useClauses) {
1628
+ const nsName = clause.namedChildren.find((c) => c.type === 'namespace_name');
1629
+ const name = nsName
1630
+ ? nsName.namedChildren.find((c) => c.type === 'name')
1631
+ : clause.namedChildren.find((c) => c.type === 'name');
1632
+ if (name) {
1633
+ const fullPath = `${prefix}\\${(0, tree_sitter_helpers_1.getNodeText)(name, this.source)}`;
1634
+ this.createNode('import', fullPath, node, {
1635
+ signature: importText,
1636
+ });
1637
+ }
1638
+ }
1639
+ return;
1640
+ }
1641
+ }
1642
+ // If a hook exists but returned null, it intentionally declined this node — don't create fallback
1643
+ if (this.extractor.extractImport)
1644
+ return;
1645
+ // Generic fallback for languages without hooks
1646
+ this.createNode('import', importText, node, {
1647
+ signature: importText,
1648
+ });
1649
+ }
1650
+ /**
1651
+ * Extract a function call
1652
+ */
1653
+ extractCall(node) {
1654
+ if (this.nodeStack.length === 0)
1655
+ return;
1656
+ const callerId = this.nodeStack[this.nodeStack.length - 1];
1657
+ if (!callerId)
1658
+ return;
1659
+ // Get the function/method being called
1660
+ let calleeName = '';
1661
+ // Java/Kotlin method_invocation has 'object' + 'name' fields instead of 'function'
1662
+ // PHP member_call_expression has 'object' + 'name', scoped_call_expression has 'scope' + 'name'
1663
+ const nameField = (0, tree_sitter_helpers_1.getChildByField)(node, 'name');
1664
+ const objectField = (0, tree_sitter_helpers_1.getChildByField)(node, 'object') || (0, tree_sitter_helpers_1.getChildByField)(node, 'scope');
1665
+ if (nameField && objectField && (node.type === 'method_invocation' || node.type === 'member_call_expression' || node.type === 'scoped_call_expression')) {
1666
+ // Method call with explicit receiver: receiver.method() / $receiver->method() / ClassName::method()
1667
+ const methodName = (0, tree_sitter_helpers_1.getNodeText)(nameField, this.source);
1668
+ // Java `this.userbo.toLogin2()` parses as method_invocation(object=field_access(this, userbo)).
1669
+ // Without unwrapping, receiverName is `this.userbo` and the name-matcher's
1670
+ // single-dot receiver regex fails. Pull out the immediate field after `this.`
1671
+ // so the receiver is the field name (`userbo`), which the resolver can then
1672
+ // look up in the enclosing class's field declarations.
1673
+ let receiverName;
1674
+ if (objectField.type === 'field_access') {
1675
+ const inner = (0, tree_sitter_helpers_1.getChildByField)(objectField, 'object');
1676
+ const fld = (0, tree_sitter_helpers_1.getChildByField)(objectField, 'field');
1677
+ if (inner && fld && (inner.type === 'this' || inner.type === 'this_expression')) {
1678
+ receiverName = (0, tree_sitter_helpers_1.getNodeText)(fld, this.source);
1679
+ }
1680
+ else {
1681
+ receiverName = (0, tree_sitter_helpers_1.getNodeText)(objectField, this.source);
1682
+ }
1683
+ }
1684
+ else {
1685
+ receiverName = (0, tree_sitter_helpers_1.getNodeText)(objectField, this.source);
1686
+ }
1687
+ // Strip PHP $ prefix from variable names
1688
+ receiverName = receiverName.replace(/^\$/, '');
1689
+ if (methodName) {
1690
+ // Skip self/this/parent/static receivers — they don't aid resolution
1691
+ const SKIP_RECEIVERS = new Set(['self', 'this', 'cls', 'super', 'parent', 'static']);
1692
+ if (SKIP_RECEIVERS.has(receiverName)) {
1693
+ calleeName = methodName;
1694
+ }
1695
+ else {
1696
+ calleeName = `${receiverName}.${methodName}`;
1697
+ }
1698
+ }
1699
+ }
1700
+ else if (node.type === 'message_expression') {
1701
+ // ObjC message expressions emit one `method` field child per selector
1702
+ // keyword: `[obj a:1 b:2 c:3]` has three `method=identifier` siblings.
1703
+ // Joining them with `:` reconstructs the full selector and matches the
1704
+ // multi-part selector names produced by the ObjC method_definition
1705
+ // extractor (`extractObjcMethodName` in languages/objc.ts). Without this
1706
+ // join, multi-keyword call sites only emitted the first keyword and never
1707
+ // resolved to their target methods (e.g. `GET:parameters:headers:...` had
1708
+ // zero callers despite obviously being called).
1709
+ const methodKeywords = [];
1710
+ for (let i = 0; i < node.namedChildCount; i++) {
1711
+ if (node.fieldNameForNamedChild(i) === 'method') {
1712
+ const kw = node.namedChild(i);
1713
+ if (kw)
1714
+ methodKeywords.push((0, tree_sitter_helpers_1.getNodeText)(kw, this.source));
1715
+ }
1716
+ }
1717
+ if (methodKeywords.length > 0) {
1718
+ const methodName = methodKeywords.length === 1
1719
+ ? methodKeywords[0]
1720
+ : methodKeywords.map((k) => `${k}:`).join('');
1721
+ const receiverField = (0, tree_sitter_helpers_1.getChildByField)(node, 'receiver');
1722
+ const SKIP_RECEIVERS = new Set(['self', 'super']);
1723
+ if (receiverField && receiverField.type !== 'message_expression') {
1724
+ const receiverName = (0, tree_sitter_helpers_1.getNodeText)(receiverField, this.source);
1725
+ if (receiverName && !SKIP_RECEIVERS.has(receiverName)) {
1726
+ calleeName = `${receiverName}.${methodName}`;
1727
+ }
1728
+ else {
1729
+ calleeName = methodName;
1730
+ }
1731
+ }
1732
+ else {
1733
+ calleeName = methodName;
1734
+ }
1735
+ }
1736
+ }
1737
+ else {
1738
+ const func = (0, tree_sitter_helpers_1.getChildByField)(node, 'function') || node.namedChild(0);
1739
+ if (func) {
1740
+ if (func.type === 'member_expression' || func.type === 'attribute' || func.type === 'selector_expression' || func.type === 'navigation_expression' || func.type === 'field_expression') {
1741
+ // Method call: obj.method() or obj.field.method()
1742
+ // Go uses selector_expression with 'field', JS/TS uses member_expression with 'property'
1743
+ // Kotlin uses navigation_expression with navigation_suffix > simple_identifier
1744
+ // C/C++ use field_expression for both `obj.method()` and `ptr->method()`
1745
+ let property = (0, tree_sitter_helpers_1.getChildByField)(func, 'property') || (0, tree_sitter_helpers_1.getChildByField)(func, 'field');
1746
+ if (!property) {
1747
+ const child1 = func.namedChild(1);
1748
+ // Kotlin: navigation_suffix wraps the method name — extract simple_identifier from it
1749
+ if (child1?.type === 'navigation_suffix') {
1750
+ property = child1.namedChildren.find((c) => c.type === 'simple_identifier') ?? child1;
1751
+ }
1752
+ else {
1753
+ property = child1;
1754
+ }
1755
+ }
1756
+ if (property) {
1757
+ const methodName = (0, tree_sitter_helpers_1.getNodeText)(property, this.source);
1758
+ // Include receiver name for qualified resolution (e.g., console.print → "console.print")
1759
+ // This helps the resolver distinguish method calls from bare function calls
1760
+ // (e.g., Python's console.print() vs builtin print())
1761
+ // Skip self/this/cls as they don't aid resolution
1762
+ const receiver = (0, tree_sitter_helpers_1.getChildByField)(func, 'object') ||
1763
+ (0, tree_sitter_helpers_1.getChildByField)(func, 'operand') ||
1764
+ (0, tree_sitter_helpers_1.getChildByField)(func, 'argument') ||
1765
+ func.namedChild(0);
1766
+ const SKIP_RECEIVERS = new Set(['self', 'this', 'cls', 'super']);
1767
+ if (receiver && (receiver.type === 'identifier' || receiver.type === 'simple_identifier' || receiver.type === 'field_identifier')) {
1768
+ const receiverName = (0, tree_sitter_helpers_1.getNodeText)(receiver, this.source);
1769
+ if (!SKIP_RECEIVERS.has(receiverName)) {
1770
+ calleeName = `${receiverName}.${methodName}`;
1771
+ }
1772
+ else {
1773
+ calleeName = methodName;
1774
+ }
1775
+ }
1776
+ else {
1777
+ calleeName = methodName;
1778
+ }
1779
+ }
1780
+ }
1781
+ else if (func.type === 'scoped_identifier' || func.type === 'scoped_call_expression') {
1782
+ // Scoped call: Module::function()
1783
+ calleeName = (0, tree_sitter_helpers_1.getNodeText)(func, this.source);
1784
+ }
1785
+ else {
1786
+ calleeName = (0, tree_sitter_helpers_1.getNodeText)(func, this.source);
1787
+ }
1788
+ }
1789
+ }
1790
+ if (calleeName) {
1791
+ this.unresolvedReferences.push({
1792
+ fromNodeId: callerId,
1793
+ referenceName: calleeName,
1794
+ referenceKind: 'calls',
1795
+ line: node.startPosition.row + 1,
1796
+ column: node.startPosition.column,
1797
+ });
1798
+ }
1799
+ }
1800
+ /**
1801
+ * `new Foo(...)` / `Foo::new(...)` / object_creation_expression —
1802
+ * emit an `instantiates` reference to the class name. The resolver
1803
+ * then links it to the class node, producing the `instantiates`
1804
+ * edge that powers "what creates instances of X" queries.
1805
+ *
1806
+ * Children are still walked so nested calls inside the constructor
1807
+ * arguments (`new Foo(bar())`) get their own `calls` references.
1808
+ */
1809
+ extractInstantiation(node) {
1810
+ if (this.nodeStack.length === 0)
1811
+ return;
1812
+ const fromId = this.nodeStack[this.nodeStack.length - 1];
1813
+ if (!fromId)
1814
+ return;
1815
+ // The class name is in the `constructor`/`type`/first-named-child
1816
+ // depending on grammar.
1817
+ const ctor = (0, tree_sitter_helpers_1.getChildByField)(node, 'constructor') ||
1818
+ (0, tree_sitter_helpers_1.getChildByField)(node, 'type') ||
1819
+ (0, tree_sitter_helpers_1.getChildByField)(node, 'name') ||
1820
+ node.namedChild(0);
1821
+ if (!ctor)
1822
+ return;
1823
+ let className = (0, tree_sitter_helpers_1.getNodeText)(ctor, this.source);
1824
+ // Strip type-argument suffix first: `new Map<K, V>()` would
1825
+ // otherwise produce className 'Map<K, V>' (the constructor
1826
+ // field is a `generic_type` node) and resolution would fail
1827
+ // because no class is named with the angle-bracket suffix.
1828
+ const ltIdx = className.indexOf('<');
1829
+ if (ltIdx > 0)
1830
+ className = className.slice(0, ltIdx);
1831
+ // For namespaced/qualified constructors (`new ns.Foo()`,
1832
+ // `new ns::Foo()`) keep the trailing identifier — that's what
1833
+ // matches a class node in the index.
1834
+ const lastDot = Math.max(className.lastIndexOf('.'), className.lastIndexOf('::'));
1835
+ if (lastDot >= 0)
1836
+ className = className.slice(lastDot + 1).replace(/^[:.]/, '');
1837
+ className = className.trim();
1838
+ if (className) {
1839
+ this.unresolvedReferences.push({
1840
+ fromNodeId: fromId,
1841
+ referenceName: className,
1842
+ referenceKind: 'instantiates',
1843
+ line: node.startPosition.row + 1,
1844
+ column: node.startPosition.column,
1845
+ });
1846
+ }
1847
+ }
1848
+ /**
1849
+ * Find a `class_body` child of an `object_creation_expression` — the
1850
+ * marker for an anonymous class (`new T() { ... }`). Returns the body
1851
+ * node so the caller can walk it as the anon class's members.
1852
+ */
1853
+ findAnonymousClassBody(node) {
1854
+ for (let i = 0; i < node.namedChildCount; i++) {
1855
+ const child = node.namedChild(i);
1856
+ // Java: `class_body`. C# uses the same node kind.
1857
+ if (child && (child.type === 'class_body' || child.type === 'declaration_list')) {
1858
+ return child;
1859
+ }
1860
+ }
1861
+ return null;
1862
+ }
1863
+ /**
1864
+ * Extract a Java/C# anonymous class — `new T() { ...members }`. Emits a
1865
+ * `class` node named `<T$anon@line>`, an `extends` reference to T (so
1866
+ * Phase 5.5 interface-impl can bridge), and walks the body so its
1867
+ * `method_declaration` members become method nodes under the anon class.
1868
+ *
1869
+ * Why this matters: without anon-class extraction, the overrides inside
1870
+ * a lambda-returned `new T() { @Override int foo(){...} }` are not nodes,
1871
+ * so a call through T.foo (the abstract parent method) has no static
1872
+ * target — the agent has to Read the file to find the implementation.
1873
+ */
1874
+ extractAnonymousClass(node, body) {
1875
+ if (!this.extractor)
1876
+ return;
1877
+ // The instantiated type sits in the same field/position that
1878
+ // extractInstantiation reads from. Use the same lookup so the anon
1879
+ // class's `extends` target matches the `instantiates` edge.
1880
+ const typeNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'constructor') ||
1881
+ (0, tree_sitter_helpers_1.getChildByField)(node, 'type') ||
1882
+ (0, tree_sitter_helpers_1.getChildByField)(node, 'name') ||
1883
+ node.namedChild(0);
1884
+ let typeName = typeNode ? (0, tree_sitter_helpers_1.getNodeText)(typeNode, this.source) : 'Object';
1885
+ const ltIdx = typeName.indexOf('<');
1886
+ if (ltIdx > 0)
1887
+ typeName = typeName.slice(0, ltIdx);
1888
+ const lastDot = Math.max(typeName.lastIndexOf('.'), typeName.lastIndexOf('::'));
1889
+ if (lastDot >= 0)
1890
+ typeName = typeName.slice(lastDot + 1).replace(/^[:.]/, '');
1891
+ typeName = typeName.trim() || 'Object';
1892
+ const anonName = `<${typeName}$anon@${node.startPosition.row + 1}>`;
1893
+ const classNode = this.createNode('class', anonName, node, {});
1894
+ if (!classNode)
1895
+ return;
1896
+ // The anonymous class implicitly extends/implements the named type.
1897
+ // We can't tell at extraction time whether T is a class or an interface,
1898
+ // so emit `extends`. Resolution will still bind T to whatever it is, and
1899
+ // Phase 5.5 (which already handles both `extends` and `implements`) will
1900
+ // bridge T's methods to the override names found in the anon body.
1901
+ this.unresolvedReferences.push({
1902
+ fromNodeId: classNode.id,
1903
+ referenceName: typeName,
1904
+ referenceKind: 'extends',
1905
+ line: typeNode?.startPosition.row ?? node.startPosition.row,
1906
+ column: typeNode?.startPosition.column ?? node.startPosition.column,
1907
+ });
1908
+ // Walk the body's children so method_declaration nodes inside become
1909
+ // method nodes scoped to the anon class.
1910
+ this.nodeStack.push(classNode.id);
1911
+ for (let i = 0; i < body.namedChildCount; i++) {
1912
+ const child = body.namedChild(i);
1913
+ if (child)
1914
+ this.visitNode(child);
1915
+ }
1916
+ this.nodeStack.pop();
1917
+ }
1918
+ /**
1919
+ * Scan `declNode` and its preceding siblings (within the parent's
1920
+ * named children) for decorator nodes, emitting a `decorates`
1921
+ * reference from `decoratedId` to each decorator's function name.
1922
+ *
1923
+ * Why preceding siblings: in TypeScript, `@Foo class Bar {}` parses
1924
+ * as an `export_statement` (or top-level wrapper) with the
1925
+ * `decorator` as a child *before* the `class_declaration` — so the
1926
+ * decorator isn't a child of the class itself. For methods/
1927
+ * properties, the decorator IS a direct child of the declaration,
1928
+ * so we also scan declNode.namedChildren.
1929
+ *
1930
+ * Idempotent across grammars: if neither location yields decorators
1931
+ * (most non-decorator-using languages), the function is a no-op.
1932
+ */
1933
+ extractDecoratorsFor(declNode, decoratedId) {
1934
+ const consider = (n) => {
1935
+ if (!n)
1936
+ return;
1937
+ // `marker_annotation` is Java's grammar for arg-less annotations
1938
+ // (`@Override`, `@Deprecated`); without including it, every
1939
+ // such Java annotation would be silently skipped.
1940
+ if (n.type !== 'decorator' &&
1941
+ n.type !== 'annotation' &&
1942
+ n.type !== 'marker_annotation') {
1943
+ return;
1944
+ }
1945
+ // Find the leading identifier: skip the `@` punct, unwrap
1946
+ // a call_expression if the decorator is invoked with args.
1947
+ let target = null;
1948
+ for (let i = 0; i < n.namedChildCount; i++) {
1949
+ const child = n.namedChild(i);
1950
+ if (!child)
1951
+ continue;
1952
+ if (child.type === 'call_expression') {
1953
+ const fn = (0, tree_sitter_helpers_1.getChildByField)(child, 'function') ?? child.namedChild(0);
1954
+ if (fn)
1955
+ target = fn;
1956
+ if (target)
1957
+ break;
1958
+ }
1959
+ if (child.type === 'identifier' ||
1960
+ child.type === 'member_expression' ||
1961
+ child.type === 'scoped_identifier' ||
1962
+ child.type === 'navigation_expression') {
1963
+ target = child;
1964
+ break;
1965
+ }
1966
+ }
1967
+ if (!target)
1968
+ return;
1969
+ let name = (0, tree_sitter_helpers_1.getNodeText)(target, this.source);
1970
+ const lastDot = Math.max(name.lastIndexOf('.'), name.lastIndexOf('::'));
1971
+ if (lastDot >= 0)
1972
+ name = name.slice(lastDot + 1).replace(/^[:.]/, '');
1973
+ if (!name)
1974
+ return;
1975
+ this.unresolvedReferences.push({
1976
+ fromNodeId: decoratedId,
1977
+ referenceName: name,
1978
+ referenceKind: 'decorates',
1979
+ line: n.startPosition.row + 1,
1980
+ column: n.startPosition.column,
1981
+ });
1982
+ };
1983
+ // 1. Decorators that are direct children of the declaration
1984
+ // (method/property style, also some grammars for class).
1985
+ for (let i = 0; i < declNode.namedChildCount; i++) {
1986
+ consider(declNode.namedChild(i));
1987
+ }
1988
+ // 2. Decorators that are PRECEDING siblings of the declaration
1989
+ // inside the parent's children (TypeScript class style).
1990
+ // Walk BACKWARDS from the declaration and stop at the first
1991
+ // non-decorator sibling — without that stop, decorators
1992
+ // belonging to an EARLIER unrelated declaration leak in
1993
+ // (e.g. `@A class Foo {} @B class Bar {}` would otherwise
1994
+ // attribute @A to Bar).
1995
+ //
1996
+ // Note on identity: tree-sitter web bindings return fresh JS
1997
+ // wrapper objects from `parent`/`namedChild` navigation, so
1998
+ // `sibling === declNode` is unreliable — `startIndex` does
1999
+ // the matching instead.
2000
+ const parent = declNode.parent;
2001
+ if (parent) {
2002
+ const declStart = declNode.startIndex;
2003
+ let declIdx = -1;
2004
+ for (let i = 0; i < parent.namedChildCount; i++) {
2005
+ const sibling = parent.namedChild(i);
2006
+ if (sibling && sibling.startIndex === declStart) {
2007
+ declIdx = i;
2008
+ break;
2009
+ }
2010
+ }
2011
+ if (declIdx > 0) {
2012
+ for (let j = declIdx - 1; j >= 0; j--) {
2013
+ const sibling = parent.namedChild(j);
2014
+ if (!sibling)
2015
+ continue;
2016
+ if (sibling.type !== 'decorator' && sibling.type !== 'annotation' && sibling.type !== 'marker_annotation') {
2017
+ break; // non-decorator separator → stop consuming
2018
+ }
2019
+ consider(sibling);
2020
+ }
2021
+ }
2022
+ }
2023
+ }
2024
+ /**
2025
+ * Visit function body and extract calls (and structural nodes).
2026
+ *
2027
+ * In addition to call expressions, this also detects class/struct/enum
2028
+ * definitions inside function bodies. This handles two cases:
2029
+ * 1. Local class/struct/enum definitions (valid in C++, Java, etc.)
2030
+ * 2. C++ macro misparsing — macros like NLOHMANN_JSON_NAMESPACE_BEGIN cause
2031
+ * tree-sitter to interpret the namespace block as a function_definition,
2032
+ * hiding real class/struct/enum nodes inside the "function body".
2033
+ */
2034
+ visitFunctionBody(body, _functionId) {
2035
+ if (!this.extractor)
2036
+ return;
2037
+ const visitForCallsAndStructure = (node) => {
2038
+ const nodeType = node.type;
2039
+ if (this.extractor.callTypes.includes(nodeType)) {
2040
+ this.extractCall(node);
2041
+ }
2042
+ else if (INSTANTIATION_KINDS.has(nodeType)) {
2043
+ // `new Foo()` inside a function body — emit an `instantiates`
2044
+ // reference. Without this branch the body walker only knew
2045
+ // about `call_expression`, so constructor invocations
2046
+ // produced no graph edges at all.
2047
+ this.extractInstantiation(node);
2048
+ // Anonymous class with body: `new T() { ... }` (Java/C#). Extract as
2049
+ // a class so interface-impl synthesis (Phase 5.5) can bridge T's
2050
+ // methods to the overrides — same rationale as in visitNode.
2051
+ const anonBody = this.findAnonymousClassBody(node);
2052
+ if (anonBody) {
2053
+ this.extractAnonymousClass(node, anonBody);
2054
+ return;
2055
+ }
2056
+ }
2057
+ else if (this.extractor.extractBareCall) {
2058
+ const calleeName = this.extractor.extractBareCall(node, this.source);
2059
+ if (calleeName && this.nodeStack.length > 0) {
2060
+ const callerId = this.nodeStack[this.nodeStack.length - 1];
2061
+ if (callerId) {
2062
+ this.unresolvedReferences.push({
2063
+ fromNodeId: callerId,
2064
+ referenceName: calleeName,
2065
+ referenceKind: 'calls',
2066
+ line: node.startPosition.row + 1,
2067
+ column: node.startPosition.column,
2068
+ });
2069
+ }
2070
+ }
2071
+ }
2072
+ // Nested NAMED functions inside a body — function declarations and named
2073
+ // function expressions like `.on('mount', function onmount(){})` — become
2074
+ // their own nodes so the graph can link to them (callback handlers, local
2075
+ // helpers). Anonymous arrows/expressions fall through to the default
2076
+ // recursion below, keeping their inner calls attributed to the enclosing
2077
+ // function: this bounds the new nodes to NAMED functions only (no explosion,
2078
+ // no lost edges). extractFunction walks the nested body itself, so we return.
2079
+ if (this.extractor.functionTypes.includes(nodeType)) {
2080
+ const nestedName = extractName(node, this.source, this.extractor);
2081
+ if (nestedName && nestedName !== '<anonymous>') {
2082
+ this.extractFunction(node);
2083
+ return;
2084
+ }
2085
+ }
2086
+ // Extract structural nodes found inside function bodies.
2087
+ // Each extract method visits its own children, so we return after extracting.
2088
+ if (this.extractor.classTypes.includes(nodeType)) {
2089
+ const classification = this.extractor.classifyClassNode?.(node) ?? 'class';
2090
+ if (classification === 'struct')
2091
+ this.extractStruct(node);
2092
+ else if (classification === 'enum')
2093
+ this.extractEnum(node);
2094
+ else if (classification === 'interface')
2095
+ this.extractInterface(node);
2096
+ else if (classification === 'trait')
2097
+ this.extractClass(node, 'trait');
2098
+ else
2099
+ this.extractClass(node);
2100
+ return;
2101
+ }
2102
+ if (this.extractor.structTypes.includes(nodeType)) {
2103
+ this.extractStruct(node);
2104
+ return;
2105
+ }
2106
+ if (this.extractor.enumTypes.includes(nodeType)) {
2107
+ this.extractEnum(node);
2108
+ return;
2109
+ }
2110
+ if (this.extractor.interfaceTypes.includes(nodeType)) {
2111
+ this.extractInterface(node);
2112
+ return;
2113
+ }
2114
+ for (let i = 0; i < node.namedChildCount; i++) {
2115
+ const child = node.namedChild(i);
2116
+ if (child) {
2117
+ visitForCallsAndStructure(child);
2118
+ }
2119
+ }
2120
+ };
2121
+ visitForCallsAndStructure(body);
2122
+ }
2123
+ /**
2124
+ * Extract inheritance relationships
2125
+ */
2126
+ extractInheritance(node, classId) {
2127
+ // Objective-C @interface MyClass : NSObject <ProtoA, ProtoB>
2128
+ if (node.type === 'class_interface') {
2129
+ const superclass = (0, tree_sitter_helpers_1.getChildByField)(node, 'superclass');
2130
+ if (superclass) {
2131
+ const name = (0, tree_sitter_helpers_1.getNodeText)(superclass, this.source);
2132
+ this.unresolvedReferences.push({
2133
+ fromNodeId: classId,
2134
+ referenceName: name,
2135
+ referenceKind: 'extends',
2136
+ line: superclass.startPosition.row + 1,
2137
+ column: superclass.startPosition.column,
2138
+ });
2139
+ }
2140
+ for (let j = 0; j < node.namedChildCount; j++) {
2141
+ const argList = node.namedChild(j);
2142
+ if (argList?.type !== 'parameterized_arguments')
2143
+ continue;
2144
+ for (let k = 0; k < argList.namedChildCount; k++) {
2145
+ const typeName = argList.namedChild(k);
2146
+ if (!typeName)
2147
+ continue;
2148
+ const typeId = typeName.namedChildren.find((c) => c.type === 'type_identifier' || c.type === 'identifier');
2149
+ if (!typeId)
2150
+ continue;
2151
+ const protocolName = (0, tree_sitter_helpers_1.getNodeText)(typeId, this.source);
2152
+ this.unresolvedReferences.push({
2153
+ fromNodeId: classId,
2154
+ referenceName: protocolName,
2155
+ referenceKind: 'implements',
2156
+ line: typeId.startPosition.row + 1,
2157
+ column: typeId.startPosition.column,
2158
+ });
2159
+ }
2160
+ }
2161
+ return;
2162
+ }
2163
+ // Look for extends/implements clauses
2164
+ for (let i = 0; i < node.namedChildCount; i++) {
2165
+ const child = node.namedChild(i);
2166
+ if (!child)
2167
+ continue;
2168
+ if (child.type === 'extends_clause' ||
2169
+ child.type === 'superclass' ||
2170
+ child.type === 'base_clause' || // PHP class extends
2171
+ child.type === 'extends_interfaces' // Java interface extends
2172
+ ) {
2173
+ // Extract parent class/interface names
2174
+ // Java uses type_list wrapper: superclass -> type_identifier, extends_interfaces -> type_list -> type_identifier
2175
+ const typeList = child.namedChildren.find((c) => c.type === 'type_list');
2176
+ const targets = typeList ? typeList.namedChildren : [child.namedChild(0)];
2177
+ for (const target of targets) {
2178
+ if (target) {
2179
+ const name = (0, tree_sitter_helpers_1.getNodeText)(target, this.source);
2180
+ this.unresolvedReferences.push({
2181
+ fromNodeId: classId,
2182
+ referenceName: name,
2183
+ referenceKind: 'extends',
2184
+ line: target.startPosition.row + 1,
2185
+ column: target.startPosition.column,
2186
+ });
2187
+ }
2188
+ }
2189
+ }
2190
+ // C++ base classes: `class Derived : public Base, private Other` →
2191
+ // base_class_clause holds access specifiers + base type(s). Emit an extends
2192
+ // ref per base type (skip the public/private/protected keywords).
2193
+ if (child.type === 'base_class_clause') {
2194
+ for (const t of child.namedChildren) {
2195
+ if (t.type === 'type_identifier' ||
2196
+ t.type === 'qualified_identifier' ||
2197
+ t.type === 'template_type') {
2198
+ this.unresolvedReferences.push({
2199
+ fromNodeId: classId,
2200
+ referenceName: (0, tree_sitter_helpers_1.getNodeText)(t, this.source),
2201
+ referenceKind: 'extends',
2202
+ line: t.startPosition.row + 1,
2203
+ column: t.startPosition.column,
2204
+ });
2205
+ }
2206
+ }
2207
+ }
2208
+ if (child.type === 'implements_clause' ||
2209
+ child.type === 'class_interface_clause' ||
2210
+ child.type === 'super_interfaces' || // Java class implements
2211
+ child.type === 'interfaces' // Dart
2212
+ ) {
2213
+ // Extract implemented interfaces
2214
+ // Java uses type_list wrapper: super_interfaces -> type_list -> type_identifier
2215
+ const typeList = child.namedChildren.find((c) => c.type === 'type_list');
2216
+ const targets = typeList ? typeList.namedChildren : child.namedChildren;
2217
+ for (const iface of targets) {
2218
+ if (iface) {
2219
+ const name = (0, tree_sitter_helpers_1.getNodeText)(iface, this.source);
2220
+ this.unresolvedReferences.push({
2221
+ fromNodeId: classId,
2222
+ referenceName: name,
2223
+ referenceKind: 'implements',
2224
+ line: iface.startPosition.row + 1,
2225
+ column: iface.startPosition.column,
2226
+ });
2227
+ }
2228
+ }
2229
+ }
2230
+ // Python superclass list: `class Flask(Scaffold, Mixin):`
2231
+ // argument_list contains identifier children for each parent class
2232
+ if (child.type === 'argument_list' && node.type === 'class_definition') {
2233
+ for (const arg of child.namedChildren) {
2234
+ if (arg.type === 'identifier' || arg.type === 'attribute') {
2235
+ const name = (0, tree_sitter_helpers_1.getNodeText)(arg, this.source);
2236
+ this.unresolvedReferences.push({
2237
+ fromNodeId: classId,
2238
+ referenceName: name,
2239
+ referenceKind: 'extends',
2240
+ line: arg.startPosition.row + 1,
2241
+ column: arg.startPosition.column,
2242
+ });
2243
+ }
2244
+ }
2245
+ }
2246
+ // Go interface embedding: `type Querier interface { LabelQuerier; ... }`
2247
+ // constraint_elem wraps the embedded interface type identifier
2248
+ if (child.type === 'constraint_elem') {
2249
+ const typeId = child.namedChildren.find((c) => c.type === 'type_identifier');
2250
+ if (typeId) {
2251
+ const name = (0, tree_sitter_helpers_1.getNodeText)(typeId, this.source);
2252
+ this.unresolvedReferences.push({
2253
+ fromNodeId: classId,
2254
+ referenceName: name,
2255
+ referenceKind: 'extends',
2256
+ line: typeId.startPosition.row + 1,
2257
+ column: typeId.startPosition.column,
2258
+ });
2259
+ }
2260
+ }
2261
+ // Go struct embedding: field_declaration without field_identifier
2262
+ // e.g. `type DB struct { *Head; Queryable }` — no field name means embedded type
2263
+ if (child.type === 'field_declaration') {
2264
+ const hasFieldIdentifier = child.namedChildren.some((c) => c.type === 'field_identifier');
2265
+ if (!hasFieldIdentifier) {
2266
+ const typeId = child.namedChildren.find((c) => c.type === 'type_identifier');
2267
+ if (typeId) {
2268
+ const name = (0, tree_sitter_helpers_1.getNodeText)(typeId, this.source);
2269
+ this.unresolvedReferences.push({
2270
+ fromNodeId: classId,
2271
+ referenceName: name,
2272
+ referenceKind: 'extends',
2273
+ line: typeId.startPosition.row + 1,
2274
+ column: typeId.startPosition.column,
2275
+ });
2276
+ }
2277
+ }
2278
+ }
2279
+ // Rust trait supertraits: `trait SubTrait: SuperTrait + Display { ... }`
2280
+ // trait_bounds contains type_identifier, generic_type, or higher_ranked_trait_bound children
2281
+ if (child.type === 'trait_bounds') {
2282
+ for (const bound of child.namedChildren) {
2283
+ let typeName;
2284
+ let posNode;
2285
+ if (bound.type === 'type_identifier') {
2286
+ typeName = (0, tree_sitter_helpers_1.getNodeText)(bound, this.source);
2287
+ posNode = bound;
2288
+ }
2289
+ else if (bound.type === 'generic_type') {
2290
+ // e.g. `Deserialize<'de>`
2291
+ const inner = bound.namedChildren.find((c) => c.type === 'type_identifier');
2292
+ if (inner) {
2293
+ typeName = (0, tree_sitter_helpers_1.getNodeText)(inner, this.source);
2294
+ posNode = inner;
2295
+ }
2296
+ }
2297
+ else if (bound.type === 'higher_ranked_trait_bound') {
2298
+ // e.g. `for<'de> Deserialize<'de>`
2299
+ const generic = bound.namedChildren.find((c) => c.type === 'generic_type');
2300
+ const typeId = generic?.namedChildren.find((c) => c.type === 'type_identifier')
2301
+ ?? bound.namedChildren.find((c) => c.type === 'type_identifier');
2302
+ if (typeId) {
2303
+ typeName = (0, tree_sitter_helpers_1.getNodeText)(typeId, this.source);
2304
+ posNode = typeId;
2305
+ }
2306
+ }
2307
+ if (typeName && posNode) {
2308
+ this.unresolvedReferences.push({
2309
+ fromNodeId: classId,
2310
+ referenceName: typeName,
2311
+ referenceKind: 'extends',
2312
+ line: posNode.startPosition.row + 1,
2313
+ column: posNode.startPosition.column,
2314
+ });
2315
+ }
2316
+ }
2317
+ }
2318
+ // C#: `class Movie : BaseItem, IPlugin` → base_list with identifier children
2319
+ // base_list combines both base class and interfaces in a single colon-separated list.
2320
+ // We emit all as 'extends' since the syntax doesn't distinguish them.
2321
+ if (child.type === 'base_list') {
2322
+ for (const baseType of child.namedChildren) {
2323
+ if (baseType) {
2324
+ // For generic base types like `ClientBase<T>`, extract just the type name
2325
+ const name = baseType.type === 'generic_name'
2326
+ ? (0, tree_sitter_helpers_1.getNodeText)(baseType.namedChildren.find((c) => c.type === 'identifier') ?? baseType, this.source)
2327
+ : (0, tree_sitter_helpers_1.getNodeText)(baseType, this.source);
2328
+ this.unresolvedReferences.push({
2329
+ fromNodeId: classId,
2330
+ referenceName: name,
2331
+ referenceKind: 'extends',
2332
+ line: baseType.startPosition.row + 1,
2333
+ column: baseType.startPosition.column,
2334
+ });
2335
+ }
2336
+ }
2337
+ }
2338
+ // Kotlin: `class Foo : Bar, Baz` → delegation_specifier > user_type > type_identifier
2339
+ // Also handles `class Foo : Bar()` → delegation_specifier > constructor_invocation > user_type
2340
+ if (child.type === 'delegation_specifier') {
2341
+ const userType = child.namedChildren.find((c) => c.type === 'user_type');
2342
+ const constructorInvocation = child.namedChildren.find((c) => c.type === 'constructor_invocation');
2343
+ const target = userType ?? constructorInvocation;
2344
+ if (target) {
2345
+ const typeId = target.type === 'user_type'
2346
+ ? target.namedChildren.find((c) => c.type === 'type_identifier') ?? target
2347
+ : target.namedChildren.find((c) => c.type === 'user_type')?.namedChildren.find((c) => c.type === 'type_identifier')
2348
+ ?? target.namedChildren.find((c) => c.type === 'user_type') ?? target;
2349
+ const name = (0, tree_sitter_helpers_1.getNodeText)(typeId, this.source);
2350
+ this.unresolvedReferences.push({
2351
+ fromNodeId: classId,
2352
+ referenceName: name,
2353
+ referenceKind: 'extends',
2354
+ line: typeId.startPosition.row + 1,
2355
+ column: typeId.startPosition.column,
2356
+ });
2357
+ }
2358
+ }
2359
+ // Swift: inheritance_specifier > user_type > type_identifier
2360
+ // Used for class inheritance, protocol conformance, and protocol inheritance
2361
+ if (child.type === 'inheritance_specifier') {
2362
+ const userType = child.namedChildren.find((c) => c.type === 'user_type');
2363
+ const typeId = userType?.namedChildren.find((c) => c.type === 'type_identifier');
2364
+ if (typeId) {
2365
+ const name = (0, tree_sitter_helpers_1.getNodeText)(typeId, this.source);
2366
+ this.unresolvedReferences.push({
2367
+ fromNodeId: classId,
2368
+ referenceName: name,
2369
+ referenceKind: 'extends',
2370
+ line: typeId.startPosition.row + 1,
2371
+ column: typeId.startPosition.column,
2372
+ });
2373
+ }
2374
+ }
2375
+ // JavaScript class_heritage has bare identifier without extends_clause wrapper
2376
+ // e.g. `class Foo extends Bar {}` → class_heritage → identifier("Bar")
2377
+ if ((child.type === 'identifier' || child.type === 'type_identifier') &&
2378
+ node.type === 'class_heritage') {
2379
+ const name = (0, tree_sitter_helpers_1.getNodeText)(child, this.source);
2380
+ this.unresolvedReferences.push({
2381
+ fromNodeId: classId,
2382
+ referenceName: name,
2383
+ referenceKind: 'extends',
2384
+ line: child.startPosition.row + 1,
2385
+ column: child.startPosition.column,
2386
+ });
2387
+ }
2388
+ // Recurse into container nodes (e.g. field_declaration_list in Go structs,
2389
+ // class_heritage in TypeScript which wraps extends_clause/implements_clause)
2390
+ if (child.type === 'field_declaration_list' || child.type === 'class_heritage') {
2391
+ this.extractInheritance(child, classId);
2392
+ }
2393
+ }
2394
+ }
2395
+ /**
2396
+ * Rust `impl Trait for Type` — creates an implements edge from Type to Trait.
2397
+ * For plain `impl Type { ... }` (no trait), no inheritance edge is needed.
2398
+ */
2399
+ extractRustImplItem(node) {
2400
+ // Check if this is `impl Trait for Type` by looking for a `for` keyword
2401
+ const hasFor = node.children.some((c) => c.type === 'for' && !c.isNamed);
2402
+ if (!hasFor)
2403
+ return;
2404
+ // In `impl Trait for Type`, the type_identifiers are:
2405
+ // first = Trait name, last = implementing Type name
2406
+ // Also handle generic types like `impl<T> Trait for MyStruct<T>`
2407
+ const typeIdents = node.namedChildren.filter((c) => c.type === 'type_identifier' || c.type === 'generic_type' || c.type === 'scoped_type_identifier');
2408
+ if (typeIdents.length < 2)
2409
+ return;
2410
+ const traitNode = typeIdents[0];
2411
+ const typeNode = typeIdents[typeIdents.length - 1];
2412
+ // Get the trait name (handle scoped paths like std::fmt::Display)
2413
+ const traitName = traitNode.type === 'scoped_type_identifier'
2414
+ ? this.source.substring(traitNode.startIndex, traitNode.endIndex)
2415
+ : (0, tree_sitter_helpers_1.getNodeText)(traitNode, this.source);
2416
+ // Get the implementing type name (extract inner type_identifier for generics)
2417
+ let typeName;
2418
+ if (typeNode.type === 'generic_type') {
2419
+ const inner = typeNode.namedChildren.find((c) => c.type === 'type_identifier');
2420
+ typeName = inner ? (0, tree_sitter_helpers_1.getNodeText)(inner, this.source) : (0, tree_sitter_helpers_1.getNodeText)(typeNode, this.source);
2421
+ }
2422
+ else {
2423
+ typeName = (0, tree_sitter_helpers_1.getNodeText)(typeNode, this.source);
2424
+ }
2425
+ // Find the struct/type node for the implementing type
2426
+ const typeNodeId = this.findNodeByName(typeName);
2427
+ if (typeNodeId) {
2428
+ this.unresolvedReferences.push({
2429
+ fromNodeId: typeNodeId,
2430
+ referenceName: traitName,
2431
+ referenceKind: 'implements',
2432
+ line: traitNode.startPosition.row + 1,
2433
+ column: traitNode.startPosition.column,
2434
+ });
2435
+ }
2436
+ }
2437
+ /**
2438
+ * Find a previously-extracted node by name (used for back-references like impl blocks)
2439
+ */
2440
+ findNodeByName(name) {
2441
+ for (const node of this.nodes) {
2442
+ if (node.name === name && (node.kind === 'struct' || node.kind === 'enum' || node.kind === 'class')) {
2443
+ return node.id;
2444
+ }
2445
+ }
2446
+ return undefined;
2447
+ }
2448
+ /**
2449
+ * Languages that support type annotations (TypeScript, etc.)
2450
+ */
2451
+ TYPE_ANNOTATION_LANGUAGES = new Set([
2452
+ 'typescript', 'tsx', 'dart', 'kotlin', 'swift', 'rust', 'go', 'java', 'csharp',
2453
+ ]);
2454
+ /**
2455
+ * Built-in/primitive type names that shouldn't create references
2456
+ */
2457
+ BUILTIN_TYPES = new Set([
2458
+ 'string', 'number', 'boolean', 'void', 'null', 'undefined', 'never', 'any', 'unknown',
2459
+ 'object', 'symbol', 'bigint', 'true', 'false',
2460
+ // Rust
2461
+ 'str', 'bool', 'i8', 'i16', 'i32', 'i64', 'i128', 'isize',
2462
+ 'u8', 'u16', 'u32', 'u64', 'u128', 'usize', 'f32', 'f64', 'char',
2463
+ // Java/C#
2464
+ 'int', 'long', 'short', 'byte', 'float', 'double', 'char',
2465
+ // Go
2466
+ 'int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64',
2467
+ 'float32', 'float64', 'complex64', 'complex128', 'rune', 'error',
2468
+ ]);
2469
+ /**
2470
+ * Extract type references from type annotations on a function/method/field node.
2471
+ * Creates 'references' edges for parameter types, return types, and field types.
2472
+ */
2473
+ extractTypeAnnotations(node, nodeId) {
2474
+ if (!this.extractor)
2475
+ return;
2476
+ if (!this.TYPE_ANNOTATION_LANGUAGES.has(this.language))
2477
+ return;
2478
+ // C# tree-sitter doesn't produce `type_identifier` leaves — it uses
2479
+ // `identifier`, `predefined_type`, `qualified_name`, `generic_name`,
2480
+ // etc. — so the generic walker below emits zero references for it.
2481
+ // Dispatch to a C#-aware path that only walks type-position subtrees
2482
+ // (the `type` field of a parameter/method/property/field), so
2483
+ // parameter NAMES never accidentally surface as type refs (#381).
2484
+ if (this.language === 'csharp') {
2485
+ this.extractCsharpTypeRefs(node, nodeId);
2486
+ return;
2487
+ }
2488
+ // Extract parameter type annotations
2489
+ const params = (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.paramsField || 'parameters');
2490
+ if (params) {
2491
+ this.extractTypeRefsFromSubtree(params, nodeId);
2492
+ }
2493
+ // Extract return type annotation
2494
+ const returnType = (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.returnField || 'return_type');
2495
+ if (returnType) {
2496
+ this.extractTypeRefsFromSubtree(returnType, nodeId);
2497
+ }
2498
+ // Extract direct type annotation (for class fields like `model: ITextModel`)
2499
+ const typeAnnotation = node.namedChildren.find((c) => c.type === 'type_annotation');
2500
+ if (typeAnnotation) {
2501
+ this.extractTypeRefsFromSubtree(typeAnnotation, nodeId);
2502
+ }
2503
+ }
2504
+ /**
2505
+ * Extract C# type references from a node that owns a type position —
2506
+ * a method/constructor declaration, a property declaration, or a
2507
+ * field declaration (which wraps `variable_declaration → type`).
2508
+ *
2509
+ * Walks ONLY into known type fields, so parameter names like
2510
+ * `request` in `Build(UserDto request)` are never mis-emitted as
2511
+ * type references. Once inside a type subtree, `walkCsharpTypePosition`
2512
+ * recognizes C#'s actual type-leaf node kinds (`identifier`,
2513
+ * `qualified_name`, `generic_name`, `array_type`, `nullable_type`,
2514
+ * `tuple_type`, …) — none of which are `type_identifier`. Closes #381.
2515
+ */
2516
+ extractCsharpTypeRefs(node, nodeId) {
2517
+ // Return type / property type — the field is named `type`.
2518
+ const directType = (0, tree_sitter_helpers_1.getChildByField)(node, 'type');
2519
+ if (directType)
2520
+ this.walkCsharpTypePosition(directType, nodeId);
2521
+ // Field declarations wrap declarators in a `variable_declaration`
2522
+ // whose `type` field carries the type. The outer `field_declaration`
2523
+ // has no `type` field of its own, so the call above is a no-op here
2524
+ // and we descend one level.
2525
+ const varDecl = node.namedChildren.find((c) => c.type === 'variable_declaration');
2526
+ if (varDecl) {
2527
+ const vdType = (0, tree_sitter_helpers_1.getChildByField)(varDecl, 'type');
2528
+ if (vdType)
2529
+ this.walkCsharpTypePosition(vdType, nodeId);
2530
+ }
2531
+ // Method / constructor parameters. The field name on
2532
+ // `method_declaration` is `parameters`; it points at a
2533
+ // `parameter_list` whose `parameter` children each have their own
2534
+ // `type` field. Walking ONLY the type field skips parameter NAMES,
2535
+ // which would otherwise mis-emit as type references.
2536
+ const params = (0, tree_sitter_helpers_1.getChildByField)(node, 'parameters');
2537
+ if (params) {
2538
+ for (let i = 0; i < params.namedChildCount; i++) {
2539
+ const child = params.namedChild(i);
2540
+ if (!child || child.type !== 'parameter')
2541
+ continue;
2542
+ const paramType = (0, tree_sitter_helpers_1.getChildByField)(child, 'type');
2543
+ if (paramType)
2544
+ this.walkCsharpTypePosition(paramType, nodeId);
2545
+ }
2546
+ }
2547
+ }
2548
+ /**
2549
+ * Walk a C# subtree that is KNOWN to be in a type position
2550
+ * (return type, parameter type, property type, field type, generic
2551
+ * argument). Identifiers here are type names, not parameter names.
2552
+ */
2553
+ walkCsharpTypePosition(node, fromNodeId) {
2554
+ // `predefined_type` is int/string/bool/etc. — never a project ref.
2555
+ if (node.type === 'predefined_type')
2556
+ return;
2557
+ // Bare type name: `Foo` in `Foo bar`, or the `Foo` inside `List<Foo>`.
2558
+ if (node.type === 'identifier') {
2559
+ const name = (0, tree_sitter_helpers_1.getNodeText)(node, this.source);
2560
+ if (name && !this.BUILTIN_TYPES.has(name)) {
2561
+ this.unresolvedReferences.push({
2562
+ fromNodeId,
2563
+ referenceName: name,
2564
+ referenceKind: 'references',
2565
+ line: node.startPosition.row + 1,
2566
+ column: node.startPosition.column,
2567
+ });
2568
+ }
2569
+ return;
2570
+ }
2571
+ // `Namespace.Foo` → the rightmost identifier is the type. Emit the
2572
+ // full qualified name as the reference; the resolver can still match
2573
+ // on the trailing simple name when needed.
2574
+ if (node.type === 'qualified_name') {
2575
+ const text = (0, tree_sitter_helpers_1.getNodeText)(node, this.source);
2576
+ const last = text.split('.').pop() ?? text;
2577
+ if (last && !this.BUILTIN_TYPES.has(last)) {
2578
+ this.unresolvedReferences.push({
2579
+ fromNodeId,
2580
+ referenceName: last,
2581
+ referenceKind: 'references',
2582
+ line: node.startPosition.row + 1,
2583
+ column: node.startPosition.column,
2584
+ });
2585
+ }
2586
+ return;
2587
+ }
2588
+ // `(int Code, Foo Payload)` — tuple element has BOTH a `type` and a
2589
+ // `name` field; descending into all named children would mis-emit
2590
+ // the element name (`Code`, `Payload`) as a type ref. Walk only the
2591
+ // type field.
2592
+ if (node.type === 'tuple_element') {
2593
+ const t = (0, tree_sitter_helpers_1.getChildByField)(node, 'type');
2594
+ if (t)
2595
+ this.walkCsharpTypePosition(t, fromNodeId);
2596
+ return;
2597
+ }
2598
+ // Composite type nodes — recurse into named children. Covers
2599
+ // `generic_name` (head identifier + `type_argument_list`),
2600
+ // `nullable_type`, `array_type`, `pointer_type`, `tuple_type`,
2601
+ // `ref_type`, and any newer wrapping shapes the grammar adds.
2602
+ // Identifiers reached here are all type-positional (parameter/field
2603
+ // names are gated out before we descend).
2604
+ for (let i = 0; i < node.namedChildCount; i++) {
2605
+ const child = node.namedChild(i);
2606
+ if (child)
2607
+ this.walkCsharpTypePosition(child, fromNodeId);
2608
+ }
2609
+ }
2610
+ /**
2611
+ * Extract type references from a variable's type annotation.
2612
+ */
2613
+ extractVariableTypeAnnotation(node, nodeId) {
2614
+ if (!this.TYPE_ANNOTATION_LANGUAGES.has(this.language))
2615
+ return;
2616
+ // Find type_annotation child (covers TS `: Type`, Rust `: Type`, etc.)
2617
+ const typeAnnotation = node.namedChildren.find((c) => c.type === 'type_annotation');
2618
+ if (typeAnnotation) {
2619
+ this.extractTypeRefsFromSubtree(typeAnnotation, nodeId);
2620
+ }
2621
+ }
2622
+ /**
2623
+ * Recursively walk a subtree and extract all type_identifier references.
2624
+ * Handles unions, intersections, generics, arrays, etc.
2625
+ */
2626
+ extractTypeRefsFromSubtree(node, fromNodeId) {
2627
+ if (node.type === 'type_identifier') {
2628
+ const typeName = (0, tree_sitter_helpers_1.getNodeText)(node, this.source);
2629
+ if (typeName && !this.BUILTIN_TYPES.has(typeName)) {
2630
+ this.unresolvedReferences.push({
2631
+ fromNodeId,
2632
+ referenceName: typeName,
2633
+ referenceKind: 'references',
2634
+ line: node.startPosition.row + 1,
2635
+ column: node.startPosition.column,
2636
+ });
2637
+ }
2638
+ return; // type_identifier is a leaf
2639
+ }
2640
+ // Recurse into children (handles union_type, intersection_type, generic_type, etc.)
2641
+ for (let i = 0; i < node.namedChildCount; i++) {
2642
+ const child = node.namedChild(i);
2643
+ if (child) {
2644
+ this.extractTypeRefsFromSubtree(child, fromNodeId);
2645
+ }
2646
+ }
2647
+ }
2648
+ /**
2649
+ * Handle Pascal-specific AST structures.
2650
+ * Returns true if the node was fully handled and children should be skipped.
2651
+ */
2652
+ visitPascalNode(node) {
2653
+ const nodeType = node.type;
2654
+ // Unit/Program/Library → module node
2655
+ if (nodeType === 'unit' || nodeType === 'program' || nodeType === 'library') {
2656
+ const moduleNameNode = node.namedChildren.find((c) => c.type === 'moduleName');
2657
+ const name = moduleNameNode ? (0, tree_sitter_helpers_1.getNodeText)(moduleNameNode, this.source) : '';
2658
+ // Fallback to filename without extension if module name is empty
2659
+ const moduleName = name || path.basename(this.filePath).replace(/\.[^.]+$/, '');
2660
+ this.createNode('module', moduleName, node);
2661
+ // Continue visiting children (interface/implementation sections)
2662
+ for (let i = 0; i < node.namedChildCount; i++) {
2663
+ const child = node.namedChild(i);
2664
+ if (child)
2665
+ this.visitNode(child);
2666
+ }
2667
+ return true;
2668
+ }
2669
+ // declType wraps declClass/declIntf/declEnum/type-alias
2670
+ // The name lives on declType, the inner node determines the kind
2671
+ if (nodeType === 'declType') {
2672
+ this.extractPascalDeclType(node);
2673
+ return true;
2674
+ }
2675
+ // declUses → import nodes for each unit name
2676
+ if (nodeType === 'declUses') {
2677
+ this.extractPascalUses(node);
2678
+ return true;
2679
+ }
2680
+ // declConsts → container; visit children for individual declConst
2681
+ if (nodeType === 'declConsts') {
2682
+ for (let i = 0; i < node.namedChildCount; i++) {
2683
+ const child = node.namedChild(i);
2684
+ if (child?.type === 'declConst') {
2685
+ this.extractPascalConst(child);
2686
+ }
2687
+ }
2688
+ return true;
2689
+ }
2690
+ // declConst at top level (outside declConsts)
2691
+ if (nodeType === 'declConst') {
2692
+ this.extractPascalConst(node);
2693
+ return true;
2694
+ }
2695
+ // declTypes → container for type declarations
2696
+ if (nodeType === 'declTypes') {
2697
+ for (let i = 0; i < node.namedChildCount; i++) {
2698
+ const child = node.namedChild(i);
2699
+ if (child)
2700
+ this.visitNode(child);
2701
+ }
2702
+ return true;
2703
+ }
2704
+ // declVars → container for variable declarations
2705
+ if (nodeType === 'declVars') {
2706
+ for (let i = 0; i < node.namedChildCount; i++) {
2707
+ const child = node.namedChild(i);
2708
+ if (child?.type === 'declVar') {
2709
+ const nameNode = (0, tree_sitter_helpers_1.getChildByField)(child, 'name');
2710
+ if (nameNode) {
2711
+ const name = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
2712
+ this.createNode('variable', name, child);
2713
+ }
2714
+ }
2715
+ }
2716
+ return true;
2717
+ }
2718
+ // defProc in implementation section → extract calls but don't create duplicate nodes
2719
+ if (nodeType === 'defProc') {
2720
+ this.extractPascalDefProc(node);
2721
+ return true;
2722
+ }
2723
+ // declProp → property node
2724
+ if (nodeType === 'declProp') {
2725
+ const nameNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'name');
2726
+ if (nameNode) {
2727
+ const name = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
2728
+ const visibility = this.extractor.getVisibility?.(node);
2729
+ this.createNode('property', name, node, { visibility });
2730
+ }
2731
+ return true;
2732
+ }
2733
+ // declField → field node
2734
+ if (nodeType === 'declField') {
2735
+ const nameNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'name');
2736
+ if (nameNode) {
2737
+ const name = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
2738
+ const visibility = this.extractor.getVisibility?.(node);
2739
+ this.createNode('field', name, node, { visibility });
2740
+ }
2741
+ return true;
2742
+ }
2743
+ // declSection → visit children (propagates visibility via getVisibility)
2744
+ if (nodeType === 'declSection') {
2745
+ for (let i = 0; i < node.namedChildCount; i++) {
2746
+ const child = node.namedChild(i);
2747
+ if (child)
2748
+ this.visitNode(child);
2749
+ }
2750
+ return true;
2751
+ }
2752
+ // exprCall → extract function call reference
2753
+ if (nodeType === 'exprCall') {
2754
+ this.extractPascalCall(node);
2755
+ return true;
2756
+ }
2757
+ // interface/implementation sections → visit children
2758
+ if (nodeType === 'interface' || nodeType === 'implementation') {
2759
+ for (let i = 0; i < node.namedChildCount; i++) {
2760
+ const child = node.namedChild(i);
2761
+ if (child)
2762
+ this.visitNode(child);
2763
+ }
2764
+ return true;
2765
+ }
2766
+ // block (begin..end) → visit for calls
2767
+ if (nodeType === 'block') {
2768
+ this.visitPascalBlock(node);
2769
+ return true;
2770
+ }
2771
+ return false;
2772
+ }
2773
+ /**
2774
+ * Extract a Pascal declType node (class, interface, enum, or type alias)
2775
+ */
2776
+ extractPascalDeclType(node) {
2777
+ const nameNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'name');
2778
+ if (!nameNode)
2779
+ return;
2780
+ const name = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
2781
+ // Find the inner type declaration
2782
+ const declClass = node.namedChildren.find((c) => c.type === 'declClass');
2783
+ const declIntf = node.namedChildren.find((c) => c.type === 'declIntf');
2784
+ const typeChild = node.namedChildren.find((c) => c.type === 'type');
2785
+ if (declClass) {
2786
+ const classNode = this.createNode('class', name, node);
2787
+ if (classNode) {
2788
+ // Extract inheritance from typeref children of declClass
2789
+ this.extractPascalInheritance(declClass, classNode.id);
2790
+ // Visit class body
2791
+ this.nodeStack.push(classNode.id);
2792
+ for (let i = 0; i < declClass.namedChildCount; i++) {
2793
+ const child = declClass.namedChild(i);
2794
+ if (child)
2795
+ this.visitNode(child);
2796
+ }
2797
+ this.nodeStack.pop();
2798
+ }
2799
+ }
2800
+ else if (declIntf) {
2801
+ const ifaceNode = this.createNode('interface', name, node);
2802
+ if (ifaceNode) {
2803
+ // Visit interface members
2804
+ this.nodeStack.push(ifaceNode.id);
2805
+ for (let i = 0; i < declIntf.namedChildCount; i++) {
2806
+ const child = declIntf.namedChild(i);
2807
+ if (child)
2808
+ this.visitNode(child);
2809
+ }
2810
+ this.nodeStack.pop();
2811
+ }
2812
+ }
2813
+ else if (typeChild) {
2814
+ // Check if it contains a declEnum
2815
+ const declEnum = typeChild.namedChildren.find((c) => c.type === 'declEnum');
2816
+ if (declEnum) {
2817
+ const enumNode = this.createNode('enum', name, node);
2818
+ if (enumNode) {
2819
+ // Extract enum members
2820
+ this.nodeStack.push(enumNode.id);
2821
+ for (let i = 0; i < declEnum.namedChildCount; i++) {
2822
+ const child = declEnum.namedChild(i);
2823
+ if (child?.type === 'declEnumValue') {
2824
+ const memberName = (0, tree_sitter_helpers_1.getChildByField)(child, 'name');
2825
+ if (memberName) {
2826
+ this.createNode('enum_member', (0, tree_sitter_helpers_1.getNodeText)(memberName, this.source), child);
2827
+ }
2828
+ }
2829
+ }
2830
+ this.nodeStack.pop();
2831
+ }
2832
+ }
2833
+ else {
2834
+ // Simple type alias: type TFoo = string / type TFoo = Integer
2835
+ this.createNode('type_alias', name, node);
2836
+ }
2837
+ }
2838
+ else {
2839
+ // Fallback: could be a forward declaration or simple alias
2840
+ this.createNode('type_alias', name, node);
2841
+ }
2842
+ }
2843
+ /**
2844
+ * Extract Pascal uses clause into individual import nodes
2845
+ */
2846
+ extractPascalUses(node) {
2847
+ const importText = (0, tree_sitter_helpers_1.getNodeText)(node, this.source).trim();
2848
+ for (let i = 0; i < node.namedChildCount; i++) {
2849
+ const child = node.namedChild(i);
2850
+ if (child?.type === 'moduleName') {
2851
+ const unitName = (0, tree_sitter_helpers_1.getNodeText)(child, this.source);
2852
+ this.createNode('import', unitName, child, {
2853
+ signature: importText,
2854
+ });
2855
+ // Create unresolved reference for resolution
2856
+ if (this.nodeStack.length > 0) {
2857
+ const parentId = this.nodeStack[this.nodeStack.length - 1];
2858
+ if (parentId) {
2859
+ this.unresolvedReferences.push({
2860
+ fromNodeId: parentId,
2861
+ referenceName: unitName,
2862
+ referenceKind: 'imports',
2863
+ line: child.startPosition.row + 1,
2864
+ column: child.startPosition.column,
2865
+ });
2866
+ }
2867
+ }
2868
+ }
2869
+ }
2870
+ }
2871
+ /**
2872
+ * Extract a Pascal constant declaration
2873
+ */
2874
+ extractPascalConst(node) {
2875
+ const nameNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'name');
2876
+ if (!nameNode)
2877
+ return;
2878
+ const name = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
2879
+ const defaultValue = node.namedChildren.find((c) => c.type === 'defaultValue');
2880
+ const sig = defaultValue ? (0, tree_sitter_helpers_1.getNodeText)(defaultValue, this.source) : undefined;
2881
+ this.createNode('constant', name, node, { signature: sig });
2882
+ }
2883
+ /**
2884
+ * Extract Pascal inheritance (extends/implements) from declClass typeref children
2885
+ */
2886
+ extractPascalInheritance(declClass, classId) {
2887
+ const typerefs = declClass.namedChildren.filter((c) => c.type === 'typeref');
2888
+ for (let i = 0; i < typerefs.length; i++) {
2889
+ const ref = typerefs[i];
2890
+ const name = (0, tree_sitter_helpers_1.getNodeText)(ref, this.source);
2891
+ this.unresolvedReferences.push({
2892
+ fromNodeId: classId,
2893
+ referenceName: name,
2894
+ referenceKind: i === 0 ? 'extends' : 'implements',
2895
+ line: ref.startPosition.row + 1,
2896
+ column: ref.startPosition.column,
2897
+ });
2898
+ }
2899
+ }
2900
+ /**
2901
+ * Extract calls and resolve method context from a Pascal defProc (implementation body).
2902
+ * Does not create a new node — the declaration was already captured from the interface section.
2903
+ */
2904
+ extractPascalDefProc(node) {
2905
+ // Find the matching declaration node by name to use as call parent
2906
+ const declProc = node.namedChildren.find((c) => c.type === 'declProc');
2907
+ if (!declProc)
2908
+ return;
2909
+ const nameNode = (0, tree_sitter_helpers_1.getChildByField)(declProc, 'name');
2910
+ if (!nameNode)
2911
+ return;
2912
+ const fullName = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source).trim();
2913
+ // fullName is like "TAuthService.Create"
2914
+ const shortName = fullName.includes('.') ? fullName.split('.').pop() : fullName;
2915
+ const fullNameKey = fullName.toLowerCase();
2916
+ const shortNameKey = shortName.toLowerCase();
2917
+ // Build method index on first use (O(n) once, then O(1) per lookup)
2918
+ if (!this.methodIndex) {
2919
+ this.methodIndex = new Map();
2920
+ for (const n of this.nodes) {
2921
+ if (n.kind === 'method' || n.kind === 'function') {
2922
+ const nameKey = n.name.toLowerCase();
2923
+ // Keep first seen short-name mapping to avoid silently overwriting earlier entries.
2924
+ if (!this.methodIndex.has(nameKey)) {
2925
+ this.methodIndex.set(nameKey, n.id);
2926
+ }
2927
+ // For Pascal methods, also index qualified forms (e.g. TAuthService.Create).
2928
+ if (n.kind === 'method') {
2929
+ const qualifiedParts = n.qualifiedName.split('::');
2930
+ if (qualifiedParts.length >= 2) {
2931
+ // Create suffix keys so both "Module.Class.Method" and "Class.Method" can resolve.
2932
+ for (let i = 0; i < qualifiedParts.length - 1; i++) {
2933
+ const scopedName = qualifiedParts.slice(i).join('.').toLowerCase();
2934
+ this.methodIndex.set(scopedName, n.id);
2935
+ }
2936
+ }
2937
+ }
2938
+ }
2939
+ }
2940
+ }
2941
+ const parentId = this.methodIndex.get(fullNameKey) ||
2942
+ this.methodIndex.get(shortNameKey) ||
2943
+ this.nodeStack[this.nodeStack.length - 1];
2944
+ if (!parentId)
2945
+ return;
2946
+ // Visit the block for calls
2947
+ const block = node.namedChildren.find((c) => c.type === 'block');
2948
+ if (block) {
2949
+ this.nodeStack.push(parentId);
2950
+ this.visitPascalBlock(block);
2951
+ this.nodeStack.pop();
2952
+ }
2953
+ }
2954
+ /**
2955
+ * Extract function calls from a Pascal expression
2956
+ */
2957
+ extractPascalCall(node) {
2958
+ if (this.nodeStack.length === 0)
2959
+ return;
2960
+ const callerId = this.nodeStack[this.nodeStack.length - 1];
2961
+ if (!callerId)
2962
+ return;
2963
+ // Get the callee name — first child is typically the identifier or exprDot
2964
+ const firstChild = node.namedChild(0);
2965
+ if (!firstChild)
2966
+ return;
2967
+ let calleeName = '';
2968
+ if (firstChild.type === 'exprDot') {
2969
+ // Qualified call: Obj.Method(...)
2970
+ const identifiers = firstChild.namedChildren.filter((c) => c.type === 'identifier');
2971
+ if (identifiers.length > 0) {
2972
+ calleeName = identifiers.map((id) => (0, tree_sitter_helpers_1.getNodeText)(id, this.source)).join('.');
2973
+ }
2974
+ }
2975
+ else if (firstChild.type === 'identifier') {
2976
+ calleeName = (0, tree_sitter_helpers_1.getNodeText)(firstChild, this.source);
2977
+ }
2978
+ if (calleeName) {
2979
+ this.unresolvedReferences.push({
2980
+ fromNodeId: callerId,
2981
+ referenceName: calleeName,
2982
+ referenceKind: 'calls',
2983
+ line: node.startPosition.row + 1,
2984
+ column: node.startPosition.column,
2985
+ });
2986
+ }
2987
+ // Also visit arguments for nested calls
2988
+ const args = node.namedChildren.find((c) => c.type === 'exprArgs');
2989
+ if (args) {
2990
+ this.visitPascalBlock(args);
2991
+ }
2992
+ }
2993
+ /**
2994
+ * Recursively visit a Pascal block/statement tree for call expressions
2995
+ */
2996
+ visitPascalBlock(node) {
2997
+ for (let i = 0; i < node.namedChildCount; i++) {
2998
+ const child = node.namedChild(i);
2999
+ if (!child)
3000
+ continue;
3001
+ if (child.type === 'exprCall') {
3002
+ this.extractPascalCall(child);
3003
+ }
3004
+ else if (child.type === 'exprDot') {
3005
+ // Check if exprDot contains an exprCall
3006
+ for (let j = 0; j < child.namedChildCount; j++) {
3007
+ const grandchild = child.namedChild(j);
3008
+ if (grandchild?.type === 'exprCall') {
3009
+ this.extractPascalCall(grandchild);
3010
+ }
3011
+ }
3012
+ }
3013
+ else {
3014
+ this.visitPascalBlock(child);
3015
+ }
3016
+ }
3017
+ }
3018
+ }
3019
+ exports.TreeSitterExtractor = TreeSitterExtractor;
3020
+ /**
3021
+ * Extract nodes and edges from source code.
3022
+ *
3023
+ * If `frameworkNames` is provided, framework-specific extractors matching
3024
+ * those names and the file's language are run after the tree-sitter pass.
3025
+ * Their nodes/references/errors are merged into the returned result.
3026
+ */
3027
+ function extractFromSource(filePath, source, language, frameworkNames) {
3028
+ const detectedLanguage = language || (0, grammars_1.detectLanguage)(filePath, source);
3029
+ const fileExtension = path.extname(filePath).toLowerCase();
3030
+ let result;
3031
+ // Use custom extractor for Svelte
3032
+ if (detectedLanguage === 'svelte') {
3033
+ const extractor = new svelte_extractor_1.SvelteExtractor(filePath, source);
3034
+ result = extractor.extract();
3035
+ }
3036
+ else if (detectedLanguage === 'vue') {
3037
+ // Use custom extractor for Vue
3038
+ const extractor = new vue_extractor_1.VueExtractor(filePath, source);
3039
+ result = extractor.extract();
3040
+ }
3041
+ else if (detectedLanguage === 'liquid') {
3042
+ // Use custom extractor for Liquid
3043
+ const extractor = new liquid_extractor_1.LiquidExtractor(filePath, source);
3044
+ result = extractor.extract();
3045
+ }
3046
+ else if (detectedLanguage === 'xml') {
3047
+ // Custom extractor for MyBatis mapper XML. Non-mapper XML returns just a
3048
+ // file node so the watcher tracks it without emitting symbols.
3049
+ const extractor = new mybatis_extractor_1.MyBatisExtractor(filePath, source);
3050
+ result = extractor.extract();
3051
+ }
3052
+ else if ((0, grammars_1.isFileLevelOnlyLanguage)(detectedLanguage)) {
3053
+ // No symbol extraction at this stage — files are tracked at the file-record
3054
+ // level only. Framework extractors (Drupal routing yml, Spring `@Value`
3055
+ // resolution against application.yml/application.properties) run later and
3056
+ // add per-file nodes/references when they apply.
3057
+ result = { nodes: [], edges: [], unresolvedReferences: [], errors: [], durationMs: 0 };
3058
+ }
3059
+ else if (detectedLanguage === 'pascal' &&
3060
+ (fileExtension === '.dfm' || fileExtension === '.fmx')) {
3061
+ // Use custom extractor for DFM/FMX form files
3062
+ const extractor = new dfm_extractor_1.DfmExtractor(filePath, source);
3063
+ result = extractor.extract();
3064
+ }
3065
+ else {
3066
+ const extractor = new TreeSitterExtractor(filePath, source, detectedLanguage);
3067
+ result = extractor.extract();
3068
+ }
3069
+ // Framework-specific extraction (routes, middleware, etc.)
3070
+ if (frameworkNames && frameworkNames.length > 0) {
3071
+ const allResolvers = (0, frameworks_1.getAllFrameworkResolvers)();
3072
+ const applicable = (0, frameworks_1.getApplicableFrameworks)(allResolvers.filter((r) => frameworkNames.includes(r.name)), detectedLanguage);
3073
+ for (const fw of applicable) {
3074
+ if (!fw.extract)
3075
+ continue;
3076
+ try {
3077
+ const fwResult = fw.extract(filePath, source);
3078
+ result.nodes.push(...fwResult.nodes);
3079
+ result.unresolvedReferences.push(...fwResult.references);
3080
+ }
3081
+ catch (err) {
3082
+ result.errors.push({
3083
+ message: `Framework extractor '${fw.name}' failed: ${err instanceof Error ? err.message : String(err)}`,
3084
+ filePath,
3085
+ severity: 'warning',
3086
+ });
3087
+ }
3088
+ }
3089
+ }
3090
+ return result;
3091
+ }
3092
+ //# sourceMappingURL=tree-sitter.js.map