cotx-engine 0.1.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 (501) hide show
  1. package/LICENSE +94 -0
  2. package/README.md +103 -0
  3. package/dist/commands/compile.d.ts +3 -0
  4. package/dist/commands/compile.js +93 -0
  5. package/dist/commands/compile.js.map +1 -0
  6. package/dist/commands/context.d.ts +1 -0
  7. package/dist/commands/context.js +98 -0
  8. package/dist/commands/context.js.map +1 -0
  9. package/dist/commands/diff.d.ts +19 -0
  10. package/dist/commands/diff.js +127 -0
  11. package/dist/commands/diff.js.map +1 -0
  12. package/dist/commands/impact.d.ts +3 -0
  13. package/dist/commands/impact.js +91 -0
  14. package/dist/commands/impact.js.map +1 -0
  15. package/dist/commands/init.d.ts +1 -0
  16. package/dist/commands/init.js +13 -0
  17. package/dist/commands/init.js.map +1 -0
  18. package/dist/commands/lint.d.ts +13 -0
  19. package/dist/commands/lint.js +290 -0
  20. package/dist/commands/lint.js.map +1 -0
  21. package/dist/commands/map.d.ts +6 -0
  22. package/dist/commands/map.js +409 -0
  23. package/dist/commands/map.js.map +1 -0
  24. package/dist/commands/migrate.d.ts +16 -0
  25. package/dist/commands/migrate.js +150 -0
  26. package/dist/commands/migrate.js.map +1 -0
  27. package/dist/commands/query.d.ts +3 -0
  28. package/dist/commands/query.js +47 -0
  29. package/dist/commands/query.js.map +1 -0
  30. package/dist/commands/rename.d.ts +5 -0
  31. package/dist/commands/rename.js +163 -0
  32. package/dist/commands/rename.js.map +1 -0
  33. package/dist/commands/snapshot.d.ts +6 -0
  34. package/dist/commands/snapshot.js +48 -0
  35. package/dist/commands/snapshot.js.map +1 -0
  36. package/dist/commands/status.d.ts +1 -0
  37. package/dist/commands/status.js +72 -0
  38. package/dist/commands/status.js.map +1 -0
  39. package/dist/commands/update.d.ts +8 -0
  40. package/dist/commands/update.js +163 -0
  41. package/dist/commands/update.js.map +1 -0
  42. package/dist/commands/write.d.ts +6 -0
  43. package/dist/commands/write.js +221 -0
  44. package/dist/commands/write.js.map +1 -0
  45. package/dist/compiler/auto-describe.d.ts +13 -0
  46. package/dist/compiler/auto-describe.js +91 -0
  47. package/dist/compiler/auto-describe.js.map +1 -0
  48. package/dist/compiler/concept-compiler.d.ts +21 -0
  49. package/dist/compiler/concept-compiler.js +125 -0
  50. package/dist/compiler/concept-compiler.js.map +1 -0
  51. package/dist/compiler/contract-compiler.d.ts +16 -0
  52. package/dist/compiler/contract-compiler.js +90 -0
  53. package/dist/compiler/contract-compiler.js.map +1 -0
  54. package/dist/compiler/delta-detector.d.ts +8 -0
  55. package/dist/compiler/delta-detector.js +34 -0
  56. package/dist/compiler/delta-detector.js.map +1 -0
  57. package/dist/compiler/flow-compiler.d.ts +18 -0
  58. package/dist/compiler/flow-compiler.js +69 -0
  59. package/dist/compiler/flow-compiler.js.map +1 -0
  60. package/dist/compiler/module-compiler.d.ts +18 -0
  61. package/dist/compiler/module-compiler.js +420 -0
  62. package/dist/compiler/module-compiler.js.map +1 -0
  63. package/dist/compiler/stale-detector.d.ts +22 -0
  64. package/dist/compiler/stale-detector.js +79 -0
  65. package/dist/compiler/stale-detector.js.map +1 -0
  66. package/dist/config/ignore-service.d.ts +26 -0
  67. package/dist/config/ignore-service.js +366 -0
  68. package/dist/config/ignore-service.js.map +1 -0
  69. package/dist/core/analysis/cluster-enricher.d.ts +38 -0
  70. package/dist/core/analysis/cluster-enricher.js +169 -0
  71. package/dist/core/analysis/cluster-enricher.js.map +1 -0
  72. package/dist/core/analysis/community-processor.d.ts +39 -0
  73. package/dist/core/analysis/community-processor.js +319 -0
  74. package/dist/core/analysis/community-processor.js.map +1 -0
  75. package/dist/core/analysis/process-processor.d.ts +51 -0
  76. package/dist/core/analysis/process-processor.js +318 -0
  77. package/dist/core/analysis/process-processor.js.map +1 -0
  78. package/dist/core/bridge.d.ts +15 -0
  79. package/dist/core/bridge.js +63 -0
  80. package/dist/core/bridge.js.map +1 -0
  81. package/dist/core/export/json-exporter.d.ts +43 -0
  82. package/dist/core/export/json-exporter.js +13 -0
  83. package/dist/core/export/json-exporter.js.map +1 -0
  84. package/dist/core/graph/graph.d.ts +2 -0
  85. package/dist/core/graph/graph.js +79 -0
  86. package/dist/core/graph/graph.js.map +1 -0
  87. package/dist/core/graph/types.d.ts +25 -0
  88. package/dist/core/graph/types.js +2 -0
  89. package/dist/core/graph/types.js.map +1 -0
  90. package/dist/core/parser/ast-cache.d.ts +11 -0
  91. package/dist/core/parser/ast-cache.js +36 -0
  92. package/dist/core/parser/ast-cache.js.map +1 -0
  93. package/dist/core/parser/call-processor.d.ts +105 -0
  94. package/dist/core/parser/call-processor.js +1807 -0
  95. package/dist/core/parser/call-processor.js.map +1 -0
  96. package/dist/core/parser/call-routing.d.ts +55 -0
  97. package/dist/core/parser/call-routing.js +113 -0
  98. package/dist/core/parser/call-routing.js.map +1 -0
  99. package/dist/core/parser/call-sites/extract-language-call-site.d.ts +10 -0
  100. package/dist/core/parser/call-sites/extract-language-call-site.js +23 -0
  101. package/dist/core/parser/call-sites/extract-language-call-site.js.map +1 -0
  102. package/dist/core/parser/call-sites/java.d.ts +9 -0
  103. package/dist/core/parser/call-sites/java.js +31 -0
  104. package/dist/core/parser/call-sites/java.js.map +1 -0
  105. package/dist/core/parser/cluster-enricher.d.ts +38 -0
  106. package/dist/core/parser/cluster-enricher.js +169 -0
  107. package/dist/core/parser/cluster-enricher.js.map +1 -0
  108. package/dist/core/parser/community-processor.d.ts +39 -0
  109. package/dist/core/parser/community-processor.js +321 -0
  110. package/dist/core/parser/community-processor.js.map +1 -0
  111. package/dist/core/parser/constants.d.ts +16 -0
  112. package/dist/core/parser/constants.js +17 -0
  113. package/dist/core/parser/constants.js.map +1 -0
  114. package/dist/core/parser/entry-point-scoring.d.ts +57 -0
  115. package/dist/core/parser/entry-point-scoring.js +377 -0
  116. package/dist/core/parser/entry-point-scoring.js.map +1 -0
  117. package/dist/core/parser/export-detection.d.ts +57 -0
  118. package/dist/core/parser/export-detection.js +234 -0
  119. package/dist/core/parser/export-detection.js.map +1 -0
  120. package/dist/core/parser/field-extractor.d.ts +34 -0
  121. package/dist/core/parser/field-extractor.js +33 -0
  122. package/dist/core/parser/field-extractor.js.map +1 -0
  123. package/dist/core/parser/field-extractors/configs/c-cpp.d.ts +16 -0
  124. package/dist/core/parser/field-extractors/configs/c-cpp.js +129 -0
  125. package/dist/core/parser/field-extractors/configs/c-cpp.js.map +1 -0
  126. package/dist/core/parser/field-extractors/configs/csharp.d.ts +15 -0
  127. package/dist/core/parser/field-extractors/configs/csharp.js +129 -0
  128. package/dist/core/parser/field-extractors/configs/csharp.js.map +1 -0
  129. package/dist/core/parser/field-extractors/configs/dart.d.ts +12 -0
  130. package/dist/core/parser/field-extractors/configs/dart.js +93 -0
  131. package/dist/core/parser/field-extractors/configs/dart.js.map +1 -0
  132. package/dist/core/parser/field-extractors/configs/go.d.ts +12 -0
  133. package/dist/core/parser/field-extractors/configs/go.js +66 -0
  134. package/dist/core/parser/field-extractors/configs/go.js.map +1 -0
  135. package/dist/core/parser/field-extractors/configs/helpers.d.ts +40 -0
  136. package/dist/core/parser/field-extractors/configs/helpers.js +118 -0
  137. package/dist/core/parser/field-extractors/configs/helpers.js.map +1 -0
  138. package/dist/core/parser/field-extractors/configs/jvm.d.ts +17 -0
  139. package/dist/core/parser/field-extractors/configs/jvm.js +139 -0
  140. package/dist/core/parser/field-extractors/configs/jvm.js.map +1 -0
  141. package/dist/core/parser/field-extractors/configs/php.d.ts +12 -0
  142. package/dist/core/parser/field-extractors/configs/php.js +69 -0
  143. package/dist/core/parser/field-extractors/configs/php.js.map +1 -0
  144. package/dist/core/parser/field-extractors/configs/python.d.ts +15 -0
  145. package/dist/core/parser/field-extractors/configs/python.js +92 -0
  146. package/dist/core/parser/field-extractors/configs/python.js.map +1 -0
  147. package/dist/core/parser/field-extractors/configs/ruby.d.ts +15 -0
  148. package/dist/core/parser/field-extractors/configs/ruby.js +68 -0
  149. package/dist/core/parser/field-extractors/configs/ruby.js.map +1 -0
  150. package/dist/core/parser/field-extractors/configs/rust.d.ts +12 -0
  151. package/dist/core/parser/field-extractors/configs/rust.js +58 -0
  152. package/dist/core/parser/field-extractors/configs/rust.js.map +1 -0
  153. package/dist/core/parser/field-extractors/configs/swift.d.ts +15 -0
  154. package/dist/core/parser/field-extractors/configs/swift.js +75 -0
  155. package/dist/core/parser/field-extractors/configs/swift.js.map +1 -0
  156. package/dist/core/parser/field-extractors/configs/typescript-javascript.d.ts +14 -0
  157. package/dist/core/parser/field-extractors/configs/typescript-javascript.js +72 -0
  158. package/dist/core/parser/field-extractors/configs/typescript-javascript.js.map +1 -0
  159. package/dist/core/parser/field-extractors/generic.d.ts +61 -0
  160. package/dist/core/parser/field-extractors/generic.js +170 -0
  161. package/dist/core/parser/field-extractors/generic.js.map +1 -0
  162. package/dist/core/parser/field-extractors/typescript.d.ts +16 -0
  163. package/dist/core/parser/field-extractors/typescript.js +167 -0
  164. package/dist/core/parser/field-extractors/typescript.js.map +1 -0
  165. package/dist/core/parser/field-types.d.ts +46 -0
  166. package/dist/core/parser/field-types.js +2 -0
  167. package/dist/core/parser/field-types.js.map +1 -0
  168. package/dist/core/parser/filesystem-walker.d.ts +28 -0
  169. package/dist/core/parser/filesystem-walker.js +82 -0
  170. package/dist/core/parser/filesystem-walker.js.map +1 -0
  171. package/dist/core/parser/framework-detection.d.ts +149 -0
  172. package/dist/core/parser/framework-detection.js +782 -0
  173. package/dist/core/parser/framework-detection.js.map +1 -0
  174. package/dist/core/parser/heritage-processor.d.ts +52 -0
  175. package/dist/core/parser/heritage-processor.js +339 -0
  176. package/dist/core/parser/heritage-processor.js.map +1 -0
  177. package/dist/core/parser/import-processor.d.ts +33 -0
  178. package/dist/core/parser/import-processor.js +382 -0
  179. package/dist/core/parser/import-processor.js.map +1 -0
  180. package/dist/core/parser/import-resolvers/csharp.d.ts +19 -0
  181. package/dist/core/parser/import-resolvers/csharp.js +132 -0
  182. package/dist/core/parser/import-resolvers/csharp.js.map +1 -0
  183. package/dist/core/parser/import-resolvers/dart.d.ts +7 -0
  184. package/dist/core/parser/import-resolvers/dart.js +45 -0
  185. package/dist/core/parser/import-resolvers/dart.js.map +1 -0
  186. package/dist/core/parser/import-resolvers/go.d.ts +18 -0
  187. package/dist/core/parser/import-resolvers/go.js +62 -0
  188. package/dist/core/parser/import-resolvers/go.js.map +1 -0
  189. package/dist/core/parser/import-resolvers/jvm.d.ts +32 -0
  190. package/dist/core/parser/import-resolvers/jvm.js +160 -0
  191. package/dist/core/parser/import-resolvers/jvm.js.map +1 -0
  192. package/dist/core/parser/import-resolvers/php.d.ts +25 -0
  193. package/dist/core/parser/import-resolvers/php.js +81 -0
  194. package/dist/core/parser/import-resolvers/php.js.map +1 -0
  195. package/dist/core/parser/import-resolvers/python.d.ts +25 -0
  196. package/dist/core/parser/import-resolvers/python.js +85 -0
  197. package/dist/core/parser/import-resolvers/python.js.map +1 -0
  198. package/dist/core/parser/import-resolvers/ruby.d.ts +15 -0
  199. package/dist/core/parser/import-resolvers/ruby.js +21 -0
  200. package/dist/core/parser/import-resolvers/ruby.js.map +1 -0
  201. package/dist/core/parser/import-resolvers/rust.d.ts +18 -0
  202. package/dist/core/parser/import-resolvers/rust.js +119 -0
  203. package/dist/core/parser/import-resolvers/rust.js.map +1 -0
  204. package/dist/core/parser/import-resolvers/standard.d.ts +36 -0
  205. package/dist/core/parser/import-resolvers/standard.js +144 -0
  206. package/dist/core/parser/import-resolvers/standard.js.map +1 -0
  207. package/dist/core/parser/import-resolvers/swift.d.ts +7 -0
  208. package/dist/core/parser/import-resolvers/swift.js +25 -0
  209. package/dist/core/parser/import-resolvers/swift.js.map +1 -0
  210. package/dist/core/parser/import-resolvers/types.d.ts +44 -0
  211. package/dist/core/parser/import-resolvers/types.js +7 -0
  212. package/dist/core/parser/import-resolvers/types.js.map +1 -0
  213. package/dist/core/parser/import-resolvers/utils.d.ts +35 -0
  214. package/dist/core/parser/import-resolvers/utils.js +150 -0
  215. package/dist/core/parser/import-resolvers/utils.js.map +1 -0
  216. package/dist/core/parser/import-resolvers/vue.d.ts +8 -0
  217. package/dist/core/parser/import-resolvers/vue.js +10 -0
  218. package/dist/core/parser/import-resolvers/vue.js.map +1 -0
  219. package/dist/core/parser/language-config.d.ts +52 -0
  220. package/dist/core/parser/language-config.js +182 -0
  221. package/dist/core/parser/language-config.js.map +1 -0
  222. package/dist/core/parser/language-provider.d.ts +126 -0
  223. package/dist/core/parser/language-provider.js +25 -0
  224. package/dist/core/parser/language-provider.js.map +1 -0
  225. package/dist/core/parser/languages/c-cpp.d.ts +12 -0
  226. package/dist/core/parser/languages/c-cpp.js +312 -0
  227. package/dist/core/parser/languages/c-cpp.js.map +1 -0
  228. package/dist/core/parser/languages/csharp.d.ts +8 -0
  229. package/dist/core/parser/languages/csharp.js +127 -0
  230. package/dist/core/parser/languages/csharp.js.map +1 -0
  231. package/dist/core/parser/languages/dart.d.ts +12 -0
  232. package/dist/core/parser/languages/dart.js +91 -0
  233. package/dist/core/parser/languages/dart.js.map +1 -0
  234. package/dist/core/parser/languages/go.d.ts +11 -0
  235. package/dist/core/parser/languages/go.js +32 -0
  236. package/dist/core/parser/languages/go.js.map +1 -0
  237. package/dist/core/parser/languages/index.d.ts +38 -0
  238. package/dist/core/parser/languages/index.js +63 -0
  239. package/dist/core/parser/languages/index.js.map +1 -0
  240. package/dist/core/parser/languages/java.d.ts +9 -0
  241. package/dist/core/parser/languages/java.js +33 -0
  242. package/dist/core/parser/languages/java.js.map +1 -0
  243. package/dist/core/parser/languages/kotlin.d.ts +9 -0
  244. package/dist/core/parser/languages/kotlin.js +112 -0
  245. package/dist/core/parser/languages/kotlin.js.map +1 -0
  246. package/dist/core/parser/languages/php.d.ts +8 -0
  247. package/dist/core/parser/languages/php.js +226 -0
  248. package/dist/core/parser/languages/php.js.map +1 -0
  249. package/dist/core/parser/languages/python.d.ts +12 -0
  250. package/dist/core/parser/languages/python.js +66 -0
  251. package/dist/core/parser/languages/python.js.map +1 -0
  252. package/dist/core/parser/languages/ruby.d.ts +9 -0
  253. package/dist/core/parser/languages/ruby.js +109 -0
  254. package/dist/core/parser/languages/ruby.js.map +1 -0
  255. package/dist/core/parser/languages/rust.d.ts +12 -0
  256. package/dist/core/parser/languages/rust.js +121 -0
  257. package/dist/core/parser/languages/rust.js.map +1 -0
  258. package/dist/core/parser/languages/swift.d.ts +12 -0
  259. package/dist/core/parser/languages/swift.js +233 -0
  260. package/dist/core/parser/languages/swift.js.map +1 -0
  261. package/dist/core/parser/languages/typescript.d.ts +11 -0
  262. package/dist/core/parser/languages/typescript.js +169 -0
  263. package/dist/core/parser/languages/typescript.js.map +1 -0
  264. package/dist/core/parser/languages/vue.d.ts +13 -0
  265. package/dist/core/parser/languages/vue.js +65 -0
  266. package/dist/core/parser/languages/vue.js.map +1 -0
  267. package/dist/core/parser/markdown-processor.d.ts +17 -0
  268. package/dist/core/parser/markdown-processor.js +125 -0
  269. package/dist/core/parser/markdown-processor.js.map +1 -0
  270. package/dist/core/parser/method-extractors/configs/c-cpp.d.ts +3 -0
  271. package/dist/core/parser/method-extractors/configs/c-cpp.js +276 -0
  272. package/dist/core/parser/method-extractors/configs/c-cpp.js.map +1 -0
  273. package/dist/core/parser/method-extractors/configs/csharp.d.ts +2 -0
  274. package/dist/core/parser/method-extractors/configs/csharp.js +243 -0
  275. package/dist/core/parser/method-extractors/configs/csharp.js.map +1 -0
  276. package/dist/core/parser/method-extractors/configs/dart.d.ts +2 -0
  277. package/dist/core/parser/method-extractors/configs/dart.js +263 -0
  278. package/dist/core/parser/method-extractors/configs/dart.js.map +1 -0
  279. package/dist/core/parser/method-extractors/configs/go.d.ts +2 -0
  280. package/dist/core/parser/method-extractors/configs/go.js +120 -0
  281. package/dist/core/parser/method-extractors/configs/go.js.map +1 -0
  282. package/dist/core/parser/method-extractors/configs/jvm.d.ts +3 -0
  283. package/dist/core/parser/method-extractors/configs/jvm.js +309 -0
  284. package/dist/core/parser/method-extractors/configs/jvm.js.map +1 -0
  285. package/dist/core/parser/method-extractors/configs/php.d.ts +2 -0
  286. package/dist/core/parser/method-extractors/configs/php.js +243 -0
  287. package/dist/core/parser/method-extractors/configs/php.js.map +1 -0
  288. package/dist/core/parser/method-extractors/configs/python.d.ts +2 -0
  289. package/dist/core/parser/method-extractors/configs/python.js +219 -0
  290. package/dist/core/parser/method-extractors/configs/python.js.map +1 -0
  291. package/dist/core/parser/method-extractors/configs/ruby.d.ts +2 -0
  292. package/dist/core/parser/method-extractors/configs/ruby.js +201 -0
  293. package/dist/core/parser/method-extractors/configs/ruby.js.map +1 -0
  294. package/dist/core/parser/method-extractors/configs/rust.d.ts +2 -0
  295. package/dist/core/parser/method-extractors/configs/rust.js +120 -0
  296. package/dist/core/parser/method-extractors/configs/rust.js.map +1 -0
  297. package/dist/core/parser/method-extractors/configs/swift.d.ts +2 -0
  298. package/dist/core/parser/method-extractors/configs/swift.js +191 -0
  299. package/dist/core/parser/method-extractors/configs/swift.js.map +1 -0
  300. package/dist/core/parser/method-extractors/configs/typescript-javascript.d.ts +3 -0
  301. package/dist/core/parser/method-extractors/configs/typescript-javascript.js +231 -0
  302. package/dist/core/parser/method-extractors/configs/typescript-javascript.js.map +1 -0
  303. package/dist/core/parser/method-extractors/generic.d.ts +11 -0
  304. package/dist/core/parser/method-extractors/generic.js +162 -0
  305. package/dist/core/parser/method-extractors/generic.js.map +1 -0
  306. package/dist/core/parser/method-types.d.ts +110 -0
  307. package/dist/core/parser/method-types.js +2 -0
  308. package/dist/core/parser/method-types.js.map +1 -0
  309. package/dist/core/parser/mro-processor.d.ts +46 -0
  310. package/dist/core/parser/mro-processor.js +677 -0
  311. package/dist/core/parser/mro-processor.js.map +1 -0
  312. package/dist/core/parser/named-binding-processor.d.ts +18 -0
  313. package/dist/core/parser/named-binding-processor.js +43 -0
  314. package/dist/core/parser/named-binding-processor.js.map +1 -0
  315. package/dist/core/parser/named-bindings/csharp.d.ts +3 -0
  316. package/dist/core/parser/named-bindings/csharp.js +38 -0
  317. package/dist/core/parser/named-bindings/csharp.js.map +1 -0
  318. package/dist/core/parser/named-bindings/java.d.ts +3 -0
  319. package/dist/core/parser/named-bindings/java.js +30 -0
  320. package/dist/core/parser/named-bindings/java.js.map +1 -0
  321. package/dist/core/parser/named-bindings/kotlin.d.ts +3 -0
  322. package/dist/core/parser/named-bindings/kotlin.js +37 -0
  323. package/dist/core/parser/named-bindings/kotlin.js.map +1 -0
  324. package/dist/core/parser/named-bindings/php.d.ts +3 -0
  325. package/dist/core/parser/named-bindings/php.js +62 -0
  326. package/dist/core/parser/named-bindings/php.js.map +1 -0
  327. package/dist/core/parser/named-bindings/python.d.ts +3 -0
  328. package/dist/core/parser/named-bindings/python.js +50 -0
  329. package/dist/core/parser/named-bindings/python.js.map +1 -0
  330. package/dist/core/parser/named-bindings/rust.d.ts +3 -0
  331. package/dist/core/parser/named-bindings/rust.js +67 -0
  332. package/dist/core/parser/named-bindings/rust.js.map +1 -0
  333. package/dist/core/parser/named-bindings/types.d.ts +16 -0
  334. package/dist/core/parser/named-bindings/types.js +7 -0
  335. package/dist/core/parser/named-bindings/types.js.map +1 -0
  336. package/dist/core/parser/named-bindings/typescript.d.ts +3 -0
  337. package/dist/core/parser/named-bindings/typescript.js +59 -0
  338. package/dist/core/parser/named-bindings/typescript.js.map +1 -0
  339. package/dist/core/parser/parsing-processor.d.ts +23 -0
  340. package/dist/core/parser/parsing-processor.js +464 -0
  341. package/dist/core/parser/parsing-processor.js.map +1 -0
  342. package/dist/core/parser/pipeline.d.ts +17 -0
  343. package/dist/core/parser/pipeline.js +1405 -0
  344. package/dist/core/parser/pipeline.js.map +1 -0
  345. package/dist/core/parser/process-processor.d.ts +51 -0
  346. package/dist/core/parser/process-processor.js +318 -0
  347. package/dist/core/parser/process-processor.js.map +1 -0
  348. package/dist/core/parser/resolution-context.d.ts +58 -0
  349. package/dist/core/parser/resolution-context.js +136 -0
  350. package/dist/core/parser/resolution-context.js.map +1 -0
  351. package/dist/core/parser/route-extractors/expo.d.ts +1 -0
  352. package/dist/core/parser/route-extractors/expo.js +37 -0
  353. package/dist/core/parser/route-extractors/expo.js.map +1 -0
  354. package/dist/core/parser/route-extractors/middleware.d.ts +47 -0
  355. package/dist/core/parser/route-extractors/middleware.js +168 -0
  356. package/dist/core/parser/route-extractors/middleware.js.map +1 -0
  357. package/dist/core/parser/route-extractors/nextjs.d.ts +3 -0
  358. package/dist/core/parser/route-extractors/nextjs.js +77 -0
  359. package/dist/core/parser/route-extractors/nextjs.js.map +1 -0
  360. package/dist/core/parser/route-extractors/php.d.ts +7 -0
  361. package/dist/core/parser/route-extractors/php.js +23 -0
  362. package/dist/core/parser/route-extractors/php.js.map +1 -0
  363. package/dist/core/parser/route-extractors/response-shapes.d.ts +20 -0
  364. package/dist/core/parser/route-extractors/response-shapes.js +295 -0
  365. package/dist/core/parser/route-extractors/response-shapes.js.map +1 -0
  366. package/dist/core/parser/structure-processor.d.ts +2 -0
  367. package/dist/core/parser/structure-processor.js +37 -0
  368. package/dist/core/parser/structure-processor.js.map +1 -0
  369. package/dist/core/parser/symbol-table.d.ts +79 -0
  370. package/dist/core/parser/symbol-table.js +116 -0
  371. package/dist/core/parser/symbol-table.js.map +1 -0
  372. package/dist/core/parser/tree-sitter-queries.d.ts +16 -0
  373. package/dist/core/parser/tree-sitter-queries.js +1180 -0
  374. package/dist/core/parser/tree-sitter-queries.js.map +1 -0
  375. package/dist/core/parser/type-env.d.ts +81 -0
  376. package/dist/core/parser/type-env.js +1048 -0
  377. package/dist/core/parser/type-env.js.map +1 -0
  378. package/dist/core/parser/type-extractors/c-cpp.d.ts +7 -0
  379. package/dist/core/parser/type-extractors/c-cpp.js +533 -0
  380. package/dist/core/parser/type-extractors/c-cpp.js.map +1 -0
  381. package/dist/core/parser/type-extractors/csharp.d.ts +2 -0
  382. package/dist/core/parser/type-extractors/csharp.js +584 -0
  383. package/dist/core/parser/type-extractors/csharp.js.map +1 -0
  384. package/dist/core/parser/type-extractors/dart.d.ts +15 -0
  385. package/dist/core/parser/type-extractors/dart.js +370 -0
  386. package/dist/core/parser/type-extractors/dart.js.map +1 -0
  387. package/dist/core/parser/type-extractors/go.d.ts +2 -0
  388. package/dist/core/parser/type-extractors/go.js +514 -0
  389. package/dist/core/parser/type-extractors/go.js.map +1 -0
  390. package/dist/core/parser/type-extractors/jvm.d.ts +3 -0
  391. package/dist/core/parser/type-extractors/jvm.js +857 -0
  392. package/dist/core/parser/type-extractors/jvm.js.map +1 -0
  393. package/dist/core/parser/type-extractors/php.d.ts +2 -0
  394. package/dist/core/parser/type-extractors/php.js +535 -0
  395. package/dist/core/parser/type-extractors/php.js.map +1 -0
  396. package/dist/core/parser/type-extractors/python.d.ts +2 -0
  397. package/dist/core/parser/type-extractors/python.js +475 -0
  398. package/dist/core/parser/type-extractors/python.js.map +1 -0
  399. package/dist/core/parser/type-extractors/ruby.d.ts +2 -0
  400. package/dist/core/parser/type-extractors/ruby.js +378 -0
  401. package/dist/core/parser/type-extractors/ruby.js.map +1 -0
  402. package/dist/core/parser/type-extractors/rust.d.ts +2 -0
  403. package/dist/core/parser/type-extractors/rust.js +516 -0
  404. package/dist/core/parser/type-extractors/rust.js.map +1 -0
  405. package/dist/core/parser/type-extractors/shared.d.ts +131 -0
  406. package/dist/core/parser/type-extractors/shared.js +797 -0
  407. package/dist/core/parser/type-extractors/shared.js.map +1 -0
  408. package/dist/core/parser/type-extractors/swift.d.ts +2 -0
  409. package/dist/core/parser/type-extractors/swift.js +485 -0
  410. package/dist/core/parser/type-extractors/swift.js.map +1 -0
  411. package/dist/core/parser/type-extractors/types.d.ts +172 -0
  412. package/dist/core/parser/type-extractors/types.js +2 -0
  413. package/dist/core/parser/type-extractors/types.js.map +1 -0
  414. package/dist/core/parser/type-extractors/typescript.d.ts +2 -0
  415. package/dist/core/parser/type-extractors/typescript.js +662 -0
  416. package/dist/core/parser/type-extractors/typescript.js.map +1 -0
  417. package/dist/core/parser/utils/ast-helpers.d.ts +73 -0
  418. package/dist/core/parser/utils/ast-helpers.js +415 -0
  419. package/dist/core/parser/utils/ast-helpers.js.map +1 -0
  420. package/dist/core/parser/utils/call-analysis.d.ts +75 -0
  421. package/dist/core/parser/utils/call-analysis.js +575 -0
  422. package/dist/core/parser/utils/call-analysis.js.map +1 -0
  423. package/dist/core/parser/utils/event-loop.d.ts +5 -0
  424. package/dist/core/parser/utils/event-loop.js +6 -0
  425. package/dist/core/parser/utils/event-loop.js.map +1 -0
  426. package/dist/core/parser/utils/method-props.d.ts +8 -0
  427. package/dist/core/parser/utils/method-props.js +39 -0
  428. package/dist/core/parser/utils/method-props.js.map +1 -0
  429. package/dist/core/parser/utils/verbose.d.ts +1 -0
  430. package/dist/core/parser/utils/verbose.js +8 -0
  431. package/dist/core/parser/utils/verbose.js.map +1 -0
  432. package/dist/core/parser/vue-sfc-extractor.d.ts +44 -0
  433. package/dist/core/parser/vue-sfc-extractor.js +95 -0
  434. package/dist/core/parser/vue-sfc-extractor.js.map +1 -0
  435. package/dist/core/parser/workers/parse-worker.d.ts +171 -0
  436. package/dist/core/parser/workers/parse-worker.js +1724 -0
  437. package/dist/core/parser/workers/parse-worker.js.map +1 -0
  438. package/dist/core/parser/workers/worker-pool.d.ts +16 -0
  439. package/dist/core/parser/workers/worker-pool.js +124 -0
  440. package/dist/core/parser/workers/worker-pool.js.map +1 -0
  441. package/dist/core/shared/graph-types.d.ts +61 -0
  442. package/dist/core/shared/graph-types.js +5 -0
  443. package/dist/core/shared/graph-types.js.map +1 -0
  444. package/dist/core/shared/index.d.ts +4 -0
  445. package/dist/core/shared/index.js +4 -0
  446. package/dist/core/shared/index.js.map +1 -0
  447. package/dist/core/shared/language-detection.d.ts +22 -0
  448. package/dist/core/shared/language-detection.js +137 -0
  449. package/dist/core/shared/language-detection.js.map +1 -0
  450. package/dist/core/shared/languages.d.ts +23 -0
  451. package/dist/core/shared/languages.js +25 -0
  452. package/dist/core/shared/languages.js.map +1 -0
  453. package/dist/core/shared/pipeline.d.ts +15 -0
  454. package/dist/core/shared/pipeline.js +5 -0
  455. package/dist/core/shared/pipeline.js.map +1 -0
  456. package/dist/core/tree-sitter/parser-loader.d.ts +5 -0
  457. package/dist/core/tree-sitter/parser-loader.js +71 -0
  458. package/dist/core/tree-sitter/parser-loader.js.map +1 -0
  459. package/dist/index.d.ts +2 -0
  460. package/dist/index.js +132 -0
  461. package/dist/index.js.map +1 -0
  462. package/dist/lib/hash.d.ts +1 -0
  463. package/dist/lib/hash.js +6 -0
  464. package/dist/lib/hash.js.map +1 -0
  465. package/dist/lib/naming.d.ts +12 -0
  466. package/dist/lib/naming.js +28 -0
  467. package/dist/lib/naming.js.map +1 -0
  468. package/dist/lib/utils.d.ts +1 -0
  469. package/dist/lib/utils.js +4 -0
  470. package/dist/lib/utils.js.map +1 -0
  471. package/dist/mcp/server.d.ts +26 -0
  472. package/dist/mcp/server.js +282 -0
  473. package/dist/mcp/server.js.map +1 -0
  474. package/dist/mcp/tools.d.ts +37 -0
  475. package/dist/mcp/tools.js +650 -0
  476. package/dist/mcp/tools.js.map +1 -0
  477. package/dist/query/bm25.d.ts +19 -0
  478. package/dist/query/bm25.js +60 -0
  479. package/dist/query/bm25.js.map +1 -0
  480. package/dist/query/graph-index.d.ts +40 -0
  481. package/dist/query/graph-index.js +178 -0
  482. package/dist/query/graph-index.js.map +1 -0
  483. package/dist/store/derived-index.d.ts +4 -0
  484. package/dist/store/derived-index.js +68 -0
  485. package/dist/store/derived-index.js.map +1 -0
  486. package/dist/store/meta.d.ts +1 -0
  487. package/dist/store/meta.js +3 -0
  488. package/dist/store/meta.js.map +1 -0
  489. package/dist/store/schema.d.ts +135 -0
  490. package/dist/store/schema.js +2 -0
  491. package/dist/store/schema.js.map +1 -0
  492. package/dist/store/store.d.ts +49 -0
  493. package/dist/store/store.js +254 -0
  494. package/dist/store/store.js.map +1 -0
  495. package/dist/types/pipeline.d.ts +12 -0
  496. package/dist/types/pipeline.js +2 -0
  497. package/dist/types/pipeline.js.map +1 -0
  498. package/package.json +69 -0
  499. package/skills/cotx-enrich/SKILL.md +59 -0
  500. package/vendor/leiden/index.cjs +355 -0
  501. package/vendor/leiden/utils.cjs +392 -0
@@ -0,0 +1,1724 @@
1
+ import { parentPort } from 'node:worker_threads';
2
+ import Parser from 'tree-sitter';
3
+ import JavaScript from 'tree-sitter-javascript';
4
+ import TypeScript from 'tree-sitter-typescript';
5
+ import Python from 'tree-sitter-python';
6
+ import Java from 'tree-sitter-java';
7
+ import C from 'tree-sitter-c';
8
+ import CPP from 'tree-sitter-cpp';
9
+ import CSharp from 'tree-sitter-c-sharp';
10
+ import Go from 'tree-sitter-go';
11
+ import Rust from 'tree-sitter-rust';
12
+ import PHP from 'tree-sitter-php';
13
+ import Ruby from 'tree-sitter-ruby';
14
+ import { createRequire } from 'node:module';
15
+ import { SupportedLanguages } from '../../shared/index.js';
16
+ import { getProvider } from '../languages/index.js';
17
+ import { getTreeSitterBufferSize, TREE_SITTER_MAX_BUFFER } from '../constants.js';
18
+ // tree-sitter-swift is an optionalDependency — may not be installed
19
+ const _require = createRequire(import.meta.url);
20
+ let Swift = null;
21
+ try {
22
+ Swift = _require('tree-sitter-swift');
23
+ }
24
+ catch { }
25
+ // tree-sitter-dart is an optionalDependency — may not be installed
26
+ let Dart = null;
27
+ try {
28
+ Dart = _require('tree-sitter-dart');
29
+ }
30
+ catch { }
31
+ // tree-sitter-kotlin is an optionalDependency — may not be installed
32
+ let Kotlin = null;
33
+ try {
34
+ Kotlin = _require('tree-sitter-kotlin');
35
+ }
36
+ catch { }
37
+ import { getLanguageFromFilename } from '../../shared/index.js';
38
+ import { FUNCTION_NODE_TYPES, getDefinitionNodeFromCaptures, findEnclosingClassInfo, getLabelFromCaptures, findDescendant, extractStringContent, genericFuncName, inferFunctionLabel, CLASS_CONTAINER_TYPES, } from '../utils/ast-helpers.js';
39
+ import { countCallArguments, inferCallForm, extractReceiverName, extractReceiverNode, extractMixedChain, extractCallArgTypes, } from '../utils/call-analysis.js';
40
+ import { extractParsedCallSite } from '../call-sites/extract-language-call-site.js';
41
+ import { buildTypeEnv } from '../type-env.js';
42
+ import { detectFrameworkFromAST } from '../framework-detection.js';
43
+ import { generateId } from '../../../lib/utils.js';
44
+ import { preprocessImportPath } from '../import-processor.js';
45
+ import { extractVueScript, extractTemplateComponents, isVueSetupTopLevel, } from '../vue-sfc-extractor.js';
46
+ import { buildMethodProps, arityForIdFromInfo } from '../utils/method-props.js';
47
+ // ============================================================================
48
+ // Worker-local parser + language map
49
+ // ============================================================================
50
+ const parser = new Parser();
51
+ const languageMap = {
52
+ [SupportedLanguages.JavaScript]: JavaScript,
53
+ [SupportedLanguages.TypeScript]: TypeScript.typescript,
54
+ [`${SupportedLanguages.TypeScript}:tsx`]: TypeScript.tsx,
55
+ [SupportedLanguages.Python]: Python,
56
+ [SupportedLanguages.Java]: Java,
57
+ [SupportedLanguages.C]: C,
58
+ [SupportedLanguages.CPlusPlus]: CPP,
59
+ [SupportedLanguages.CSharp]: CSharp,
60
+ [SupportedLanguages.Go]: Go,
61
+ [SupportedLanguages.Rust]: Rust,
62
+ ...(Kotlin ? { [SupportedLanguages.Kotlin]: Kotlin } : {}),
63
+ [SupportedLanguages.PHP]: PHP.php_only,
64
+ [SupportedLanguages.Ruby]: Ruby,
65
+ [SupportedLanguages.Vue]: TypeScript.typescript,
66
+ ...(Dart ? { [SupportedLanguages.Dart]: Dart } : {}),
67
+ ...(Swift ? { [SupportedLanguages.Swift]: Swift } : {}),
68
+ };
69
+ /**
70
+ * Check if a language grammar is available in this worker.
71
+ * Duplicated from parser-loader.ts because workers can't import from the main thread.
72
+ * Extra filePath parameter needed to distinguish .tsx from .ts (different grammars
73
+ * under the same SupportedLanguages.TypeScript key).
74
+ */
75
+ const isLanguageAvailable = (language, filePath) => {
76
+ const key = language === SupportedLanguages.TypeScript && filePath.endsWith('.tsx')
77
+ ? `${language}:tsx`
78
+ : language;
79
+ return key in languageMap && languageMap[key] != null;
80
+ };
81
+ const setLanguage = (language, filePath) => {
82
+ const key = language === SupportedLanguages.TypeScript && filePath.endsWith('.tsx')
83
+ ? `${language}:tsx`
84
+ : language;
85
+ const lang = languageMap[key];
86
+ if (!lang)
87
+ throw new Error(`Unsupported language: ${language}`);
88
+ parser.setLanguage(lang);
89
+ };
90
+ // ============================================================================
91
+ // Per-file O(1) memoization — avoids repeated parent-chain walks per symbol.
92
+ // Three bare Maps cleared at file boundaries. Map.get() returns undefined for
93
+ // missing keys, so `cached !== undefined` distinguishes "not computed" from
94
+ // a stored null (enclosing class/function not found = top-level).
95
+ // ============================================================================
96
+ const classIdCache = new Map();
97
+ const functionIdCache = new Map();
98
+ const exportCache = new Map();
99
+ const clearCaches = () => {
100
+ classIdCache.clear();
101
+ functionIdCache.clear();
102
+ exportCache.clear();
103
+ fieldInfoCache.clear();
104
+ methodInfoCache.clear();
105
+ };
106
+ // ============================================================================
107
+ // FieldExtractor cache — extract field metadata once per class, reuse for each property.
108
+ // Keyed by class node startIndex (unique per AST node within a file).
109
+ // ============================================================================
110
+ const fieldInfoCache = new Map();
111
+ /**
112
+ * Walk up from a definition node to find the nearest enclosing class/struct/interface
113
+ * AST node. Returns the SyntaxNode itself (not an ID) for passing to FieldExtractor.
114
+ */
115
+ function findEnclosingClassNode(node) {
116
+ let current = node.parent;
117
+ while (current) {
118
+ if (CLASS_CONTAINER_TYPES.has(current.type)) {
119
+ // Ruby singleton_class (class << self) has no name field — walk up to
120
+ // the enclosing class/module so the caller gets a node with a findable name.
121
+ if (current.type === 'singleton_class') {
122
+ current = current.parent;
123
+ continue;
124
+ }
125
+ return current;
126
+ }
127
+ current = current.parent;
128
+ }
129
+ return null;
130
+ }
131
+ /**
132
+ * For C++ out-of-class method definitions (e.g. `void Foo::bar() {}`), extract the
133
+ * class name from the qualified_identifier scope and find the class declaration in the
134
+ * file's AST. Returns the class SyntaxNode or null if not found.
135
+ *
136
+ * Handles pointer/reference return types where function_declarator is nested inside
137
+ * pointer_declarator or reference_declarator.
138
+ */
139
+ function findClassNodeByQualifiedName(node) {
140
+ const declarator = node.childForFieldName('declarator');
141
+ if (!declarator)
142
+ return null;
143
+ // Find the function_declarator, recursively unwrapping pointer_declarator /
144
+ // reference_declarator chains (e.g. int** Foo::bar() has
145
+ // pointer_declarator → pointer_declarator → function_declarator).
146
+ let funcDecl = null;
147
+ if (declarator.type === 'function_declarator') {
148
+ funcDecl = declarator;
149
+ }
150
+ else {
151
+ let current = declarator;
152
+ while (current && !funcDecl) {
153
+ for (let i = 0; i < current.namedChildCount; i++) {
154
+ const child = current.namedChild(i);
155
+ if (child?.type === 'function_declarator') {
156
+ funcDecl = child;
157
+ break;
158
+ }
159
+ }
160
+ if (!funcDecl) {
161
+ const next = current.namedChildren.find((c) => c.type === 'pointer_declarator' || c.type === 'reference_declarator');
162
+ current = next ?? null;
163
+ }
164
+ }
165
+ }
166
+ if (!funcDecl)
167
+ return null;
168
+ // Check if the inner declarator is a qualified_identifier (Foo::bar)
169
+ const innerDecl = funcDecl.childForFieldName('declarator');
170
+ if (!innerDecl || innerDecl.type !== 'qualified_identifier')
171
+ return null;
172
+ const scope = innerDecl.childForFieldName('scope');
173
+ if (!scope)
174
+ return null;
175
+ const className = scope.text;
176
+ // Search the file for a matching class/struct specifier, including inside
177
+ // namespace_definition blocks (the majority of production C++ uses namespaces).
178
+ const root = node.tree.rootNode;
179
+ const classTypes = new Set(['class_specifier', 'struct_specifier']);
180
+ const searchIn = (parent) => {
181
+ for (let i = 0; i < parent.namedChildCount; i++) {
182
+ const child = parent.namedChild(i);
183
+ if (!child)
184
+ continue;
185
+ if (classTypes.has(child.type)) {
186
+ const nameNode = child.childForFieldName('name');
187
+ if (nameNode?.text === className)
188
+ return child;
189
+ }
190
+ // Recurse into namespace blocks
191
+ if (child.type === 'namespace_definition') {
192
+ const found = searchIn(child);
193
+ if (found)
194
+ return found;
195
+ }
196
+ }
197
+ return null;
198
+ };
199
+ return searchIn(root);
200
+ }
201
+ /**
202
+ * Minimal no-op SymbolTable stub for FieldExtractorContext in the worker.
203
+ * Field extraction only uses symbolTable.lookupExactAll for optional type resolution —
204
+ * returning [] causes the extractor to use the raw type string, which is fine for us.
205
+ */
206
+ const NOOP_SYMBOL_TABLE = {
207
+ lookupExactAll: () => [],
208
+ lookupExact: () => undefined,
209
+ lookupExactFull: () => undefined,
210
+ };
211
+ /**
212
+ * Get (or extract and cache) field info for a class node.
213
+ * Returns a name→FieldInfo map, or undefined if the provider has no field extractor
214
+ * or the class yielded no fields.
215
+ */
216
+ function getFieldInfo(classNode, provider, context) {
217
+ if (!provider.fieldExtractor)
218
+ return undefined;
219
+ const cacheKey = classNode.startIndex;
220
+ let cached = fieldInfoCache.get(cacheKey);
221
+ if (cached)
222
+ return cached;
223
+ const result = provider.fieldExtractor.extract(classNode, context);
224
+ if (!result?.fields?.length)
225
+ return undefined;
226
+ cached = new Map();
227
+ for (const field of result.fields) {
228
+ cached.set(field.name, field);
229
+ }
230
+ fieldInfoCache.set(cacheKey, cached);
231
+ return cached;
232
+ }
233
+ // ============================================================================
234
+ // MethodExtractor cache — extract method metadata once per class, reuse for each method.
235
+ // Keyed by class node startIndex (unique per AST node within a file).
236
+ // ============================================================================
237
+ const methodInfoCache = new Map();
238
+ /**
239
+ * Get (or extract and cache) method info for a class node.
240
+ * Returns a "name:line" → MethodInfo map, or undefined if the provider has no method extractor
241
+ * or the class yielded no methods.
242
+ * Keyed by name:line (not name alone) to support overloaded methods in Java/Kotlin.
243
+ */
244
+ function getMethodInfo(classNode, provider, context) {
245
+ if (!provider.methodExtractor)
246
+ return undefined;
247
+ const cacheKey = classNode.startIndex;
248
+ let cached = methodInfoCache.get(cacheKey);
249
+ if (cached)
250
+ return cached;
251
+ const result = provider.methodExtractor.extract(classNode, context);
252
+ if (!result?.methods?.length)
253
+ return undefined;
254
+ cached = new Map();
255
+ for (const method of result.methods) {
256
+ cached.set(`${method.name}:${method.line}`, method);
257
+ }
258
+ methodInfoCache.set(cacheKey, cached);
259
+ return cached;
260
+ }
261
+ // ============================================================================
262
+ // Enclosing function detection (for call extraction) — cached
263
+ // ============================================================================
264
+ /** Walk up AST to find enclosing function, return its generateId or null for top-level.
265
+ * Applies provider.labelOverride so the label matches the definition phase (single source of truth). */
266
+ const findEnclosingFunctionId = (node, filePath, provider) => {
267
+ const cached = functionIdCache.get(node);
268
+ if (cached !== undefined)
269
+ return cached;
270
+ let current = node.parent;
271
+ while (current) {
272
+ if (FUNCTION_NODE_TYPES.has(current.type)) {
273
+ const efnResult = provider.methodExtractor?.extractFunctionName?.(current);
274
+ const funcName = efnResult?.funcName ?? genericFuncName(current);
275
+ const label = efnResult?.label ?? inferFunctionLabel(current.type);
276
+ if (funcName) {
277
+ // Apply labelOverride so label matches definition phase (e.g., Kotlin Function→Method).
278
+ // null means "skip as definition" — keep original label for scope identification.
279
+ let finalLabel = label;
280
+ if (provider.labelOverride) {
281
+ const override = provider.labelOverride(current, label);
282
+ if (override !== null)
283
+ finalLabel = override;
284
+ }
285
+ // Qualify with enclosing class to match definition-phase node IDs
286
+ const classInfo = cachedFindEnclosingClassInfo(current, filePath);
287
+ const qualifiedName = classInfo ? `${classInfo.className}.${funcName}` : funcName;
288
+ // Include #<arity> suffix to match definition-phase Method/Constructor IDs.
289
+ // Use the same MethodExtractor (getMethodInfo) as the definition phase.
290
+ let arity;
291
+ if (finalLabel === 'Method' || finalLabel === 'Constructor') {
292
+ const classNode = findEnclosingClassNode(current) ?? findClassNodeByQualifiedName(current);
293
+ if (classNode) {
294
+ const methodMap = getMethodInfo(classNode, provider, {
295
+ filePath,
296
+ language: getLanguageFromFilename(filePath),
297
+ });
298
+ const defLine = current.startPosition.row + 1;
299
+ const info = methodMap?.get(`${funcName}:${defLine}`);
300
+ if (info) {
301
+ arity = info.parameters.some((p) => p.isVariadic)
302
+ ? undefined
303
+ : info.parameters.length;
304
+ }
305
+ }
306
+ }
307
+ const arityTag = arity !== undefined ? `#${arity}` : '';
308
+ const result = generateId(finalLabel, `${filePath}:${qualifiedName}${arityTag}`);
309
+ functionIdCache.set(node, result);
310
+ return result;
311
+ }
312
+ }
313
+ // Language-specific enclosing function resolution (e.g., Dart where
314
+ // function_body is a sibling of function_signature, not a child).
315
+ if (provider.enclosingFunctionFinder) {
316
+ const customResult = provider.enclosingFunctionFinder(current);
317
+ if (customResult) {
318
+ let finalLabel = customResult.label;
319
+ if (provider.labelOverride) {
320
+ const override = provider.labelOverride(current.previousSibling, finalLabel);
321
+ if (override !== null)
322
+ finalLabel = override;
323
+ }
324
+ // Qualify custom result with enclosing class
325
+ const classInfo = cachedFindEnclosingClassInfo(current.previousSibling ?? current, filePath);
326
+ const qualifiedName = classInfo
327
+ ? `${classInfo.className}.${customResult.funcName}`
328
+ : customResult.funcName;
329
+ // Include #<arity> suffix to match definition-phase Method/Constructor IDs.
330
+ const sigNode = current.previousSibling ?? current;
331
+ let arity2;
332
+ if (finalLabel === 'Method' || finalLabel === 'Constructor') {
333
+ const classNode2 = findEnclosingClassNode(sigNode) ?? findClassNodeByQualifiedName(sigNode);
334
+ if (classNode2) {
335
+ const methodMap2 = getMethodInfo(classNode2, provider, {
336
+ filePath,
337
+ language: getLanguageFromFilename(filePath),
338
+ });
339
+ const defLine2 = sigNode.startPosition.row + 1;
340
+ const info2 = methodMap2?.get(`${customResult.funcName}:${defLine2}`);
341
+ if (info2) {
342
+ arity2 = info2.parameters.some((p) => p.isVariadic)
343
+ ? undefined
344
+ : info2.parameters.length;
345
+ }
346
+ }
347
+ }
348
+ const arityTag2 = arity2 !== undefined ? `#${arity2}` : '';
349
+ const result = generateId(finalLabel, `${filePath}:${qualifiedName}${arityTag2}`);
350
+ functionIdCache.set(node, result);
351
+ return result;
352
+ }
353
+ }
354
+ current = current.parent;
355
+ }
356
+ functionIdCache.set(node, null);
357
+ return null;
358
+ };
359
+ /** Cached wrapper for findEnclosingClassInfo — avoids repeated parent walks. */
360
+ const cachedFindEnclosingClassInfo = (node, filePath) => {
361
+ const cached = classIdCache.get(node);
362
+ if (cached !== undefined)
363
+ return cached;
364
+ const result = findEnclosingClassInfo(node, filePath);
365
+ classIdCache.set(node, result);
366
+ return result;
367
+ };
368
+ /** Cached wrapper for export checking — avoids repeated parent walks per symbol. */
369
+ const cachedExportCheck = (checker, node, name) => {
370
+ const cached = exportCache.get(node);
371
+ if (cached !== undefined)
372
+ return cached;
373
+ const result = checker(node, name);
374
+ exportCache.set(node, result);
375
+ return result;
376
+ };
377
+ // Label detection moved to shared getLabelFromCaptures in utils.ts
378
+ // DEFINITION_CAPTURE_KEYS and getDefinitionNodeFromCaptures imported from ../utils.js
379
+ // ============================================================================
380
+ // Process a batch of files
381
+ // ============================================================================
382
+ const processBatch = (files, onProgress) => {
383
+ const result = {
384
+ nodes: [],
385
+ relationships: [],
386
+ symbols: [],
387
+ imports: [],
388
+ calls: [],
389
+ assignments: [],
390
+ heritage: [],
391
+ routes: [],
392
+ fetchCalls: [],
393
+ decoratorRoutes: [],
394
+ toolDefs: [],
395
+ ormQueries: [],
396
+ constructorBindings: [],
397
+ typeEnvBindings: [],
398
+ skippedLanguages: {},
399
+ fileCount: 0,
400
+ };
401
+ // Group by language to minimize setLanguage calls
402
+ const byLanguage = new Map();
403
+ for (const file of files) {
404
+ const lang = getLanguageFromFilename(file.path);
405
+ if (!lang)
406
+ continue;
407
+ let list = byLanguage.get(lang);
408
+ if (!list) {
409
+ list = [];
410
+ byLanguage.set(lang, list);
411
+ }
412
+ list.push(file);
413
+ }
414
+ let totalProcessed = 0;
415
+ let lastReported = 0;
416
+ const PROGRESS_INTERVAL = 100; // report every 100 files
417
+ const onFileProcessed = onProgress
418
+ ? () => {
419
+ totalProcessed++;
420
+ if (totalProcessed - lastReported >= PROGRESS_INTERVAL) {
421
+ lastReported = totalProcessed;
422
+ onProgress(totalProcessed);
423
+ }
424
+ }
425
+ : undefined;
426
+ for (const [language, langFiles] of byLanguage) {
427
+ const provider = getProvider(language);
428
+ const queryString = provider.treeSitterQueries;
429
+ if (!queryString)
430
+ continue;
431
+ // Track if we need to handle tsx separately
432
+ const tsxFiles = [];
433
+ const regularFiles = [];
434
+ if (language === SupportedLanguages.TypeScript) {
435
+ for (const f of langFiles) {
436
+ if (f.path.endsWith('.tsx')) {
437
+ tsxFiles.push(f);
438
+ }
439
+ else {
440
+ regularFiles.push(f);
441
+ }
442
+ }
443
+ }
444
+ else {
445
+ regularFiles.push(...langFiles);
446
+ }
447
+ // Process regular files for this language
448
+ if (regularFiles.length > 0) {
449
+ if (isLanguageAvailable(language, regularFiles[0].path)) {
450
+ try {
451
+ setLanguage(language, regularFiles[0].path);
452
+ processFileGroup(regularFiles, language, queryString, result, onFileProcessed);
453
+ }
454
+ catch {
455
+ // parser unavailable — skip this language group
456
+ }
457
+ }
458
+ else {
459
+ result.skippedLanguages[language] =
460
+ (result.skippedLanguages[language] || 0) + regularFiles.length;
461
+ }
462
+ }
463
+ // Process tsx files separately (different grammar)
464
+ if (tsxFiles.length > 0) {
465
+ if (isLanguageAvailable(language, tsxFiles[0].path)) {
466
+ try {
467
+ setLanguage(language, tsxFiles[0].path);
468
+ processFileGroup(tsxFiles, language, queryString, result, onFileProcessed);
469
+ }
470
+ catch {
471
+ // parser unavailable — skip this language group
472
+ }
473
+ }
474
+ else {
475
+ result.skippedLanguages[language] =
476
+ (result.skippedLanguages[language] || 0) + tsxFiles.length;
477
+ }
478
+ }
479
+ }
480
+ return result;
481
+ };
482
+ const ROUTE_HTTP_METHODS = new Set([
483
+ 'get',
484
+ 'post',
485
+ 'put',
486
+ 'patch',
487
+ 'delete',
488
+ 'options',
489
+ 'any',
490
+ 'match',
491
+ ]);
492
+ const ROUTE_RESOURCE_METHODS = new Set(['resource', 'apiResource']);
493
+ // Express/Hono method names that register routes
494
+ const EXPRESS_ROUTE_METHODS = new Set([
495
+ 'get',
496
+ 'post',
497
+ 'put',
498
+ 'delete',
499
+ 'patch',
500
+ 'all',
501
+ 'use',
502
+ 'route',
503
+ ]);
504
+ // HTTP client methods that are ONLY used by clients, not Express route registration.
505
+ // Methods like get/post/put/delete/patch overlap with Express — those are captured by
506
+ // the express_route handler as route definitions, not consumers. The fetch() global
507
+ // function is captured separately by the route.fetch query.
508
+ const HTTP_CLIENT_ONLY_METHODS = new Set(['head', 'options', 'request', 'ajax']);
509
+ // Decorator names that indicate HTTP route handlers (NestJS, Flask, FastAPI, Spring)
510
+ const ROUTE_DECORATOR_NAMES = new Set([
511
+ 'Get',
512
+ 'Post',
513
+ 'Put',
514
+ 'Delete',
515
+ 'Patch',
516
+ 'Route',
517
+ 'get',
518
+ 'post',
519
+ 'put',
520
+ 'delete',
521
+ 'patch',
522
+ 'route',
523
+ 'RequestMapping',
524
+ 'GetMapping',
525
+ 'PostMapping',
526
+ 'PutMapping',
527
+ 'DeleteMapping',
528
+ ]);
529
+ const RESOURCE_ACTIONS = ['index', 'create', 'store', 'show', 'edit', 'update', 'destroy'];
530
+ const API_RESOURCE_ACTIONS = ['index', 'store', 'show', 'update', 'destroy'];
531
+ /** Check if node is a scoped_call_expression with object 'Route' */
532
+ function isRouteStaticCall(node) {
533
+ if (node.type !== 'scoped_call_expression')
534
+ return false;
535
+ const obj = node.childForFieldName?.('object') ?? node.children?.[0];
536
+ return obj?.text === 'Route';
537
+ }
538
+ /** Get the method name from a scoped_call_expression or member_call_expression */
539
+ function getCallMethodName(node) {
540
+ const nameNode = node.childForFieldName?.('name') ?? node.children?.find((c) => c.type === 'name');
541
+ return nameNode?.text ?? null;
542
+ }
543
+ /** Get the arguments node from a call expression */
544
+ function getArguments(node) {
545
+ return node.children?.find((c) => c.type === 'arguments') ?? null;
546
+ }
547
+ /** Find the closure body inside arguments */
548
+ function findClosureBody(argsNode) {
549
+ if (!argsNode)
550
+ return null;
551
+ for (const child of argsNode.children ?? []) {
552
+ if (child.type === 'argument') {
553
+ for (const inner of child.children ?? []) {
554
+ if (inner.type === 'anonymous_function' || inner.type === 'arrow_function') {
555
+ return (inner.childForFieldName?.('body') ??
556
+ inner.children?.find((c) => c.type === 'compound_statement') ??
557
+ null);
558
+ }
559
+ }
560
+ }
561
+ if (child.type === 'anonymous_function' || child.type === 'arrow_function') {
562
+ return (child.childForFieldName?.('body') ??
563
+ child.children?.find((c) => c.type === 'compound_statement') ??
564
+ null);
565
+ }
566
+ }
567
+ return null;
568
+ }
569
+ /** Extract first string argument from arguments node */
570
+ function extractFirstStringArg(argsNode) {
571
+ if (!argsNode)
572
+ return null;
573
+ for (const child of argsNode.children ?? []) {
574
+ const target = child.type === 'argument' ? child.children?.[0] : child;
575
+ if (!target)
576
+ continue;
577
+ if (target.type === 'string' || target.type === 'encapsed_string') {
578
+ return extractStringContent(target);
579
+ }
580
+ }
581
+ return null;
582
+ }
583
+ /** Extract middleware from arguments — handles string or array */
584
+ function extractMiddlewareArg(argsNode) {
585
+ if (!argsNode)
586
+ return [];
587
+ for (const child of argsNode.children ?? []) {
588
+ const target = child.type === 'argument' ? child.children?.[0] : child;
589
+ if (!target)
590
+ continue;
591
+ if (target.type === 'string' || target.type === 'encapsed_string') {
592
+ const val = extractStringContent(target);
593
+ return val ? [val] : [];
594
+ }
595
+ if (target.type === 'array_creation_expression') {
596
+ const items = [];
597
+ for (const el of target.children ?? []) {
598
+ if (el.type === 'array_element_initializer') {
599
+ const str = el.children?.find((c) => c.type === 'string' || c.type === 'encapsed_string');
600
+ const val = str ? extractStringContent(str) : null;
601
+ if (val)
602
+ items.push(val);
603
+ }
604
+ }
605
+ return items;
606
+ }
607
+ }
608
+ return [];
609
+ }
610
+ /** Extract Controller::class from arguments */
611
+ function extractClassArg(argsNode) {
612
+ if (!argsNode)
613
+ return null;
614
+ for (const child of argsNode.children ?? []) {
615
+ const target = child.type === 'argument' ? child.children?.[0] : child;
616
+ if (target?.type === 'class_constant_access_expression') {
617
+ return target.children?.find((c) => c.type === 'name')?.text ?? null;
618
+ }
619
+ }
620
+ return null;
621
+ }
622
+ /** Extract controller class name from arguments: [Controller::class, 'method'] or 'Controller@method' */
623
+ function extractControllerTarget(argsNode) {
624
+ if (!argsNode)
625
+ return { controller: null, method: null };
626
+ const args = [];
627
+ for (const child of argsNode.children ?? []) {
628
+ if (child.type === 'argument')
629
+ args.push(child.children?.[0]);
630
+ else if (child.type !== '(' && child.type !== ')' && child.type !== ',')
631
+ args.push(child);
632
+ }
633
+ // Second arg is the handler
634
+ const handlerNode = args[1];
635
+ if (!handlerNode)
636
+ return { controller: null, method: null };
637
+ // Array syntax: [UserController::class, 'index']
638
+ if (handlerNode.type === 'array_creation_expression') {
639
+ let controller = null;
640
+ let method = null;
641
+ const elements = [];
642
+ for (const el of handlerNode.children ?? []) {
643
+ if (el.type === 'array_element_initializer')
644
+ elements.push(el);
645
+ }
646
+ if (elements[0]) {
647
+ const classAccess = findDescendant(elements[0], 'class_constant_access_expression');
648
+ if (classAccess) {
649
+ controller = classAccess.children?.find((c) => c.type === 'name')?.text ?? null;
650
+ }
651
+ }
652
+ if (elements[1]) {
653
+ const str = findDescendant(elements[1], 'string');
654
+ method = str ? extractStringContent(str) : null;
655
+ }
656
+ return { controller, method };
657
+ }
658
+ // String syntax: 'UserController@index'
659
+ if (handlerNode.type === 'string' || handlerNode.type === 'encapsed_string') {
660
+ const text = extractStringContent(handlerNode);
661
+ if (text?.includes('@')) {
662
+ const [controller, method] = text.split('@');
663
+ return { controller, method };
664
+ }
665
+ }
666
+ // Class reference: UserController::class (invokable controller)
667
+ if (handlerNode.type === 'class_constant_access_expression') {
668
+ const controller = handlerNode.children?.find((c) => c.type === 'name')?.text ?? null;
669
+ return { controller, method: '__invoke' };
670
+ }
671
+ return { controller: null, method: null };
672
+ }
673
+ /**
674
+ * Unwrap a chained call like Route::middleware('auth')->prefix('api')->group(fn)
675
+ */
676
+ function unwrapRouteChain(node) {
677
+ if (node.type !== 'member_call_expression')
678
+ return null;
679
+ const terminalMethod = getCallMethodName(node);
680
+ if (!terminalMethod)
681
+ return null;
682
+ const terminalArgs = getArguments(node);
683
+ const attributes = [];
684
+ let current = node.children?.[0];
685
+ while (current) {
686
+ if (current.type === 'member_call_expression') {
687
+ const method = getCallMethodName(current);
688
+ const args = getArguments(current);
689
+ if (method)
690
+ attributes.unshift({ method, argsNode: args });
691
+ current = current.children?.[0];
692
+ }
693
+ else if (current.type === 'scoped_call_expression') {
694
+ const obj = current.childForFieldName?.('object') ?? current.children?.[0];
695
+ if (obj?.text !== 'Route')
696
+ return null;
697
+ const method = getCallMethodName(current);
698
+ const args = getArguments(current);
699
+ if (method)
700
+ attributes.unshift({ method, argsNode: args });
701
+ return { isRouteFacade: true, terminalMethod, attributes, terminalArgs, node };
702
+ }
703
+ else {
704
+ break;
705
+ }
706
+ }
707
+ return null;
708
+ }
709
+ /** Parse Route::group(['middleware' => ..., 'prefix' => ...], fn) array syntax */
710
+ function parseArrayGroupArgs(argsNode) {
711
+ const ctx = { middleware: [], prefix: null, controller: null };
712
+ if (!argsNode)
713
+ return ctx;
714
+ for (const child of argsNode.children ?? []) {
715
+ const target = child.type === 'argument' ? child.children?.[0] : child;
716
+ if (target?.type === 'array_creation_expression') {
717
+ for (const el of target.children ?? []) {
718
+ if (el.type !== 'array_element_initializer')
719
+ continue;
720
+ const children = el.children ?? [];
721
+ const arrowIdx = children.findIndex((c) => c.type === '=>');
722
+ if (arrowIdx === -1)
723
+ continue;
724
+ const key = extractStringContent(children[arrowIdx - 1]);
725
+ const val = children[arrowIdx + 1];
726
+ if (key === 'middleware') {
727
+ if (val?.type === 'string') {
728
+ const s = extractStringContent(val);
729
+ if (s)
730
+ ctx.middleware.push(s);
731
+ }
732
+ else if (val?.type === 'array_creation_expression') {
733
+ for (const item of val.children ?? []) {
734
+ if (item.type === 'array_element_initializer') {
735
+ const str = item.children?.find((c) => c.type === 'string');
736
+ const s = str ? extractStringContent(str) : null;
737
+ if (s)
738
+ ctx.middleware.push(s);
739
+ }
740
+ }
741
+ }
742
+ }
743
+ else if (key === 'prefix') {
744
+ ctx.prefix = extractStringContent(val) ?? null;
745
+ }
746
+ else if (key === 'controller') {
747
+ if (val?.type === 'class_constant_access_expression') {
748
+ ctx.controller = val.children?.find((c) => c.type === 'name')?.text ?? null;
749
+ }
750
+ }
751
+ }
752
+ }
753
+ }
754
+ return ctx;
755
+ }
756
+ function extractLaravelRoutes(tree, filePath) {
757
+ const routes = [];
758
+ function resolveStack(stack) {
759
+ const middleware = [];
760
+ let prefix = null;
761
+ let controller = null;
762
+ for (const ctx of stack) {
763
+ middleware.push(...ctx.middleware);
764
+ if (ctx.prefix)
765
+ prefix = prefix ? `${prefix}/${ctx.prefix}`.replace(/\/+/g, '/') : ctx.prefix;
766
+ if (ctx.controller)
767
+ controller = ctx.controller;
768
+ }
769
+ return { middleware, prefix, controller };
770
+ }
771
+ function emitRoute(httpMethod, argsNode, lineNumber, groupStack, chainAttrs) {
772
+ const effective = resolveStack(groupStack);
773
+ for (const attr of chainAttrs) {
774
+ if (attr.method === 'middleware')
775
+ effective.middleware.push(...extractMiddlewareArg(attr.argsNode));
776
+ if (attr.method === 'prefix') {
777
+ const p = extractFirstStringArg(attr.argsNode);
778
+ if (p)
779
+ effective.prefix = effective.prefix ? `${effective.prefix}/${p}` : p;
780
+ }
781
+ if (attr.method === 'controller') {
782
+ const cls = extractClassArg(attr.argsNode);
783
+ if (cls)
784
+ effective.controller = cls;
785
+ }
786
+ }
787
+ const routePath = extractFirstStringArg(argsNode);
788
+ if (ROUTE_RESOURCE_METHODS.has(httpMethod)) {
789
+ const target = extractControllerTarget(argsNode);
790
+ const actions = httpMethod === 'apiResource' ? API_RESOURCE_ACTIONS : RESOURCE_ACTIONS;
791
+ for (const action of actions) {
792
+ routes.push({
793
+ filePath,
794
+ httpMethod,
795
+ routePath,
796
+ controllerName: target.controller ?? effective.controller,
797
+ methodName: action,
798
+ middleware: [...effective.middleware],
799
+ prefix: effective.prefix,
800
+ lineNumber,
801
+ });
802
+ }
803
+ }
804
+ else {
805
+ const target = extractControllerTarget(argsNode);
806
+ routes.push({
807
+ filePath,
808
+ httpMethod,
809
+ routePath,
810
+ controllerName: target.controller ?? effective.controller,
811
+ methodName: target.method,
812
+ middleware: [...effective.middleware],
813
+ prefix: effective.prefix,
814
+ lineNumber,
815
+ });
816
+ }
817
+ }
818
+ function walk(node, groupStack) {
819
+ // Case 1: Simple Route::get(...), Route::post(...), etc.
820
+ if (isRouteStaticCall(node)) {
821
+ const method = getCallMethodName(node);
822
+ if (method && (ROUTE_HTTP_METHODS.has(method) || ROUTE_RESOURCE_METHODS.has(method))) {
823
+ emitRoute(method, getArguments(node), node.startPosition.row, groupStack, []);
824
+ return;
825
+ }
826
+ if (method === 'group') {
827
+ const argsNode = getArguments(node);
828
+ const groupCtx = parseArrayGroupArgs(argsNode);
829
+ const body = findClosureBody(argsNode);
830
+ if (body) {
831
+ groupStack.push(groupCtx);
832
+ walkChildren(body, groupStack);
833
+ groupStack.pop();
834
+ }
835
+ return;
836
+ }
837
+ }
838
+ // Case 2: Fluent chain — Route::middleware(...)->group(...) or Route::middleware(...)->get(...)
839
+ const chain = unwrapRouteChain(node);
840
+ if (chain) {
841
+ if (chain.terminalMethod === 'group') {
842
+ const groupCtx = { middleware: [], prefix: null, controller: null };
843
+ for (const attr of chain.attributes) {
844
+ if (attr.method === 'middleware')
845
+ groupCtx.middleware.push(...extractMiddlewareArg(attr.argsNode));
846
+ if (attr.method === 'prefix')
847
+ groupCtx.prefix = extractFirstStringArg(attr.argsNode);
848
+ if (attr.method === 'controller')
849
+ groupCtx.controller = extractClassArg(attr.argsNode);
850
+ }
851
+ const body = findClosureBody(chain.terminalArgs);
852
+ if (body) {
853
+ groupStack.push(groupCtx);
854
+ walkChildren(body, groupStack);
855
+ groupStack.pop();
856
+ }
857
+ return;
858
+ }
859
+ if (ROUTE_HTTP_METHODS.has(chain.terminalMethod) ||
860
+ ROUTE_RESOURCE_METHODS.has(chain.terminalMethod)) {
861
+ emitRoute(chain.terminalMethod, chain.terminalArgs, node.startPosition.row, groupStack, chain.attributes);
862
+ return;
863
+ }
864
+ }
865
+ // Default: recurse into children
866
+ walkChildren(node, groupStack);
867
+ }
868
+ function walkChildren(node, groupStack) {
869
+ for (const child of node.children ?? []) {
870
+ walk(child, groupStack);
871
+ }
872
+ }
873
+ walk(tree.rootNode, []);
874
+ return routes;
875
+ }
876
+ // ============================================================================
877
+ // ORM Query Detection (Prisma + Supabase)
878
+ // ============================================================================
879
+ const PRISMA_QUERY_RE = /\bprisma\.(\w+)\.(findMany|findFirst|findUnique|findUniqueOrThrow|findFirstOrThrow|create|createMany|update|updateMany|delete|deleteMany|upsert|count|aggregate|groupBy)\s*\(/g;
880
+ const SUPABASE_QUERY_RE = /\bsupabase\.from\s*\(\s*['"](\w+)['"]\s*\)\s*\.(select|insert|update|delete|upsert)\s*\(/g;
881
+ /**
882
+ * Extract ORM query calls from file content via regex.
883
+ * Appends results to the provided array (avoids allocation when no matches).
884
+ */
885
+ export function extractORMQueries(filePath, content, out) {
886
+ const hasPrisma = content.includes('prisma.');
887
+ const hasSupabase = content.includes('supabase.from');
888
+ if (!hasPrisma && !hasSupabase)
889
+ return;
890
+ if (hasPrisma) {
891
+ PRISMA_QUERY_RE.lastIndex = 0;
892
+ let m;
893
+ while ((m = PRISMA_QUERY_RE.exec(content)) !== null) {
894
+ const model = m[1];
895
+ if (model.startsWith('$'))
896
+ continue;
897
+ out.push({
898
+ filePath,
899
+ orm: 'prisma',
900
+ model,
901
+ method: m[2],
902
+ lineNumber: content.substring(0, m.index).split('\n').length - 1,
903
+ });
904
+ }
905
+ }
906
+ if (hasSupabase) {
907
+ SUPABASE_QUERY_RE.lastIndex = 0;
908
+ let m;
909
+ while ((m = SUPABASE_QUERY_RE.exec(content)) !== null) {
910
+ out.push({
911
+ filePath,
912
+ orm: 'supabase',
913
+ model: m[1],
914
+ method: m[2],
915
+ lineNumber: content.substring(0, m.index).split('\n').length - 1,
916
+ });
917
+ }
918
+ }
919
+ }
920
+ const processFileGroup = (files, language, queryString, result, onFileProcessed) => {
921
+ let query;
922
+ try {
923
+ const lang = parser.getLanguage();
924
+ query = new Parser.Query(lang, queryString);
925
+ }
926
+ catch (err) {
927
+ const message = `Query compilation failed for ${language}: ${err instanceof Error ? err.message : String(err)}`;
928
+ if (parentPort) {
929
+ parentPort.postMessage({ type: 'warning', message });
930
+ }
931
+ else {
932
+ console.warn(message);
933
+ }
934
+ return;
935
+ }
936
+ for (const file of files) {
937
+ // Skip files larger than the max tree-sitter buffer (32 MB)
938
+ if (file.content.length > TREE_SITTER_MAX_BUFFER)
939
+ continue;
940
+ // Vue SFC preprocessing: extract <script> block content
941
+ let parseContent = file.content;
942
+ let lineOffset = 0;
943
+ let isVueSetup = false;
944
+ if (language === SupportedLanguages.Vue) {
945
+ const extracted = extractVueScript(file.content);
946
+ if (!extracted)
947
+ continue; // skip .vue files with no script block
948
+ parseContent = extracted.scriptContent;
949
+ lineOffset = extracted.lineOffset;
950
+ isVueSetup = extracted.isSetup;
951
+ }
952
+ clearCaches(); // Reset memoization before each new file
953
+ let tree;
954
+ try {
955
+ tree = parser.parse(parseContent, undefined, {
956
+ bufferSize: getTreeSitterBufferSize(parseContent.length),
957
+ });
958
+ }
959
+ catch (err) {
960
+ console.warn(`Failed to parse file ${file.path}: ${err instanceof Error ? err.message : String(err)}`);
961
+ continue;
962
+ }
963
+ result.fileCount++;
964
+ onFileProcessed?.();
965
+ let matches;
966
+ try {
967
+ matches = query.matches(tree.rootNode);
968
+ }
969
+ catch (err) {
970
+ console.warn(`Query execution failed for ${file.path}: ${err instanceof Error ? err.message : String(err)}`);
971
+ continue;
972
+ }
973
+ // Pre-pass: extract heritage from query matches to build parentMap for buildTypeEnv.
974
+ // Heritage edges (EXTENDS/IMPLEMENTS) are created by heritage-processor which runs
975
+ // in PARALLEL with call-processor, so the graph edges don't exist when buildTypeEnv
976
+ // runs. This pre-pass makes parent class information available for type resolution.
977
+ const fileParentMap = new Map();
978
+ for (const match of matches) {
979
+ const captureMap = {};
980
+ for (const c of match.captures) {
981
+ captureMap[c.name] = c.node;
982
+ }
983
+ if (captureMap['heritage.class'] && captureMap['heritage.extends']) {
984
+ const className = captureMap['heritage.class'].text;
985
+ const parentName = captureMap['heritage.extends'].text;
986
+ // Skip Go named fields (only anonymous fields are struct embedding)
987
+ const extendsNode = captureMap['heritage.extends'];
988
+ const fieldDecl = extendsNode.parent;
989
+ if (fieldDecl?.type === 'field_declaration' && fieldDecl.childForFieldName('name'))
990
+ continue;
991
+ let parents = fileParentMap.get(className);
992
+ if (!parents) {
993
+ parents = [];
994
+ fileParentMap.set(className, parents);
995
+ }
996
+ if (!parents.includes(parentName))
997
+ parents.push(parentName);
998
+ }
999
+ }
1000
+ // Build per-file type environment + constructor bindings in a single AST walk.
1001
+ // Constructor bindings are verified against the SymbolTable in processCallsFromExtracted.
1002
+ const parentMap = fileParentMap;
1003
+ const provider = getProvider(language);
1004
+ const typeEnv = buildTypeEnv(tree, language, {
1005
+ parentMap,
1006
+ enclosingFunctionFinder: provider?.enclosingFunctionFinder,
1007
+ extractFunctionName: provider?.methodExtractor?.extractFunctionName,
1008
+ });
1009
+ const callRouter = provider.callRouter;
1010
+ if (typeEnv.constructorBindings.length > 0) {
1011
+ result.constructorBindings.push({
1012
+ filePath: file.path,
1013
+ bindings: [...typeEnv.constructorBindings],
1014
+ });
1015
+ }
1016
+ // Extract file-scope bindings for ExportedTypeMap (closes worker/sequential quality gap).
1017
+ // Sequential path uses collectExportedBindings(typeEnv) directly; worker path serializes
1018
+ // these bindings so the main thread can merge them into ExportedTypeMap.
1019
+ const fileScope = typeEnv.fileScope();
1020
+ if (fileScope.size > 0) {
1021
+ const bindings = [];
1022
+ for (const [name, type] of fileScope)
1023
+ bindings.push([name, type]);
1024
+ result.typeEnvBindings.push({ filePath: file.path, bindings });
1025
+ }
1026
+ // Per-file map: decorator end-line → decorator info, for associating with definitions
1027
+ const fileDecorators = new Map();
1028
+ for (const match of matches) {
1029
+ const captureMap = {};
1030
+ for (const c of match.captures) {
1031
+ captureMap[c.name] = c.node;
1032
+ }
1033
+ // Extract import paths before skipping
1034
+ if (captureMap['import'] && captureMap['import.source']) {
1035
+ const rawImportPath = preprocessImportPath(captureMap['import.source'].text, captureMap['import'], provider);
1036
+ if (!rawImportPath)
1037
+ continue;
1038
+ const extractor = provider.namedBindingExtractor;
1039
+ const namedBindings = extractor ? extractor(captureMap['import']) : undefined;
1040
+ result.imports.push({
1041
+ filePath: file.path,
1042
+ rawImportPath,
1043
+ language: language,
1044
+ ...(namedBindings ? { namedBindings } : {}),
1045
+ });
1046
+ continue;
1047
+ }
1048
+ // Extract assignment sites (field write access)
1049
+ if (captureMap['assignment'] &&
1050
+ captureMap['assignment.receiver'] &&
1051
+ captureMap['assignment.property']) {
1052
+ const receiverText = captureMap['assignment.receiver'].text;
1053
+ const propertyName = captureMap['assignment.property'].text;
1054
+ if (receiverText && propertyName) {
1055
+ const srcId = findEnclosingFunctionId(captureMap['assignment'], file.path, provider) ||
1056
+ generateId('File', file.path);
1057
+ let receiverTypeName;
1058
+ if (typeEnv) {
1059
+ receiverTypeName = typeEnv.lookup(receiverText, captureMap['assignment']) ?? undefined;
1060
+ }
1061
+ result.assignments.push({
1062
+ filePath: file.path,
1063
+ sourceId: srcId,
1064
+ receiverText,
1065
+ propertyName,
1066
+ ...(receiverTypeName ? { receiverTypeName } : {}),
1067
+ });
1068
+ }
1069
+ if (!captureMap['call'])
1070
+ continue;
1071
+ }
1072
+ // Store decorator metadata for later association with definitions
1073
+ if (captureMap['decorator'] && captureMap['decorator.name']) {
1074
+ const decoratorName = captureMap['decorator.name'].text;
1075
+ const decoratorArg = captureMap['decorator.arg']?.text;
1076
+ const decoratorNode = captureMap['decorator'];
1077
+ // Store by the decorator's end line — the definition follows immediately after
1078
+ fileDecorators.set(decoratorNode.endPosition.row, {
1079
+ name: decoratorName,
1080
+ arg: decoratorArg,
1081
+ });
1082
+ if (ROUTE_DECORATOR_NAMES.has(decoratorName)) {
1083
+ const routePath = decoratorArg || '';
1084
+ const method = decoratorName.replace('Mapping', '').toUpperCase();
1085
+ const httpMethod = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(method)
1086
+ ? method
1087
+ : 'GET';
1088
+ result.decoratorRoutes.push({
1089
+ filePath: file.path,
1090
+ routePath,
1091
+ httpMethod,
1092
+ decoratorName,
1093
+ lineNumber: decoratorNode.startPosition.row + lineOffset,
1094
+ });
1095
+ }
1096
+ // MCP/RPC tool detection: @mcp.tool(), @app.tool(), @server.tool()
1097
+ if (decoratorName === 'tool') {
1098
+ // Re-store with isTool flag for the definition handler
1099
+ fileDecorators.set(decoratorNode.endPosition.row, {
1100
+ name: decoratorName,
1101
+ arg: decoratorArg,
1102
+ isTool: true,
1103
+ });
1104
+ }
1105
+ continue;
1106
+ }
1107
+ // Extract HTTP consumer URLs: fetch(), axios.get(), $.get(), requests.get(), etc.
1108
+ if (captureMap['route.fetch']) {
1109
+ const urlNode = captureMap['route.url'] ?? captureMap['route.template_url'];
1110
+ if (urlNode) {
1111
+ result.fetchCalls.push({
1112
+ filePath: file.path,
1113
+ fetchURL: urlNode.text,
1114
+ lineNumber: captureMap['route.fetch'].startPosition.row + lineOffset,
1115
+ });
1116
+ }
1117
+ continue;
1118
+ }
1119
+ // HTTP client calls: axios.get('/path'), $.post('/path'), requests.get('/path')
1120
+ // Skip methods also in EXPRESS_ROUTE_METHODS to avoid double-registering Express
1121
+ // routes as both route definitions AND consumers (both queries match same AST node)
1122
+ if (captureMap['http_client'] && captureMap['http_client.url']) {
1123
+ const method = captureMap['http_client.method']?.text;
1124
+ const url = captureMap['http_client.url'].text;
1125
+ if (method && HTTP_CLIENT_ONLY_METHODS.has(method) && url.startsWith('/')) {
1126
+ result.fetchCalls.push({
1127
+ filePath: file.path,
1128
+ fetchURL: url,
1129
+ lineNumber: captureMap['http_client'].startPosition.row + lineOffset,
1130
+ });
1131
+ }
1132
+ continue;
1133
+ }
1134
+ // Express/Hono route registration: app.get('/path', handler)
1135
+ if (captureMap['express_route'] &&
1136
+ captureMap['express_route.method'] &&
1137
+ captureMap['express_route.path']) {
1138
+ const method = captureMap['express_route.method'].text;
1139
+ const routePath = captureMap['express_route.path'].text;
1140
+ if (EXPRESS_ROUTE_METHODS.has(method) && routePath.startsWith('/')) {
1141
+ const httpMethod = method === 'all' || method === 'use' || method === 'route'
1142
+ ? 'GET'
1143
+ : method.toUpperCase();
1144
+ result.decoratorRoutes.push({
1145
+ filePath: file.path,
1146
+ routePath,
1147
+ httpMethod,
1148
+ decoratorName: `express.${method}`,
1149
+ lineNumber: captureMap['express_route'].startPosition.row + lineOffset,
1150
+ });
1151
+ }
1152
+ continue;
1153
+ }
1154
+ // Extract call sites
1155
+ if (captureMap['call']) {
1156
+ const callNode0 = captureMap['call'];
1157
+ const languageSeed = extractParsedCallSite(language, callNode0);
1158
+ if (languageSeed) {
1159
+ if (!provider.isBuiltInName(languageSeed.calledName)) {
1160
+ const sourceId = findEnclosingFunctionId(callNode0, file.path, provider) ||
1161
+ generateId('File', file.path);
1162
+ const receiverName = languageSeed.callForm === 'member' ? languageSeed.receiverName : undefined;
1163
+ let receiverTypeName = receiverName
1164
+ ? typeEnv.lookup(receiverName, callNode0)
1165
+ : undefined;
1166
+ // Type-as-receiver (e.g. Java `User::getName`): no TypeEnv binding for the class name
1167
+ if (receiverName !== undefined &&
1168
+ receiverTypeName === undefined &&
1169
+ languageSeed.callForm === 'member' &&
1170
+ (language === SupportedLanguages.Java ||
1171
+ language === SupportedLanguages.CSharp ||
1172
+ language === SupportedLanguages.Kotlin)) {
1173
+ const c0 = receiverName.charCodeAt(0);
1174
+ if (c0 >= 65 && c0 <= 90)
1175
+ receiverTypeName = receiverName;
1176
+ }
1177
+ result.calls.push({
1178
+ filePath: file.path,
1179
+ calledName: languageSeed.calledName,
1180
+ sourceId,
1181
+ callForm: languageSeed.callForm,
1182
+ ...(receiverName !== undefined ? { receiverName } : {}),
1183
+ ...(receiverTypeName !== undefined ? { receiverTypeName } : {}),
1184
+ });
1185
+ }
1186
+ continue;
1187
+ }
1188
+ const callNameNode = captureMap['call.name'];
1189
+ if (callNameNode) {
1190
+ const calledName = callNameNode.text;
1191
+ // Dispatch: route language-specific calls (heritage, properties, imports)
1192
+ const routed = callRouter?.(calledName, captureMap['call']);
1193
+ if (routed) {
1194
+ if (routed.kind === 'skip')
1195
+ continue;
1196
+ if (routed.kind === 'import') {
1197
+ result.imports.push({
1198
+ filePath: file.path,
1199
+ rawImportPath: routed.importPath,
1200
+ language,
1201
+ });
1202
+ continue;
1203
+ }
1204
+ if (routed.kind === 'heritage') {
1205
+ for (const item of routed.items) {
1206
+ result.heritage.push({
1207
+ filePath: file.path,
1208
+ className: item.enclosingClass,
1209
+ parentName: item.mixinName,
1210
+ kind: item.heritageKind,
1211
+ });
1212
+ }
1213
+ continue;
1214
+ }
1215
+ if (routed.kind === 'properties') {
1216
+ const propEnclosingInfo = cachedFindEnclosingClassInfo(captureMap['call'], file.path);
1217
+ const propEnclosingClassId = propEnclosingInfo?.classId ?? null;
1218
+ // Enrich routed properties with FieldExtractor metadata
1219
+ let routedFieldMap;
1220
+ if (provider.fieldExtractor && typeEnv) {
1221
+ const classNode = findEnclosingClassNode(captureMap['call']);
1222
+ if (classNode) {
1223
+ routedFieldMap = getFieldInfo(classNode, provider, {
1224
+ typeEnv,
1225
+ symbolTable: NOOP_SYMBOL_TABLE,
1226
+ filePath: file.path,
1227
+ language,
1228
+ });
1229
+ }
1230
+ }
1231
+ for (const item of routed.items) {
1232
+ const routedFieldInfo = routedFieldMap?.get(item.propName);
1233
+ const propQualifiedName = propEnclosingInfo
1234
+ ? `${propEnclosingInfo.className}.${item.propName}`
1235
+ : item.propName;
1236
+ const nodeId = generateId('Property', `${file.path}:${propQualifiedName}`);
1237
+ result.nodes.push({
1238
+ id: nodeId,
1239
+ label: 'Property',
1240
+ properties: {
1241
+ name: item.propName,
1242
+ filePath: file.path,
1243
+ startLine: item.startLine,
1244
+ endLine: item.endLine,
1245
+ language,
1246
+ isExported: true,
1247
+ description: item.accessorType,
1248
+ ...(item.declaredType
1249
+ ? { declaredType: item.declaredType }
1250
+ : routedFieldInfo?.type
1251
+ ? { declaredType: routedFieldInfo.type }
1252
+ : {}),
1253
+ ...(routedFieldInfo?.visibility !== undefined
1254
+ ? { visibility: routedFieldInfo.visibility }
1255
+ : {}),
1256
+ ...(routedFieldInfo?.isStatic !== undefined
1257
+ ? { isStatic: routedFieldInfo.isStatic }
1258
+ : {}),
1259
+ ...(routedFieldInfo?.isReadonly !== undefined
1260
+ ? { isReadonly: routedFieldInfo.isReadonly }
1261
+ : {}),
1262
+ },
1263
+ });
1264
+ result.symbols.push({
1265
+ filePath: file.path,
1266
+ name: item.propName,
1267
+ nodeId,
1268
+ type: 'Property',
1269
+ ...(propEnclosingClassId ? { ownerId: propEnclosingClassId } : {}),
1270
+ ...(item.declaredType
1271
+ ? { declaredType: item.declaredType }
1272
+ : routedFieldInfo?.type
1273
+ ? { declaredType: routedFieldInfo.type }
1274
+ : {}),
1275
+ ...(routedFieldInfo?.visibility !== undefined
1276
+ ? { visibility: routedFieldInfo.visibility }
1277
+ : {}),
1278
+ ...(routedFieldInfo?.isStatic !== undefined
1279
+ ? { isStatic: routedFieldInfo.isStatic }
1280
+ : {}),
1281
+ ...(routedFieldInfo?.isReadonly !== undefined
1282
+ ? { isReadonly: routedFieldInfo.isReadonly }
1283
+ : {}),
1284
+ });
1285
+ const fileId = generateId('File', file.path);
1286
+ const relId = generateId('DEFINES', `${fileId}->${nodeId}`);
1287
+ result.relationships.push({
1288
+ id: relId,
1289
+ sourceId: fileId,
1290
+ targetId: nodeId,
1291
+ type: 'DEFINES',
1292
+ confidence: 1.0,
1293
+ reason: '',
1294
+ });
1295
+ if (propEnclosingClassId) {
1296
+ result.relationships.push({
1297
+ id: generateId('HAS_PROPERTY', `${propEnclosingClassId}->${nodeId}`),
1298
+ sourceId: propEnclosingClassId,
1299
+ targetId: nodeId,
1300
+ type: 'HAS_PROPERTY',
1301
+ confidence: 1.0,
1302
+ reason: '',
1303
+ });
1304
+ }
1305
+ }
1306
+ continue;
1307
+ }
1308
+ // kind === 'call' — fall through to normal call processing below
1309
+ }
1310
+ if (!provider.isBuiltInName(calledName)) {
1311
+ const callNode = captureMap['call'];
1312
+ const sourceId = findEnclosingFunctionId(callNode, file.path, provider) ||
1313
+ generateId('File', file.path);
1314
+ const callForm = inferCallForm(callNode, callNameNode);
1315
+ let receiverName = callForm === 'member' ? extractReceiverName(callNameNode) : undefined;
1316
+ let receiverTypeName = receiverName
1317
+ ? typeEnv.lookup(receiverName, callNode)
1318
+ : undefined;
1319
+ let receiverMixedChain;
1320
+ // When the receiver is a complex expression (call chain, field chain, or mixed),
1321
+ // extractReceiverName returns undefined. Walk the receiver node to build a unified
1322
+ // mixed chain for deferred resolution in processCallsFromExtracted.
1323
+ if (callForm === 'member' && receiverName === undefined && !receiverTypeName) {
1324
+ const receiverNode = extractReceiverNode(callNameNode);
1325
+ if (receiverNode) {
1326
+ const extracted = extractMixedChain(receiverNode);
1327
+ if (extracted && extracted.chain.length > 0) {
1328
+ receiverMixedChain = extracted.chain;
1329
+ receiverName = extracted.baseReceiverName;
1330
+ // Try the type environment immediately for the base receiver
1331
+ // (covers explicitly-typed locals and annotated parameters).
1332
+ if (receiverName) {
1333
+ receiverTypeName = typeEnv.lookup(receiverName, callNode);
1334
+ }
1335
+ }
1336
+ }
1337
+ }
1338
+ const inferLiteralType = provider.typeConfig?.inferLiteralType;
1339
+ const argCountForOverloadHints = countCallArguments(callNode);
1340
+ // Skip when no arg list / zero args: nothing to infer for overload typing; saves AST walks + payload size.
1341
+ const argTypes = inferLiteralType &&
1342
+ argCountForOverloadHints !== undefined &&
1343
+ argCountForOverloadHints > 0
1344
+ ? extractCallArgTypes(callNode, inferLiteralType, (varName, cn) => typeEnv.lookup(varName, cn))
1345
+ : undefined;
1346
+ result.calls.push({
1347
+ filePath: file.path,
1348
+ calledName,
1349
+ sourceId,
1350
+ argCount: countCallArguments(callNode),
1351
+ ...(callForm !== undefined ? { callForm } : {}),
1352
+ ...(receiverName !== undefined ? { receiverName } : {}),
1353
+ ...(receiverTypeName !== undefined ? { receiverTypeName } : {}),
1354
+ ...(receiverMixedChain !== undefined ? { receiverMixedChain } : {}),
1355
+ ...(argTypes !== undefined ? { argTypes } : {}),
1356
+ });
1357
+ }
1358
+ }
1359
+ continue;
1360
+ }
1361
+ // Extract heritage (extends/implements)
1362
+ if (captureMap['heritage.class']) {
1363
+ if (captureMap['heritage.extends']) {
1364
+ // Go struct embedding: the query matches ALL field_declarations with
1365
+ // type_identifier, but only anonymous fields (no name) are embedded.
1366
+ // Named fields like `Breed string` also match — skip them.
1367
+ const extendsNode = captureMap['heritage.extends'];
1368
+ const fieldDecl = extendsNode.parent;
1369
+ const isNamedField = fieldDecl?.type === 'field_declaration' && fieldDecl.childForFieldName('name');
1370
+ if (!isNamedField) {
1371
+ result.heritage.push({
1372
+ filePath: file.path,
1373
+ className: captureMap['heritage.class'].text,
1374
+ parentName: captureMap['heritage.extends'].text,
1375
+ kind: 'extends',
1376
+ });
1377
+ }
1378
+ }
1379
+ if (captureMap['heritage.implements']) {
1380
+ result.heritage.push({
1381
+ filePath: file.path,
1382
+ className: captureMap['heritage.class'].text,
1383
+ parentName: captureMap['heritage.implements'].text,
1384
+ kind: 'implements',
1385
+ });
1386
+ }
1387
+ if (captureMap['heritage.trait']) {
1388
+ result.heritage.push({
1389
+ filePath: file.path,
1390
+ className: captureMap['heritage.class'].text,
1391
+ parentName: captureMap['heritage.trait'].text,
1392
+ kind: 'trait-impl',
1393
+ });
1394
+ }
1395
+ if (captureMap['heritage.extends'] ||
1396
+ captureMap['heritage.implements'] ||
1397
+ captureMap['heritage.trait']) {
1398
+ continue;
1399
+ }
1400
+ }
1401
+ const nodeLabel = getLabelFromCaptures(captureMap, provider);
1402
+ if (!nodeLabel)
1403
+ continue;
1404
+ const nameNode = captureMap['name'];
1405
+ // Synthesize name for constructors without explicit @name capture (e.g. Swift init)
1406
+ if (!nameNode && nodeLabel !== 'Constructor')
1407
+ continue;
1408
+ const nodeName = nameNode ? nameNode.text : 'init';
1409
+ const definitionNode = getDefinitionNodeFromCaptures(captureMap);
1410
+ const startLine = definitionNode
1411
+ ? definitionNode.startPosition.row + lineOffset
1412
+ : nameNode
1413
+ ? nameNode.startPosition.row + lineOffset
1414
+ : lineOffset;
1415
+ // Compute enclosing class BEFORE node ID — needed to qualify method IDs
1416
+ const needsOwner = nodeLabel === 'Method' ||
1417
+ nodeLabel === 'Constructor' ||
1418
+ nodeLabel === 'Property' ||
1419
+ nodeLabel === 'Function';
1420
+ const enclosingClassInfo = needsOwner
1421
+ ? cachedFindEnclosingClassInfo(nameNode || definitionNode, file.path)
1422
+ : null;
1423
+ const enclosingClassId = enclosingClassInfo?.classId ?? null;
1424
+ // Qualify method/property IDs with enclosing class name to avoid collisions
1425
+ const qualifiedName = enclosingClassInfo
1426
+ ? `${enclosingClassInfo.className}.${nodeName}`
1427
+ : nodeName;
1428
+ // Extract method metadata BEFORE generating node ID — parameterCount is needed
1429
+ // to disambiguate overloaded methods via #<arity> suffix in the ID.
1430
+ let declaredType;
1431
+ let methodProps = {};
1432
+ let arityForId; // raw param count for ID, even for variadic
1433
+ if (nodeLabel === 'Function' || nodeLabel === 'Method' || nodeLabel === 'Constructor') {
1434
+ // Use MethodExtractor for method metadata — provides parameterCount, parameterTypes,
1435
+ // returnType, isAbstract/isFinal/annotations, visibility, and more.
1436
+ let enrichedByMethodExtractor = false;
1437
+ if (provider.methodExtractor && definitionNode) {
1438
+ const classNode = findEnclosingClassNode(definitionNode) ?? findClassNodeByQualifiedName(definitionNode);
1439
+ if (classNode) {
1440
+ const methodMap = getMethodInfo(classNode, provider, {
1441
+ filePath: file.path,
1442
+ language,
1443
+ });
1444
+ const defLine = definitionNode.startPosition.row + 1;
1445
+ const info = methodMap?.get(`${nodeName}:${defLine}`);
1446
+ if (info) {
1447
+ enrichedByMethodExtractor = true;
1448
+ arityForId = arityForIdFromInfo(info);
1449
+ methodProps = buildMethodProps(info);
1450
+ }
1451
+ }
1452
+ }
1453
+ // For top-level methods (e.g. Go method_declaration), try extractFromNode
1454
+ if (!enrichedByMethodExtractor &&
1455
+ provider.methodExtractor?.extractFromNode &&
1456
+ definitionNode) {
1457
+ const info = provider.methodExtractor.extractFromNode(definitionNode, {
1458
+ filePath: file.path,
1459
+ language,
1460
+ });
1461
+ if (info) {
1462
+ enrichedByMethodExtractor = true;
1463
+ arityForId = arityForIdFromInfo(info);
1464
+ methodProps = buildMethodProps(info);
1465
+ }
1466
+ }
1467
+ }
1468
+ // Append #<paramCount> to Method/Constructor IDs to disambiguate overloads.
1469
+ // Functions are not suffixed — they don't overload by name in the same scope.
1470
+ const needsAritySuffix = nodeLabel === 'Method' || nodeLabel === 'Constructor';
1471
+ const arityTag = needsAritySuffix && arityForId !== undefined ? `#${arityForId}` : '';
1472
+ const nodeId = generateId(nodeLabel, `${file.path}:${qualifiedName}${arityTag}`);
1473
+ const description = provider.descriptionExtractor?.(nodeLabel, nodeName, captureMap);
1474
+ let frameworkHint = definitionNode
1475
+ ? detectFrameworkFromAST(language, (definitionNode.text || '').slice(0, 300))
1476
+ : null;
1477
+ // Decorators appear on lines immediately before their definition; allow up to
1478
+ // MAX_DECORATOR_SCAN_LINES gap for blank lines / multi-line decorator stacks.
1479
+ const MAX_DECORATOR_SCAN_LINES = 5;
1480
+ if (definitionNode) {
1481
+ const defStartLine = definitionNode.startPosition.row;
1482
+ for (let checkLine = defStartLine - 1; checkLine >= Math.max(0, defStartLine - MAX_DECORATOR_SCAN_LINES); checkLine--) {
1483
+ const dec = fileDecorators.get(checkLine);
1484
+ if (dec) {
1485
+ // Use first (closest) decorator found for framework hint
1486
+ if (!frameworkHint) {
1487
+ frameworkHint = {
1488
+ framework: 'decorator',
1489
+ entryPointMultiplier: 1.2,
1490
+ reason: `@${dec.name}${dec.arg ? `("${dec.arg}")` : ''}`,
1491
+ };
1492
+ }
1493
+ // Emit tool definition if this is a @tool decorator
1494
+ if (dec.isTool) {
1495
+ result.toolDefs.push({
1496
+ filePath: file.path,
1497
+ toolName: nodeName,
1498
+ description: dec.arg || '',
1499
+ lineNumber: definitionNode.startPosition.row + lineOffset,
1500
+ });
1501
+ }
1502
+ fileDecorators.delete(checkLine);
1503
+ }
1504
+ }
1505
+ }
1506
+ // Property metadata extraction (not needed before nodeId — Properties don't overload)
1507
+ if (nodeLabel === 'Property' && definitionNode) {
1508
+ // FieldExtractor is the single source of truth when available
1509
+ if (provider.fieldExtractor && typeEnv) {
1510
+ const classNode = findEnclosingClassNode(definitionNode);
1511
+ if (classNode) {
1512
+ const fieldMap = getFieldInfo(classNode, provider, {
1513
+ typeEnv,
1514
+ symbolTable: NOOP_SYMBOL_TABLE,
1515
+ filePath: file.path,
1516
+ language,
1517
+ });
1518
+ const info = fieldMap?.get(nodeName);
1519
+ if (info) {
1520
+ declaredType = info.type ?? undefined;
1521
+ methodProps.visibility = info.visibility;
1522
+ methodProps.isStatic = info.isStatic;
1523
+ methodProps.isReadonly = info.isReadonly;
1524
+ }
1525
+ }
1526
+ }
1527
+ }
1528
+ result.nodes.push({
1529
+ id: nodeId,
1530
+ label: nodeLabel,
1531
+ properties: {
1532
+ name: nodeName,
1533
+ filePath: file.path,
1534
+ startLine: definitionNode ? definitionNode.startPosition.row + lineOffset : startLine,
1535
+ endLine: definitionNode ? definitionNode.endPosition.row + lineOffset : startLine,
1536
+ language: language,
1537
+ isExported: language === SupportedLanguages.Vue && isVueSetup
1538
+ ? isVueSetupTopLevel(nameNode || definitionNode)
1539
+ : cachedExportCheck(provider.exportChecker, nameNode || definitionNode, nodeName),
1540
+ ...(frameworkHint
1541
+ ? {
1542
+ astFrameworkMultiplier: frameworkHint.entryPointMultiplier,
1543
+ astFrameworkReason: frameworkHint.reason,
1544
+ }
1545
+ : {}),
1546
+ ...(description !== undefined ? { description } : {}),
1547
+ ...methodProps,
1548
+ ...(declaredType !== undefined ? { declaredType } : {}),
1549
+ },
1550
+ });
1551
+ // enclosingClassId already computed above (before nodeId generation)
1552
+ result.symbols.push({
1553
+ filePath: file.path,
1554
+ name: nodeName,
1555
+ nodeId,
1556
+ type: nodeLabel,
1557
+ parameterCount: methodProps.parameterCount,
1558
+ requiredParameterCount: methodProps.requiredParameterCount,
1559
+ parameterTypes: methodProps.parameterTypes,
1560
+ returnType: methodProps.returnType,
1561
+ ...(declaredType !== undefined ? { declaredType } : {}),
1562
+ ...(enclosingClassId ? { ownerId: enclosingClassId } : {}),
1563
+ visibility: methodProps.visibility,
1564
+ isStatic: methodProps.isStatic,
1565
+ isReadonly: methodProps.isReadonly,
1566
+ isAbstract: methodProps.isAbstract,
1567
+ isFinal: methodProps.isFinal,
1568
+ ...(methodProps.isVirtual !== undefined
1569
+ ? { isVirtual: methodProps.isVirtual }
1570
+ : {}),
1571
+ ...(methodProps.isOverride !== undefined
1572
+ ? { isOverride: methodProps.isOverride }
1573
+ : {}),
1574
+ ...(methodProps.isAsync !== undefined ? { isAsync: methodProps.isAsync } : {}),
1575
+ ...(methodProps.isPartial !== undefined
1576
+ ? { isPartial: methodProps.isPartial }
1577
+ : {}),
1578
+ ...(methodProps.annotations !== undefined
1579
+ ? { annotations: methodProps.annotations }
1580
+ : {}),
1581
+ });
1582
+ const fileId = generateId('File', file.path);
1583
+ const relId = generateId('DEFINES', `${fileId}->${nodeId}`);
1584
+ result.relationships.push({
1585
+ id: relId,
1586
+ sourceId: fileId,
1587
+ targetId: nodeId,
1588
+ type: 'DEFINES',
1589
+ confidence: 1.0,
1590
+ reason: '',
1591
+ });
1592
+ // ── HAS_METHOD / HAS_PROPERTY: link member to enclosing class ──
1593
+ if (enclosingClassId) {
1594
+ const memberEdgeType = nodeLabel === 'Property' ? 'HAS_PROPERTY' : 'HAS_METHOD';
1595
+ result.relationships.push({
1596
+ id: generateId(memberEdgeType, `${enclosingClassId}->${nodeId}`),
1597
+ sourceId: enclosingClassId,
1598
+ targetId: nodeId,
1599
+ type: memberEdgeType,
1600
+ confidence: 1.0,
1601
+ reason: '',
1602
+ });
1603
+ }
1604
+ }
1605
+ // Extract framework routes via provider detection (e.g., Laravel routes.php)
1606
+ if (provider.isRouteFile?.(file.path)) {
1607
+ const extractedRoutes = extractLaravelRoutes(tree, file.path);
1608
+ result.routes.push(...extractedRoutes);
1609
+ }
1610
+ // Extract ORM queries (Prisma, Supabase)
1611
+ extractORMQueries(file.path, parseContent, result.ormQueries);
1612
+ // Vue: emit CALLS edges for components used in <template>
1613
+ if (language === SupportedLanguages.Vue) {
1614
+ const templateComponents = extractTemplateComponents(file.content);
1615
+ for (const componentName of templateComponents) {
1616
+ result.calls.push({
1617
+ filePath: file.path,
1618
+ calledName: componentName,
1619
+ sourceId: generateId('File', file.path),
1620
+ callForm: 'free',
1621
+ });
1622
+ }
1623
+ }
1624
+ }
1625
+ };
1626
+ // ============================================================================
1627
+ // Worker message handler — supports sub-batch streaming
1628
+ // ============================================================================
1629
+ /** Accumulated result across sub-batches */
1630
+ let accumulated = {
1631
+ nodes: [],
1632
+ relationships: [],
1633
+ symbols: [],
1634
+ imports: [],
1635
+ calls: [],
1636
+ assignments: [],
1637
+ heritage: [],
1638
+ routes: [],
1639
+ fetchCalls: [],
1640
+ decoratorRoutes: [],
1641
+ toolDefs: [],
1642
+ ormQueries: [],
1643
+ constructorBindings: [],
1644
+ typeEnvBindings: [],
1645
+ skippedLanguages: {},
1646
+ fileCount: 0,
1647
+ };
1648
+ let cumulativeProcessed = 0;
1649
+ const mergeResult = (target, src) => {
1650
+ target.nodes.push(...src.nodes);
1651
+ target.relationships.push(...src.relationships);
1652
+ target.symbols.push(...src.symbols);
1653
+ target.imports.push(...src.imports);
1654
+ target.calls.push(...src.calls);
1655
+ target.assignments.push(...src.assignments);
1656
+ target.heritage.push(...src.heritage);
1657
+ target.routes.push(...src.routes);
1658
+ target.fetchCalls.push(...src.fetchCalls);
1659
+ target.decoratorRoutes.push(...src.decoratorRoutes);
1660
+ target.toolDefs.push(...src.toolDefs);
1661
+ target.ormQueries.push(...src.ormQueries);
1662
+ target.constructorBindings.push(...src.constructorBindings);
1663
+ target.typeEnvBindings.push(...src.typeEnvBindings);
1664
+ for (const [lang, count] of Object.entries(src.skippedLanguages)) {
1665
+ target.skippedLanguages[lang] = (target.skippedLanguages[lang] || 0) + count;
1666
+ }
1667
+ target.fileCount += src.fileCount;
1668
+ };
1669
+ parentPort.on('message', (msg) => {
1670
+ try {
1671
+ // Legacy single-message mode (backward compat): array of files
1672
+ if (Array.isArray(msg)) {
1673
+ const result = processBatch(msg, (filesProcessed) => {
1674
+ parentPort.postMessage({ type: 'progress', filesProcessed });
1675
+ });
1676
+ parentPort.postMessage({ type: 'result', data: result });
1677
+ return;
1678
+ }
1679
+ // Sub-batch mode: { type: 'sub-batch', files: [...] }
1680
+ if (msg.type === 'sub-batch') {
1681
+ const result = processBatch(msg.files, (filesProcessed) => {
1682
+ parentPort.postMessage({
1683
+ type: 'progress',
1684
+ filesProcessed: cumulativeProcessed + filesProcessed,
1685
+ });
1686
+ });
1687
+ cumulativeProcessed += result.fileCount;
1688
+ mergeResult(accumulated, result);
1689
+ // Signal ready for next sub-batch
1690
+ parentPort.postMessage({ type: 'sub-batch-done' });
1691
+ return;
1692
+ }
1693
+ // Flush: send accumulated results
1694
+ if (msg.type === 'flush') {
1695
+ parentPort.postMessage({ type: 'result', data: accumulated });
1696
+ // Reset for potential reuse
1697
+ accumulated = {
1698
+ nodes: [],
1699
+ relationships: [],
1700
+ symbols: [],
1701
+ imports: [],
1702
+ calls: [],
1703
+ assignments: [],
1704
+ heritage: [],
1705
+ routes: [],
1706
+ fetchCalls: [],
1707
+ decoratorRoutes: [],
1708
+ toolDefs: [],
1709
+ ormQueries: [],
1710
+ constructorBindings: [],
1711
+ typeEnvBindings: [],
1712
+ skippedLanguages: {},
1713
+ fileCount: 0,
1714
+ };
1715
+ cumulativeProcessed = 0;
1716
+ return;
1717
+ }
1718
+ }
1719
+ catch (err) {
1720
+ const message = err instanceof Error ? err.message : String(err);
1721
+ parentPort.postMessage({ type: 'error', error: message });
1722
+ }
1723
+ });
1724
+ //# sourceMappingURL=parse-worker.js.map