@vizalice/codegraph 1.5.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 (821) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +872 -0
  3. package/dist/bin/codegraph.d.ts +26 -0
  4. package/dist/bin/codegraph.d.ts.map +1 -0
  5. package/dist/bin/codegraph.js +2324 -0
  6. package/dist/bin/codegraph.js.map +1 -0
  7. package/dist/bin/command-supervision.d.ts +49 -0
  8. package/dist/bin/command-supervision.d.ts.map +1 -0
  9. package/dist/bin/command-supervision.js +95 -0
  10. package/dist/bin/command-supervision.js.map +1 -0
  11. package/dist/bin/fatal-handler.d.ts +20 -0
  12. package/dist/bin/fatal-handler.d.ts.map +1 -0
  13. package/dist/bin/fatal-handler.js +118 -0
  14. package/dist/bin/fatal-handler.js.map +1 -0
  15. package/dist/bin/node-version-check.d.ts +37 -0
  16. package/dist/bin/node-version-check.d.ts.map +1 -0
  17. package/dist/bin/node-version-check.js +79 -0
  18. package/dist/bin/node-version-check.js.map +1 -0
  19. package/dist/bin/uninstall.d.ts +14 -0
  20. package/dist/bin/uninstall.d.ts.map +1 -0
  21. package/dist/bin/uninstall.js +36 -0
  22. package/dist/bin/uninstall.js.map +1 -0
  23. package/dist/context/formatter.d.ts +36 -0
  24. package/dist/context/formatter.d.ts.map +1 -0
  25. package/dist/context/formatter.js +269 -0
  26. package/dist/context/formatter.js.map +1 -0
  27. package/dist/context/index.d.ts +119 -0
  28. package/dist/context/index.d.ts.map +1 -0
  29. package/dist/context/index.js +1333 -0
  30. package/dist/context/index.js.map +1 -0
  31. package/dist/context/markers.d.ts +19 -0
  32. package/dist/context/markers.d.ts.map +1 -0
  33. package/dist/context/markers.js +22 -0
  34. package/dist/context/markers.js.map +1 -0
  35. package/dist/db/index.d.ts +378 -0
  36. package/dist/db/index.d.ts.map +1 -0
  37. package/dist/db/index.js +831 -0
  38. package/dist/db/index.js.map +1 -0
  39. package/dist/db/migrations.d.ts +44 -0
  40. package/dist/db/migrations.d.ts.map +1 -0
  41. package/dist/db/migrations.js +236 -0
  42. package/dist/db/migrations.js.map +1 -0
  43. package/dist/db/queries.d.ts +705 -0
  44. package/dist/db/queries.d.ts.map +1 -0
  45. package/dist/db/queries.js +2435 -0
  46. package/dist/db/queries.js.map +1 -0
  47. package/dist/db/schema.sql +207 -0
  48. package/dist/db/sqlite-adapter.d.ts +55 -0
  49. package/dist/db/sqlite-adapter.d.ts.map +1 -0
  50. package/dist/db/sqlite-adapter.js +135 -0
  51. package/dist/db/sqlite-adapter.js.map +1 -0
  52. package/dist/db/wal-valve.d.ts +119 -0
  53. package/dist/db/wal-valve.d.ts.map +1 -0
  54. package/dist/db/wal-valve.js +290 -0
  55. package/dist/db/wal-valve.js.map +1 -0
  56. package/dist/directory.d.ts +183 -0
  57. package/dist/directory.d.ts.map +1 -0
  58. package/dist/directory.js +797 -0
  59. package/dist/directory.js.map +1 -0
  60. package/dist/errors.d.ts +136 -0
  61. package/dist/errors.d.ts.map +1 -0
  62. package/dist/errors.js +219 -0
  63. package/dist/errors.js.map +1 -0
  64. package/dist/extraction/astro-extractor.d.ts +79 -0
  65. package/dist/extraction/astro-extractor.d.ts.map +1 -0
  66. package/dist/extraction/astro-extractor.js +320 -0
  67. package/dist/extraction/astro-extractor.js.map +1 -0
  68. package/dist/extraction/cfml-extractor.d.ts +107 -0
  69. package/dist/extraction/cfml-extractor.d.ts.map +1 -0
  70. package/dist/extraction/cfml-extractor.js +494 -0
  71. package/dist/extraction/cfml-extractor.js.map +1 -0
  72. package/dist/extraction/dfm-extractor.d.ts +31 -0
  73. package/dist/extraction/dfm-extractor.d.ts.map +1 -0
  74. package/dist/extraction/dfm-extractor.js +151 -0
  75. package/dist/extraction/dfm-extractor.js.map +1 -0
  76. package/dist/extraction/extraction-version.d.ts +25 -0
  77. package/dist/extraction/extraction-version.d.ts.map +1 -0
  78. package/dist/extraction/extraction-version.js +28 -0
  79. package/dist/extraction/extraction-version.js.map +1 -0
  80. package/dist/extraction/function-ref.d.ts +118 -0
  81. package/dist/extraction/function-ref.d.ts.map +1 -0
  82. package/dist/extraction/function-ref.js +733 -0
  83. package/dist/extraction/function-ref.js.map +1 -0
  84. package/dist/extraction/generated-detection.d.ts +66 -0
  85. package/dist/extraction/generated-detection.d.ts.map +1 -0
  86. package/dist/extraction/generated-detection.js +248 -0
  87. package/dist/extraction/generated-detection.js.map +1 -0
  88. package/dist/extraction/grammars.d.ts +138 -0
  89. package/dist/extraction/grammars.d.ts.map +1 -0
  90. package/dist/extraction/grammars.js +694 -0
  91. package/dist/extraction/grammars.js.map +1 -0
  92. package/dist/extraction/index.d.ts +308 -0
  93. package/dist/extraction/index.d.ts.map +1 -0
  94. package/dist/extraction/index.js +2711 -0
  95. package/dist/extraction/index.js.map +1 -0
  96. package/dist/extraction/kernel/decode.d.ts +9 -0
  97. package/dist/extraction/kernel/decode.d.ts.map +1 -0
  98. package/dist/extraction/kernel/decode.js +162 -0
  99. package/dist/extraction/kernel/decode.js.map +1 -0
  100. package/dist/extraction/kernel/index.d.ts +64 -0
  101. package/dist/extraction/kernel/index.d.ts.map +1 -0
  102. package/dist/extraction/kernel/index.js +279 -0
  103. package/dist/extraction/kernel/index.js.map +1 -0
  104. package/dist/extraction/kernel/layout.d.ts +101 -0
  105. package/dist/extraction/kernel/layout.d.ts.map +1 -0
  106. package/dist/extraction/kernel/layout.js +104 -0
  107. package/dist/extraction/kernel/layout.js.map +1 -0
  108. package/dist/extraction/kernel/loader.d.ts +103 -0
  109. package/dist/extraction/kernel/loader.d.ts.map +1 -0
  110. package/dist/extraction/kernel/loader.js +146 -0
  111. package/dist/extraction/kernel/loader.js.map +1 -0
  112. package/dist/extraction/languages/arkts.d.ts +3 -0
  113. package/dist/extraction/languages/arkts.d.ts.map +1 -0
  114. package/dist/extraction/languages/arkts.js +127 -0
  115. package/dist/extraction/languages/arkts.js.map +1 -0
  116. package/dist/extraction/languages/c-cpp.d.ts +124 -0
  117. package/dist/extraction/languages/c-cpp.d.ts.map +1 -0
  118. package/dist/extraction/languages/c-cpp.js +1689 -0
  119. package/dist/extraction/languages/c-cpp.js.map +1 -0
  120. package/dist/extraction/languages/cfquery.d.ts +12 -0
  121. package/dist/extraction/languages/cfquery.d.ts.map +1 -0
  122. package/dist/extraction/languages/cfquery.js +28 -0
  123. package/dist/extraction/languages/cfquery.js.map +1 -0
  124. package/dist/extraction/languages/cfscript.d.ts +3 -0
  125. package/dist/extraction/languages/cfscript.d.ts.map +1 -0
  126. package/dist/extraction/languages/cfscript.js +73 -0
  127. package/dist/extraction/languages/cfscript.js.map +1 -0
  128. package/dist/extraction/languages/cobol.d.ts +33 -0
  129. package/dist/extraction/languages/cobol.d.ts.map +1 -0
  130. package/dist/extraction/languages/cobol.js +499 -0
  131. package/dist/extraction/languages/cobol.js.map +1 -0
  132. package/dist/extraction/languages/csharp.d.ts +25 -0
  133. package/dist/extraction/languages/csharp.d.ts.map +1 -0
  134. package/dist/extraction/languages/csharp.js +175 -0
  135. package/dist/extraction/languages/csharp.js.map +1 -0
  136. package/dist/extraction/languages/dart.d.ts +3 -0
  137. package/dist/extraction/languages/dart.d.ts.map +1 -0
  138. package/dist/extraction/languages/dart.js +374 -0
  139. package/dist/extraction/languages/dart.js.map +1 -0
  140. package/dist/extraction/languages/erlang.d.ts +3 -0
  141. package/dist/extraction/languages/erlang.d.ts.map +1 -0
  142. package/dist/extraction/languages/erlang.js +350 -0
  143. package/dist/extraction/languages/erlang.js.map +1 -0
  144. package/dist/extraction/languages/go.d.ts +3 -0
  145. package/dist/extraction/languages/go.d.ts.map +1 -0
  146. package/dist/extraction/languages/go.js +111 -0
  147. package/dist/extraction/languages/go.js.map +1 -0
  148. package/dist/extraction/languages/index.d.ts +10 -0
  149. package/dist/extraction/languages/index.d.ts.map +1 -0
  150. package/dist/extraction/languages/index.js +71 -0
  151. package/dist/extraction/languages/index.js.map +1 -0
  152. package/dist/extraction/languages/java.d.ts +3 -0
  153. package/dist/extraction/languages/java.d.ts.map +1 -0
  154. package/dist/extraction/languages/java.js +315 -0
  155. package/dist/extraction/languages/java.js.map +1 -0
  156. package/dist/extraction/languages/javascript.d.ts +3 -0
  157. package/dist/extraction/languages/javascript.d.ts.map +1 -0
  158. package/dist/extraction/languages/javascript.js +106 -0
  159. package/dist/extraction/languages/javascript.js.map +1 -0
  160. package/dist/extraction/languages/kotlin.d.ts +3 -0
  161. package/dist/extraction/languages/kotlin.d.ts.map +1 -0
  162. package/dist/extraction/languages/kotlin.js +379 -0
  163. package/dist/extraction/languages/kotlin.js.map +1 -0
  164. package/dist/extraction/languages/lua.d.ts +3 -0
  165. package/dist/extraction/languages/lua.d.ts.map +1 -0
  166. package/dist/extraction/languages/lua.js +150 -0
  167. package/dist/extraction/languages/lua.js.map +1 -0
  168. package/dist/extraction/languages/luau.d.ts +3 -0
  169. package/dist/extraction/languages/luau.d.ts.map +1 -0
  170. package/dist/extraction/languages/luau.js +37 -0
  171. package/dist/extraction/languages/luau.js.map +1 -0
  172. package/dist/extraction/languages/nix.d.ts +3 -0
  173. package/dist/extraction/languages/nix.d.ts.map +1 -0
  174. package/dist/extraction/languages/nix.js +294 -0
  175. package/dist/extraction/languages/nix.js.map +1 -0
  176. package/dist/extraction/languages/objc.d.ts +3 -0
  177. package/dist/extraction/languages/objc.d.ts.map +1 -0
  178. package/dist/extraction/languages/objc.js +179 -0
  179. package/dist/extraction/languages/objc.js.map +1 -0
  180. package/dist/extraction/languages/pascal.d.ts +3 -0
  181. package/dist/extraction/languages/pascal.d.ts.map +1 -0
  182. package/dist/extraction/languages/pascal.js +77 -0
  183. package/dist/extraction/languages/pascal.js.map +1 -0
  184. package/dist/extraction/languages/php.d.ts +3 -0
  185. package/dist/extraction/languages/php.d.ts.map +1 -0
  186. package/dist/extraction/languages/php.js +196 -0
  187. package/dist/extraction/languages/php.js.map +1 -0
  188. package/dist/extraction/languages/python.d.ts +3 -0
  189. package/dist/extraction/languages/python.d.ts.map +1 -0
  190. package/dist/extraction/languages/python.js +56 -0
  191. package/dist/extraction/languages/python.js.map +1 -0
  192. package/dist/extraction/languages/r.d.ts +3 -0
  193. package/dist/extraction/languages/r.d.ts.map +1 -0
  194. package/dist/extraction/languages/r.js +314 -0
  195. package/dist/extraction/languages/r.js.map +1 -0
  196. package/dist/extraction/languages/ruby.d.ts +3 -0
  197. package/dist/extraction/languages/ruby.d.ts.map +1 -0
  198. package/dist/extraction/languages/ruby.js +149 -0
  199. package/dist/extraction/languages/ruby.js.map +1 -0
  200. package/dist/extraction/languages/rust.d.ts +3 -0
  201. package/dist/extraction/languages/rust.d.ts.map +1 -0
  202. package/dist/extraction/languages/rust.js +145 -0
  203. package/dist/extraction/languages/rust.js.map +1 -0
  204. package/dist/extraction/languages/scala.d.ts +3 -0
  205. package/dist/extraction/languages/scala.d.ts.map +1 -0
  206. package/dist/extraction/languages/scala.js +209 -0
  207. package/dist/extraction/languages/scala.js.map +1 -0
  208. package/dist/extraction/languages/solidity.d.ts +3 -0
  209. package/dist/extraction/languages/solidity.d.ts.map +1 -0
  210. package/dist/extraction/languages/solidity.js +293 -0
  211. package/dist/extraction/languages/solidity.js.map +1 -0
  212. package/dist/extraction/languages/swift.d.ts +3 -0
  213. package/dist/extraction/languages/swift.d.ts.map +1 -0
  214. package/dist/extraction/languages/swift.js +152 -0
  215. package/dist/extraction/languages/swift.js.map +1 -0
  216. package/dist/extraction/languages/terraform.d.ts +3 -0
  217. package/dist/extraction/languages/terraform.d.ts.map +1 -0
  218. package/dist/extraction/languages/terraform.js +641 -0
  219. package/dist/extraction/languages/terraform.js.map +1 -0
  220. package/dist/extraction/languages/typescript.d.ts +16 -0
  221. package/dist/extraction/languages/typescript.d.ts.map +1 -0
  222. package/dist/extraction/languages/typescript.js +167 -0
  223. package/dist/extraction/languages/typescript.js.map +1 -0
  224. package/dist/extraction/languages/vbnet.d.ts +11 -0
  225. package/dist/extraction/languages/vbnet.d.ts.map +1 -0
  226. package/dist/extraction/languages/vbnet.js +141 -0
  227. package/dist/extraction/languages/vbnet.js.map +1 -0
  228. package/dist/extraction/liquid-extractor.d.ts +59 -0
  229. package/dist/extraction/liquid-extractor.d.ts.map +1 -0
  230. package/dist/extraction/liquid-extractor.js +357 -0
  231. package/dist/extraction/liquid-extractor.js.map +1 -0
  232. package/dist/extraction/mybatis-extractor.d.ts +68 -0
  233. package/dist/extraction/mybatis-extractor.d.ts.map +1 -0
  234. package/dist/extraction/mybatis-extractor.js +300 -0
  235. package/dist/extraction/mybatis-extractor.js.map +1 -0
  236. package/dist/extraction/parse-pool.d.ts +160 -0
  237. package/dist/extraction/parse-pool.d.ts.map +1 -0
  238. package/dist/extraction/parse-pool.js +402 -0
  239. package/dist/extraction/parse-pool.js.map +1 -0
  240. package/dist/extraction/parse-worker.d.ts +8 -0
  241. package/dist/extraction/parse-worker.d.ts.map +1 -0
  242. package/dist/extraction/parse-worker.js +138 -0
  243. package/dist/extraction/parse-worker.js.map +1 -0
  244. package/dist/extraction/razor-extractor.d.ts +42 -0
  245. package/dist/extraction/razor-extractor.d.ts.map +1 -0
  246. package/dist/extraction/razor-extractor.js +285 -0
  247. package/dist/extraction/razor-extractor.js.map +1 -0
  248. package/dist/extraction/store-worker.d.ts +24 -0
  249. package/dist/extraction/store-worker.d.ts.map +1 -0
  250. package/dist/extraction/store-worker.js +139 -0
  251. package/dist/extraction/store-worker.js.map +1 -0
  252. package/dist/extraction/store-writer.d.ts +63 -0
  253. package/dist/extraction/store-writer.d.ts.map +1 -0
  254. package/dist/extraction/store-writer.js +174 -0
  255. package/dist/extraction/store-writer.js.map +1 -0
  256. package/dist/extraction/svelte-extractor.d.ts +56 -0
  257. package/dist/extraction/svelte-extractor.d.ts.map +1 -0
  258. package/dist/extraction/svelte-extractor.js +275 -0
  259. package/dist/extraction/svelte-extractor.js.map +1 -0
  260. package/dist/extraction/tree-sitter-helpers.d.ts +28 -0
  261. package/dist/extraction/tree-sitter-helpers.d.ts.map +1 -0
  262. package/dist/extraction/tree-sitter-helpers.js +153 -0
  263. package/dist/extraction/tree-sitter-helpers.js.map +1 -0
  264. package/dist/extraction/tree-sitter-types.d.ts +260 -0
  265. package/dist/extraction/tree-sitter-types.d.ts.map +1 -0
  266. package/dist/extraction/tree-sitter-types.js +10 -0
  267. package/dist/extraction/tree-sitter-types.js.map +1 -0
  268. package/dist/extraction/tree-sitter.d.ts +728 -0
  269. package/dist/extraction/tree-sitter.d.ts.map +1 -0
  270. package/dist/extraction/tree-sitter.js +6676 -0
  271. package/dist/extraction/tree-sitter.js.map +1 -0
  272. package/dist/extraction/vue-extractor.d.ts +51 -0
  273. package/dist/extraction/vue-extractor.d.ts.map +1 -0
  274. package/dist/extraction/vue-extractor.js +254 -0
  275. package/dist/extraction/vue-extractor.js.map +1 -0
  276. package/dist/extraction/wasm/tree-sitter-arkts.wasm +0 -0
  277. package/dist/extraction/wasm/tree-sitter-c.wasm +0 -0
  278. package/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
  279. package/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
  280. package/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
  281. package/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
  282. package/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
  283. package/dist/extraction/wasm/tree-sitter-cpp.wasm +0 -0
  284. package/dist/extraction/wasm/tree-sitter-dart.wasm +0 -0
  285. package/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
  286. package/dist/extraction/wasm/tree-sitter-go.wasm +0 -0
  287. package/dist/extraction/wasm/tree-sitter-java.wasm +0 -0
  288. package/dist/extraction/wasm/tree-sitter-javascript.wasm +0 -0
  289. package/dist/extraction/wasm/tree-sitter-kotlin.wasm +0 -0
  290. package/dist/extraction/wasm/tree-sitter-lua.wasm +0 -0
  291. package/dist/extraction/wasm/tree-sitter-luau.wasm +0 -0
  292. package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
  293. package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  294. package/dist/extraction/wasm/tree-sitter-php.wasm +0 -0
  295. package/dist/extraction/wasm/tree-sitter-python.wasm +0 -0
  296. package/dist/extraction/wasm/tree-sitter-r.wasm +0 -0
  297. package/dist/extraction/wasm/tree-sitter-ruby.wasm +0 -0
  298. package/dist/extraction/wasm/tree-sitter-rust.wasm +0 -0
  299. package/dist/extraction/wasm/tree-sitter-scala.wasm +0 -0
  300. package/dist/extraction/wasm/tree-sitter-swift.wasm +0 -0
  301. package/dist/extraction/wasm/tree-sitter-terraform.wasm +0 -0
  302. package/dist/extraction/wasm/tree-sitter-tsx.wasm +0 -0
  303. package/dist/extraction/wasm/tree-sitter-typescript.wasm +0 -0
  304. package/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
  305. package/dist/extraction/wasm-runtime-flags.d.ts +53 -0
  306. package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -0
  307. package/dist/extraction/wasm-runtime-flags.js +130 -0
  308. package/dist/extraction/wasm-runtime-flags.js.map +1 -0
  309. package/dist/graph/index.d.ts +8 -0
  310. package/dist/graph/index.d.ts.map +1 -0
  311. package/dist/graph/index.js +13 -0
  312. package/dist/graph/index.js.map +1 -0
  313. package/dist/graph/queries.d.ts +106 -0
  314. package/dist/graph/queries.d.ts.map +1 -0
  315. package/dist/graph/queries.js +341 -0
  316. package/dist/graph/queries.js.map +1 -0
  317. package/dist/graph/traversal.d.ts +127 -0
  318. package/dist/graph/traversal.d.ts.map +1 -0
  319. package/dist/graph/traversal.js +599 -0
  320. package/dist/graph/traversal.js.map +1 -0
  321. package/dist/index.d.ts +677 -0
  322. package/dist/index.d.ts.map +1 -0
  323. package/dist/index.js +1718 -0
  324. package/dist/index.js.map +1 -0
  325. package/dist/installer/beta-signup.d.ts +54 -0
  326. package/dist/installer/beta-signup.d.ts.map +1 -0
  327. package/dist/installer/beta-signup.js +178 -0
  328. package/dist/installer/beta-signup.js.map +1 -0
  329. package/dist/installer/config-writer.d.ts +28 -0
  330. package/dist/installer/config-writer.d.ts.map +1 -0
  331. package/dist/installer/config-writer.js +91 -0
  332. package/dist/installer/config-writer.js.map +1 -0
  333. package/dist/installer/index.d.ts +144 -0
  334. package/dist/installer/index.d.ts.map +1 -0
  335. package/dist/installer/index.js +634 -0
  336. package/dist/installer/index.js.map +1 -0
  337. package/dist/installer/instructions-template.d.ts +41 -0
  338. package/dist/installer/instructions-template.d.ts.map +1 -0
  339. package/dist/installer/instructions-template.js +53 -0
  340. package/dist/installer/instructions-template.js.map +1 -0
  341. package/dist/installer/targets/antigravity.d.ts +57 -0
  342. package/dist/installer/targets/antigravity.d.ts.map +1 -0
  343. package/dist/installer/targets/antigravity.js +308 -0
  344. package/dist/installer/targets/antigravity.js.map +1 -0
  345. package/dist/installer/targets/claude.d.ts +62 -0
  346. package/dist/installer/targets/claude.d.ts.map +1 -0
  347. package/dist/installer/targets/claude.js +486 -0
  348. package/dist/installer/targets/claude.js.map +1 -0
  349. package/dist/installer/targets/codex.d.ts +18 -0
  350. package/dist/installer/targets/codex.d.ts.map +1 -0
  351. package/dist/installer/targets/codex.js +185 -0
  352. package/dist/installer/targets/codex.js.map +1 -0
  353. package/dist/installer/targets/copilot-cli.d.ts +32 -0
  354. package/dist/installer/targets/copilot-cli.d.ts.map +1 -0
  355. package/dist/installer/targets/copilot-cli.js +209 -0
  356. package/dist/installer/targets/copilot-cli.js.map +1 -0
  357. package/dist/installer/targets/copilot-jetbrains.d.ts +42 -0
  358. package/dist/installer/targets/copilot-jetbrains.d.ts.map +1 -0
  359. package/dist/installer/targets/copilot-jetbrains.js +238 -0
  360. package/dist/installer/targets/copilot-jetbrains.js.map +1 -0
  361. package/dist/installer/targets/copilot-vscode.d.ts +47 -0
  362. package/dist/installer/targets/copilot-vscode.d.ts.map +1 -0
  363. package/dist/installer/targets/copilot-vscode.js +219 -0
  364. package/dist/installer/targets/copilot-vscode.js.map +1 -0
  365. package/dist/installer/targets/cursor.d.ts +35 -0
  366. package/dist/installer/targets/cursor.d.ts.map +1 -0
  367. package/dist/installer/targets/cursor.js +254 -0
  368. package/dist/installer/targets/cursor.js.map +1 -0
  369. package/dist/installer/targets/dsh.d.ts +97 -0
  370. package/dist/installer/targets/dsh.d.ts.map +1 -0
  371. package/dist/installer/targets/dsh.js +358 -0
  372. package/dist/installer/targets/dsh.js.map +1 -0
  373. package/dist/installer/targets/gemini.d.ts +26 -0
  374. package/dist/installer/targets/gemini.d.ts.map +1 -0
  375. package/dist/installer/targets/gemini.js +165 -0
  376. package/dist/installer/targets/gemini.js.map +1 -0
  377. package/dist/installer/targets/hermes.d.ts +18 -0
  378. package/dist/installer/targets/hermes.d.ts.map +1 -0
  379. package/dist/installer/targets/hermes.js +359 -0
  380. package/dist/installer/targets/hermes.js.map +1 -0
  381. package/dist/installer/targets/kiro.d.ts +27 -0
  382. package/dist/installer/targets/kiro.d.ts.map +1 -0
  383. package/dist/installer/targets/kiro.js +178 -0
  384. package/dist/installer/targets/kiro.js.map +1 -0
  385. package/dist/installer/targets/opencode.d.ts +38 -0
  386. package/dist/installer/targets/opencode.d.ts.map +1 -0
  387. package/dist/installer/targets/opencode.js +288 -0
  388. package/dist/installer/targets/opencode.js.map +1 -0
  389. package/dist/installer/targets/registry.d.ts +35 -0
  390. package/dist/installer/targets/registry.d.ts.map +1 -0
  391. package/dist/installer/targets/registry.js +101 -0
  392. package/dist/installer/targets/registry.js.map +1 -0
  393. package/dist/installer/targets/shared.d.ts +132 -0
  394. package/dist/installer/targets/shared.d.ts.map +1 -0
  395. package/dist/installer/targets/shared.js +314 -0
  396. package/dist/installer/targets/shared.js.map +1 -0
  397. package/dist/installer/targets/toml.d.ts +53 -0
  398. package/dist/installer/targets/toml.d.ts.map +1 -0
  399. package/dist/installer/targets/toml.js +226 -0
  400. package/dist/installer/targets/toml.js.map +1 -0
  401. package/dist/installer/targets/types.d.ts +109 -0
  402. package/dist/installer/targets/types.d.ts.map +1 -0
  403. package/dist/installer/targets/types.js +16 -0
  404. package/dist/installer/targets/types.js.map +1 -0
  405. package/dist/installer/targets/zcode.d.ts +106 -0
  406. package/dist/installer/targets/zcode.d.ts.map +1 -0
  407. package/dist/installer/targets/zcode.js +451 -0
  408. package/dist/installer/targets/zcode.js.map +1 -0
  409. package/dist/mcp/daemon-manager.d.ts +42 -0
  410. package/dist/mcp/daemon-manager.d.ts.map +1 -0
  411. package/dist/mcp/daemon-manager.js +129 -0
  412. package/dist/mcp/daemon-manager.js.map +1 -0
  413. package/dist/mcp/daemon-paths.d.ts +73 -0
  414. package/dist/mcp/daemon-paths.d.ts.map +1 -0
  415. package/dist/mcp/daemon-paths.js +165 -0
  416. package/dist/mcp/daemon-paths.js.map +1 -0
  417. package/dist/mcp/daemon-registry.d.ts +47 -0
  418. package/dist/mcp/daemon-registry.d.ts.map +1 -0
  419. package/dist/mcp/daemon-registry.js +233 -0
  420. package/dist/mcp/daemon-registry.js.map +1 -0
  421. package/dist/mcp/daemon.d.ts +290 -0
  422. package/dist/mcp/daemon.d.ts.map +1 -0
  423. package/dist/mcp/daemon.js +862 -0
  424. package/dist/mcp/daemon.js.map +1 -0
  425. package/dist/mcp/dynamic-boundaries.d.ts +41 -0
  426. package/dist/mcp/dynamic-boundaries.d.ts.map +1 -0
  427. package/dist/mcp/dynamic-boundaries.js +360 -0
  428. package/dist/mcp/dynamic-boundaries.js.map +1 -0
  429. package/dist/mcp/early-ppid.d.ts +26 -0
  430. package/dist/mcp/early-ppid.d.ts.map +1 -0
  431. package/dist/mcp/early-ppid.js +29 -0
  432. package/dist/mcp/early-ppid.js.map +1 -0
  433. package/dist/mcp/engine.d.ts +122 -0
  434. package/dist/mcp/engine.d.ts.map +1 -0
  435. package/dist/mcp/engine.js +350 -0
  436. package/dist/mcp/engine.js.map +1 -0
  437. package/dist/mcp/explore-dedup.d.ts +137 -0
  438. package/dist/mcp/explore-dedup.d.ts.map +1 -0
  439. package/dist/mcp/explore-dedup.js +236 -0
  440. package/dist/mcp/explore-dedup.js.map +1 -0
  441. package/dist/mcp/explore-diagnostics.d.ts +287 -0
  442. package/dist/mcp/explore-diagnostics.d.ts.map +1 -0
  443. package/dist/mcp/explore-diagnostics.js +555 -0
  444. package/dist/mcp/explore-diagnostics.js.map +1 -0
  445. package/dist/mcp/explore-session-state.d.ts +217 -0
  446. package/dist/mcp/explore-session-state.d.ts.map +1 -0
  447. package/dist/mcp/explore-session-state.js +322 -0
  448. package/dist/mcp/explore-session-state.js.map +1 -0
  449. package/dist/mcp/index.d.ts +137 -0
  450. package/dist/mcp/index.d.ts.map +1 -0
  451. package/dist/mcp/index.js +554 -0
  452. package/dist/mcp/index.js.map +1 -0
  453. package/dist/mcp/liveness-watchdog.d.ts +35 -0
  454. package/dist/mcp/liveness-watchdog.d.ts.map +1 -0
  455. package/dist/mcp/liveness-watchdog.js +269 -0
  456. package/dist/mcp/liveness-watchdog.js.map +1 -0
  457. package/dist/mcp/ppid-watchdog.d.ts +62 -0
  458. package/dist/mcp/ppid-watchdog.d.ts.map +1 -0
  459. package/dist/mcp/ppid-watchdog.js +64 -0
  460. package/dist/mcp/ppid-watchdog.js.map +1 -0
  461. package/dist/mcp/proxy.d.ts +87 -0
  462. package/dist/mcp/proxy.d.ts.map +1 -0
  463. package/dist/mcp/proxy.js +672 -0
  464. package/dist/mcp/proxy.js.map +1 -0
  465. package/dist/mcp/query-pool.d.ts +108 -0
  466. package/dist/mcp/query-pool.d.ts.map +1 -0
  467. package/dist/mcp/query-pool.js +315 -0
  468. package/dist/mcp/query-pool.js.map +1 -0
  469. package/dist/mcp/query-worker.d.ts +24 -0
  470. package/dist/mcp/query-worker.d.ts.map +1 -0
  471. package/dist/mcp/query-worker.js +87 -0
  472. package/dist/mcp/query-worker.js.map +1 -0
  473. package/dist/mcp/server-instructions.d.ts +34 -0
  474. package/dist/mcp/server-instructions.d.ts.map +1 -0
  475. package/dist/mcp/server-instructions.js +111 -0
  476. package/dist/mcp/server-instructions.js.map +1 -0
  477. package/dist/mcp/session.d.ts +109 -0
  478. package/dist/mcp/session.d.ts.map +1 -0
  479. package/dist/mcp/session.js +375 -0
  480. package/dist/mcp/session.js.map +1 -0
  481. package/dist/mcp/startup-handshake.d.ts +44 -0
  482. package/dist/mcp/startup-handshake.d.ts.map +1 -0
  483. package/dist/mcp/startup-handshake.js +73 -0
  484. package/dist/mcp/startup-handshake.js.map +1 -0
  485. package/dist/mcp/stdin-teardown.d.ts +27 -0
  486. package/dist/mcp/stdin-teardown.d.ts.map +1 -0
  487. package/dist/mcp/stdin-teardown.js +49 -0
  488. package/dist/mcp/stdin-teardown.js.map +1 -0
  489. package/dist/mcp/tools.d.ts +862 -0
  490. package/dist/mcp/tools.d.ts.map +1 -0
  491. package/dist/mcp/tools.js +6526 -0
  492. package/dist/mcp/tools.js.map +1 -0
  493. package/dist/mcp/transport.d.ts +188 -0
  494. package/dist/mcp/transport.d.ts.map +1 -0
  495. package/dist/mcp/transport.js +377 -0
  496. package/dist/mcp/transport.js.map +1 -0
  497. package/dist/mcp/version.d.ts +19 -0
  498. package/dist/mcp/version.d.ts.map +1 -0
  499. package/dist/mcp/version.js +71 -0
  500. package/dist/mcp/version.js.map +1 -0
  501. package/dist/project-config.d.ts +94 -0
  502. package/dist/project-config.d.ts.map +1 -0
  503. package/dist/project-config.js +374 -0
  504. package/dist/project-config.js.map +1 -0
  505. package/dist/prompt-hook-output.d.ts +23 -0
  506. package/dist/prompt-hook-output.d.ts.map +1 -0
  507. package/dist/prompt-hook-output.js +35 -0
  508. package/dist/prompt-hook-output.js.map +1 -0
  509. package/dist/resolution/c-fnptr-synthesizer.d.ts +6 -0
  510. package/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -0
  511. package/dist/resolution/c-fnptr-synthesizer.js +1506 -0
  512. package/dist/resolution/c-fnptr-synthesizer.js.map +1 -0
  513. package/dist/resolution/callback-synthesizer.d.ts +59 -0
  514. package/dist/resolution/callback-synthesizer.d.ts.map +1 -0
  515. package/dist/resolution/callback-synthesizer.js +4030 -0
  516. package/dist/resolution/callback-synthesizer.js.map +1 -0
  517. package/dist/resolution/cooperative-yield.d.ts +40 -0
  518. package/dist/resolution/cooperative-yield.d.ts.map +1 -0
  519. package/dist/resolution/cooperative-yield.js +44 -0
  520. package/dist/resolution/cooperative-yield.js.map +1 -0
  521. package/dist/resolution/frameworks/astro.d.ts +9 -0
  522. package/dist/resolution/frameworks/astro.d.ts.map +1 -0
  523. package/dist/resolution/frameworks/astro.js +169 -0
  524. package/dist/resolution/frameworks/astro.js.map +1 -0
  525. package/dist/resolution/frameworks/cargo-workspace.d.ts +18 -0
  526. package/dist/resolution/frameworks/cargo-workspace.d.ts.map +1 -0
  527. package/dist/resolution/frameworks/cargo-workspace.js +225 -0
  528. package/dist/resolution/frameworks/cargo-workspace.js.map +1 -0
  529. package/dist/resolution/frameworks/cics.d.ts +20 -0
  530. package/dist/resolution/frameworks/cics.d.ts.map +1 -0
  531. package/dist/resolution/frameworks/cics.js +90 -0
  532. package/dist/resolution/frameworks/cics.js.map +1 -0
  533. package/dist/resolution/frameworks/csharp.d.ts +8 -0
  534. package/dist/resolution/frameworks/csharp.d.ts.map +1 -0
  535. package/dist/resolution/frameworks/csharp.js +241 -0
  536. package/dist/resolution/frameworks/csharp.js.map +1 -0
  537. package/dist/resolution/frameworks/drupal.d.ts +51 -0
  538. package/dist/resolution/frameworks/drupal.d.ts.map +1 -0
  539. package/dist/resolution/frameworks/drupal.js +367 -0
  540. package/dist/resolution/frameworks/drupal.js.map +1 -0
  541. package/dist/resolution/frameworks/expo-modules.d.ts +3 -0
  542. package/dist/resolution/frameworks/expo-modules.d.ts.map +1 -0
  543. package/dist/resolution/frameworks/expo-modules.js +148 -0
  544. package/dist/resolution/frameworks/expo-modules.js.map +1 -0
  545. package/dist/resolution/frameworks/express.d.ts +8 -0
  546. package/dist/resolution/frameworks/express.d.ts.map +1 -0
  547. package/dist/resolution/frameworks/express.js +308 -0
  548. package/dist/resolution/frameworks/express.js.map +1 -0
  549. package/dist/resolution/frameworks/fabric.d.ts +3 -0
  550. package/dist/resolution/frameworks/fabric.d.ts.map +1 -0
  551. package/dist/resolution/frameworks/fabric.js +354 -0
  552. package/dist/resolution/frameworks/fabric.js.map +1 -0
  553. package/dist/resolution/frameworks/go.d.ts +8 -0
  554. package/dist/resolution/frameworks/go.d.ts.map +1 -0
  555. package/dist/resolution/frameworks/go.js +184 -0
  556. package/dist/resolution/frameworks/go.js.map +1 -0
  557. package/dist/resolution/frameworks/goframe.d.ts +41 -0
  558. package/dist/resolution/frameworks/goframe.d.ts.map +1 -0
  559. package/dist/resolution/frameworks/goframe.js +112 -0
  560. package/dist/resolution/frameworks/goframe.js.map +1 -0
  561. package/dist/resolution/frameworks/index.d.ts +50 -0
  562. package/dist/resolution/frameworks/index.d.ts.map +1 -0
  563. package/dist/resolution/frameworks/index.js +175 -0
  564. package/dist/resolution/frameworks/index.js.map +1 -0
  565. package/dist/resolution/frameworks/java.d.ts +8 -0
  566. package/dist/resolution/frameworks/java.d.ts.map +1 -0
  567. package/dist/resolution/frameworks/java.js +517 -0
  568. package/dist/resolution/frameworks/java.js.map +1 -0
  569. package/dist/resolution/frameworks/laravel.d.ts +13 -0
  570. package/dist/resolution/frameworks/laravel.d.ts.map +1 -0
  571. package/dist/resolution/frameworks/laravel.js +257 -0
  572. package/dist/resolution/frameworks/laravel.js.map +1 -0
  573. package/dist/resolution/frameworks/nestjs.d.ts +26 -0
  574. package/dist/resolution/frameworks/nestjs.d.ts.map +1 -0
  575. package/dist/resolution/frameworks/nestjs.js +698 -0
  576. package/dist/resolution/frameworks/nestjs.js.map +1 -0
  577. package/dist/resolution/frameworks/play.d.ts +19 -0
  578. package/dist/resolution/frameworks/play.d.ts.map +1 -0
  579. package/dist/resolution/frameworks/play.js +111 -0
  580. package/dist/resolution/frameworks/play.js.map +1 -0
  581. package/dist/resolution/frameworks/python.d.ts +10 -0
  582. package/dist/resolution/frameworks/python.d.ts.map +1 -0
  583. package/dist/resolution/frameworks/python.js +400 -0
  584. package/dist/resolution/frameworks/python.js.map +1 -0
  585. package/dist/resolution/frameworks/react-native.d.ts +3 -0
  586. package/dist/resolution/frameworks/react-native.d.ts.map +1 -0
  587. package/dist/resolution/frameworks/react-native.js +410 -0
  588. package/dist/resolution/frameworks/react-native.js.map +1 -0
  589. package/dist/resolution/frameworks/react.d.ts +8 -0
  590. package/dist/resolution/frameworks/react.d.ts.map +1 -0
  591. package/dist/resolution/frameworks/react.js +334 -0
  592. package/dist/resolution/frameworks/react.js.map +1 -0
  593. package/dist/resolution/frameworks/ruby.d.ts +8 -0
  594. package/dist/resolution/frameworks/ruby.d.ts.map +1 -0
  595. package/dist/resolution/frameworks/ruby.js +302 -0
  596. package/dist/resolution/frameworks/ruby.js.map +1 -0
  597. package/dist/resolution/frameworks/rust.d.ts +8 -0
  598. package/dist/resolution/frameworks/rust.d.ts.map +1 -0
  599. package/dist/resolution/frameworks/rust.js +304 -0
  600. package/dist/resolution/frameworks/rust.js.map +1 -0
  601. package/dist/resolution/frameworks/svelte.d.ts +9 -0
  602. package/dist/resolution/frameworks/svelte.d.ts.map +1 -0
  603. package/dist/resolution/frameworks/svelte.js +253 -0
  604. package/dist/resolution/frameworks/svelte.js.map +1 -0
  605. package/dist/resolution/frameworks/swift-objc.d.ts +37 -0
  606. package/dist/resolution/frameworks/swift-objc.d.ts.map +1 -0
  607. package/dist/resolution/frameworks/swift-objc.js +252 -0
  608. package/dist/resolution/frameworks/swift-objc.js.map +1 -0
  609. package/dist/resolution/frameworks/swift.d.ts +10 -0
  610. package/dist/resolution/frameworks/swift.d.ts.map +1 -0
  611. package/dist/resolution/frameworks/swift.js +400 -0
  612. package/dist/resolution/frameworks/swift.js.map +1 -0
  613. package/dist/resolution/frameworks/terraform.d.ts +38 -0
  614. package/dist/resolution/frameworks/terraform.d.ts.map +1 -0
  615. package/dist/resolution/frameworks/terraform.js +277 -0
  616. package/dist/resolution/frameworks/terraform.js.map +1 -0
  617. package/dist/resolution/frameworks/vue.d.ts +9 -0
  618. package/dist/resolution/frameworks/vue.d.ts.map +1 -0
  619. package/dist/resolution/frameworks/vue.js +303 -0
  620. package/dist/resolution/frameworks/vue.js.map +1 -0
  621. package/dist/resolution/go-module.d.ts +26 -0
  622. package/dist/resolution/go-module.d.ts.map +1 -0
  623. package/dist/resolution/go-module.js +78 -0
  624. package/dist/resolution/go-module.js.map +1 -0
  625. package/dist/resolution/goframe-synthesizer.d.ts +29 -0
  626. package/dist/resolution/goframe-synthesizer.d.ts.map +1 -0
  627. package/dist/resolution/goframe-synthesizer.js +163 -0
  628. package/dist/resolution/goframe-synthesizer.js.map +1 -0
  629. package/dist/resolution/import-resolver.d.ts +84 -0
  630. package/dist/resolution/import-resolver.d.ts.map +1 -0
  631. package/dist/resolution/import-resolver.js +2134 -0
  632. package/dist/resolution/import-resolver.js.map +1 -0
  633. package/dist/resolution/index.d.ts +343 -0
  634. package/dist/resolution/index.d.ts.map +1 -0
  635. package/dist/resolution/index.js +2339 -0
  636. package/dist/resolution/index.js.map +1 -0
  637. package/dist/resolution/lru-cache.d.ts +24 -0
  638. package/dist/resolution/lru-cache.d.ts.map +1 -0
  639. package/dist/resolution/lru-cache.js +62 -0
  640. package/dist/resolution/lru-cache.js.map +1 -0
  641. package/dist/resolution/memory-budget.d.ts +48 -0
  642. package/dist/resolution/memory-budget.d.ts.map +1 -0
  643. package/dist/resolution/memory-budget.js +162 -0
  644. package/dist/resolution/memory-budget.js.map +1 -0
  645. package/dist/resolution/name-matcher.d.ts +123 -0
  646. package/dist/resolution/name-matcher.d.ts.map +1 -0
  647. package/dist/resolution/name-matcher.js +2134 -0
  648. package/dist/resolution/name-matcher.js.map +1 -0
  649. package/dist/resolution/path-aliases.d.ts +68 -0
  650. package/dist/resolution/path-aliases.d.ts.map +1 -0
  651. package/dist/resolution/path-aliases.js +238 -0
  652. package/dist/resolution/path-aliases.js.map +1 -0
  653. package/dist/resolution/resolver-pool.d.ts +106 -0
  654. package/dist/resolution/resolver-pool.d.ts.map +1 -0
  655. package/dist/resolution/resolver-pool.js +344 -0
  656. package/dist/resolution/resolver-pool.js.map +1 -0
  657. package/dist/resolution/resolver-worker.d.ts +17 -0
  658. package/dist/resolution/resolver-worker.d.ts.map +1 -0
  659. package/dist/resolution/resolver-worker.js +141 -0
  660. package/dist/resolution/resolver-worker.js.map +1 -0
  661. package/dist/resolution/strip-comments.d.ts +27 -0
  662. package/dist/resolution/strip-comments.d.ts.map +1 -0
  663. package/dist/resolution/strip-comments.js +492 -0
  664. package/dist/resolution/strip-comments.js.map +1 -0
  665. package/dist/resolution/swift-objc-bridge.d.ts +134 -0
  666. package/dist/resolution/swift-objc-bridge.d.ts.map +1 -0
  667. package/dist/resolution/swift-objc-bridge.js +256 -0
  668. package/dist/resolution/swift-objc-bridge.js.map +1 -0
  669. package/dist/resolution/types.d.ts +265 -0
  670. package/dist/resolution/types.d.ts.map +1 -0
  671. package/dist/resolution/types.js +8 -0
  672. package/dist/resolution/types.js.map +1 -0
  673. package/dist/resolution/workspace-packages.d.ts +58 -0
  674. package/dist/resolution/workspace-packages.d.ts.map +1 -0
  675. package/dist/resolution/workspace-packages.js +346 -0
  676. package/dist/resolution/workspace-packages.js.map +1 -0
  677. package/dist/search/identifier-segments.d.ts +60 -0
  678. package/dist/search/identifier-segments.d.ts.map +1 -0
  679. package/dist/search/identifier-segments.js +176 -0
  680. package/dist/search/identifier-segments.js.map +1 -0
  681. package/dist/search/query-parser.d.ts +57 -0
  682. package/dist/search/query-parser.d.ts.map +1 -0
  683. package/dist/search/query-parser.js +177 -0
  684. package/dist/search/query-parser.js.map +1 -0
  685. package/dist/search/query-utils.d.ts +87 -0
  686. package/dist/search/query-utils.d.ts.map +1 -0
  687. package/dist/search/query-utils.js +450 -0
  688. package/dist/search/query-utils.js.map +1 -0
  689. package/dist/sync/git-hooks.d.ts +45 -0
  690. package/dist/sync/git-hooks.d.ts.map +1 -0
  691. package/dist/sync/git-hooks.js +227 -0
  692. package/dist/sync/git-hooks.js.map +1 -0
  693. package/dist/sync/index.d.ts +19 -0
  694. package/dist/sync/index.d.ts.map +1 -0
  695. package/dist/sync/index.js +35 -0
  696. package/dist/sync/index.js.map +1 -0
  697. package/dist/sync/watch-policy.d.ts +48 -0
  698. package/dist/sync/watch-policy.d.ts.map +1 -0
  699. package/dist/sync/watch-policy.js +124 -0
  700. package/dist/sync/watch-policy.js.map +1 -0
  701. package/dist/sync/watcher.d.ts +379 -0
  702. package/dist/sync/watcher.d.ts.map +1 -0
  703. package/dist/sync/watcher.js +921 -0
  704. package/dist/sync/watcher.js.map +1 -0
  705. package/dist/sync/worktree.d.ts +63 -0
  706. package/dist/sync/worktree.d.ts.map +1 -0
  707. package/dist/sync/worktree.js +182 -0
  708. package/dist/sync/worktree.js.map +1 -0
  709. package/dist/telemetry/index.d.ts +143 -0
  710. package/dist/telemetry/index.d.ts.map +1 -0
  711. package/dist/telemetry/index.js +541 -0
  712. package/dist/telemetry/index.js.map +1 -0
  713. package/dist/types.d.ts +465 -0
  714. package/dist/types.d.ts.map +1 -0
  715. package/dist/types.js +117 -0
  716. package/dist/types.js.map +1 -0
  717. package/dist/ui/color.d.ts +21 -0
  718. package/dist/ui/color.d.ts.map +1 -0
  719. package/dist/ui/color.js +42 -0
  720. package/dist/ui/color.js.map +1 -0
  721. package/dist/ui/glyphs.d.ts +67 -0
  722. package/dist/ui/glyphs.d.ts.map +1 -0
  723. package/dist/ui/glyphs.js +125 -0
  724. package/dist/ui/glyphs.js.map +1 -0
  725. package/dist/ui/shimmer-progress.d.ts +11 -0
  726. package/dist/ui/shimmer-progress.d.ts.map +1 -0
  727. package/dist/ui/shimmer-progress.js +164 -0
  728. package/dist/ui/shimmer-progress.js.map +1 -0
  729. package/dist/ui/shimmer-worker.d.ts +2 -0
  730. package/dist/ui/shimmer-worker.d.ts.map +1 -0
  731. package/dist/ui/shimmer-worker.js +126 -0
  732. package/dist/ui/shimmer-worker.js.map +1 -0
  733. package/dist/ui/types.d.ts +15 -0
  734. package/dist/ui/types.d.ts.map +1 -0
  735. package/dist/ui/types.js +3 -0
  736. package/dist/ui/types.js.map +1 -0
  737. package/dist/upgrade/index.d.ts +171 -0
  738. package/dist/upgrade/index.d.ts.map +1 -0
  739. package/dist/upgrade/index.js +659 -0
  740. package/dist/upgrade/index.js.map +1 -0
  741. package/dist/upgrade/remove-binary.d.ts +87 -0
  742. package/dist/upgrade/remove-binary.d.ts.map +1 -0
  743. package/dist/upgrade/remove-binary.js +289 -0
  744. package/dist/upgrade/remove-binary.js.map +1 -0
  745. package/dist/upgrade/update-check.d.ts +92 -0
  746. package/dist/upgrade/update-check.d.ts.map +1 -0
  747. package/dist/upgrade/update-check.js +258 -0
  748. package/dist/upgrade/update-check.js.map +1 -0
  749. package/dist/utils.d.ts +224 -0
  750. package/dist/utils.d.ts.map +1 -0
  751. package/dist/utils.js +583 -0
  752. package/dist/utils.js.map +1 -0
  753. package/package.json +61 -0
  754. package/scripts/add-lang/bench.sh +60 -0
  755. package/scripts/add-lang/check-grammar.mjs +75 -0
  756. package/scripts/add-lang/dump-ast.mjs +103 -0
  757. package/scripts/add-lang/verify-extraction.mjs +70 -0
  758. package/scripts/agent-eval/ab-adoption.sh +91 -0
  759. package/scripts/agent-eval/ab-hook.sh +86 -0
  760. package/scripts/agent-eval/ab-impl.sh +78 -0
  761. package/scripts/agent-eval/ab-new-vs-baseline.sh +161 -0
  762. package/scripts/agent-eval/ab-sufficiency.sh +78 -0
  763. package/scripts/agent-eval/allocation-fixtures.json +344 -0
  764. package/scripts/agent-eval/arms-F.sh +21 -0
  765. package/scripts/agent-eval/arms-matrix.sh +37 -0
  766. package/scripts/agent-eval/audit.sh +68 -0
  767. package/scripts/agent-eval/bench-readme.sh +48 -0
  768. package/scripts/agent-eval/bench-why-repo.sh +22 -0
  769. package/scripts/agent-eval/block-read-hook.sh +19 -0
  770. package/scripts/agent-eval/compare-arms.mjs +209 -0
  771. package/scripts/agent-eval/diff-index-drift.mjs +102 -0
  772. package/scripts/agent-eval/hook-settings.json +15 -0
  773. package/scripts/agent-eval/itrun.sh +120 -0
  774. package/scripts/agent-eval/no-cli-shim.sh +96 -0
  775. package/scripts/agent-eval/offload-eval-3arm.sh +72 -0
  776. package/scripts/agent-eval/offload-eval-cost.mjs +133 -0
  777. package/scripts/agent-eval/offload-eval-effort.mjs +108 -0
  778. package/scripts/agent-eval/offload-eval-frontload-matrix.sh +25 -0
  779. package/scripts/agent-eval/offload-eval-frontload.sh +47 -0
  780. package/scripts/agent-eval/offload-eval-ground-truth.json +18 -0
  781. package/scripts/agent-eval/offload-eval-hook.mjs +84 -0
  782. package/scripts/agent-eval/offload-eval-judge.mjs +103 -0
  783. package/scripts/agent-eval/offload-eval-matrix.sh +20 -0
  784. package/scripts/agent-eval/offload-eval-metrics.mjs +94 -0
  785. package/scripts/agent-eval/offload-eval-refs1.sh +50 -0
  786. package/scripts/agent-eval/offload-eval-setup.sh +24 -0
  787. package/scripts/agent-eval/offload-eval-styles.sh +72 -0
  788. package/scripts/agent-eval/offload-eval-summarize.mjs +68 -0
  789. package/scripts/agent-eval/offload-eval.md +76 -0
  790. package/scripts/agent-eval/parse-arms.mjs +116 -0
  791. package/scripts/agent-eval/parse-bench-readme.mjs +238 -0
  792. package/scripts/agent-eval/parse-run.mjs +1401 -0
  793. package/scripts/agent-eval/parse-session.mjs +130 -0
  794. package/scripts/agent-eval/probe-allocation.mjs +335 -0
  795. package/scripts/agent-eval/probe-context.mjs +21 -0
  796. package/scripts/agent-eval/probe-decl-only.mjs +198 -0
  797. package/scripts/agent-eval/probe-explore.mjs +40 -0
  798. package/scripts/agent-eval/probe-factory-closure.mjs +147 -0
  799. package/scripts/agent-eval/probe-file-spend.mjs +195 -0
  800. package/scripts/agent-eval/probe-named-symbol.mjs +163 -0
  801. package/scripts/agent-eval/probe-node.mjs +20 -0
  802. package/scripts/agent-eval/probe-suite-envelope.mjs +124 -0
  803. package/scripts/agent-eval/probe-sweep.mjs +119 -0
  804. package/scripts/agent-eval/probe-trace.mjs +20 -0
  805. package/scripts/agent-eval/redirect-read-hook.sh +38 -0
  806. package/scripts/agent-eval/repro-concurrent-explore.mjs +119 -0
  807. package/scripts/agent-eval/repro-daemon-clients.mjs +125 -0
  808. package/scripts/agent-eval/run-agent.sh +34 -0
  809. package/scripts/agent-eval/run-all.sh +149 -0
  810. package/scripts/agent-eval/run-arms.sh +56 -0
  811. package/scripts/agent-eval/seq-matrix.mjs +137 -0
  812. package/scripts/build-bundle.sh +145 -0
  813. package/scripts/build-kernel.sh +87 -0
  814. package/scripts/dump-graph.mjs +57 -0
  815. package/scripts/extract-release-notes.mjs +130 -0
  816. package/scripts/kernel-parity.mjs +283 -0
  817. package/scripts/local-install.sh +41 -0
  818. package/scripts/npm-sdk.js +75 -0
  819. package/scripts/npm-shim.js +279 -0
  820. package/scripts/pack-npm.sh +123 -0
  821. package/scripts/prepare-release.mjs +270 -0
@@ -0,0 +1,2134 @@
1
+ "use strict";
2
+ /**
3
+ * Name Matcher
4
+ *
5
+ * Handles symbol name matching for reference resolution.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.matchByFilePath = matchByFilePath;
9
+ exports.sameLanguageFamily = sameLanguageFamily;
10
+ exports.isKnownLanguageFamily = isKnownLanguageFamily;
11
+ exports.crossesKnownFamily = crossesKnownFamily;
12
+ exports.matchFunctionRef = matchFunctionRef;
13
+ exports.matchByExactName = matchByExactName;
14
+ exports.matchByQualifiedName = matchByQualifiedName;
15
+ exports.preferCallSiteFile = preferCallSiteFile;
16
+ exports.resolveMethodOnType = resolveMethodOnType;
17
+ exports.matchCppCallChain = matchCppCallChain;
18
+ exports.matchScopedCallChain = matchScopedCallChain;
19
+ exports.matchDottedCallChain = matchDottedCallChain;
20
+ exports.normalizeInferredTypeName = normalizeInferredTypeName;
21
+ exports.clearNameMatcherMemos = clearNameMatcherMemos;
22
+ exports.localReceiverTypePatterns = localReceiverTypePatterns;
23
+ exports.matchMethodCall = matchMethodCall;
24
+ exports.matchFuzzy = matchFuzzy;
25
+ exports.dumpNameMatcherProfile = dumpNameMatcherProfile;
26
+ exports.matchReference = matchReference;
27
+ /**
28
+ * Ceiling on how many same-named definitions a FUZZY name-match strategy will
29
+ * score. A name defined more times than this is "ubiquitous" — a method/symbol
30
+ * re-declared across a vendored theme or SDK (e.g. `init`/`update`/`render` on
31
+ * every widget of a committed Metronic theme — #999). No directory-proximity or
32
+ * receiver-word-overlap score can reliably pick THE one true target among
33
+ * thousands, so the fuzzy strategies (matchByExactName's findBestMatch, and
34
+ * matchMethodCall Strategy 3) decline above the ceiling instead of emitting a
35
+ * low-confidence, almost-certainly-wrong edge. This also caps their per-ref cost
36
+ * at O(ceiling): without it, K same-named refs each scored K candidates — the
37
+ * O(K²) blow-up that pinned a core for 15-28 min at "Resolving refs … 94%" on a
38
+ * repo vendoring a large JS/TS theme (#999). The PRECISE strategies are
39
+ * unaffected: qualified-name, import-based, and class-name (Strategy 1/2)
40
+ * resolution all still run and resolve a ubiquitous name when the context names
41
+ * its exact target. Real repos top out near ~40 same-named methods, so a normal
42
+ * codebase never reaches this; only bulk-vendored code does. Tune via
43
+ * `CODEGRAPH_AMBIGUOUS_NAME_CEILING`.
44
+ */
45
+ const DEFAULT_AMBIGUOUS_NAME_CEILING = 500;
46
+ function resolveAmbiguousNameCeiling() {
47
+ const raw = process.env.CODEGRAPH_AMBIGUOUS_NAME_CEILING;
48
+ if (!raw)
49
+ return DEFAULT_AMBIGUOUS_NAME_CEILING;
50
+ const parsed = Number.parseInt(raw, 10);
51
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_AMBIGUOUS_NAME_CEILING;
52
+ }
53
+ const AMBIGUOUS_NAME_CEILING = resolveAmbiguousNameCeiling();
54
+ /**
55
+ * Try to resolve a path-like reference (e.g., "snippets/drawer-menu.liquid")
56
+ * by matching the filename against file nodes.
57
+ */
58
+ function matchByFilePath(ref, context) {
59
+ // Path-like (`a/b.liquid`) OR a bare filename ending in a short extension
60
+ // (`Foo.h` — an Objective-C `#import "Foo.h"`, resolved to the header by
61
+ // basename). A bare ref WITHOUT an extension is a symbol name, not a file, so
62
+ // leave it to the symbol-matching strategies.
63
+ if (!ref.referenceName.includes('/') && !/\.[A-Za-z][A-Za-z0-9]{0,3}$/.test(ref.referenceName)) {
64
+ return null;
65
+ }
66
+ // Extract the filename from the path
67
+ const fileName = ref.referenceName.split('/').pop();
68
+ if (!fileName)
69
+ return null;
70
+ // Search for file nodes with this name
71
+ const candidates = context.getNodesByName(fileName);
72
+ const fileNodes = candidates.filter(n => n.kind === 'file');
73
+ if (fileNodes.length === 0)
74
+ return null;
75
+ // Prefer exact path match on qualified_name
76
+ const exactMatch = fileNodes.find(n => n.qualifiedName === ref.referenceName || n.filePath === ref.referenceName);
77
+ if (exactMatch) {
78
+ return {
79
+ original: ref,
80
+ targetNodeId: exactMatch.id,
81
+ confidence: 0.95,
82
+ resolvedBy: 'file-path',
83
+ };
84
+ }
85
+ // Fall back to suffix match (e.g., ref="snippets/foo.liquid" matches
86
+ // "src/snippets/foo.liquid"). When several files share the basename — a
87
+ // `#include "RNCAsyncStorage.h"` with a same-named header on another platform
88
+ // (windows/code/ vs apple/) — prefer the one in the includer's own directory,
89
+ // then by directory proximity / same language family. A C/C++ include (and any
90
+ // bare-filename import) resolves relative to the including file, not to an
91
+ // arbitrary same-named header elsewhere in the tree.
92
+ const suffixMatches = fileNodes.filter(n => n.qualifiedName.endsWith(ref.referenceName) || n.filePath.endsWith(ref.referenceName));
93
+ if (suffixMatches.length > 0) {
94
+ return {
95
+ original: ref,
96
+ targetNodeId: pickClosestFileNode(suffixMatches, ref).id,
97
+ confidence: 0.85,
98
+ resolvedBy: 'file-path',
99
+ };
100
+ }
101
+ // If only one file node with this name, use it with lower confidence
102
+ if (fileNodes.length === 1) {
103
+ return {
104
+ original: ref,
105
+ targetNodeId: fileNodes[0].id,
106
+ confidence: 0.7,
107
+ resolvedBy: 'file-path',
108
+ };
109
+ }
110
+ return null;
111
+ }
112
+ /**
113
+ * Among several file nodes that all match a bare include/import by basename,
114
+ * pick the one closest to the referencing file: same directory first, then by
115
+ * directory-tree proximity, with the same language family as a tiebreak. A
116
+ * C/C++ `#include "X.h"` (and any bare-filename import) resolves relative to the
117
+ * including file — not to an arbitrary same-named header on another platform.
118
+ */
119
+ function pickClosestFileNode(candidates, ref) {
120
+ const dirOf = (p) => {
121
+ const i = p.lastIndexOf('/');
122
+ return i >= 0 ? p.slice(0, i) : '';
123
+ };
124
+ const refDir = dirOf(ref.filePath);
125
+ const sameDir = candidates.filter((c) => dirOf(c.filePath) === refDir);
126
+ const pool = sameDir.length > 0 ? sameDir : candidates;
127
+ let best = pool[0];
128
+ let bestScore = -Infinity;
129
+ for (const c of pool) {
130
+ const score = computePathProximity(ref.filePath, c.filePath) +
131
+ (sameLanguageFamily(c.language, ref.language) ? 5 : 0);
132
+ if (score > bestScore) {
133
+ bestScore = score;
134
+ best = c;
135
+ }
136
+ }
137
+ return best;
138
+ }
139
+ /**
140
+ * Language families that share a type system / runtime, so a same-language-only
141
+ * reference may still resolve across them (a Kotlin `Foo.BAR` can name a Java
142
+ * `Foo`). Anything not listed forms its own singleton family.
143
+ */
144
+ const LANGUAGE_FAMILY = {
145
+ java: 'jvm', kotlin: 'jvm', scala: 'jvm',
146
+ swift: 'apple', objc: 'apple',
147
+ // ArkTS is a TS superset — every HarmonyOS project mixes `.ets` UI with
148
+ // `.ts` logic modules, so refs must cross freely between them.
149
+ typescript: 'web', tsx: 'web', javascript: 'web', jsx: 'web', arkts: 'web',
150
+ c: 'c', cpp: 'c',
151
+ // Razor/Blazor markup names C# types — same family so `@model Foo` /
152
+ // `<MyComponent/>` resolve to their `.cs` class through the cross-family gate.
153
+ csharp: 'dotnet', razor: 'dotnet',
154
+ };
155
+ function sameLanguageFamily(a, b) {
156
+ if (a === b)
157
+ return true;
158
+ const fa = LANGUAGE_FAMILY[a];
159
+ return fa !== undefined && fa === LANGUAGE_FAMILY[b];
160
+ }
161
+ /**
162
+ * True when `lang` belongs to a known multi-language family (jvm/apple/web/c).
163
+ * Languages not listed (php, python, go, ruby, rust, dart, …) and config
164
+ * formats (yaml/xml/blade) form their own singleton families and return
165
+ * `false` — used to leave config↔code framework bridges (whose config side is
166
+ * never a known programming-language family) out of the cross-family gate.
167
+ */
168
+ function isKnownLanguageFamily(lang) {
169
+ return LANGUAGE_FAMILY[lang] !== undefined;
170
+ }
171
+ /**
172
+ * True when `a` and `b` are two DIFFERENT *known* language families — the
173
+ * signature of a coincidental cross-language name collision (a TS `import
174
+ * React` matching a Swift `import React`, a C++ `#include "X.h"` matching a
175
+ * same-named ObjC header on another platform). The both-*known* test is
176
+ * deliberately weaker than {@link sameLanguageFamily}'s negation: a
177
+ * single-file-component language that carries its own tag (`vue`/`svelte`)
178
+ * importing a `.ts` module, or any singleton-family language (php/go/ruby/…),
179
+ * returns `false` here and is left alone.
180
+ */
181
+ function crossesKnownFamily(a, b) {
182
+ return isKnownLanguageFamily(a) && isKnownLanguageFamily(b) && !sameLanguageFamily(a, b);
183
+ }
184
+ /**
185
+ * Drop cross-language candidates from a name lookup. Two regimes:
186
+ * - `references` (type-usage): a type named in language X resolves to a
187
+ * SAME-family type, never a coincidentally same-named symbol in another
188
+ * language (the Android `BatteryManager` system class vs a JS one). Strict
189
+ * same-family filter — cross-language communication is `calls`, not refs.
190
+ * - `imports` (import binding): an `import`/`#include` never crosses two
191
+ * KNOWN families (TS `import React` ↮ Swift `import React`). Weaker
192
+ * both-known filter so `.vue`/`.svelte` (own tag) importing `.ts` survives.
193
+ */
194
+ function applyLanguageGate(candidates, ref) {
195
+ if (ref.referenceKind === 'references' || ref.referenceKind === 'function_ref') {
196
+ return candidates.filter((c) => sameLanguageFamily(c.language, ref.language));
197
+ }
198
+ if (ref.referenceKind === 'imports') {
199
+ return candidates.filter((c) => !crossesKnownFamily(c.language, ref.language));
200
+ }
201
+ return candidates;
202
+ }
203
+ /**
204
+ * Resolve a function-as-value reference (#756) — a function name used as a
205
+ * callback/function-pointer value (`register(handler)`, `o->cb = handler`,
206
+ * `{ .cb = handler }`, `signal(SIGINT, handler)`). The ONLY strategy allowed
207
+ * for `function_ref` refs: exact name, function/method targets only, same
208
+ * language family, same-file first, and cross-file only when the match is
209
+ * UNIQUE. No fuzzy fallback, no qualified-name walking — a wrong callback
210
+ * edge is worse than none.
211
+ */
212
+ function matchFunctionRef(ref, context) {
213
+ // `this.<member>` refs are resolved ONLY by the class-scoped resolver in
214
+ // resolveOne (resolveThisMemberFnRef) — never by name matching here.
215
+ if (ref.referenceName.startsWith('this.'))
216
+ return null;
217
+ // In JS/TS/Python a bare identifier can never be a method value (methods
218
+ // are only reachable through a receiver — `this.m` / `self.m` /
219
+ // `Cls.m`), so bare fn-refs match FUNCTIONS only. This also sidesteps the
220
+ // pre-existing TS quirk of class fields extracting as method-kind nodes,
221
+ // which otherwise soaked up local names passed as arguments (excalidraw
222
+ // A/B finding; same pattern in vendored docopt.py). Python's `self.m`
223
+ // form keeps method targets via its own capture shape. C++ likewise: a
224
+ // bare identifier can only be a FREE function (member values need
225
+ // `&Cls::method`). PHP string callables name global FUNCTIONS (methods
226
+ // need the `[$obj, 'm']` array form, which carries its own shape). Other
227
+ // languages keep method targets: C# method groups, Swift/Dart
228
+ // implicit-self, Java/Kotlin method references.
229
+ const bareFnOnly = ref.language === 'typescript' || ref.language === 'tsx' ||
230
+ ref.language === 'javascript' || ref.language === 'jsx' ||
231
+ ref.language === 'arkts' ||
232
+ ref.language === 'cpp' || ref.language === 'python' ||
233
+ ref.language === 'php';
234
+ // Python additionally accepts CLASS targets for bare identifiers (#1478):
235
+ // class-as-value is a core Python idiom (`return SomeSerializer`,
236
+ // `Meta.model = Org`, registry dicts, `admin.site.register(Model, Admin)`)
237
+ // and, unlike TS, Python has no type-annotation recovery path. The
238
+ // false-positive mechanism behind the function-only rule was lowercase
239
+ // locals colliding with same-named METHODS (docopt.py) — a candidate must
240
+ // be an exact-name CLASS node here, and the extraction gate (same-file
241
+ // class ∪ imports) plus unique-or-drop still apply. Methods stay excluded.
242
+ const bareClassOk = ref.language === 'python';
243
+ // Qualified member-pointer (`&Widget::on_click` → "Widget::on_click"):
244
+ // resolve the member ON THAT SCOPE — exempt from bareFnOnly (the `&Cls::m`
245
+ // shape is an explicit member reference). Unique-or-drop like everything else.
246
+ if (ref.referenceName.includes('::')) {
247
+ const memberName = ref.referenceName.slice(ref.referenceName.lastIndexOf('::') + 2);
248
+ const scoped = context
249
+ .getNodesByName(memberName)
250
+ .filter((n) => (n.kind === 'function' || n.kind === 'method') &&
251
+ sameLanguageFamily(n.language, ref.language) &&
252
+ n.id !== ref.fromNodeId &&
253
+ (n.qualifiedName === ref.referenceName ||
254
+ n.qualifiedName.endsWith(`::${ref.referenceName}`)));
255
+ if (scoped.length === 0)
256
+ return null;
257
+ const sameFileScoped = scoped.filter((n) => n.filePath === ref.filePath);
258
+ const pool = sameFileScoped.length > 0 ? sameFileScoped : scoped;
259
+ if (sameFileScoped.length === 0 && scoped.length > 1)
260
+ return null;
261
+ const target = pool.reduce((a, b) => (a.startLine <= b.startLine ? a : b));
262
+ return {
263
+ original: ref,
264
+ targetNodeId: target.id,
265
+ confidence: 0.9,
266
+ resolvedBy: 'function-ref',
267
+ };
268
+ }
269
+ let candidates = context
270
+ .getNodesByName(ref.referenceName)
271
+ .filter((n) => (n.kind === 'function' ||
272
+ (!bareFnOnly && n.kind === 'method') ||
273
+ (bareClassOk && n.kind === 'class')) &&
274
+ sameLanguageFamily(n.language, ref.language) &&
275
+ n.id !== ref.fromNodeId // a function registering itself is not a dependency edge
276
+ );
277
+ if (candidates.length === 0)
278
+ return null;
279
+ // Swift implicit-self: a bare identifier can name a METHOD only of the
280
+ // ENCLOSING type (`Button(action: handleTap)` written inside that type) —
281
+ // a same-named method on any OTHER class is a parameter collision
282
+ // (Alamofire: a `request` parameter resolving to EventMonitor::request).
283
+ // Scope method candidates to the from-symbol's type; top-level code has no
284
+ // implicit self, so method targets are excluded there entirely. Free
285
+ // functions are unaffected.
286
+ if (ref.language === 'swift' && candidates.some((n) => n.kind === 'method')) {
287
+ const fromNode = context.getNodeById?.(ref.fromNodeId);
288
+ const sep = fromNode ? fromNode.qualifiedName.lastIndexOf('::') : -1;
289
+ const classPrefix = fromNode && sep > 0 ? fromNode.qualifiedName.slice(0, sep) : null;
290
+ candidates = candidates.filter((n) => {
291
+ if (n.kind !== 'method')
292
+ return true;
293
+ if (!classPrefix)
294
+ return false;
295
+ const mSep = n.qualifiedName.lastIndexOf('::');
296
+ if (mSep <= 0)
297
+ return false;
298
+ const methodPrefix = n.qualifiedName.slice(0, mSep);
299
+ // Accept exact-scope matches plus suffix relationships either way, so
300
+ // extension-declared members (`Holder::m`) still match a nested
301
+ // from-scope (`Module::Holder::wire`) and vice versa.
302
+ return (methodPrefix === classPrefix ||
303
+ methodPrefix.endsWith(`::${classPrefix}`) ||
304
+ classPrefix.endsWith(`::${methodPrefix}`));
305
+ });
306
+ if (candidates.length === 0)
307
+ return null;
308
+ }
309
+ // Same-file definition wins — the extraction gate guarantees most survivors
310
+ // have one, and it's the dominant C pattern (static callback registered in
311
+ // a same-file ops struct).
312
+ const sameFile = candidates.filter((n) => n.filePath === ref.filePath);
313
+ if (sameFile.length > 0) {
314
+ // Swift: several same-named METHODS in one file is an API overload family
315
+ // (`Session.request(...)` × N), and a bare identifier hitting it is almost
316
+ // always a same-named parameter, not a method value (Alamofire A/B
317
+ // finding) — refuse rather than guess. A single method (SwiftUI's
318
+ // `action: handleTap`) still resolves.
319
+ if (ref.language === 'swift' &&
320
+ sameFile.length > 1 &&
321
+ sameFile.every((n) => n.kind === 'method')) {
322
+ return null;
323
+ }
324
+ // Same-name overloads in one file are the same conceptual symbol; pick
325
+ // the first by position for determinism.
326
+ const target = sameFile.reduce((a, b) => (a.startLine <= b.startLine ? a : b));
327
+ return {
328
+ original: ref,
329
+ targetNodeId: target.id,
330
+ confidence: sameFile.length === 1 ? 0.95 : 0.9,
331
+ resolvedBy: 'function-ref',
332
+ };
333
+ }
334
+ // Cross-file (imported names the import resolver didn't already claim):
335
+ // only an unambiguous match resolves.
336
+ if (candidates.length === 1) {
337
+ return {
338
+ original: ref,
339
+ targetNodeId: candidates[0].id,
340
+ confidence: 0.8,
341
+ resolvedBy: 'function-ref',
342
+ };
343
+ }
344
+ return null;
345
+ }
346
+ /**
347
+ * A function nested inside another FUNCTION is only callable from within its
348
+ * container — Python, JS/TS, and every closure language scope it lexically.
349
+ * Resolving a bare name from elsewhere to a nested local fabricates an edge
350
+ * scope already rules out: `join(...)` in one function must never bind to a
351
+ * `join` defined inside a DIFFERENT function (#1230). A candidate whose
352
+ * qualifiedName parent is a same-file function/method is kept only when the
353
+ * ref originates inside that parent's line range. Class members are
354
+ * unaffected (their parent resolves to a class-like node), as are top-level
355
+ * symbols and C++ namespace-prefixed names (the prefix has no node).
356
+ */
357
+ function isLexicallyReachable(candidate, ref, context) {
358
+ if (candidate.kind !== 'function')
359
+ return true;
360
+ const qn = candidate.qualifiedName;
361
+ if (!qn || !qn.includes('::'))
362
+ return true;
363
+ const parentQn = qn.slice(0, qn.lastIndexOf('::'));
364
+ const containers = context
365
+ .getNodesByQualifiedName(parentQn)
366
+ .filter((p) => p.filePath === candidate.filePath &&
367
+ (p.kind === 'function' || p.kind === 'method') &&
368
+ p.startLine <= candidate.startLine &&
369
+ p.endLine >= candidate.endLine);
370
+ if (containers.length === 0)
371
+ return true;
372
+ return (ref.filePath === candidate.filePath &&
373
+ containers.some((p) => ref.line >= p.startLine && ref.line <= p.endLine));
374
+ }
375
+ /**
376
+ * Try to resolve a reference by exact name match
377
+ */
378
+ function matchByExactName(ref, context) {
379
+ // `import`-kind nodes are import STATEMENTS, not definitions, so a reference
380
+ // resolving to a sibling file's `import` is a meaningless edge — the real
381
+ // import→definition resolution is the import resolver's job (resolveViaImport),
382
+ // never name-matching here. Excluding them also removes a quadratic blow-up:
383
+ // a ubiquitous package (`react`, `@superset-ui/core`, Python `logging`/`typing`)
384
+ // is re-declared as an `import` node in every file that imports it, so K
385
+ // unresolved import refs each scored K same-named import candidates through
386
+ // findBestMatch — O(K²) per package, the dominant cost of "Resolving refs" on
387
+ // large import-heavy (front-end + back-end) repos (#915).
388
+ const candidates = applyLanguageGate(context.getNodesByName(ref.referenceName), ref)
389
+ .filter((n) => n.kind !== 'import')
390
+ // Nested locals are only reachable from inside their container (#1230).
391
+ .filter((n) => isLexicallyReachable(n, ref, context));
392
+ if (candidates.length === 0) {
393
+ return null;
394
+ }
395
+ // If only one match, use it — but penalize cross-language matches
396
+ if (candidates.length === 1) {
397
+ const isCrossLanguage = candidates[0].language !== ref.language;
398
+ return {
399
+ original: ref,
400
+ targetNodeId: candidates[0].id,
401
+ confidence: isCrossLanguage ? 0.5 : 0.9,
402
+ resolvedBy: 'exact-match',
403
+ };
404
+ }
405
+ // Ubiquitous-name ceiling (#999): above it, picking one target among K
406
+ // same-named defs by directory proximity is unreliable AND O(K) per ref — the
407
+ // quadratic behind the "Resolving refs" wedge on theme/SDK-vendoring repos.
408
+ // Decline; the precise strategies (qualified-name, import, class-name) already
409
+ // ran. Falls through to fuzzy, which itself only resolves a UNIQUE candidate.
410
+ if (candidates.length > AMBIGUOUS_NAME_CEILING) {
411
+ return null;
412
+ }
413
+ // Multiple matches - try to narrow down
414
+ const bestMatch = findBestMatch(ref, candidates, context);
415
+ if (bestMatch) {
416
+ // Lower confidence when the match is from a distant/unrelated module
417
+ const proximity = computePathProximity(ref.filePath, bestMatch.filePath);
418
+ const confidence = proximity >= 30 ? 0.7 : 0.4;
419
+ return {
420
+ original: ref,
421
+ targetNodeId: bestMatch.id,
422
+ confidence,
423
+ resolvedBy: 'exact-match',
424
+ };
425
+ }
426
+ return null;
427
+ }
428
+ /**
429
+ * Try to resolve by qualified name
430
+ */
431
+ function matchByQualifiedName(ref, context) {
432
+ // Check if the reference name looks qualified (contains :: or .)
433
+ if (!ref.referenceName.includes('::') && !ref.referenceName.includes('.')) {
434
+ return null;
435
+ }
436
+ // A method call `receiver.method()` can share an exact qualified name with a
437
+ // config-file key: `service.process()` (a `calls` ref named `service.process`)
438
+ // vs the yaml key `service.process`. Config keys are bound to their code refs
439
+ // upstream by the framework resolvers (`@Value` → `references`); a `calls` ref
440
+ // must never resolve to a yaml/properties config node — that's a wrong edge
441
+ // AND it hides the real callee. Drop those from both the exact and the partial
442
+ // candidate sets so resolution falls through to method resolution below (#1180).
443
+ const keepForRef = (nodes) => ref.referenceKind === 'calls'
444
+ ? nodes.filter((n) => !(n.kind === 'constant' && (n.language === 'yaml' || n.language === 'properties')))
445
+ : nodes;
446
+ const candidates = keepForRef(context.getNodesByQualifiedName(ref.referenceName));
447
+ if (candidates.length === 1) {
448
+ return {
449
+ original: ref,
450
+ targetNodeId: candidates[0].id,
451
+ confidence: 0.95,
452
+ resolvedBy: 'qualified-name',
453
+ };
454
+ }
455
+ // Several symbols share this exact qualified name (e.g. `Logger::log` declared
456
+ // in two files — an ODR clash or separate translation units): prefer the one
457
+ // in the call site's own file before the partial-match fallback below, else
458
+ // the first-indexed def wins and a call in `b/svc` targets `a/svc` (#1079).
459
+ if (candidates.length > 1) {
460
+ const ordered = preferCallSiteFile(candidates, ref.filePath);
461
+ if (ordered[0].filePath === ref.filePath) {
462
+ return {
463
+ original: ref,
464
+ targetNodeId: ordered[0].id,
465
+ confidence: 0.95,
466
+ resolvedBy: 'qualified-name',
467
+ };
468
+ }
469
+ }
470
+ // Try partial qualified name match — again preferring the call site's own
471
+ // file when more than one symbol's qualifiedName ends with the reference.
472
+ const parts = ref.referenceName.split(/[:.]/);
473
+ const lastName = parts[parts.length - 1];
474
+ if (lastName) {
475
+ const partialCandidates = keepForRef(context.getNodesByName(lastName))
476
+ .filter((candidate) => candidate.qualifiedName.endsWith(ref.referenceName));
477
+ const chosen = preferCallSiteFile(partialCandidates, ref.filePath)[0];
478
+ if (chosen) {
479
+ return {
480
+ original: ref,
481
+ targetNodeId: chosen.id,
482
+ confidence: 0.85,
483
+ resolvedBy: 'qualified-name',
484
+ };
485
+ }
486
+ }
487
+ return null;
488
+ }
489
+ /**
490
+ * When a symbol name is ambiguous across files, prefer the candidate(s) declared
491
+ * in the call site's own file, keeping the rest in their original order (#1079).
492
+ * A same-file definition is the strongest language-agnostic signal for which of
493
+ * several same-named symbols a call means; without it, resolution collapses onto
494
+ * whichever was indexed first, so a call in `b/svc` wrongly targets `a/svc`.
495
+ * No-op when there are <2 candidates or none share the call site's file.
496
+ */
497
+ function preferCallSiteFile(nodes, callSiteFile) {
498
+ if (nodes.length < 2)
499
+ return nodes;
500
+ const same = [];
501
+ const other = [];
502
+ for (const n of nodes) {
503
+ if (n.filePath === callSiteFile)
504
+ same.push(n);
505
+ else
506
+ other.push(n);
507
+ }
508
+ return same.length ? [...same, ...other] : nodes;
509
+ }
510
+ // Exported for the precedence unit tests (#1079): they assert the
511
+ // preferredFqn → same-file → matches[0] ordering directly.
512
+ function resolveMethodOnType(typeName, methodName, ref, context, confidence, resolvedBy,
513
+ /**
514
+ * Optional FQN that identifies WHICH class declaration `typeName`
515
+ * refers to in the caller's file. When multiple candidates share
516
+ * the same qualifiedName (`FooConverter::convert` in both
517
+ * `dao/converter/` and `service/converter/`), the FQN's
518
+ * file-path-suffix picks the right one — the disambiguation
519
+ * signal Java imports carry but the call site doesn't (#314).
520
+ */
521
+ preferredFqn,
522
+ /** Recursion guard for the supertype/conformance walk. */
523
+ depth = 0) {
524
+ // Look up methods by name and match by qualifiedName ending in
525
+ // `<typeName>::<methodName>`. This works whether the method is defined
526
+ // in-class (`class Foo { int bar() { ... } }`) or out-of-line in a separate
527
+ // file (`int Foo::bar() { ... }` in foo.cpp while class Foo is in foo.hpp).
528
+ // The previous same-file approach missed the latter — the typical C++ layout.
529
+ // Prefer the context's per-(type, method) memo: the raw name lookup fetches
530
+ // EVERY node sharing the method name — tens of thousands of rows for a
531
+ // collision-heavy Java name like `execute` — and re-filtering that per ref
532
+ // was a dominant term in the #1122 watchdog kill on large repos. Only the
533
+ // ref-independent filter is memoized; per-ref disambiguation stays below.
534
+ let matches;
535
+ if (context.getMethodMatches) {
536
+ matches = context.getMethodMatches(typeName, methodName, ref.language);
537
+ }
538
+ else {
539
+ const methodCandidates = context.getNodesByName(methodName);
540
+ const want = `${typeName}::${methodName}`;
541
+ matches = [];
542
+ for (const m of methodCandidates) {
543
+ if (m.kind !== 'method')
544
+ continue;
545
+ if (m.language !== ref.language)
546
+ continue;
547
+ const qn = m.qualifiedName;
548
+ if (qn === want || qn.endsWith(`::${want}`)) {
549
+ matches.push(m);
550
+ }
551
+ }
552
+ }
553
+ if (matches.length === 0) {
554
+ // Conformance fallback: the method may be defined on a supertype `typeName`
555
+ // extends, or on a protocol / trait it conforms to (e.g. a Swift protocol-
556
+ // extension method, a C# default-interface or extension method, a Kotlin
557
+ // extension on a supertype). Walk supertypes transitively (depth-capped) via
558
+ // the resolved implements/extends edges — empty in the first resolution pass,
559
+ // populated in the conformance pass. Still VALIDATED (the method must exist on
560
+ // a supertype), so a wrong inference produces no edge.
561
+ if (depth < 4 && context.getSupertypes) {
562
+ const viaSupers = nmTimedT('rmot-supers', ref, () => {
563
+ for (const supertype of context.getSupertypes(typeName, ref.language)) {
564
+ const via = resolveMethodOnType(supertype, methodName, ref, context, confidence, resolvedBy, preferredFqn, depth + 1);
565
+ if (via)
566
+ return via;
567
+ }
568
+ return null;
569
+ });
570
+ if (viaSupers)
571
+ return viaSupers;
572
+ }
573
+ return null;
574
+ }
575
+ if (matches.length > 1 && preferredFqn) {
576
+ const ext = ref.language === 'kotlin' ? '.kt' : '.java';
577
+ const fqnPath = preferredFqn.replace(/\./g, '/') + ext;
578
+ const chosen = matches.find((m) => {
579
+ const fp = m.filePath.replace(/\\/g, '/');
580
+ return fp.endsWith(fqnPath) || fp.endsWith('/' + fqnPath);
581
+ });
582
+ if (chosen) {
583
+ return {
584
+ original: ref,
585
+ targetNodeId: chosen.id,
586
+ confidence,
587
+ resolvedBy,
588
+ };
589
+ }
590
+ }
591
+ // Language-agnostic disambiguation: when several same-named methods survive
592
+ // (e.g. two files each declaring `class Logger { void log(); }` — an ODR
593
+ // clash, an anonymous-namespace type, or separate translation units), prefer
594
+ // the definition in the CALL SITE's own file. Without this, every ambiguous
595
+ // call collapses onto the first-indexed definition, so a call in `b/svc.cpp`
596
+ // wrongly points at `a/svc.cpp` (#1079). This runs AFTER the `preferredFqn`
597
+ // block, so Java/Kotlin import disambiguation — whose target is intentionally
598
+ // in ANOTHER file (#314) — is unaffected: that block returns early whenever
599
+ // an import FQN pins the class.
600
+ const ordered = preferCallSiteFile(matches, ref.filePath);
601
+ return {
602
+ original: ref,
603
+ targetNodeId: ordered[0].id,
604
+ confidence,
605
+ resolvedBy,
606
+ };
607
+ }
608
+ // C++ keywords/control-flow tokens that can appear right before a receiver
609
+ // (e.g. `return ptr->m()`) and must NOT be treated as a type.
610
+ const CPP_NON_TYPE_TOKENS = new Set([
611
+ 'return', 'if', 'else', 'for', 'while', 'do', 'switch', 'case', 'default',
612
+ 'break', 'continue', 'goto', 'throw', 'new', 'delete', 'co_await', 'co_yield',
613
+ 'co_return', 'static_cast', 'const_cast', 'dynamic_cast', 'reinterpret_cast',
614
+ 'sizeof', 'alignof', 'typeid', 'and', 'or', 'not', 'xor',
615
+ ]);
616
+ function normalizeCppTypeName(typeName) {
617
+ const normalized = typeName
618
+ .replace(/\b(const|volatile|mutable|typename|class|struct)\b/g, ' ')
619
+ .replace(/[&*]+/g, ' ')
620
+ .replace(/<[^>]*>/g, ' ')
621
+ .replace(/\s+/g, ' ')
622
+ .trim();
623
+ if (!normalized)
624
+ return null;
625
+ const parts = normalized.split(/::/).filter(Boolean);
626
+ const last = parts[parts.length - 1];
627
+ if (!last)
628
+ return null;
629
+ if (CPP_NON_TYPE_TOKENS.has(last))
630
+ return null;
631
+ return last;
632
+ }
633
+ // Declarator regex: matches `Type receiver`, `Type* receiver`, `Type *receiver`,
634
+ // `Type*receiver`, `Type<X> receiver`, etc., REQUIRING a declarator terminator
635
+ // (`;`, `=`, `,`, `)`, `[`, `{`, `(`, or end-of-line) after the receiver. The
636
+ // terminator rules out uses like `return receiver->m()` where the preceding
637
+ // token is a keyword, not a type.
638
+ function buildDeclaratorRegex(escapedReceiver) {
639
+ return new RegExp(`([A-Za-z_][\\w:]*(?:\\s*<[^;=(){}]+>)?(?:\\s*[*&]+)?)\\s*\\b${escapedReceiver}\\b\\s*(?=[;=,)\\[{(]|$)`);
640
+ }
641
+ function inferCppReceiverType(receiverName, ref, context, depth = 0) {
642
+ // Per-file lines cache when available — this runs per `receiver->method()`
643
+ // ref and re-splitting the file each time is the same quadratic as the
644
+ // shared inferrer's (#1122).
645
+ const lines = context.getFileLines
646
+ ? context.getFileLines(ref.filePath)
647
+ : (context.readFile(ref.filePath)?.split(/\r?\n/) ?? null);
648
+ if (!lines || lines.length === 0)
649
+ return null;
650
+ const callLineIndex = Math.max(0, Math.min(lines.length - 1, ref.line - 1));
651
+ const escapedReceiver = receiverName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
652
+ const receiverPattern = new RegExp(`\\b${escapedReceiver}\\b`);
653
+ const declaratorRegex = buildDeclaratorRegex(escapedReceiver);
654
+ for (let i = callLineIndex; i >= 0; i--) {
655
+ const line = lines[i];
656
+ if (!line || !receiverPattern.test(line))
657
+ continue;
658
+ const declaratorMatch = line.match(declaratorRegex);
659
+ if (declaratorMatch) {
660
+ const normalized = normalizeCppTypeName(declaratorMatch[1] ?? '');
661
+ if (normalized === 'auto') {
662
+ // `auto x = Foo::instance();` — the declared type is deduced; recover it
663
+ // from the initializer (call return type / construction) (#645).
664
+ const initType = inferCppAutoInitializerType(line, receiverName, ref, context, depth);
665
+ if (initType)
666
+ return initType;
667
+ // No usable initializer on this line — keep scanning earlier ones.
668
+ }
669
+ else if (normalized) {
670
+ return normalized;
671
+ }
672
+ }
673
+ }
674
+ const headerCandidates = [
675
+ ref.filePath.replace(/\.(?:c|cc|cpp|cxx)$/i, '.h'),
676
+ ref.filePath.replace(/\.(?:c|cc|cpp|cxx)$/i, '.hpp'),
677
+ ref.filePath.replace(/\.(?:c|cc|cpp|cxx)$/i, '.hxx'),
678
+ ].filter((candidate, index, arr) => arr.indexOf(candidate) === index && candidate !== ref.filePath);
679
+ for (const headerPath of headerCandidates) {
680
+ if (!context.fileExists(headerPath))
681
+ continue;
682
+ const headerLines = context.getFileLines
683
+ ? context.getFileLines(headerPath)
684
+ : (context.readFile(headerPath)?.split(/\r?\n/) ?? null);
685
+ if (!headerLines)
686
+ continue;
687
+ for (const line of headerLines) {
688
+ if (!receiverPattern.test(line))
689
+ continue;
690
+ const declaratorMatch = line.match(declaratorRegex);
691
+ if (!declaratorMatch)
692
+ continue;
693
+ const normalized = normalizeCppTypeName(declaratorMatch[1] ?? '');
694
+ if (normalized && normalized !== 'auto')
695
+ return normalized;
696
+ }
697
+ }
698
+ return null;
699
+ }
700
+ /**
701
+ * Last `::`-separated segment of a (possibly namespace-qualified) C++ name.
702
+ */
703
+ function cppLastSegment(name) {
704
+ const parts = name.split('::').filter(Boolean);
705
+ return parts[parts.length - 1] ?? name;
706
+ }
707
+ /**
708
+ * Return type captured at extraction for `Class::method` (or a free function),
709
+ * read off the indexed node's `returnType` — used by the C++ (#645) and PHP
710
+ * (#608) chained-call resolvers. Language-filtered. Null when not indexed or no
711
+ * return type was recorded (a `void`/primitive return).
712
+ */
713
+ function lookupCalleeReturnType(callee, ref, context) {
714
+ let method = callee;
715
+ let cls = null;
716
+ if (callee.includes('::')) {
717
+ const parts = callee.split('::').filter(Boolean);
718
+ method = parts[parts.length - 1] ?? callee;
719
+ cls = parts.slice(0, -1).join('::');
720
+ }
721
+ const candidates = context.getNodesByName(method).filter((n) => (n.kind === 'method' || n.kind === 'function') &&
722
+ n.language === ref.language &&
723
+ !!n.returnType);
724
+ if (cls) {
725
+ const want = `${cls}::${method}`;
726
+ // The call site may name the class with MORE namespace qualification than
727
+ // the stored node (`details::registry::instance` at the call vs
728
+ // `registry::instance` on the node — the receiver type only carries the
729
+ // immediate class), or LESS. Accept an exact match or either being a
730
+ // namespace-suffix of the other; the shared `::<class>::<method>` tail keeps
731
+ // it specific.
732
+ const m = candidates.find((n) => n.qualifiedName === want ||
733
+ n.qualifiedName.endsWith(`::${want}`) ||
734
+ want.endsWith(`::${n.qualifiedName}`));
735
+ return m?.returnType ?? null;
736
+ }
737
+ return candidates.find((n) => n.kind === 'function')?.returnType ?? null;
738
+ }
739
+ /** Does the graph contain an aggregate type named `name`'s last segment? */
740
+ function cppClassExists(name, ref, context) {
741
+ const last = cppLastSegment(name);
742
+ return context
743
+ .getNodesByName(last)
744
+ .some((n) => (n.kind === 'class' || n.kind === 'struct' || n.kind === 'union') && n.language === ref.language);
745
+ }
746
+ /**
747
+ * Infer the class produced by a C++ call/construction expression, using return
748
+ * types captured at extraction (#645). Handles, in order:
749
+ * - `make_unique<T>()` / `make_shared<T>()` → T
750
+ * - single-level member call `recv.method()` → recv's type, then method's return
751
+ * - `Class::method()` / free `func()` → the callee's recorded return type
752
+ * - direct construction `Type()` / `ns::Type()` → Type
753
+ * Returns null when undeterminable. Callers MUST still validate the outer method
754
+ * exists on the result before creating an edge, so a wrong guess stays silent.
755
+ */
756
+ function resolveCppCallResultType(inner, ref, context, depth = 0) {
757
+ if (depth > 3)
758
+ return null; // guard against pathological mutual recursion
759
+ const expr = inner.trim();
760
+ const make = expr.match(/(?:^|::)(?:make_unique|make_shared)\s*<\s*([A-Za-z_]\w*)/);
761
+ if (make)
762
+ return make[1] ?? null;
763
+ // Single-level member call `recv.method` (the `manager.view().render()` shape).
764
+ const dotIdx = expr.lastIndexOf('.');
765
+ if (dotIdx > 0) {
766
+ const recv = expr.slice(0, dotIdx);
767
+ const method = expr.slice(dotIdx + 1);
768
+ if (recv.includes('.') || recv.includes('(') || recv.includes('::'))
769
+ return null; // single level only
770
+ const recvType = inferCppReceiverType(recv, ref, context, depth + 1);
771
+ if (!recvType)
772
+ return null;
773
+ return lookupCalleeReturnType(`${recvType}::${method}`, ref, context);
774
+ }
775
+ const ret = lookupCalleeReturnType(expr, ref, context);
776
+ if (ret)
777
+ return ret;
778
+ // Direct construction — the callee itself names a class/struct.
779
+ if (cppClassExists(expr, ref, context))
780
+ return cppLastSegment(expr);
781
+ return null;
782
+ }
783
+ /**
784
+ * Recover the type of an `auto`-declared local from its initializer on the
785
+ * declaration line — `auto x = Foo::instance();`, `auto w = make_unique<W>();`,
786
+ * `auto p = new W();`, `auto w = Widget();` (#645).
787
+ */
788
+ function inferCppAutoInitializerType(line, receiverName, ref, context, depth) {
789
+ const escaped = receiverName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
790
+ const m = line.match(new RegExp(`\\b${escaped}\\b\\s*=\\s*([^;]+)`));
791
+ if (!m || !m[1])
792
+ return null;
793
+ const init = m[1].trim();
794
+ const neu = init.match(/^new\s+([A-Za-z_][\w:]*)/);
795
+ if (neu && neu[1])
796
+ return cppLastSegment(neu[1]);
797
+ // A call or construction: `Foo(...)`, `A::b(...)`, `make_unique<T>(...)`.
798
+ const call = init.match(/^([A-Za-z_][\w:]*(?:\s*<[^>;]*>)?)\s*\(/);
799
+ if (call && call[1])
800
+ return resolveCppCallResultType(call[1].replace(/\s+/g, ''), ref, context, depth + 1);
801
+ return null;
802
+ }
803
+ /**
804
+ * Resolve a C++ chained call whose receiver is itself a call — encoded by the
805
+ * extractor as `<innerCallee>().<method>` (#645). The receiver's type is what
806
+ * the inner call returns; the outer method is then resolved and VALIDATED on it
807
+ * (resolveMethodOnType requires `cls::method` to exist), so a wrong inference
808
+ * produces no edge rather than a wrong one.
809
+ */
810
+ function matchCppCallChain(ref, context) {
811
+ const m = ref.referenceName.match(/^(.+)\(\)\.(\w+)$/);
812
+ if (!m || !m[1] || !m[2])
813
+ return null;
814
+ const cls = resolveCppCallResultType(m[1], ref, context);
815
+ if (!cls)
816
+ return null;
817
+ return resolveMethodOnType(cls, m[2], ref, context, 0.85, 'instance-method');
818
+ }
819
+ /**
820
+ * Resolve a `::`-scoped factory chain whose receiver is a scoped/static call —
821
+ * PHP `Cls::for($x)->method()` (#608, the per-credential Laravel client idiom) or
822
+ * Rust `Foo::new().bar()` (an associated-function call) — both encoded by the
823
+ * extractor as `Cls::factory().method`. The receiver's type is what `Cls::factory`
824
+ * returns: a `self` marker (PHP `: self`/`: static`, Rust `-> Self`) resolves to
825
+ * the factory's own type, a concrete return type to that type. The outer method is
826
+ * then resolved and VALIDATED on it (resolveMethodOnType requires the method to
827
+ * exist on the type or a supertype it conforms to), so a wrong inference yields no
828
+ * edge rather than a wrong one. Shared by the `::`-receiver languages (PHP, Rust).
829
+ */
830
+ function matchScopedCallChain(ref, context) {
831
+ const m = ref.referenceName.match(/^(.+)\(\)\.(\w+)$/);
832
+ if (!m || !m[1] || !m[2])
833
+ return null;
834
+ const inner = m[1];
835
+ const method = m[2];
836
+ if (!inner.includes('::'))
837
+ return null; // only static-factory (`Cls::method`) chains
838
+ const factoryClass = inner.slice(0, inner.lastIndexOf('::'));
839
+ const ret = lookupCalleeReturnType(inner, ref, context);
840
+ if (!ret)
841
+ return null;
842
+ // `self` (the extractor's marker for self/static/$this) → the factory's class.
843
+ const resolvedClass = ret === 'self' ? factoryClass : ret;
844
+ return resolveMethodOnType(resolvedClass, method, ref, context, 0.85, 'instance-method');
845
+ }
846
+ /**
847
+ * Languages where an unprefixed capitalized call `Foo(args)` constructs the
848
+ * class (so a `Foo(args).method()` receiver's type is `Foo`). Java/C# need `new`,
849
+ * so a bare `Foo()` there is a method call, not construction — excluded. Scala's
850
+ * `Foo(args)` is a case-class / companion `apply`, which conventionally returns
851
+ * `Foo` — and resolveMethodOnType validates, so a non-conventional `apply` that
852
+ * returns another type simply yields no edge rather than a wrong one. Pascal/Delphi:
853
+ * a `TFoo(x)` is a TYPECAST whose result is a `TFoo`, so `TFoo(x).method()` resolves
854
+ * the method on `TFoo` — same shape, same validation.
855
+ */
856
+ const CONSTRUCTS_VIA_BARE_CALL = new Set(['kotlin', 'swift', 'scala', 'dart', 'pascal']);
857
+ /**
858
+ * Resolve a dotted chained call whose receiver is a static factory / fluent call —
859
+ * `Foo.getInstance().bar()`, encoded by the extractor as `Foo.getInstance().bar`
860
+ * (#645/#608 mechanism). The receiver's type is what `Foo.getInstance` returns
861
+ * (its declared return type); the outer method is then resolved and VALIDATED on
862
+ * it (resolveMethodOnType requires `Type::method` to exist), so a wrong inference
863
+ * yields no edge rather than a wrong one (e.g. a same-named `bar()` on an
864
+ * unrelated class is never matched). Shared by the dot-notation languages
865
+ * (Java, Kotlin, C#, Swift) — same receiver shape, same `Class::method` qualified names.
866
+ */
867
+ function matchDottedCallChain(ref, context) {
868
+ const m = ref.referenceName.match(/^(.+)\(\)\.(\w+)$/);
869
+ if (!m || !m[1] || !m[2])
870
+ return null;
871
+ const inner = m[1]; // `Foo.getInstance`
872
+ const method = m[2]; // `bar`
873
+ const lastDot = inner.lastIndexOf('.');
874
+ if (lastDot <= 0) {
875
+ // Go: bare package-level factory FUNCTION `New().method()` — the receiver's
876
+ // type is what `New` returns; resolve the method on that.
877
+ if (ref.language === 'go') {
878
+ const ret = lookupCalleeReturnType(inner, ref, context);
879
+ if (ret) {
880
+ return resolveMethodOnType(ret, method, ref, context, 0.85, 'instance-method', importedFqnOf(ret, ref, context));
881
+ }
882
+ // `inner` isn't a function with a captured return type — typically a
883
+ // package-level VARIABLE holding a function value (e.g. gin's `engine()`),
884
+ // whose type we can't recover. Fall back to bare-name resolution of the
885
+ // method so we don't DROP an edge the un-re-encoded bare path would have
886
+ // found. (When `inner` IS a real factory function but the method doesn't
887
+ // exist on its return type, `ret` is truthy and we returned no edge above —
888
+ // the absent-method safety guarantee is preserved.)
889
+ //
890
+ // CRITICAL: resolve the TARGET via a synthetic bare-name ref, but return the
891
+ // match tied to the ORIGINAL `ref` (referenceName `inner().method`). The
892
+ // batched resolver (resolveAndPersistBatched) reads unresolved rows from
893
+ // offset 0 every pass and relies on the post-batch cleanup (row-id delete
894
+ // for DB-loaded refs, referenceName-keyed delete otherwise, #1269) to
895
+ // clear each resolved row so the batch empties. If we propagated the
896
+ // synthetic ref's bare `method` as `.original`, a key-based delete
897
+ // would never match the stored `inner().method` row, the batch would
898
+ // never drain, and the loop would re-resolve + re-insert forever (a runaway
899
+ // that grew gin's graph to 5M edges / 1.4 GB before this fix).
900
+ const bareRef = { ...ref, referenceName: method };
901
+ const bareMatch = matchByExactName(bareRef, context) ?? matchFuzzy(bareRef, context);
902
+ return bareMatch ? { ...bareMatch, original: ref } : null;
903
+ }
904
+ // Constructor receiver `Foo(args).method()` (encoded `Foo().method`): a bare,
905
+ // capitalized inner is a class construction, so the receiver's type is the
906
+ // class itself — resolve the method on it. Only in languages where an
907
+ // unprefixed capitalized call constructs the class (Kotlin, Swift); in Java/C#
908
+ // a bare `Foo()` is a method call (constructors need `new`), so we must not
909
+ // assume construction. A lowercase bare inner is a top-level `factory().method()`
910
+ // whose type we can't recover — bail.
911
+ if (!CONSTRUCTS_VIA_BARE_CALL.has(ref.language) || !/^[A-Z]/.test(inner))
912
+ return null;
913
+ return resolveMethodOnType(inner, method, ref, context, 0.85, 'instance-method', importedFqnOf(inner, ref, context));
914
+ }
915
+ // Factory/fluent receiver `Receiver.factory(args).method()`: the receiver's
916
+ // type is what `Receiver.factory` returns (its declared return type).
917
+ const factoryClass = inner.slice(0, lastDot).split('.').pop(); // simple class name
918
+ const factoryMethod = inner.slice(lastDot + 1);
919
+ if (!factoryClass || !factoryMethod)
920
+ return null;
921
+ const ret = lookupCalleeReturnType(`${factoryClass}::${factoryMethod}`, ref, context);
922
+ if (!ret) {
923
+ // Objective-C: a class-message factory — `[X alloc]`, `[X new]`,
924
+ // `[X sharedFoo]` — returns an instance of the RECEIVER class `X` by
925
+ // convention (`instancetype`). So when the factory's own return type isn't
926
+ // recoverable (its selector returns `instancetype`, or `alloc`/`new` aren't
927
+ // user-defined nodes at all), the receiver's type is the class `X` itself.
928
+ // This resolves the ubiquitous `[[X alloc] init]` and singleton chains.
929
+ // resolveMethodOnType validates against X (and its supertypes), so a class
930
+ // whose method actually lives elsewhere yields NO edge, not a wrong one — and
931
+ // crucially this does NOT fire when a concrete return type WAS captured but
932
+ // simply lacks the method (that already returned null above: absent-method
933
+ // safety, so a same-named decoy is still never matched).
934
+ if (ref.language === 'objc' && /^[A-Z]/.test(factoryClass)) {
935
+ return resolveMethodOnType(factoryClass, method, ref, context, 0.8, 'instance-method', importedFqnOf(factoryClass, ref, context));
936
+ }
937
+ // Pascal/Delphi: the extractor only re-encodes a `TFoo`/`IFoo`-prefixed chain
938
+ // (the type-naming convention), so `factoryClass` is always a real class here.
939
+ // A factory whose return type wasn't captured is a CONSTRUCTOR
940
+ // (`TFileMem.Create().SetCachePerformance` — `constructor Create` has no `:
941
+ // TBar` annotation but returns its own class) or an unannotated function. In
942
+ // both cases the receiver's type is the class itself, so resolve the method on
943
+ // `factoryClass`. resolveMethodOnType validates against it (and its
944
+ // supertypes), so a wrong inference yields no edge — and this never fires when
945
+ // a return type WAS captured but lacks the method (absent-method safety above).
946
+ if (ref.language === 'pascal' && /^[TI]/.test(factoryClass)) {
947
+ return resolveMethodOnType(factoryClass, method, ref, context, 0.8, 'instance-method', importedFqnOf(factoryClass, ref, context));
948
+ }
949
+ return null;
950
+ }
951
+ return resolveMethodOnType(ret, method, ref, context, 0.85, 'instance-method', importedFqnOf(ret, ref, context));
952
+ }
953
+ /**
954
+ * When several classes share a simple type name, the caller file's import of
955
+ * that type is the only signal that names WHICH one (#314). Returns the imported
956
+ * FQN for `typeName` in the ref's file, or undefined.
957
+ */
958
+ function importedFqnOf(typeName, ref, context) {
959
+ const imports = context.getImportMappings(ref.filePath, ref.language);
960
+ return imports.find((i) => i.localName === typeName)?.source;
961
+ }
962
+ /**
963
+ * Java/Kotlin: infer a receiver's declared type by walking field declarations
964
+ * in the class enclosing the call site. The field's `signature` is already in
965
+ * the form "<TypeName> <fieldName>" (set by tree-sitter.ts extractField), so we
966
+ * pull the type from there. Handles Spring `@Resource UserBO userbo;` /
967
+ * `@Autowired private UserService userService;` where the receiver field name
968
+ * doesn't match the class name by Java naming convention.
969
+ *
970
+ * Returns the bare type name (generics stripped, dotted package stripped) or
971
+ * null when no matching field is in the enclosing class.
972
+ */
973
+ function inferJavaFieldReceiverType(receiverName, ref, context) {
974
+ const inFile = context.getNodesInFile(ref.filePath);
975
+ if (inFile.length === 0)
976
+ return null;
977
+ // Find the class enclosing the call line (tightest match by latest start).
978
+ let enclosing = null;
979
+ for (const n of inFile) {
980
+ if (n.kind !== 'class' && n.kind !== 'interface')
981
+ continue;
982
+ if (n.language !== ref.language)
983
+ continue;
984
+ const end = n.endLine ?? n.startLine;
985
+ if (n.startLine <= ref.line && end >= ref.line) {
986
+ if (!enclosing || n.startLine >= enclosing.startLine)
987
+ enclosing = n;
988
+ }
989
+ }
990
+ if (!enclosing)
991
+ return null;
992
+ const enclosingEnd = enclosing.endLine ?? enclosing.startLine;
993
+ const field = inFile.find((n) => n.kind === 'field' &&
994
+ n.name === receiverName &&
995
+ n.language === ref.language &&
996
+ n.startLine >= enclosing.startLine &&
997
+ (n.endLine ?? n.startLine) <= enclosingEnd);
998
+ if (!field || !field.signature)
999
+ return null;
1000
+ // Signature shape: "<TypeName> <fieldName>" (extractField). Pull the type,
1001
+ // strip generics + dotted package, drop array/varargs markers.
1002
+ const beforeName = field.signature.slice(0, field.signature.lastIndexOf(field.name));
1003
+ const typeRaw = beforeName.trim();
1004
+ if (!typeRaw)
1005
+ return null;
1006
+ const typeNoGenerics = typeRaw.replace(/<[^>]*>/g, '').trim();
1007
+ const typeNoArray = typeNoGenerics.replace(/\[\s*\]/g, '').replace(/\.\.\.$/, '').trim();
1008
+ const parts = typeNoArray.split(/[.\s]+/).filter(Boolean);
1009
+ const lastPart = parts[parts.length - 1];
1010
+ if (!lastPart)
1011
+ return null;
1012
+ if (!/^[A-Z]/.test(lastPart))
1013
+ return null; // primitives / lowercase → skip
1014
+ return lastPart;
1015
+ }
1016
+ // ── Local-variable receiver-type inference (#1108) ──────────────────────────
1017
+ //
1018
+ // Instance calls through a local variable (`const lg = new Logger(); lg.log()`)
1019
+ // only resolved in C++ before this — no other language could learn the
1020
+ // receiver's type. Local variables are not indexed as nodes (node-explosion),
1021
+ // so, like the C++ inferrer above, we read the enclosing function's source and
1022
+ // match the receiver's declaration/initializer to recover its type. The type is
1023
+ // then handed to resolveMethodOnType, which VALIDATES that the type actually
1024
+ // declares the method, so a mis-inference produces NO edge — the safety net
1025
+ // that lets the patterns below stay simple. C++ keeps its dedicated inferrer
1026
+ // (header scan + `auto`); this covers every other language.
1027
+ // Tokens a loose pattern might capture that are never a user-defined type.
1028
+ const NON_TYPE_RECEIVER_TOKENS = new Set([
1029
+ 'this', 'self', 'super', 'new', 'return', 'await', 'yield', 'typeof',
1030
+ 'null', 'nil', 'None', 'true', 'false', 'True', 'False', 'undefined',
1031
+ ]);
1032
+ /**
1033
+ * Normalize a captured type expression to a simple type name: drop generic
1034
+ * args and pointer/ref markers, take the last `.`/`::`-qualified segment, and
1035
+ * reject obvious non-types.
1036
+ */
1037
+ function normalizeInferredTypeName(raw) {
1038
+ const cleaned = raw.replace(/<[^>]*>/g, '').replace(/[&*]/g, '').trim();
1039
+ const seg = cleaned.split(/[.:]+/).filter(Boolean).pop();
1040
+ if (!seg)
1041
+ return null;
1042
+ if (NON_TYPE_RECEIVER_TOKENS.has(seg))
1043
+ return null;
1044
+ return seg;
1045
+ }
1046
+ /**
1047
+ * Per-language patterns that recover a local variable's (or typed parameter's)
1048
+ * type from its declaration/initializer. Each regex captures the type in group
1049
+ * 1; `r` is the already-escaped receiver name. Ordered most-specific first.
1050
+ * PascalCase is required in the capture where the language convention allows,
1051
+ * as a cheap false-positive guard on top of resolveMethodOnType's validation.
1052
+ */
1053
+ /**
1054
+ * Compiled-pattern memo for the receiver-type pattern builders below. They
1055
+ * run for EVERY `receiver.method()` ref the matcher attempts, compiling 2–4
1056
+ * fresh RegExp objects per call — and receivers repeat massively (`self`
1057
+ * alone accounts for tens of thousands of refs on a Lua repo, measured 41µs
1058
+ * per methodCall miss on kong with compilation a large slice). The patterns
1059
+ * are a pure function of (language, receiver) and non-global (`.match()`
1060
+ * never touches lastIndex), so shared instances are behavior-identical.
1061
+ * FIFO-capped with no per-get mutation (the §7a.6 LRU-churn lesson): a hit
1062
+ * costs one Map lookup, overflow evicts oldest, and an evicted entry simply
1063
+ * recompiles exactly as every call did before this memo.
1064
+ */
1065
+ const PATTERN_MEMO = new Map();
1066
+ const PATTERN_MEMO_CAP = 8192;
1067
+ const INFER_SCAN_STATES = new WeakMap();
1068
+ function getInferScanStates(context) {
1069
+ let m = INFER_SCAN_STATES.get(context);
1070
+ if (!m) {
1071
+ m = new Map();
1072
+ INFER_SCAN_STATES.set(context, m);
1073
+ }
1074
+ return m;
1075
+ }
1076
+ /** Drop the per-context scan states (see ReferenceResolver.clearCaches). */
1077
+ function clearNameMatcherMemos(context) {
1078
+ INFER_SCAN_STATES.delete(context);
1079
+ }
1080
+ function memoPatterns(key, build) {
1081
+ const hit = PATTERN_MEMO.get(key);
1082
+ if (hit)
1083
+ return hit;
1084
+ const patterns = build();
1085
+ if (PATTERN_MEMO.size >= PATTERN_MEMO_CAP) {
1086
+ const oldest = PATTERN_MEMO.keys().next().value;
1087
+ if (oldest !== undefined)
1088
+ PATTERN_MEMO.delete(oldest);
1089
+ }
1090
+ PATTERN_MEMO.set(key, patterns);
1091
+ return patterns;
1092
+ }
1093
+ function localReceiverTypePatterns(language, r) {
1094
+ return memoPatterns(`${language}|${r}`, () => buildLocalReceiverTypePatterns(language, r));
1095
+ }
1096
+ function buildLocalReceiverTypePatterns(language, r) {
1097
+ switch (language) {
1098
+ case 'typescript':
1099
+ case 'javascript':
1100
+ case 'tsx':
1101
+ case 'jsx':
1102
+ case 'arkts':
1103
+ return [
1104
+ new RegExp(`\\b${r}\\b\\s*=\\s*new\\s+([A-Za-z_$][\\w.$]*)`), // = new Logger()
1105
+ // No keyword requirement, so this matches BOTH a local annotation
1106
+ // (`const lg: Logger`) and a typed parameter (`function use(lg: Logger)`
1107
+ // / `(lg: Logger) =>`) — the parameter case the old `const|let|var`
1108
+ // prefix excluded (#1125). Mirrors Kotlin/Swift/Scala; the capture stops
1109
+ // at `<` so a generic-typed param (`repo: Repository<User>`) still yields
1110
+ // `Repository`. resolveMethodOnType validates the type actually declares
1111
+ // the method, so the looser match produces no edge on a mis-inference.
1112
+ new RegExp(`\\b${r}\\b\\s*:\\s*([A-Z][\\w.$]*)`), // lg: Logger (annotation or typed param)
1113
+ ];
1114
+ case 'python':
1115
+ return [
1116
+ new RegExp(`\\b${r}\\b\\s*=\\s*([A-Z][\\w.]*)\\s*\\(`), // lg = Logger(...)
1117
+ new RegExp(`\\b${r}\\b\\s*:\\s*([A-Z][\\w.]*)`), // lg: Logger (PEP 526)
1118
+ ];
1119
+ case 'java':
1120
+ return [
1121
+ new RegExp(`\\b${r}\\b\\s*=\\s*new\\s+([A-Za-z_][\\w.]*)`), // = new Logger()
1122
+ new RegExp(`\\b([A-Z][\\w.]*)\\s+${r}\\b\\s*[=;,)]`), // Logger lg; / param
1123
+ ];
1124
+ case 'kotlin':
1125
+ return [
1126
+ new RegExp(`\\b${r}\\b\\s*=\\s*([A-Z][\\w.]*)\\s*\\(`), // val lg = Logger(...)
1127
+ new RegExp(`\\b${r}\\b\\s*:\\s*([A-Z][\\w.]*)`), // val lg: Logger / param
1128
+ ];
1129
+ case 'csharp':
1130
+ return [
1131
+ new RegExp(`\\b${r}\\b\\s*=\\s*new\\s+([A-Za-z_][\\w.]*)`), // = new Logger()
1132
+ new RegExp(`\\b([A-Z][\\w.]*)\\s+${r}\\b\\s*[=;,)]`), // Logger lg; / param
1133
+ ];
1134
+ case 'swift':
1135
+ return [
1136
+ new RegExp(`\\b${r}\\b\\s*=\\s*([A-Z][\\w.]*)\\s*\\(`), // let lg = Logger(...)
1137
+ new RegExp(`\\b${r}\\b\\s*:\\s*([A-Z][\\w.]*)`), // let lg: Logger / param
1138
+ ];
1139
+ case 'rust':
1140
+ return [
1141
+ new RegExp(`\\blet\\s+(?:mut\\s+)?${r}\\b(?:\\s*:[^=]+)?=\\s*&?(?:mut\\s+)?([A-Z][\\w]*)`), // let lg = Logger::new()/Logger{}/Logger
1142
+ // No `let`, so this covers a `let lg: Logger` binding AND a typed
1143
+ // parameter (`fn use(lg: &Logger)`, a closure `|lg: Logger|`) — the
1144
+ // parameter case the old `let`-anchored pattern excluded (#1125).
1145
+ new RegExp(`\\b${r}\\s*:\\s*&?(?:mut\\s+)?([A-Z][\\w]*)`), // lg: Logger (binding or typed param)
1146
+ ];
1147
+ case 'go':
1148
+ return [
1149
+ new RegExp(`\\b${r}\\b\\s*:=\\s*&?([A-Za-z_][\\w.]*)\\s*{`), // lg := Logger{} / &Logger{}
1150
+ new RegExp(`\\bvar\\s+${r}\\s+\\*?([A-Za-z_][\\w.]*)`), // var lg Logger / *Logger
1151
+ // A typed parameter / method receiver (`func use(lg Logger)`,
1152
+ // `func (l Logger) M()`) — name-before-type with no `var`/`:=` (#1125).
1153
+ // PascalCase-guarded (unlike the anchored patterns above) to keep the
1154
+ // keyword-free `ident Type` shape from matching unrelated pairs; the
1155
+ // enclosing-scope bound already excludes package-level struct fields.
1156
+ new RegExp(`\\b${r}\\s+\\*?([A-Z][\\w.]*)`), // func use(lg Logger) / (l Logger)
1157
+ ];
1158
+ case 'ruby':
1159
+ return [
1160
+ new RegExp(`\\b${r}\\b\\s*=\\s*([A-Z][\\w:]*)\\.new\\b`), // lg = Logger.new
1161
+ ];
1162
+ case 'scala':
1163
+ return [
1164
+ new RegExp(`\\b${r}\\b\\s*=\\s*(?:new\\s+)?([A-Z][\\w.]*)`), // val lg = new Logger / Logger(...)
1165
+ new RegExp(`\\b${r}\\b\\s*:\\s*([A-Z][\\w.]*)`), // val lg: Logger / param
1166
+ ];
1167
+ case 'dart':
1168
+ return [
1169
+ new RegExp(`\\b${r}\\b\\s*=\\s*([A-Z][\\w.]*)\\s*\\(`), // var lg = Logger(...)
1170
+ // Trailing `[=;,)]` (not just `[=;]`) so a typed parameter — `Logger lg)`
1171
+ // / `Logger lg,` — matches too, not only `Logger lg = ...` / `Logger lg;`
1172
+ // (#1125). Mirrors Java/C#.
1173
+ new RegExp(`\\b([A-Z][\\w.]*)\\s+${r}\\b\\s*[=;,)]`), // Logger lg = ... / param
1174
+ ];
1175
+ case 'php':
1176
+ return [
1177
+ new RegExp(`\\$?${r}\\b\\s*=\\s*new\\s+([A-Za-z_\\\\][\\w\\\\]*)`), // $lg = new Logger()
1178
+ // A typed parameter (`function use(Logger $lg)`, `?Logger $lg`,
1179
+ // `\\App\\Logger $lg`, `&$lg` by-ref) and a typed `catch (E $e)` — the
1180
+ // type sits before the `$`-variable (#1125). Namespace `\\` allowed.
1181
+ new RegExp(`\\b([A-Za-z_\\\\][\\w\\\\]*)\\s+&?\\$${r}\\b`), // Logger $lg (typed param)
1182
+ ];
1183
+ case 'lua':
1184
+ case 'luau':
1185
+ return [
1186
+ new RegExp(`\\b${r}\\b\\s*=\\s*([A-Z][\\w]*)\\.new\\b`), // local lg = Logger.new()
1187
+ new RegExp(`\\b${r}\\b\\s*=\\s*([A-Z][\\w]*)\\s*\\(`), // local lg = Logger(...) (callable table)
1188
+ // Luau annotation (`local lg: Logger`) / typed param — but Lua's
1189
+ // method-call syntax is the IDENTICAL `receiver:Name` shape, and the
1190
+ // backward scan starts on the call's own line, so without a gate any
1191
+ // PascalCase method call (`lg:Log()`, the Roblox convention)
1192
+ // self-matches as "type = Log" before the scan reaches the real
1193
+ // declaration (#1124). The lookahead rejects a capture followed by
1194
+ // any of Lua's three call forms — `(args)`, `"s"`/`'s'`/`[[s]]`,
1195
+ // `{t}` — and its leading `[\w.]` alternative stops backtracking from
1196
+ // shrinking the capture to dodge the gate (`lg:Log()` would otherwise
1197
+ // still match, as `Lo`).
1198
+ new RegExp(`\\b${r}\\b\\s*:\\s*([A-Z][\\w.]*)(?![\\w.]|\\s*[({"'\\[])`), // local lg: Logger / typed param
1199
+ ];
1200
+ case 'r':
1201
+ return [
1202
+ new RegExp(`\\b${r}\\b\\s*(?:<-|<<-|=)\\s*([A-Z][\\w.]*)\\$new\\b`), // lg <- Logger$new() (R6)
1203
+ ];
1204
+ case 'pascal':
1205
+ return [
1206
+ new RegExp(`\\b${r}\\b\\s*:\\s*([A-Z][\\w]*)`), // var lg: TLogger / param lg: TLogger
1207
+ new RegExp(`\\b${r}\\b\\s*:=\\s*([A-Z][\\w.]*)\\.Create\\b`), // lg := TLogger.Create
1208
+ ];
1209
+ case 'cfml':
1210
+ case 'cfscript':
1211
+ return [
1212
+ // svc = new UserService() / new path.to.UserService() — dotted component
1213
+ // paths reduce to their final segment via normalizeInferredTypeName.
1214
+ // Also matches inside tag markup (`<cfset svc = new UserService()>`)
1215
+ // since the scan reads raw source lines.
1216
+ new RegExp(`\\b${r}\\b\\s*=\\s*new\\s+([A-Za-z_][\\w.]*)`),
1217
+ // The classic form: svc = createObject("component", "path.to.UserService")
1218
+ // (casing of createObject varies in the wild), plus the modern
1219
+ // single-argument form createObject("path.to.UserService").
1220
+ new RegExp(`\\b${r}\\b\\s*=\\s*[Cc]reate[Oo]bject\\s*\\(\\s*["']component["']\\s*,\\s*["']([\\w.]+)["']`),
1221
+ new RegExp(`\\b${r}\\b\\s*=\\s*[Cc]reate[Oo]bject\\s*\\(\\s*["']([\\w.]+)["']\\s*\\)`),
1222
+ // Typed cfscript parameter: `function save(UserService svc)` /
1223
+ // `required UserService svc` — CFML's built-in types (string, numeric,
1224
+ // any, struct…) are lowercase by convention, so the PascalCase guard
1225
+ // excludes them.
1226
+ new RegExp(`\\b([A-Z][\\w.]*)\\s+${r}\\b\\s*[=;,)]`),
1227
+ // Tag-form typed argument, either attribute order:
1228
+ // <cfargument name="svc" type="path.to.UserService">
1229
+ new RegExp(`\\bcfargument[^>\\n]*\\bname\\s*=\\s*["']${r}["'][^>\\n]*\\btype\\s*=\\s*["']([\\w.]+)["']`, 'i'),
1230
+ new RegExp(`\\bcfargument[^>\\n]*\\btype\\s*=\\s*["']([\\w.]+)["'][^>\\n]*\\bname\\s*=\\s*["']${r}["']`, 'i'),
1231
+ // Component property (incl. WireBox DI): `property name="svc"
1232
+ // inject="UserService";` / `<cfproperty name="svc" type="UserService">`,
1233
+ // either attribute order. An inject DSL value with a namespace
1234
+ // (`inject="svc@core"`) captures only the leading name and simply
1235
+ // fails type-validation — no edge, never a wrong one.
1236
+ new RegExp(`\\b(?:cf)?property\\b[^;\\n]*\\bname\\s*=\\s*["']${r}["'][^;\\n]*\\b(?:type|inject)\\s*=\\s*["']([\\w.]+)["']`, 'i'),
1237
+ new RegExp(`\\b(?:cf)?property\\b[^;\\n]*\\b(?:type|inject)\\s*=\\s*["']([\\w.]+)["'][^;\\n]*\\bname\\s*=\\s*["']${r}["']`, 'i'),
1238
+ ];
1239
+ default:
1240
+ return [];
1241
+ }
1242
+ }
1243
+ /** 1-based start line of the tightest function/method enclosing the call. */
1244
+ function enclosingScopeStartLine(ref, context) {
1245
+ let start = 1;
1246
+ for (const n of context.getNodesInFile(ref.filePath)) {
1247
+ if (n.kind !== 'function' && n.kind !== 'method')
1248
+ continue;
1249
+ if (n.language !== ref.language)
1250
+ continue;
1251
+ const end = n.endLine ?? n.startLine;
1252
+ if (n.startLine <= ref.line && end >= ref.line && n.startLine >= start) {
1253
+ start = n.startLine;
1254
+ }
1255
+ }
1256
+ return start;
1257
+ }
1258
+ /**
1259
+ * Infer a receiver's type from its local declaration/initializer in the
1260
+ * enclosing function body. Language-dispatched; returns null for languages
1261
+ * without patterns or when no declaration is found. Bounded to the enclosing
1262
+ * scope so a same-named variable in another function can't leak in.
1263
+ */
1264
+ function inferLocalReceiverType(receiverName, ref, context) {
1265
+ // CFML scope prefixes: `variables.svc` / `this.svc` name a COMPONENT-scoped
1266
+ // field whose assignment or `property` declaration usually lives outside the
1267
+ // calling function (the init-pseudoconstructor / WireBox-injection pattern),
1268
+ // and `local.svc` is an explicit function-local. Strip the prefix so the
1269
+ // declaration patterns match (`variables.svc = new X()`, `property
1270
+ // name="svc" …`, `var svc = …` all bind the bare name), and widen the scan
1271
+ // to the whole file for the component-scoped forms — nearest-declaration-
1272
+ // backward still wins, so a function-local shadowing the field is preferred.
1273
+ let scanReceiver = receiverName;
1274
+ let componentScoped = false;
1275
+ if (ref.language === 'cfml' || ref.language === 'cfscript') {
1276
+ const scoped = receiverName.match(/^(variables|this|local|arguments)\.(.+)$/i);
1277
+ if (scoped) {
1278
+ scanReceiver = scoped[2];
1279
+ const scope = scoped[1].toLowerCase();
1280
+ componentScoped = scope === 'variables' || scope === 'this';
1281
+ }
1282
+ }
1283
+ // PHP `$this->prop` receiver — the property's declaration lives outside the
1284
+ // calling method (a promoted constructor parameter `private readonly Foo $prop`,
1285
+ // a typed property `private Foo $prop;`, or a classic constructor parameter
1286
+ // `Foo $prop` assigned in __construct). Strip the prefix and widen the scan to
1287
+ // the whole file (the constructor may sit below the calling method), but —
1288
+ // unlike CFML's scopes above — switch to PROPERTY-shaped patterns: a plain
1289
+ // `$prop` local or parameter lives in a different namespace than `$this->prop`
1290
+ // and can never shadow it, so the generic local patterns would type the
1291
+ // property from unrelated same-named variables in other methods (a wrong
1292
+ // 0.9-confidence edge, not a missing one).
1293
+ let phpProperty = false;
1294
+ if (ref.language === 'php') {
1295
+ const scoped = receiverName.match(/^this->(.+)$/);
1296
+ if (scoped) {
1297
+ scanReceiver = scoped[1];
1298
+ componentScoped = true;
1299
+ phpProperty = true;
1300
+ }
1301
+ }
1302
+ const escapedReceiver = scanReceiver.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
1303
+ const patterns = phpProperty
1304
+ ? phpPropertyTypePatterns(escapedReceiver)
1305
+ : localReceiverTypePatterns(ref.language, escapedReceiver);
1306
+ if (patterns.length === 0)
1307
+ return null;
1308
+ // Split through the context's per-file lines cache when available: this runs
1309
+ // for EVERY `receiver.method()` ref, and re-splitting the whole file per ref
1310
+ // was ~20% of total index CPU on Java-heavy repos (#1122).
1311
+ const lines = context.getFileLines
1312
+ ? context.getFileLines(ref.filePath)
1313
+ : (context.readFile(ref.filePath)?.split(/\r?\n/) ?? null);
1314
+ if (!lines || lines.length === 0)
1315
+ return null;
1316
+ const callIdx = Math.max(0, Math.min(lines.length - 1, ref.line - 1));
1317
+ const startIdx = componentScoped
1318
+ ? 0
1319
+ : Math.max(0, enclosingScopeStartLine(ref, context) - 1);
1320
+ const matchLine = (i) => {
1321
+ const line = lines[i];
1322
+ if (!line)
1323
+ return null;
1324
+ // A generated/minified line (one multi-KB statement) is not something a
1325
+ // human-written local declaration lives on, and regexing it per ref is
1326
+ // pure waste — skip it rather than scan it.
1327
+ if (line.length > 10_000)
1328
+ return null;
1329
+ for (const re of patterns) {
1330
+ const m = line.match(re);
1331
+ if (m && m[1]) {
1332
+ const type = normalizeInferredTypeName(m[1]);
1333
+ if (type)
1334
+ return type;
1335
+ }
1336
+ }
1337
+ return null;
1338
+ };
1339
+ // Incremental-scan memo (INFER_SCAN_STATES): this scan runs for EVERY
1340
+ // `receiver.method()` ref and was measured at 61µs/ref on kong (2.4s of
1341
+ // worker time, 99% misses — `self:` calls hunting a declaration Lua never
1342
+ // writes). Refs for the same (file, scope, receiver) arrive in ~ascending
1343
+ // line order, and the scan is a pure function of the file's immutable
1344
+ // lines, so each line pays its regex matches ONCE per key instead of once
1345
+ // per ref: query(c) = highest matching line in [startIdx..c]; a monotonic
1346
+ // call extends the stored watermark by scanning only (hi..c] (the region
1347
+ // at-or-below the previous answer is already proven empty above it); a
1348
+ // non-monotonic call (rare — refs are rowid-ordered) falls back to the
1349
+ // plain bounded scan and leaves the state alone. componentScoped is keyed
1350
+ // out — its position-independent whole-file sweep below has different
1351
+ // semantics.
1352
+ if (!componentScoped) {
1353
+ const states = getInferScanStates(context);
1354
+ const key = `${ref.filePath}|${startIdx}|${ref.language}|${scanReceiver}`;
1355
+ const state = states.get(key);
1356
+ if (!state) {
1357
+ for (let i = callIdx; i >= startIdx; i--) {
1358
+ const type = matchLine(i);
1359
+ if (type) {
1360
+ states.set(key, { hi: callIdx, ansIdx: i, ansType: type });
1361
+ return type;
1362
+ }
1363
+ }
1364
+ states.set(key, { hi: callIdx, ansIdx: -1, ansType: null });
1365
+ return null;
1366
+ }
1367
+ if (callIdx >= state.hi) {
1368
+ for (let i = callIdx; i > state.hi; i--) {
1369
+ const type = matchLine(i);
1370
+ if (type) {
1371
+ state.ansIdx = i;
1372
+ state.ansType = type;
1373
+ break;
1374
+ }
1375
+ }
1376
+ state.hi = callIdx;
1377
+ return state.ansIdx >= startIdx ? state.ansType : null;
1378
+ }
1379
+ for (let i = callIdx; i >= startIdx; i--) {
1380
+ const type = matchLine(i);
1381
+ if (type)
1382
+ return type;
1383
+ }
1384
+ return null;
1385
+ }
1386
+ // Nearest declaration wins: scan backward from the call to the scope start.
1387
+ for (let i = callIdx; i >= startIdx; i--) {
1388
+ const type = matchLine(i);
1389
+ if (type)
1390
+ return type;
1391
+ }
1392
+ // A component-scoped field's declaration is position-independent — the
1393
+ // `variables.svc = new X()` pseudoconstructor assignment or `property`
1394
+ // declaration may sit BELOW the calling function in the file — so when the
1395
+ // backward pass finds nothing, sweep the remainder of the file too.
1396
+ if (componentScoped) {
1397
+ for (let i = callIdx + 1; i < lines.length; i++) {
1398
+ const type = matchLine(i);
1399
+ if (type)
1400
+ return type;
1401
+ }
1402
+ }
1403
+ // A PHP property with no statically-typed declaration (classic pre-7.4
1404
+ // style) may still be typed by what gets ASSIGNED to it — follow the
1405
+ // `$this->prop = $var` assignment to the assigned variable's own typed
1406
+ // declaration (a classic or multi-line constructor parameter, or a typed
1407
+ // setter's parameter).
1408
+ if (phpProperty) {
1409
+ return inferPhpAssignedPropertyType(escapedReceiver, lines, callIdx);
1410
+ }
1411
+ return null;
1412
+ }
1413
+ /**
1414
+ * Patterns that recover a PHP class property's declared type for a
1415
+ * `$this->prop` receiver. Deliberately NOT localReceiverTypePatterns: only
1416
+ * property-shaped declarations qualify —
1417
+ * 1. a modifier-prefixed typed declaration, which covers both a typed
1418
+ * property (`private ?Foo $prop;`) and a promoted constructor parameter
1419
+ * (`private readonly Foo $prop`), and
1420
+ * 2. the pseudoconstructor assignment (`$this->prop = new Foo(...)`).
1421
+ * A bare `X $prop` parameter or `$prop = new X()` local elsewhere in the
1422
+ * file must NOT match: those variables can never alias `$this->prop`.
1423
+ * Union-typed properties (`Foo|Bar $prop`) yield no match and thus no edge —
1424
+ * silent beats wrong. The classic untyped-property-assigned-in-constructor
1425
+ * shape is handled by inferPhpAssignedPropertyType instead.
1426
+ */
1427
+ function phpPropertyTypePatterns(r) {
1428
+ return memoPatterns(`php-prop|${r}`, () => buildPhpPropertyTypePatterns(r));
1429
+ }
1430
+ function buildPhpPropertyTypePatterns(r) {
1431
+ return [
1432
+ new RegExp(`\\b(?:(?:private|protected|public|readonly|static|final)(?:\\(set\\))?\\s+)+\\??([A-Za-z_\\\\][\\w\\\\]*)\\s+&?\\$${r}\\b`), // private readonly ?Foo $prop (typed property / promoted param)
1433
+ new RegExp(`\\$this->${r}\\b\\s*=\\s*new\\s+([A-Za-z_\\\\][\\w\\\\]*)`), // $this->prop = new Foo()
1434
+ ];
1435
+ }
1436
+ /**
1437
+ * Second-chance typing for a PHP `$this->prop` receiver whose property
1438
+ * declaration carries no static type (classic pre-7.4 style): find the
1439
+ * `$this->prop = $var` assignment, then recover `$var`'s type from its own
1440
+ * declaration WITHIN the assignment's function — the constructor's (possibly
1441
+ * multi-line) parameter list, a typed setter's parameter, or a `= new X()`
1442
+ * local. The backward scan stops at the enclosing `function` line (checked
1443
+ * for a match first — a single-line `__construct(Foo $var) { ... }` carries
1444
+ * the typed parameter itself), so a same-named variable in another method
1445
+ * can never type the property.
1446
+ */
1447
+ function inferPhpAssignedPropertyType(escapedProp, lines, callIdx) {
1448
+ const assignRe = new RegExp(`\\$this->${escapedProp}\\b\\s*=\\s*\\$(\\w+)\\b`);
1449
+ const assignAt = (i) => {
1450
+ const line = lines[i];
1451
+ if (!line || line.length > 10_000)
1452
+ return null;
1453
+ return line.match(assignRe);
1454
+ };
1455
+ // The assignment is position-independent relative to the call — nearest-
1456
+ // backward first, then sweep forward, same order as the componentScoped scan.
1457
+ let assignIdx = -1;
1458
+ let varName = null;
1459
+ for (let i = callIdx; i >= 0; i--) {
1460
+ const m = assignAt(i);
1461
+ if (m) {
1462
+ assignIdx = i;
1463
+ varName = m[1];
1464
+ break;
1465
+ }
1466
+ }
1467
+ if (varName === null) {
1468
+ for (let i = callIdx + 1; i < lines.length; i++) {
1469
+ const m = assignAt(i);
1470
+ if (m) {
1471
+ assignIdx = i;
1472
+ varName = m[1];
1473
+ break;
1474
+ }
1475
+ }
1476
+ }
1477
+ if (varName === null)
1478
+ return null;
1479
+ const varPatterns = localReceiverTypePatterns('php', varName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
1480
+ for (let i = assignIdx; i >= 0; i--) {
1481
+ const line = lines[i];
1482
+ if (line && line.length <= 10_000) {
1483
+ for (const re of varPatterns) {
1484
+ const m = line.match(re);
1485
+ if (m && m[1]) {
1486
+ const type = normalizeInferredTypeName(m[1]);
1487
+ if (type)
1488
+ return type;
1489
+ }
1490
+ }
1491
+ }
1492
+ if (line && /\bfunction\b/.test(line))
1493
+ break;
1494
+ }
1495
+ return null;
1496
+ }
1497
+ /**
1498
+ * Try to resolve by method name on a class/object
1499
+ */
1500
+ function matchMethodCall(ref, context) {
1501
+ // Parse method call patterns like "obj.method" or "Class::method". The method
1502
+ // part allows trailing `:` keywords so Objective-C selectors resolve
1503
+ // (`SDImageCache.storeImage:`, `obj.setX:y:`); colons never appear in other
1504
+ // languages' method refs, so this is a no-op for them.
1505
+ // The receiver allows dots (`builder.Services.AddCoreServices`) so a CHAINED
1506
+ // call resolves by its last segment — Strategy 3 below name-matches the method
1507
+ // (with its existing single-candidate / receiver-overlap guards). Without this
1508
+ // a multi-dot extension-method call (C# DI `builder.Services.AddCoreServices()`,
1509
+ // `Guard.Against.X()`) matched no pattern and never resolved.
1510
+ // C++ explicit operator call `a.operator+(b)` reaches the resolver as
1511
+ // `a.operator+` (#1247) — the operator's symbol chars (`+`, `==`, `[]`, `()`)
1512
+ // fail the \w method part of the plain pattern, so admit them explicitly.
1513
+ // Names like `operatorTable` stay on the plain pattern (tried first); the
1514
+ // operator form requires at least one non-word char after `operator`, and
1515
+ // every downstream strategy compares the method part by exact string
1516
+ // equality, so a stray match can't invent an edge.
1517
+ const dotMatch = ref.referenceName.match(/^([\w.]+)\.(\w+:?(?:\w+:)*)$/) ??
1518
+ (ref.language === 'cpp'
1519
+ ? ref.referenceName.match(/^([\w.]+)\.(operator[^\w\s.]+)$/)
1520
+ : null);
1521
+ const colonMatch = ref.referenceName.match(/^(\w+)::(\w+)$/);
1522
+ // Lua/Luau method calls use a single colon (`lg:log`); R uses `$` (`lg$log`).
1523
+ // Recognize these receiver/method separators so local-variable receiver-type
1524
+ // inference (#1108) applies to them too — extraction already emits the ref in
1525
+ // this shape, but the resolver otherwise only understood `.` and `::`.
1526
+ const luaColonMatch = (ref.language === 'lua' || ref.language === 'luau')
1527
+ ? ref.referenceName.match(/^([\w.]+):(\w+)$/)
1528
+ : null;
1529
+ const rDollarMatch = ref.language === 'r'
1530
+ ? ref.referenceName.match(/^([\w.]+)\$(\w+)$/)
1531
+ : null;
1532
+ // PHP property receiver: `$this->prop->method()` reaches the resolver as
1533
+ // `this->prop.method` (the extractor records the receiver's raw text with the
1534
+ // leading `$` stripped). Resolve it EXCLUSIVELY through declared-type
1535
+ // inference + resolveMethodOnType validation — the name-similarity strategies
1536
+ // below must never see this shape, so a property whose type can't be
1537
+ // recovered stays unlinked rather than guessed (a wrong inference produces no
1538
+ // edge rather than a wrong one). Deeper chains (`this->a->b.method`) don't
1539
+ // match the single-property pattern and stay unlinked, same as before.
1540
+ const phpThisPropMatch = ref.language === 'php'
1541
+ ? ref.referenceName.match(/^(this->\w+)\.(\w+)$/)
1542
+ : null;
1543
+ if (phpThisPropMatch) {
1544
+ const [, receiver, phpMethodName] = phpThisPropMatch;
1545
+ const inferredType = inferLocalReceiverType(receiver, ref, context);
1546
+ if (!inferredType)
1547
+ return null;
1548
+ return resolveMethodOnType(inferredType, phpMethodName, ref, context, 0.9, 'instance-method', importedFqnOf(inferredType, ref, context));
1549
+ }
1550
+ const match = dotMatch || colonMatch || luaColonMatch || rDollarMatch;
1551
+ if (!match) {
1552
+ return null;
1553
+ }
1554
+ const [, objectOrClass, methodName] = match;
1555
+ // A simple `receiver.method` / `receiver:method` / `receiver$method` shape whose
1556
+ // receiver type we can try to infer from its local declaration.
1557
+ const inferableReceiver = dotMatch || luaColonMatch || rDollarMatch;
1558
+ // Infer the receiver's type from its local declaration/initializer in the
1559
+ // enclosing scope, then resolve the method on that type (#1108). C++ keeps its
1560
+ // dedicated inferrer (header scan + `auto`); every other language uses the
1561
+ // shared source-based inferrer. resolveMethodOnType validates the method
1562
+ // exists on the inferred type, so a mis-inference produces no edge.
1563
+ if (inferableReceiver) {
1564
+ const inferredType = nmTimedT('mc-infer', ref, () => ref.language === 'cpp'
1565
+ ? inferCppReceiverType(objectOrClass, ref, context)
1566
+ : inferLocalReceiverType(objectOrClass, ref, context));
1567
+ if (inferredType) {
1568
+ // Java/Kotlin: when two classes share the simple name, the file's import
1569
+ // pins WHICH one (#314). Other languages disambiguate by call-site file.
1570
+ const importedFqn = ref.language === 'java' || ref.language === 'kotlin'
1571
+ ? context
1572
+ .getImportMappings(ref.filePath, ref.language)
1573
+ .find((i) => i.localName === inferredType)?.source
1574
+ : undefined;
1575
+ const typedMatch = nmTimedT('mc-rmot', ref, () => resolveMethodOnType(inferredType, methodName, ref, context, 0.9, 'instance-method', importedFqn));
1576
+ if (typedMatch) {
1577
+ return typedMatch;
1578
+ }
1579
+ }
1580
+ }
1581
+ // Go 2-hop field chain `base.field.Method` (#1276): the base's type comes
1582
+ // from the enclosing scope (typed parameter / method receiver / local var),
1583
+ // the field's declared type from that struct's own declaration lines, and
1584
+ // the method is VALIDATED on the field's type by resolveMethodOnType. This
1585
+ // branch is EXCLUSIVE for chained Go receivers: when the hop can't be
1586
+ // inferred or the field's type is external (`conn *sql.DB` — no project
1587
+ // node), the ref stays unresolved rather than falling through to the
1588
+ // bare-name strategies below, which is exactly how `target.conn.Exec(...)`
1589
+ // fabricated a dependency on an unrelated local interface's same-named
1590
+ // method. Chained Go receivers were never emitted before #1276, so there
1591
+ // is no prior recall to preserve on the fallback path.
1592
+ if (ref.language === 'go' && dotMatch && objectOrClass.includes('.')) {
1593
+ return matchGoFieldChainCall(objectOrClass, methodName, ref, context);
1594
+ }
1595
+ // Java/Kotlin: receiver may be a field whose name doesn't match the type by
1596
+ // Java naming convention (`userbo` → class `UserBO`, abbreviated). Look up
1597
+ // the field in the enclosing class to get its declared type, then resolve
1598
+ // the method on that type. Covers Spring `@Resource`/`@Autowired` field
1599
+ // injection where the field type is the concrete bean class.
1600
+ if ((ref.language === 'java' || ref.language === 'kotlin') && dotMatch) {
1601
+ const inferredType = inferJavaFieldReceiverType(objectOrClass, ref, context);
1602
+ if (inferredType) {
1603
+ // When two classes share the same simple name, the caller file's
1604
+ // import is the only signal that names WHICH one — pass the
1605
+ // imported FQN so resolveMethodOnType can disambiguate (#314).
1606
+ const imports = context.getImportMappings(ref.filePath, ref.language);
1607
+ const importedFqn = imports.find((i) => i.localName === inferredType)?.source;
1608
+ const typedMatch = nmTimedT('mc-rmot', ref, () => resolveMethodOnType(inferredType, methodName, ref, context, 0.9, 'instance-method', importedFqn));
1609
+ if (typedMatch) {
1610
+ return typedMatch;
1611
+ }
1612
+ }
1613
+ }
1614
+ // Strategy 1: Direct class name match (existing logic). When the receiver
1615
+ // names a class that exists in several files (`Logger.log()` / `Logger::log()`
1616
+ // with a `Logger` in both `a/` and `b/`), try the class in the call site's
1617
+ // own file first — otherwise the first-indexed class wins and a call in `b/`
1618
+ // resolves to `a/`'s method (#1079).
1619
+ const strat1 = nmTimedT('mc-class', ref, () => {
1620
+ const classCandidates = preferCallSiteFile(context.getNodesByName(objectOrClass), ref.filePath);
1621
+ for (const classNode of classCandidates) {
1622
+ if (classNode.kind === 'class' || classNode.kind === 'struct' || classNode.kind === 'union' || classNode.kind === 'interface') {
1623
+ // Skip cross-language class matches
1624
+ if (classNode.language !== ref.language)
1625
+ continue;
1626
+ const nodesInFile = context.getNodesInFile(classNode.filePath);
1627
+ const methodNode = nodesInFile.find((n) => n.kind === 'method' &&
1628
+ n.name === methodName &&
1629
+ n.qualifiedName.includes(classNode.name));
1630
+ if (methodNode) {
1631
+ return {
1632
+ original: ref,
1633
+ targetNodeId: methodNode.id,
1634
+ confidence: 0.85,
1635
+ resolvedBy: 'qualified-name',
1636
+ };
1637
+ }
1638
+ }
1639
+ }
1640
+ return null;
1641
+ });
1642
+ if (strat1)
1643
+ return strat1;
1644
+ // Strategy 2: Instance variable receiver - try capitalized form to find class
1645
+ // e.g., "permissionEngine" → look for classes containing "PermissionEngine"
1646
+ const capitalizedReceiver = objectOrClass.charAt(0).toUpperCase() + objectOrClass.slice(1);
1647
+ if (capitalizedReceiver !== objectOrClass) {
1648
+ const strat2 = nmTimedT('mc-capital', ref, () => {
1649
+ const fuzzyClassCandidates = preferCallSiteFile(context.getNodesByName(capitalizedReceiver), ref.filePath);
1650
+ for (const classNode of fuzzyClassCandidates) {
1651
+ if (classNode.kind === 'class' || classNode.kind === 'struct' || classNode.kind === 'union' || classNode.kind === 'interface') {
1652
+ // Skip cross-language class matches
1653
+ if (classNode.language !== ref.language)
1654
+ continue;
1655
+ const nodesInFile = context.getNodesInFile(classNode.filePath);
1656
+ const methodNode = nodesInFile.find((n) => n.kind === 'method' &&
1657
+ n.name === methodName &&
1658
+ n.qualifiedName.includes(classNode.name));
1659
+ if (methodNode) {
1660
+ return {
1661
+ original: ref,
1662
+ targetNodeId: methodNode.id,
1663
+ confidence: 0.8,
1664
+ resolvedBy: 'instance-method',
1665
+ };
1666
+ }
1667
+ }
1668
+ }
1669
+ return null;
1670
+ });
1671
+ if (strat2)
1672
+ return strat2;
1673
+ }
1674
+ // Strategy 3: Find methods by name across the codebase, match by receiver
1675
+ // name similarity with the containing class. Handles abbreviated variable
1676
+ // names like permissionEngine → PermissionRuleEngine.
1677
+ if (methodName) {
1678
+ const strat3 = nmTimedT('mc-byname', ref, () => {
1679
+ const methodCandidates = context.getNodesByName(methodName);
1680
+ // Ubiquitous-method ceiling (#999): a method name re-declared across a
1681
+ // vendored theme/SDK (Metronic's `init`/`update`/… on every widget) yields
1682
+ // K candidates that receiver-word overlap can't reliably disambiguate —
1683
+ // and filtering + scoring all K per call is the O(K²) cost that wedged
1684
+ // "Resolving refs" for 15-28 min. Bail before the O(K) work; Strategy 1/2
1685
+ // (class-name match) already had their precise shot above.
1686
+ if (methodCandidates.length > AMBIGUOUS_NAME_CEILING) {
1687
+ return null;
1688
+ }
1689
+ const methods = methodCandidates.filter((n) => n.kind === 'method' && n.name === methodName);
1690
+ // Filter to same-language candidates first
1691
+ const sameLanguageMethods = methods.filter(m => m.language === ref.language);
1692
+ const targetMethods = sameLanguageMethods.length > 0 ? sameLanguageMethods : methods;
1693
+ // If only one same-language method with this name exists, use it
1694
+ if (targetMethods.length === 1 && targetMethods[0].language === ref.language) {
1695
+ return {
1696
+ original: ref,
1697
+ targetNodeId: targetMethods[0].id,
1698
+ confidence: 0.7,
1699
+ resolvedBy: 'instance-method',
1700
+ };
1701
+ }
1702
+ // Multiple methods: score by receiver name word overlap with class name
1703
+ if (targetMethods.length > 1) {
1704
+ const receiverWords = splitCamelCase(objectOrClass);
1705
+ let bestMatch;
1706
+ let bestScore = 0;
1707
+ // Same-file candidates first, so a score tie (`score > bestScore` keeps
1708
+ // the first seen) resolves to the call site's own file rather than the
1709
+ // first-indexed duplicate (#1079).
1710
+ for (const method of preferCallSiteFile(targetMethods, ref.filePath)) {
1711
+ const classWords = splitCamelCase(method.qualifiedName);
1712
+ let score = receiverWords.filter(w => classWords.some(cw => cw.toLowerCase() === w.toLowerCase())).length;
1713
+ // Bonus for same language
1714
+ if (method.language === ref.language)
1715
+ score += 1;
1716
+ if (score > bestScore) {
1717
+ bestScore = score;
1718
+ bestMatch = method;
1719
+ }
1720
+ }
1721
+ if (bestMatch && bestScore >= 2) {
1722
+ return {
1723
+ original: ref,
1724
+ targetNodeId: bestMatch.id,
1725
+ confidence: 0.65,
1726
+ resolvedBy: 'instance-method',
1727
+ };
1728
+ }
1729
+ }
1730
+ return null;
1731
+ });
1732
+ if (strat3)
1733
+ return strat3;
1734
+ }
1735
+ return null;
1736
+ }
1737
+ /** Go builtin/primitive field types that can never carry a project method. */
1738
+ const GO_BUILTIN_FIELD_TYPES = new Set([
1739
+ 'string', 'bool', 'byte', 'rune', 'error', 'any',
1740
+ 'int', 'int8', 'int16', 'int32', 'int64',
1741
+ 'uint', 'uint8', 'uint16', 'uint32', 'uint64', 'uintptr',
1742
+ 'float32', 'float64', 'complex64', 'complex128',
1743
+ 'chan', 'map', 'func', 'struct', 'interface',
1744
+ ]);
1745
+ /**
1746
+ * Resolve a Go 2-hop field-chain call `base.field.Method(...)` (#1276):
1747
+ * `target.conn.Exec("insert")` where `func (target *Target) Write()` and
1748
+ * `type Target struct { conn *sql.DB }`. Two inference hops, both read from
1749
+ * source the same way #1108 does:
1750
+ * 1. `base`'s type from the enclosing scope (method receiver, typed
1751
+ * parameter, or local declaration) via inferLocalReceiverType;
1752
+ * 2. `field`'s declared type from the struct's own declaration lines.
1753
+ * The method is then resolved AND VALIDATED on the field's type. A field
1754
+ * whose type has no project node (`sql.DB`, any external dependency) yields
1755
+ * null — the caller treats this branch as exclusive for chained Go
1756
+ * receivers, so the ref stays unresolved instead of name-guessing.
1757
+ */
1758
+ function matchGoFieldChainCall(receiverChain, methodName, ref, context) {
1759
+ const segs = receiverChain.split('.');
1760
+ if (segs.length !== 2 || !segs[0] || !segs[1])
1761
+ return null;
1762
+ const [base, field] = segs;
1763
+ const baseType = inferLocalReceiverType(base, ref, context);
1764
+ if (!baseType)
1765
+ return null;
1766
+ const fieldEsc = field.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
1767
+ const fieldTypeRe = new RegExp(`\\b${fieldEsc}\\s+\\*?\\[?\\]?([A-Za-z_][\\w.]*)`);
1768
+ const structs = preferCallSiteFile(context.getNodesByName(baseType), ref.filePath).filter((n) => (n.kind === 'struct' || n.kind === 'class') && n.language === 'go');
1769
+ for (const s of structs) {
1770
+ const source = context.readFile(s.filePath);
1771
+ if (!source)
1772
+ continue;
1773
+ // Only the struct's own declaration lines — a same-named identifier
1774
+ // elsewhere in the file can't donate a type. Matched LINE BY LINE with
1775
+ // comments stripped: chi's `Mux` has a doc comment reading "the tree
1776
+ // router" right above `tree *node`, and a whole-block match captured
1777
+ // `router` from the prose instead of `node` from the field.
1778
+ const declLines = source.split('\n').slice(Math.max(0, s.startLine - 1), s.endLine);
1779
+ for (const rawLine of declLines) {
1780
+ const line = rawLine.replace(/\/\/.*$/, '').replace(/\/\*.*?\*\//g, '');
1781
+ const m = line.match(fieldTypeRe);
1782
+ if (!m || !m[1])
1783
+ continue;
1784
+ const rawType = m[1];
1785
+ // A package-qualified field type (`http.Handler`, `sql.DB`) is only
1786
+ // followed when the package is IN-MODULE: stripping the qualifier and
1787
+ // matching the bare name would conflate a stdlib/third-party type with
1788
+ // any same-named project type — on chi, `handler http.Handler` bound
1789
+ // to an example app's unrelated local `Handler`. That is the exact
1790
+ // fabrication this matcher exists to prevent (#1276).
1791
+ if (rawType.includes('.')) {
1792
+ const pkg = rawType.split('.')[0];
1793
+ const mod = context.getGoModule?.();
1794
+ const imp = context
1795
+ .getImportMappings(s.filePath, 'go')
1796
+ .find((i) => i.localName === pkg);
1797
+ const inModule = !!mod &&
1798
+ !!imp &&
1799
+ (imp.source === mod.modulePath || imp.source.startsWith(mod.modulePath + '/'));
1800
+ if (!inModule)
1801
+ continue;
1802
+ }
1803
+ // Unexported (lowercase) types are idiomatic Go and stay eligible —
1804
+ // chi's `mx.tree.FindRoute()` chains through `tree *node`. A
1805
+ // mis-capture is harmless: resolveMethodOnType only returns a
1806
+ // validated `<type>::<method>` match.
1807
+ const fieldType = rawType.split('.').pop();
1808
+ if (!fieldType || !/^[A-Za-z_]/.test(fieldType) || GO_BUILTIN_FIELD_TYPES.has(fieldType))
1809
+ continue;
1810
+ const resolved = resolveMethodOnType(fieldType, methodName, ref, context, 0.85, 'instance-method');
1811
+ if (resolved)
1812
+ return resolved;
1813
+ }
1814
+ }
1815
+ return null;
1816
+ }
1817
+ /**
1818
+ * Split a camelCase or PascalCase string into words.
1819
+ */
1820
+ function splitCamelCase(str) {
1821
+ return str.replace(/([a-z])([A-Z])/g, '$1 $2')
1822
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
1823
+ .split(/[\s._:\/\\]+/)
1824
+ .filter(w => w.length > 1);
1825
+ }
1826
+ /**
1827
+ * Compute directory proximity from a pre-split list of directory segments
1828
+ * (`filePath1` minus its filename) and a second file path.
1829
+ * Returns a score based on the number of shared leading directory segments.
1830
+ * Higher score = closer in directory tree.
1831
+ *
1832
+ * Split into a pre-split variant because findBestMatch scores every candidate
1833
+ * against the SAME `ref.filePath`; re-splitting it per candidate was a hot spot
1834
+ * on large repos (#915), so the caller splits it once and passes the segments.
1835
+ */
1836
+ function pathProximityFromDirs(dir1, filePath2) {
1837
+ const dir2 = filePath2.split('/');
1838
+ dir2.pop(); // drop filename — matches the original slice(0, -1) on both paths
1839
+ let shared = 0;
1840
+ const limit = Math.min(dir1.length, dir2.length);
1841
+ for (let i = 0; i < limit; i++) {
1842
+ if (dir1[i] === dir2[i]) {
1843
+ shared++;
1844
+ }
1845
+ else {
1846
+ break;
1847
+ }
1848
+ }
1849
+ // Each shared directory segment contributes 15 points, capped at 80
1850
+ return Math.min(shared * 15, 80);
1851
+ }
1852
+ /**
1853
+ * Compute directory proximity between two file paths.
1854
+ * Returns a score based on the number of shared directory segments.
1855
+ */
1856
+ function computePathProximity(filePath1, filePath2) {
1857
+ const dir1 = filePath1.split('/');
1858
+ dir1.pop();
1859
+ return pathProximityFromDirs(dir1, filePath2);
1860
+ }
1861
+ /**
1862
+ * Find the best matching node when there are multiple candidates
1863
+ */
1864
+ function findBestMatch(ref, candidates, _context) {
1865
+ // Prioritization rules:
1866
+ // 1. Same file > different file
1867
+ // 2. Directory proximity (same module/package > different module)
1868
+ // 3. Same language > different language
1869
+ // 4. Functions/methods > classes/types (for call references)
1870
+ // 5. Exported > non-exported
1871
+ let bestScore = -1;
1872
+ let bestNode = null;
1873
+ // Split the ref's path once (it's the same across every candidate) instead of
1874
+ // re-splitting it inside computePathProximity per candidate (#915 hot spot).
1875
+ const refDirs = ref.filePath.split('/');
1876
+ refDirs.pop();
1877
+ // A same-language candidate ALWAYS outscores a cross-language one: same-language
1878
+ // scores at least +50 (language bonus), while a cross-language candidate maxes
1879
+ // out at +35 (−80 language, +80 proximity, +25 kind, +10 exported; it can never
1880
+ // be in the same file). So when any same-language candidate exists, skip the
1881
+ // cross-language ones — provably the same winner, without paying the per-candidate
1882
+ // scoring. Cuts the candidate set to same-language size on mixed front-end +
1883
+ // back-end repos (#915). When ALL candidates are cross-language (a legitimate
1884
+ // cross-language `calls` bridge), none are skipped and behavior is unchanged.
1885
+ const hasSameLanguage = candidates.some((c) => c.language === ref.language);
1886
+ for (const candidate of candidates) {
1887
+ if (hasSameLanguage && candidate.language !== ref.language)
1888
+ continue;
1889
+ let score = 0;
1890
+ // Same file bonus
1891
+ if (candidate.filePath === ref.filePath) {
1892
+ score += 100;
1893
+ }
1894
+ // Directory proximity bonus — strongly prefer same module/package
1895
+ score += pathProximityFromDirs(refDirs, candidate.filePath);
1896
+ // Language matching: strongly prefer same language, penalize cross-language
1897
+ if (candidate.language === ref.language) {
1898
+ score += 50;
1899
+ }
1900
+ else {
1901
+ score -= 80;
1902
+ }
1903
+ // For call references, prefer functions/methods
1904
+ if (ref.referenceKind === 'calls') {
1905
+ if (candidate.kind === 'function' || candidate.kind === 'method') {
1906
+ score += 25;
1907
+ }
1908
+ }
1909
+ // For instantiation references (`new Foo()`), prefer class-like
1910
+ // targets — without this, a function named `Foo` in another module
1911
+ // could outscore the actual class.
1912
+ if (ref.referenceKind === 'instantiates') {
1913
+ if (candidate.kind === 'class' ||
1914
+ candidate.kind === 'struct' ||
1915
+ candidate.kind === 'union' ||
1916
+ candidate.kind === 'interface') {
1917
+ score += 25;
1918
+ }
1919
+ }
1920
+ // For decorator references (`@Foo`), prefer functions. Class
1921
+ // decorators (Python `@SomeClass`, Java annotation interfaces)
1922
+ // also resolve here, hence the smaller class bonus.
1923
+ if (ref.referenceKind === 'decorates') {
1924
+ if (candidate.kind === 'function' || candidate.kind === 'method') {
1925
+ score += 25;
1926
+ }
1927
+ else if (candidate.kind === 'class' || candidate.kind === 'interface') {
1928
+ score += 15;
1929
+ }
1930
+ }
1931
+ // Exported bonus
1932
+ if (candidate.isExported) {
1933
+ score += 10;
1934
+ }
1935
+ // Closer line number (within same file)
1936
+ if (candidate.filePath === ref.filePath && candidate.startLine) {
1937
+ const distance = Math.abs(candidate.startLine - ref.line);
1938
+ score += Math.max(0, 20 - distance / 10);
1939
+ }
1940
+ if (score > bestScore) {
1941
+ bestScore = score;
1942
+ bestNode = candidate;
1943
+ }
1944
+ }
1945
+ return bestNode;
1946
+ }
1947
+ /**
1948
+ * Fuzzy match - last resort with lower confidence
1949
+ */
1950
+ function matchFuzzy(ref, context) {
1951
+ const lowerName = ref.referenceName.toLowerCase();
1952
+ // Use pre-built lowercase index for O(1) lookup instead of scanning all nodes
1953
+ const candidates = context.getNodesByLowerName(lowerName);
1954
+ // Filter to callable kinds only (function, method, class)
1955
+ const callableKinds = new Set(['function', 'method', 'class']);
1956
+ const callableCandidates = applyLanguageGate(candidates.filter((n) => callableKinds.has(n.kind)), ref);
1957
+ // Prefer same-language matches
1958
+ const sameLanguageCandidates = callableCandidates.filter(n => n.language === ref.language);
1959
+ const finalCandidates = sameLanguageCandidates.length > 0 ? sameLanguageCandidates : callableCandidates;
1960
+ if (finalCandidates.length === 1) {
1961
+ const isCrossLanguage = finalCandidates[0].language !== ref.language;
1962
+ return {
1963
+ original: ref,
1964
+ targetNodeId: finalCandidates[0].id,
1965
+ confidence: isCrossLanguage ? 0.3 : 0.5,
1966
+ resolvedBy: 'fuzzy',
1967
+ };
1968
+ }
1969
+ return null;
1970
+ }
1971
+ /**
1972
+ * Match all strategies in order of confidence
1973
+ */
1974
+ /** ArkUI attribute-helper decorators a `.attr(...)` chain may resolve to. */
1975
+ const ARKUI_ATTRIBUTE_DECORATORS = new Set(['Extend', 'Styles', 'AnimatableExtend', 'Builder']);
1976
+ /**
1977
+ * CODEGRAPH_RESOLVE_PROFILE=2 sub-stage attribution for matchReference's
1978
+ * strategy pipeline (`nm:<stage>|<refKind>|hit/miss`). Module-global because
1979
+ * the matcher is a free function; each thread (main + every pool worker) has
1980
+ * its own module instance, and dumpNameMatcherProfile is invoked from
1981
+ * ReferenceResolver.dumpResolveProfile so worker tables surface too.
1982
+ */
1983
+ const NM_PROFILE = process.env.CODEGRAPH_RESOLVE_PROFILE === '2' ? new Map() : null;
1984
+ function nmTimedT(stage, ref, fn) {
1985
+ if (!NM_PROFILE)
1986
+ return fn();
1987
+ const t0 = process.hrtime.bigint();
1988
+ const r = fn();
1989
+ const dt = process.hrtime.bigint() - t0;
1990
+ const key = `nm:${stage}|${ref.referenceKind}|${r ? 'hit' : 'miss'}`;
1991
+ const slot = NM_PROFILE.get(key);
1992
+ if (slot) {
1993
+ slot.n++;
1994
+ slot.ns += dt;
1995
+ }
1996
+ else {
1997
+ NM_PROFILE.set(key, { n: 1, ns: dt });
1998
+ }
1999
+ return r;
2000
+ }
2001
+ function nmTimed(stage, ref, fn) {
2002
+ return nmTimedT(stage, ref, fn);
2003
+ }
2004
+ /** Dump this thread's matchReference sub-stage table to stderr (no-op unless =2). */
2005
+ function dumpNameMatcherProfile(label) {
2006
+ if (!NM_PROFILE || NM_PROFILE.size === 0)
2007
+ return;
2008
+ const rows = [...NM_PROFILE.entries()]
2009
+ .map(([k, v]) => ({ k, n: v.n, ms: Number(v.ns / 1000000n) }))
2010
+ .sort((a, b) => b.ms - a.ms);
2011
+ for (const r of rows) {
2012
+ console.error(`[resolve-profile] ${label} ${r.k}: n=${r.n} total=${(r.ms / 1000).toFixed(1)}s avg=${((r.ms * 1000) / Math.max(1, r.n)).toFixed(0)}µs`);
2013
+ }
2014
+ }
2015
+ function matchReference(ref, context) {
2016
+ // Function-as-value refs (#756) resolve ONLY through the dedicated matcher —
2017
+ // never the fuzzy/qualified fallthrough below (a wrong callback edge is
2018
+ // worse than none).
2019
+ if (ref.referenceKind === 'function_ref') {
2020
+ return matchFunctionRef(ref, context);
2021
+ }
2022
+ // ArkTS chained UI attributes — emitted with a leading dot (`.titleStyle`,
2023
+ // `.width`) by the extractor — resolve ONLY to decorator-marked attribute
2024
+ // helpers: `@Extend`/`@Styles`/`@AnimatableExtend` functions (and global
2025
+ // `@Builder`s used attribute-position). Framework attributes (`.width`,
2026
+ // `.fontSize` — on nearly every UI line) match no such helper and stay
2027
+ // unresolved, NEVER falling through to bare-name matching: on a samples
2028
+ // monorepo that fallthrough manufactured 36k wrong edges, giving single
2029
+ // same-named properties thousands of false callers. Ambiguity rule matches
2030
+ // the rest of the file: several same-named helpers → prefer the call-site
2031
+ // file, still ambiguous → drop the ref rather than guess.
2032
+ if (ref.language === 'arkts' && ref.referenceName.startsWith('.')) {
2033
+ const base = ref.referenceName.slice(1);
2034
+ const candidates = context
2035
+ .getNodesByName(base)
2036
+ .filter((n) => n.language === 'arkts' &&
2037
+ n.kind === 'function' &&
2038
+ (n.decorators ?? []).some((d) => ARKUI_ATTRIBUTE_DECORATORS.has(d)));
2039
+ const chosen = candidates.length > 1 ? preferCallSiteFile(candidates, ref.filePath) : candidates;
2040
+ if (chosen.length !== 1)
2041
+ return null;
2042
+ return {
2043
+ original: ref,
2044
+ targetNodeId: chosen[0].id,
2045
+ confidence: 0.85,
2046
+ resolvedBy: 'exact-match',
2047
+ };
2048
+ }
2049
+ // Erlang `-behaviour(m)` refs target a MODULE. Letting them fall through to
2050
+ // bare-name matching grabs any same-named symbol — on emqx,
2051
+ // `-behaviour(supervisor)` resolved to a `-define(supervisor, …)` macro
2052
+ // constant in an unrelated app. Resolve only to the behaviour module's
2053
+ // namespace; an out-of-repo behaviour (OTP's gen_server/supervisor) stays
2054
+ // unresolved rather than guessed. The same module-only rule applies to every
2055
+ // ref an `.app`/`.app.src` resource file emits — its `{mod, …}` callback and
2056
+ // `{applications, …}` dependency names can only mean modules, and on emqx
2057
+ // the `ssl` OTP app otherwise resolved to a test helper FUNCTION named ssl.
2058
+ if (ref.language === 'erlang' &&
2059
+ (ref.referenceKind === 'implements' || /\.app(?:\.src)?$/i.test(ref.filePath))) {
2060
+ const modules = context
2061
+ .getNodesByName(ref.referenceName)
2062
+ .filter((n) => n.language === 'erlang' && n.kind === 'namespace');
2063
+ const chosen = preferCallSiteFile(modules, ref.filePath)[0];
2064
+ if (!chosen)
2065
+ return null;
2066
+ return {
2067
+ original: ref,
2068
+ targetNodeId: chosen.id,
2069
+ confidence: 0.9,
2070
+ resolvedBy: 'exact-match',
2071
+ };
2072
+ }
2073
+ // Try strategies in order of confidence
2074
+ let result;
2075
+ // 0. File path match (e.g., "snippets/drawer-menu.liquid" → file node)
2076
+ result = nmTimed('filePath', ref, () => matchByFilePath(ref, context));
2077
+ if (result)
2078
+ return result;
2079
+ // 1. Qualified name match (highest confidence)
2080
+ result = nmTimed('qualifiedName', ref, () => matchByQualifiedName(ref, context));
2081
+ if (result)
2082
+ return result;
2083
+ // 1b. C++ chained call whose receiver is another call — `Foo::instance().bar()`
2084
+ // encoded as `Foo::instance().bar` by the extractor (#645). Resolve the
2085
+ // receiver's type from what the inner call returns, then the method on it.
2086
+ if (ref.language === 'cpp' || ref.language === 'c') {
2087
+ result = nmTimed('cppChain', ref, () => matchCppCallChain(ref, context));
2088
+ if (result)
2089
+ return result;
2090
+ }
2091
+ // 1c. `::`-scoped factory chain — PHP `Cls::for($x)->method()` (#608) or Rust
2092
+ // `Foo::new().bar()`, both encoded as `Cls::factory().method`. The receiver's
2093
+ // type is the factory's `self` (PHP `: self`/`: static`, Rust `-> Self`) or
2094
+ // concrete return type.
2095
+ if (ref.language === 'php' || ref.language === 'rust') {
2096
+ result = nmTimed('scopedChain', ref, () => matchScopedCallChain(ref, context));
2097
+ if (result)
2098
+ return result;
2099
+ }
2100
+ // 1d. Dotted chained static-factory / fluent call (Java / Kotlin / C# / Swift /
2101
+ // Go / Scala / Dart / Objective-C) — `Foo.getInstance().bar()` encoded as
2102
+ // `Foo.getInstance().bar`, Go's bare-factory `New().Method()` as `New().Method`,
2103
+ // Scala's companion factory, Dart's static factory / factory-constructor, or
2104
+ // ObjC's chained message send `[[Foo create] doIt]` encoded as `Foo.create().doIt`
2105
+ // (#645/#608 mechanism). Resolve the method's class from the inner call's
2106
+ // declared return type, then validate it.
2107
+ if (ref.language === 'java' ||
2108
+ ref.language === 'kotlin' ||
2109
+ ref.language === 'csharp' ||
2110
+ ref.language === 'swift' ||
2111
+ ref.language === 'go' ||
2112
+ ref.language === 'scala' ||
2113
+ ref.language === 'dart' ||
2114
+ ref.language === 'objc' ||
2115
+ ref.language === 'pascal') {
2116
+ result = nmTimed('dottedChain', ref, () => matchDottedCallChain(ref, context));
2117
+ if (result)
2118
+ return result;
2119
+ }
2120
+ // 2. Method call pattern
2121
+ result = nmTimed('methodCall', ref, () => matchMethodCall(ref, context));
2122
+ if (result)
2123
+ return result;
2124
+ // 3. Exact name match
2125
+ result = nmTimed('exactName', ref, () => matchByExactName(ref, context));
2126
+ if (result)
2127
+ return result;
2128
+ // 4. Fuzzy match (lowest confidence)
2129
+ result = nmTimed('fuzzy', ref, () => matchFuzzy(ref, context));
2130
+ if (result)
2131
+ return result;
2132
+ return null;
2133
+ }
2134
+ //# sourceMappingURL=name-matcher.js.map