@quolu/lattice 0.70.0 → 0.71.1

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 (603) hide show
  1. package/bin/lattice.mjs +21 -0
  2. package/package.json +1 -1
  3. package/sensor/dist/bin/lattice-sensor.js +746 -323
  4. package/sensor/dist/bin/viewer-gate.d.ts +17 -0
  5. package/sensor/dist/bin/viewer-gate.d.ts.map +1 -0
  6. package/sensor/dist/bin/viewer-gate.js +31 -0
  7. package/sensor/dist/bin/viewer-gate.js.map +1 -0
  8. package/sensor/dist/context/formatter.d.ts +7 -1
  9. package/sensor/dist/context/formatter.d.ts.map +1 -1
  10. package/sensor/dist/context/formatter.js +12 -6
  11. package/sensor/dist/context/formatter.js.map +1 -1
  12. package/sensor/dist/context/index.d.ts +12 -0
  13. package/sensor/dist/context/index.d.ts.map +1 -1
  14. package/sensor/dist/context/index.js +103 -16
  15. package/sensor/dist/context/index.js.map +1 -1
  16. package/sensor/dist/db/index.d.ts +23 -2
  17. package/sensor/dist/db/index.d.ts.map +1 -1
  18. package/sensor/dist/db/index.js +109 -31
  19. package/sensor/dist/db/index.js.map +1 -1
  20. package/sensor/dist/db/migrations.d.ts +1 -1
  21. package/sensor/dist/db/migrations.d.ts.map +1 -1
  22. package/sensor/dist/db/migrations.js +68 -1
  23. package/sensor/dist/db/migrations.js.map +1 -1
  24. package/sensor/dist/db/queries.d.ts +583 -6
  25. package/sensor/dist/db/queries.d.ts.map +1 -1
  26. package/sensor/dist/db/queries.js +1425 -57
  27. package/sensor/dist/db/queries.js.map +1 -1
  28. package/sensor/dist/db/schema.sql +27 -4
  29. package/sensor/dist/db/sqlite-adapter.d.ts +2 -0
  30. package/sensor/dist/db/sqlite-adapter.d.ts.map +1 -1
  31. package/sensor/dist/db/sqlite-adapter.js +56 -7
  32. package/sensor/dist/db/sqlite-adapter.js.map +1 -1
  33. package/sensor/dist/db/synthesis-stage.d.ts +12 -0
  34. package/sensor/dist/db/synthesis-stage.d.ts.map +1 -0
  35. package/sensor/dist/db/synthesis-stage.js +93 -0
  36. package/sensor/dist/db/synthesis-stage.js.map +1 -0
  37. package/sensor/dist/db/wal-valve.d.ts +32 -12
  38. package/sensor/dist/db/wal-valve.d.ts.map +1 -1
  39. package/sensor/dist/db/wal-valve.js +65 -22
  40. package/sensor/dist/db/wal-valve.js.map +1 -1
  41. package/sensor/dist/db/wsl-shared-index.d.ts +53 -0
  42. package/sensor/dist/db/wsl-shared-index.d.ts.map +1 -0
  43. package/sensor/dist/db/wsl-shared-index.js +121 -0
  44. package/sensor/dist/db/wsl-shared-index.js.map +1 -0
  45. package/sensor/dist/directory.d.ts +126 -2
  46. package/sensor/dist/directory.d.ts.map +1 -1
  47. package/sensor/dist/directory.js +285 -16
  48. package/sensor/dist/directory.js.map +1 -1
  49. package/sensor/dist/errors.d.ts +14 -0
  50. package/sensor/dist/errors.d.ts.map +1 -1
  51. package/sensor/dist/errors.js +16 -1
  52. package/sensor/dist/errors.js.map +1 -1
  53. package/sensor/dist/extraction/cfml-extractor.d.ts +1 -0
  54. package/sensor/dist/extraction/cfml-extractor.d.ts.map +1 -1
  55. package/sensor/dist/extraction/cfml-extractor.js +15 -3
  56. package/sensor/dist/extraction/cfml-extractor.js.map +1 -1
  57. package/sensor/dist/extraction/dfm-extractor.d.ts.map +1 -1
  58. package/sensor/dist/extraction/dfm-extractor.js +14 -10
  59. package/sensor/dist/extraction/dfm-extractor.js.map +1 -1
  60. package/sensor/dist/extraction/extraction-version.d.ts +1 -1
  61. package/sensor/dist/extraction/extraction-version.d.ts.map +1 -1
  62. package/sensor/dist/extraction/extraction-version.js +3 -1
  63. package/sensor/dist/extraction/extraction-version.js.map +1 -1
  64. package/sensor/dist/extraction/function-ref.d.ts +6 -4
  65. package/sensor/dist/extraction/function-ref.d.ts.map +1 -1
  66. package/sensor/dist/extraction/function-ref.js +35 -14
  67. package/sensor/dist/extraction/function-ref.js.map +1 -1
  68. package/sensor/dist/extraction/generated-detection.d.ts +48 -12
  69. package/sensor/dist/extraction/generated-detection.d.ts.map +1 -1
  70. package/sensor/dist/extraction/generated-detection.js +176 -11
  71. package/sensor/dist/extraction/generated-detection.js.map +1 -1
  72. package/sensor/dist/extraction/grammars.d.ts +38 -0
  73. package/sensor/dist/extraction/grammars.d.ts.map +1 -1
  74. package/sensor/dist/extraction/grammars.js +115 -3
  75. package/sensor/dist/extraction/grammars.js.map +1 -1
  76. package/sensor/dist/extraction/index.d.ts +218 -14
  77. package/sensor/dist/extraction/index.d.ts.map +1 -1
  78. package/sensor/dist/extraction/index.js +887 -175
  79. package/sensor/dist/extraction/index.js.map +1 -1
  80. package/sensor/dist/extraction/languages/c-cpp.d.ts +58 -0
  81. package/sensor/dist/extraction/languages/c-cpp.d.ts.map +1 -1
  82. package/sensor/dist/extraction/languages/c-cpp.js +310 -19
  83. package/sensor/dist/extraction/languages/c-cpp.js.map +1 -1
  84. package/sensor/dist/extraction/languages/dart.d.ts.map +1 -1
  85. package/sensor/dist/extraction/languages/dart.js +8 -3
  86. package/sensor/dist/extraction/languages/dart.js.map +1 -1
  87. package/sensor/dist/extraction/languages/erlang.d.ts.map +1 -1
  88. package/sensor/dist/extraction/languages/erlang.js +58 -22
  89. package/sensor/dist/extraction/languages/erlang.js.map +1 -1
  90. package/sensor/dist/extraction/languages/javascript.js +1 -1
  91. package/sensor/dist/extraction/languages/javascript.js.map +1 -1
  92. package/sensor/dist/extraction/languages/kotlin.d.ts.map +1 -1
  93. package/sensor/dist/extraction/languages/kotlin.js +169 -36
  94. package/sensor/dist/extraction/languages/kotlin.js.map +1 -1
  95. package/sensor/dist/extraction/languages/lua.d.ts.map +1 -1
  96. package/sensor/dist/extraction/languages/lua.js +4 -1
  97. package/sensor/dist/extraction/languages/lua.js.map +1 -1
  98. package/sensor/dist/extraction/languages/objc.d.ts.map +1 -1
  99. package/sensor/dist/extraction/languages/objc.js +4 -0
  100. package/sensor/dist/extraction/languages/objc.js.map +1 -1
  101. package/sensor/dist/extraction/languages/python.d.ts.map +1 -1
  102. package/sensor/dist/extraction/languages/python.js +71 -0
  103. package/sensor/dist/extraction/languages/python.js.map +1 -1
  104. package/sensor/dist/extraction/languages/rust.d.ts +20 -0
  105. package/sensor/dist/extraction/languages/rust.d.ts.map +1 -1
  106. package/sensor/dist/extraction/languages/rust.js +50 -20
  107. package/sensor/dist/extraction/languages/rust.js.map +1 -1
  108. package/sensor/dist/extraction/languages/scala.d.ts.map +1 -1
  109. package/sensor/dist/extraction/languages/scala.js +18 -3
  110. package/sensor/dist/extraction/languages/scala.js.map +1 -1
  111. package/sensor/dist/extraction/languages/swift.d.ts +15 -0
  112. package/sensor/dist/extraction/languages/swift.d.ts.map +1 -1
  113. package/sensor/dist/extraction/languages/swift.js +50 -0
  114. package/sensor/dist/extraction/languages/swift.js.map +1 -1
  115. package/sensor/dist/extraction/languages/typescript.d.ts.map +1 -1
  116. package/sensor/dist/extraction/languages/typescript.js +9 -2
  117. package/sensor/dist/extraction/languages/typescript.js.map +1 -1
  118. package/sensor/dist/extraction/liquid-extractor.d.ts +18 -0
  119. package/sensor/dist/extraction/liquid-extractor.d.ts.map +1 -1
  120. package/sensor/dist/extraction/liquid-extractor.js +98 -22
  121. package/sensor/dist/extraction/liquid-extractor.js.map +1 -1
  122. package/sensor/dist/extraction/mybatis-extractor.d.ts.map +1 -1
  123. package/sensor/dist/extraction/mybatis-extractor.js +6 -4
  124. package/sensor/dist/extraction/mybatis-extractor.js.map +1 -1
  125. package/sensor/dist/extraction/parse-pool.d.ts +7 -0
  126. package/sensor/dist/extraction/parse-pool.d.ts.map +1 -1
  127. package/sensor/dist/extraction/parse-pool.js +20 -1
  128. package/sensor/dist/extraction/parse-pool.js.map +1 -1
  129. package/sensor/dist/extraction/syntax-tokens.d.ts +103 -0
  130. package/sensor/dist/extraction/syntax-tokens.d.ts.map +1 -0
  131. package/sensor/dist/extraction/syntax-tokens.js +381 -0
  132. package/sensor/dist/extraction/syntax-tokens.js.map +1 -0
  133. package/sensor/dist/extraction/tree-sitter-helpers.d.ts +5 -0
  134. package/sensor/dist/extraction/tree-sitter-helpers.d.ts.map +1 -1
  135. package/sensor/dist/extraction/tree-sitter-helpers.js +17 -0
  136. package/sensor/dist/extraction/tree-sitter-helpers.js.map +1 -1
  137. package/sensor/dist/extraction/tree-sitter-types.d.ts +31 -3
  138. package/sensor/dist/extraction/tree-sitter-types.d.ts.map +1 -1
  139. package/sensor/dist/extraction/tree-sitter.d.ts +101 -18
  140. package/sensor/dist/extraction/tree-sitter.d.ts.map +1 -1
  141. package/sensor/dist/extraction/tree-sitter.js +928 -134
  142. package/sensor/dist/extraction/tree-sitter.js.map +1 -1
  143. package/sensor/dist/extraction/wasm/tree-sitter-scala.wasm +0 -0
  144. package/sensor/dist/file-limits.d.ts +40 -0
  145. package/sensor/dist/file-limits.d.ts.map +1 -0
  146. package/sensor/dist/file-limits.js +147 -0
  147. package/sensor/dist/file-limits.js.map +1 -0
  148. package/sensor/dist/graph/branch-guards.d.ts +265 -0
  149. package/sensor/dist/graph/branch-guards.d.ts.map +1 -0
  150. package/sensor/dist/graph/branch-guards.js +2325 -0
  151. package/sensor/dist/graph/branch-guards.js.map +1 -0
  152. package/sensor/dist/graph/dead-code.d.ts +251 -0
  153. package/sensor/dist/graph/dead-code.d.ts.map +1 -0
  154. package/sensor/dist/graph/dead-code.js +776 -0
  155. package/sensor/dist/graph/dead-code.js.map +1 -0
  156. package/sensor/dist/graph/dynamic-boundary-report.d.ts +121 -0
  157. package/sensor/dist/graph/dynamic-boundary-report.d.ts.map +1 -0
  158. package/sensor/dist/graph/dynamic-boundary-report.js +283 -0
  159. package/sensor/dist/graph/dynamic-boundary-report.js.map +1 -0
  160. package/sensor/dist/graph/index.d.ts +4 -0
  161. package/sensor/dist/graph/index.d.ts.map +1 -1
  162. package/sensor/dist/graph/index.js +16 -1
  163. package/sensor/dist/graph/index.js.map +1 -1
  164. package/sensor/dist/graph/named-symbol-flow.d.ts +125 -0
  165. package/sensor/dist/graph/named-symbol-flow.d.ts.map +1 -0
  166. package/sensor/dist/graph/named-symbol-flow.js +552 -0
  167. package/sensor/dist/graph/named-symbol-flow.js.map +1 -0
  168. package/sensor/dist/graph/queries.d.ts.map +1 -1
  169. package/sensor/dist/graph/queries.js +2 -0
  170. package/sensor/dist/graph/queries.js.map +1 -1
  171. package/sensor/dist/graph/symbol-lookup.d.ts +83 -0
  172. package/sensor/dist/graph/symbol-lookup.d.ts.map +1 -0
  173. package/sensor/dist/graph/symbol-lookup.js +181 -0
  174. package/sensor/dist/graph/symbol-lookup.js.map +1 -0
  175. package/sensor/dist/graph/traversal.d.ts +9 -0
  176. package/sensor/dist/graph/traversal.d.ts.map +1 -1
  177. package/sensor/dist/graph/traversal.js +62 -36
  178. package/sensor/dist/graph/traversal.js.map +1 -1
  179. package/sensor/dist/graph/type-hierarchy.d.ts +155 -0
  180. package/sensor/dist/graph/type-hierarchy.d.ts.map +1 -0
  181. package/sensor/dist/graph/type-hierarchy.js +382 -0
  182. package/sensor/dist/graph/type-hierarchy.js.map +1 -0
  183. package/sensor/dist/index.d.ts +272 -10
  184. package/sensor/dist/index.d.ts.map +1 -1
  185. package/sensor/dist/index.js +510 -34
  186. package/sensor/dist/index.js.map +1 -1
  187. package/sensor/dist/mcp/answer-freshness.d.ts +10 -0
  188. package/sensor/dist/mcp/answer-freshness.d.ts.map +1 -0
  189. package/sensor/dist/mcp/answer-freshness.js +68 -0
  190. package/sensor/dist/mcp/answer-freshness.js.map +1 -0
  191. package/sensor/dist/mcp/daemon-manager.d.ts +1 -1
  192. package/sensor/dist/mcp/daemon-manager.d.ts.map +1 -1
  193. package/sensor/dist/mcp/daemon-manager.js +17 -1
  194. package/sensor/dist/mcp/daemon-manager.js.map +1 -1
  195. package/sensor/dist/mcp/daemon-paths.d.ts +8 -0
  196. package/sensor/dist/mcp/daemon-paths.d.ts.map +1 -1
  197. package/sensor/dist/mcp/daemon-paths.js +65 -2
  198. package/sensor/dist/mcp/daemon-paths.js.map +1 -1
  199. package/sensor/dist/mcp/daemon-registry.d.ts +17 -4
  200. package/sensor/dist/mcp/daemon-registry.d.ts.map +1 -1
  201. package/sensor/dist/mcp/daemon-registry.js +133 -23
  202. package/sensor/dist/mcp/daemon-registry.js.map +1 -1
  203. package/sensor/dist/mcp/daemon.d.ts +26 -13
  204. package/sensor/dist/mcp/daemon.d.ts.map +1 -1
  205. package/sensor/dist/mcp/daemon.js +126 -32
  206. package/sensor/dist/mcp/daemon.js.map +1 -1
  207. package/sensor/dist/mcp/dynamic-boundaries.d.ts +1 -10
  208. package/sensor/dist/mcp/dynamic-boundaries.d.ts.map +1 -1
  209. package/sensor/dist/mcp/dynamic-boundaries.js +46 -42
  210. package/sensor/dist/mcp/dynamic-boundaries.js.map +1 -1
  211. package/sensor/dist/mcp/engine.d.ts +31 -9
  212. package/sensor/dist/mcp/engine.d.ts.map +1 -1
  213. package/sensor/dist/mcp/engine.js +190 -79
  214. package/sensor/dist/mcp/engine.js.map +1 -1
  215. package/sensor/dist/mcp/explore-dedup.d.ts +140 -0
  216. package/sensor/dist/mcp/explore-dedup.d.ts.map +1 -0
  217. package/sensor/dist/mcp/explore-dedup.js +239 -0
  218. package/sensor/dist/mcp/explore-dedup.js.map +1 -0
  219. package/sensor/dist/mcp/explore-diagnostics.d.ts +289 -0
  220. package/sensor/dist/mcp/explore-diagnostics.d.ts.map +1 -0
  221. package/sensor/dist/mcp/explore-diagnostics.js +558 -0
  222. package/sensor/dist/mcp/explore-diagnostics.js.map +1 -0
  223. package/sensor/dist/mcp/explore-session-state.d.ts +217 -0
  224. package/sensor/dist/mcp/explore-session-state.d.ts.map +1 -0
  225. package/sensor/dist/mcp/explore-session-state.js +322 -0
  226. package/sensor/dist/mcp/explore-session-state.js.map +1 -0
  227. package/sensor/dist/mcp/index-freshness-worker.d.ts +2 -0
  228. package/sensor/dist/mcp/index-freshness-worker.d.ts.map +1 -0
  229. package/sensor/dist/mcp/index-freshness-worker.js +30 -0
  230. package/sensor/dist/mcp/index-freshness-worker.js.map +1 -0
  231. package/sensor/dist/mcp/index-freshness.d.ts +7 -0
  232. package/sensor/dist/mcp/index-freshness.d.ts.map +1 -0
  233. package/sensor/dist/mcp/index-freshness.js +94 -0
  234. package/sensor/dist/mcp/index-freshness.js.map +1 -0
  235. package/sensor/dist/mcp/index.d.ts +3 -1
  236. package/sensor/dist/mcp/index.d.ts.map +1 -1
  237. package/sensor/dist/mcp/index.js +109 -12
  238. package/sensor/dist/mcp/index.js.map +1 -1
  239. package/sensor/dist/mcp/liveness-watchdog.d.ts +4 -1
  240. package/sensor/dist/mcp/liveness-watchdog.d.ts.map +1 -1
  241. package/sensor/dist/mcp/liveness-watchdog.js +11 -2
  242. package/sensor/dist/mcp/liveness-watchdog.js.map +1 -1
  243. package/sensor/dist/mcp/project-lifecycle.d.ts +9 -0
  244. package/sensor/dist/mcp/project-lifecycle.d.ts.map +1 -0
  245. package/sensor/dist/mcp/project-lifecycle.js +182 -0
  246. package/sensor/dist/mcp/project-lifecycle.js.map +1 -0
  247. package/sensor/dist/mcp/proxy.d.ts.map +1 -1
  248. package/sensor/dist/mcp/proxy.js +15 -1
  249. package/sensor/dist/mcp/proxy.js.map +1 -1
  250. package/sensor/dist/mcp/query-pool.d.ts +2 -2
  251. package/sensor/dist/mcp/query-pool.d.ts.map +1 -1
  252. package/sensor/dist/mcp/query-pool.js +9 -7
  253. package/sensor/dist/mcp/query-pool.js.map +1 -1
  254. package/sensor/dist/mcp/query-worker.js +2 -2
  255. package/sensor/dist/mcp/query-worker.js.map +1 -1
  256. package/sensor/dist/mcp/server-instructions.d.ts +2 -2
  257. package/sensor/dist/mcp/server-instructions.d.ts.map +1 -1
  258. package/sensor/dist/mcp/server-instructions.js +13 -6
  259. package/sensor/dist/mcp/server-instructions.js.map +1 -1
  260. package/sensor/dist/mcp/session.d.ts +16 -0
  261. package/sensor/dist/mcp/session.d.ts.map +1 -1
  262. package/sensor/dist/mcp/session.js +36 -13
  263. package/sensor/dist/mcp/session.js.map +1 -1
  264. package/sensor/dist/mcp/startup-handshake.d.ts +3 -1
  265. package/sensor/dist/mcp/startup-handshake.d.ts.map +1 -1
  266. package/sensor/dist/mcp/startup-handshake.js +10 -2
  267. package/sensor/dist/mcp/startup-handshake.js.map +1 -1
  268. package/sensor/dist/mcp/tools.d.ts +496 -38
  269. package/sensor/dist/mcp/tools.d.ts.map +1 -1
  270. package/sensor/dist/mcp/tools.js +4021 -772
  271. package/sensor/dist/mcp/tools.js.map +1 -1
  272. package/sensor/dist/mcp/writer-lock.d.ts +61 -0
  273. package/sensor/dist/mcp/writer-lock.d.ts.map +1 -0
  274. package/sensor/dist/mcp/writer-lock.js +260 -0
  275. package/sensor/dist/mcp/writer-lock.js.map +1 -0
  276. package/sensor/dist/project-config.d.ts +23 -0
  277. package/sensor/dist/project-config.d.ts.map +1 -1
  278. package/sensor/dist/project-config.js +39 -2
  279. package/sensor/dist/project-config.js.map +1 -1
  280. package/sensor/dist/resolution/alias-binding.d.ts +56 -0
  281. package/sensor/dist/resolution/alias-binding.d.ts.map +1 -0
  282. package/sensor/dist/resolution/alias-binding.js +127 -0
  283. package/sensor/dist/resolution/alias-binding.js.map +1 -0
  284. package/sensor/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -1
  285. package/sensor/dist/resolution/c-fnptr-synthesizer.js +21 -19
  286. package/sensor/dist/resolution/c-fnptr-synthesizer.js.map +1 -1
  287. package/sensor/dist/resolution/callback-synthesizer.d.ts +23 -1
  288. package/sensor/dist/resolution/callback-synthesizer.d.ts.map +1 -1
  289. package/sensor/dist/resolution/callback-synthesizer.js +356 -155
  290. package/sensor/dist/resolution/callback-synthesizer.js.map +1 -1
  291. package/sensor/dist/resolution/cpp-constructor.d.ts +4 -0
  292. package/sensor/dist/resolution/cpp-constructor.d.ts.map +1 -0
  293. package/sensor/dist/resolution/cpp-constructor.js +123 -0
  294. package/sensor/dist/resolution/cpp-constructor.js.map +1 -0
  295. package/sensor/dist/resolution/cpp-macro-visibility.d.ts +12 -0
  296. package/sensor/dist/resolution/cpp-macro-visibility.d.ts.map +1 -0
  297. package/sensor/dist/resolution/cpp-macro-visibility.js +342 -0
  298. package/sensor/dist/resolution/cpp-macro-visibility.js.map +1 -0
  299. package/sensor/dist/resolution/expo-router-synthesizer.d.ts +32 -0
  300. package/sensor/dist/resolution/expo-router-synthesizer.d.ts.map +1 -0
  301. package/sensor/dist/resolution/expo-router-synthesizer.js +189 -0
  302. package/sensor/dist/resolution/expo-router-synthesizer.js.map +1 -0
  303. package/sensor/dist/resolution/frameworks/csharp.d.ts.map +1 -1
  304. package/sensor/dist/resolution/frameworks/csharp.js +96 -2
  305. package/sensor/dist/resolution/frameworks/csharp.js.map +1 -1
  306. package/sensor/dist/resolution/frameworks/expo-router.d.ts +189 -0
  307. package/sensor/dist/resolution/frameworks/expo-router.d.ts.map +1 -0
  308. package/sensor/dist/resolution/frameworks/expo-router.js +785 -0
  309. package/sensor/dist/resolution/frameworks/expo-router.js.map +1 -0
  310. package/sensor/dist/resolution/frameworks/express.d.ts.map +1 -1
  311. package/sensor/dist/resolution/frameworks/express.js +251 -16
  312. package/sensor/dist/resolution/frameworks/express.js.map +1 -1
  313. package/sensor/dist/resolution/frameworks/index.d.ts +5 -0
  314. package/sensor/dist/resolution/frameworks/index.d.ts.map +1 -1
  315. package/sensor/dist/resolution/frameworks/index.js +29 -1
  316. package/sensor/dist/resolution/frameworks/index.js.map +1 -1
  317. package/sensor/dist/resolution/frameworks/java.d.ts.map +1 -1
  318. package/sensor/dist/resolution/frameworks/java.js +79 -47
  319. package/sensor/dist/resolution/frameworks/java.js.map +1 -1
  320. package/sensor/dist/resolution/frameworks/laravel.d.ts.map +1 -1
  321. package/sensor/dist/resolution/frameworks/laravel.js +294 -4
  322. package/sensor/dist/resolution/frameworks/laravel.js.map +1 -1
  323. package/sensor/dist/resolution/frameworks/nestjs.d.ts.map +1 -1
  324. package/sensor/dist/resolution/frameworks/nestjs.js +6 -14
  325. package/sensor/dist/resolution/frameworks/nestjs.js.map +1 -1
  326. package/sensor/dist/resolution/frameworks/nextjs.d.ts +76 -0
  327. package/sensor/dist/resolution/frameworks/nextjs.d.ts.map +1 -0
  328. package/sensor/dist/resolution/frameworks/nextjs.js +328 -0
  329. package/sensor/dist/resolution/frameworks/nextjs.js.map +1 -0
  330. package/sensor/dist/resolution/frameworks/object-literal.d.ts +32 -0
  331. package/sensor/dist/resolution/frameworks/object-literal.d.ts.map +1 -0
  332. package/sensor/dist/resolution/frameworks/object-literal.js +139 -0
  333. package/sensor/dist/resolution/frameworks/object-literal.js.map +1 -0
  334. package/sensor/dist/resolution/frameworks/package-deps.d.ts +14 -0
  335. package/sensor/dist/resolution/frameworks/package-deps.d.ts.map +1 -0
  336. package/sensor/dist/resolution/frameworks/package-deps.js +78 -0
  337. package/sensor/dist/resolution/frameworks/package-deps.js.map +1 -0
  338. package/sensor/dist/resolution/frameworks/python.d.ts.map +1 -1
  339. package/sensor/dist/resolution/frameworks/python.js +166 -0
  340. package/sensor/dist/resolution/frameworks/python.js.map +1 -1
  341. package/sensor/dist/resolution/frameworks/react-native.d.ts +26 -0
  342. package/sensor/dist/resolution/frameworks/react-native.d.ts.map +1 -1
  343. package/sensor/dist/resolution/frameworks/react-native.js +153 -14
  344. package/sensor/dist/resolution/frameworks/react-native.js.map +1 -1
  345. package/sensor/dist/resolution/frameworks/react-router.d.ts +46 -0
  346. package/sensor/dist/resolution/frameworks/react-router.d.ts.map +1 -0
  347. package/sensor/dist/resolution/frameworks/react-router.js +187 -0
  348. package/sensor/dist/resolution/frameworks/react-router.js.map +1 -0
  349. package/sensor/dist/resolution/frameworks/react.d.ts +2 -1
  350. package/sensor/dist/resolution/frameworks/react.d.ts.map +1 -1
  351. package/sensor/dist/resolution/frameworks/react.js +188 -139
  352. package/sensor/dist/resolution/frameworks/react.js.map +1 -1
  353. package/sensor/dist/resolution/frameworks/svelte.d.ts.map +1 -1
  354. package/sensor/dist/resolution/frameworks/svelte.js +6 -1
  355. package/sensor/dist/resolution/frameworks/svelte.js.map +1 -1
  356. package/sensor/dist/resolution/frameworks/sveltekit-router.d.ts +36 -0
  357. package/sensor/dist/resolution/frameworks/sveltekit-router.d.ts.map +1 -0
  358. package/sensor/dist/resolution/frameworks/sveltekit-router.js +156 -0
  359. package/sensor/dist/resolution/frameworks/sveltekit-router.js.map +1 -0
  360. package/sensor/dist/resolution/frameworks/swift.d.ts.map +1 -1
  361. package/sensor/dist/resolution/frameworks/swift.js +140 -99
  362. package/sensor/dist/resolution/frameworks/swift.js.map +1 -1
  363. package/sensor/dist/resolution/frameworks/tanstack-router.d.ts +84 -0
  364. package/sensor/dist/resolution/frameworks/tanstack-router.d.ts.map +1 -0
  365. package/sensor/dist/resolution/frameworks/tanstack-router.js +437 -0
  366. package/sensor/dist/resolution/frameworks/tanstack-router.js.map +1 -0
  367. package/sensor/dist/resolution/frameworks/vue-router.d.ts +82 -0
  368. package/sensor/dist/resolution/frameworks/vue-router.d.ts.map +1 -0
  369. package/sensor/dist/resolution/frameworks/vue-router.js +377 -0
  370. package/sensor/dist/resolution/frameworks/vue-router.js.map +1 -0
  371. package/sensor/dist/resolution/import-resolver.d.ts +38 -0
  372. package/sensor/dist/resolution/import-resolver.d.ts.map +1 -1
  373. package/sensor/dist/resolution/import-resolver.js +394 -28
  374. package/sensor/dist/resolution/import-resolver.js.map +1 -1
  375. package/sensor/dist/resolution/index.d.ts +89 -25
  376. package/sensor/dist/resolution/index.d.ts.map +1 -1
  377. package/sensor/dist/resolution/index.js +573 -148
  378. package/sensor/dist/resolution/index.js.map +1 -1
  379. package/sensor/dist/resolution/js-builtins.d.ts +13 -0
  380. package/sensor/dist/resolution/js-builtins.d.ts.map +1 -0
  381. package/sensor/dist/resolution/js-builtins.js +46 -0
  382. package/sensor/dist/resolution/js-builtins.js.map +1 -0
  383. package/sensor/dist/resolution/name-matcher.d.ts +99 -22
  384. package/sensor/dist/resolution/name-matcher.d.ts.map +1 -1
  385. package/sensor/dist/resolution/name-matcher.js +2220 -86
  386. package/sensor/dist/resolution/name-matcher.js.map +1 -1
  387. package/sensor/dist/resolution/next-router-synthesizer.d.ts +27 -0
  388. package/sensor/dist/resolution/next-router-synthesizer.d.ts.map +1 -0
  389. package/sensor/dist/resolution/next-router-synthesizer.js +113 -0
  390. package/sensor/dist/resolution/next-router-synthesizer.js.map +1 -0
  391. package/sensor/dist/resolution/path-aliases.d.ts +6 -4
  392. package/sensor/dist/resolution/path-aliases.d.ts.map +1 -1
  393. package/sensor/dist/resolution/path-aliases.js +125 -17
  394. package/sensor/dist/resolution/path-aliases.js.map +1 -1
  395. package/sensor/dist/resolution/react-router-synthesizer.d.ts +33 -0
  396. package/sensor/dist/resolution/react-router-synthesizer.d.ts.map +1 -0
  397. package/sensor/dist/resolution/react-router-synthesizer.js +126 -0
  398. package/sensor/dist/resolution/react-router-synthesizer.js.map +1 -0
  399. package/sensor/dist/resolution/resolver-pool.d.ts +2 -0
  400. package/sensor/dist/resolution/resolver-pool.d.ts.map +1 -1
  401. package/sensor/dist/resolution/resolver-pool.js +4 -0
  402. package/sensor/dist/resolution/resolver-pool.js.map +1 -1
  403. package/sensor/dist/resolution/strip-comments.d.ts +6 -0
  404. package/sensor/dist/resolution/strip-comments.d.ts.map +1 -1
  405. package/sensor/dist/resolution/strip-comments.js +58 -0
  406. package/sensor/dist/resolution/strip-comments.js.map +1 -1
  407. package/sensor/dist/resolution/sveltekit-synthesizer.d.ts +58 -0
  408. package/sensor/dist/resolution/sveltekit-synthesizer.d.ts.map +1 -0
  409. package/sensor/dist/resolution/sveltekit-synthesizer.js +173 -0
  410. package/sensor/dist/resolution/sveltekit-synthesizer.js.map +1 -0
  411. package/sensor/dist/resolution/swift-type-visibility.d.ts +52 -0
  412. package/sensor/dist/resolution/swift-type-visibility.d.ts.map +1 -0
  413. package/sensor/dist/resolution/swift-type-visibility.js +328 -0
  414. package/sensor/dist/resolution/swift-type-visibility.js.map +1 -0
  415. package/sensor/dist/resolution/synth-utils.d.ts +26 -0
  416. package/sensor/dist/resolution/synth-utils.d.ts.map +1 -0
  417. package/sensor/dist/resolution/synth-utils.js +75 -0
  418. package/sensor/dist/resolution/synth-utils.js.map +1 -0
  419. package/sensor/dist/resolution/tanstack-router-synthesizer.d.ts +31 -0
  420. package/sensor/dist/resolution/tanstack-router-synthesizer.d.ts.map +1 -0
  421. package/sensor/dist/resolution/tanstack-router-synthesizer.js +114 -0
  422. package/sensor/dist/resolution/tanstack-router-synthesizer.js.map +1 -0
  423. package/sensor/dist/resolution/tier-synthesizer.d.ts +54 -0
  424. package/sensor/dist/resolution/tier-synthesizer.d.ts.map +1 -0
  425. package/sensor/dist/resolution/tier-synthesizer.js +1294 -0
  426. package/sensor/dist/resolution/tier-synthesizer.js.map +1 -0
  427. package/sensor/dist/resolution/types.d.ts +78 -2
  428. package/sensor/dist/resolution/types.d.ts.map +1 -1
  429. package/sensor/dist/resolution/types.js +64 -0
  430. package/sensor/dist/resolution/types.js.map +1 -1
  431. package/sensor/dist/resolution/vue-router-synthesizer.d.ts +30 -0
  432. package/sensor/dist/resolution/vue-router-synthesizer.d.ts.map +1 -0
  433. package/sensor/dist/resolution/vue-router-synthesizer.js +115 -0
  434. package/sensor/dist/resolution/vue-router-synthesizer.js.map +1 -0
  435. package/sensor/dist/search/identifier-segments.d.ts +10 -0
  436. package/sensor/dist/search/identifier-segments.d.ts.map +1 -1
  437. package/sensor/dist/search/identifier-segments.js +29 -0
  438. package/sensor/dist/search/identifier-segments.js.map +1 -1
  439. package/sensor/dist/search/query-paths.d.ts +106 -0
  440. package/sensor/dist/search/query-paths.d.ts.map +1 -0
  441. package/sensor/dist/search/query-paths.js +513 -0
  442. package/sensor/dist/search/query-paths.js.map +1 -0
  443. package/sensor/dist/search/query-utils.d.ts +22 -2
  444. package/sensor/dist/search/query-utils.d.ts.map +1 -1
  445. package/sensor/dist/search/query-utils.js +56 -16
  446. package/sensor/dist/search/query-utils.js.map +1 -1
  447. package/sensor/dist/sync/watch-policy.d.ts +14 -0
  448. package/sensor/dist/sync/watch-policy.d.ts.map +1 -1
  449. package/sensor/dist/sync/watch-policy.js +19 -0
  450. package/sensor/dist/sync/watch-policy.js.map +1 -1
  451. package/sensor/dist/sync/watcher.d.ts +74 -35
  452. package/sensor/dist/sync/watcher.d.ts.map +1 -1
  453. package/sensor/dist/sync/watcher.js +281 -99
  454. package/sensor/dist/sync/watcher.js.map +1 -1
  455. package/sensor/dist/telemetry/index.d.ts +4 -2
  456. package/sensor/dist/telemetry/index.d.ts.map +1 -1
  457. package/sensor/dist/telemetry/index.js +92 -41
  458. package/sensor/dist/telemetry/index.js.map +1 -1
  459. package/sensor/dist/types.d.ts +18 -2
  460. package/sensor/dist/types.d.ts.map +1 -1
  461. package/sensor/dist/types.js +2 -0
  462. package/sensor/dist/types.js.map +1 -1
  463. package/sensor/dist/ui-server/api/deadcode.d.ts +84 -0
  464. package/sensor/dist/ui-server/api/deadcode.d.ts.map +1 -0
  465. package/sensor/dist/ui-server/api/deadcode.js +136 -0
  466. package/sensor/dist/ui-server/api/deadcode.js.map +1 -0
  467. package/sensor/dist/ui-server/api/effects.d.ts +94 -0
  468. package/sensor/dist/ui-server/api/effects.d.ts.map +1 -0
  469. package/sensor/dist/ui-server/api/effects.js +527 -0
  470. package/sensor/dist/ui-server/api/effects.js.map +1 -0
  471. package/sensor/dist/ui-server/api/entrypoints.d.ts +92 -0
  472. package/sensor/dist/ui-server/api/entrypoints.d.ts.map +1 -0
  473. package/sensor/dist/ui-server/api/entrypoints.js +361 -0
  474. package/sensor/dist/ui-server/api/entrypoints.js.map +1 -0
  475. package/sensor/dist/ui-server/api/events.d.ts +183 -0
  476. package/sensor/dist/ui-server/api/events.d.ts.map +1 -0
  477. package/sensor/dist/ui-server/api/events.js +430 -0
  478. package/sensor/dist/ui-server/api/events.js.map +1 -0
  479. package/sensor/dist/ui-server/api/file.d.ts +66 -0
  480. package/sensor/dist/ui-server/api/file.d.ts.map +1 -0
  481. package/sensor/dist/ui-server/api/file.js +235 -0
  482. package/sensor/dist/ui-server/api/file.js.map +1 -0
  483. package/sensor/dist/ui-server/api/filecode.d.ts +126 -0
  484. package/sensor/dist/ui-server/api/filecode.d.ts.map +1 -0
  485. package/sensor/dist/ui-server/api/filecode.js +205 -0
  486. package/sensor/dist/ui-server/api/filecode.js.map +1 -0
  487. package/sensor/dist/ui-server/api/flow.d.ts +226 -0
  488. package/sensor/dist/ui-server/api/flow.d.ts.map +1 -0
  489. package/sensor/dist/ui-server/api/flow.js +612 -0
  490. package/sensor/dist/ui-server/api/flow.js.map +1 -0
  491. package/sensor/dist/ui-server/api/hierarchy.d.ts +81 -0
  492. package/sensor/dist/ui-server/api/hierarchy.d.ts.map +1 -0
  493. package/sensor/dist/ui-server/api/hierarchy.js +92 -0
  494. package/sensor/dist/ui-server/api/hierarchy.js.map +1 -0
  495. package/sensor/dist/ui-server/api/index.d.ts +90 -0
  496. package/sensor/dist/ui-server/api/index.d.ts.map +1 -0
  497. package/sensor/dist/ui-server/api/index.js +332 -0
  498. package/sensor/dist/ui-server/api/index.js.map +1 -0
  499. package/sensor/dist/ui-server/api/map.d.ts +256 -0
  500. package/sensor/dist/ui-server/api/map.d.ts.map +1 -0
  501. package/sensor/dist/ui-server/api/map.js +760 -0
  502. package/sensor/dist/ui-server/api/map.js.map +1 -0
  503. package/sensor/dist/ui-server/api/node.d.ts +81 -0
  504. package/sensor/dist/ui-server/api/node.d.ts.map +1 -0
  505. package/sensor/dist/ui-server/api/node.js +388 -0
  506. package/sensor/dist/ui-server/api/node.js.map +1 -0
  507. package/sensor/dist/ui-server/api/nodes.d.ts +25 -0
  508. package/sensor/dist/ui-server/api/nodes.d.ts.map +1 -0
  509. package/sensor/dist/ui-server/api/nodes.js +45 -0
  510. package/sensor/dist/ui-server/api/nodes.js.map +1 -0
  511. package/sensor/dist/ui-server/api/program.d.ts +139 -0
  512. package/sensor/dist/ui-server/api/program.d.ts.map +1 -0
  513. package/sensor/dist/ui-server/api/program.js +315 -0
  514. package/sensor/dist/ui-server/api/program.js.map +1 -0
  515. package/sensor/dist/ui-server/api/respond.d.ts +76 -0
  516. package/sensor/dist/ui-server/api/respond.d.ts.map +1 -0
  517. package/sensor/dist/ui-server/api/respond.js +186 -0
  518. package/sensor/dist/ui-server/api/respond.js.map +1 -0
  519. package/sensor/dist/ui-server/api/route-roots.d.ts +39 -0
  520. package/sensor/dist/ui-server/api/route-roots.d.ts.map +1 -0
  521. package/sensor/dist/ui-server/api/route-roots.js +96 -0
  522. package/sensor/dist/ui-server/api/route-roots.js.map +1 -0
  523. package/sensor/dist/ui-server/api/routes.d.ts +59 -0
  524. package/sensor/dist/ui-server/api/routes.d.ts.map +1 -0
  525. package/sensor/dist/ui-server/api/routes.js +108 -0
  526. package/sensor/dist/ui-server/api/routes.js.map +1 -0
  527. package/sensor/dist/ui-server/api/screens.d.ts +117 -0
  528. package/sensor/dist/ui-server/api/screens.d.ts.map +1 -0
  529. package/sensor/dist/ui-server/api/screens.js +611 -0
  530. package/sensor/dist/ui-server/api/screens.js.map +1 -0
  531. package/sensor/dist/ui-server/api/search.d.ts +29 -0
  532. package/sensor/dist/ui-server/api/search.d.ts.map +1 -0
  533. package/sensor/dist/ui-server/api/search.js +232 -0
  534. package/sensor/dist/ui-server/api/search.js.map +1 -0
  535. package/sensor/dist/ui-server/api/session.d.ts +52 -0
  536. package/sensor/dist/ui-server/api/session.d.ts.map +1 -0
  537. package/sensor/dist/ui-server/api/session.js +196 -0
  538. package/sensor/dist/ui-server/api/session.js.map +1 -0
  539. package/sensor/dist/ui-server/api/source.d.ts +200 -0
  540. package/sensor/dist/ui-server/api/source.d.ts.map +1 -0
  541. package/sensor/dist/ui-server/api/source.js +422 -0
  542. package/sensor/dist/ui-server/api/source.js.map +1 -0
  543. package/sensor/dist/ui-server/api/stats.d.ts +27 -0
  544. package/sensor/dist/ui-server/api/stats.d.ts.map +1 -0
  545. package/sensor/dist/ui-server/api/stats.js +164 -0
  546. package/sensor/dist/ui-server/api/stats.js.map +1 -0
  547. package/sensor/dist/ui-server/api/steps.d.ts +274 -0
  548. package/sensor/dist/ui-server/api/steps.d.ts.map +1 -0
  549. package/sensor/dist/ui-server/api/steps.js +1544 -0
  550. package/sensor/dist/ui-server/api/steps.js.map +1 -0
  551. package/sensor/dist/ui-server/api/trail-store.d.ts +142 -0
  552. package/sensor/dist/ui-server/api/trail-store.d.ts.map +1 -0
  553. package/sensor/dist/ui-server/api/trail-store.js +325 -0
  554. package/sensor/dist/ui-server/api/trail-store.js.map +1 -0
  555. package/sensor/dist/ui-server/api/trails.d.ts +163 -0
  556. package/sensor/dist/ui-server/api/trails.d.ts.map +1 -0
  557. package/sensor/dist/ui-server/api/trails.js +369 -0
  558. package/sensor/dist/ui-server/api/trails.js.map +1 -0
  559. package/sensor/dist/ui-server/api/when.d.ts +133 -0
  560. package/sensor/dist/ui-server/api/when.d.ts.map +1 -0
  561. package/sensor/dist/ui-server/api/when.js +275 -0
  562. package/sensor/dist/ui-server/api/when.js.map +1 -0
  563. package/sensor/dist/ui-server/api/wire.d.ts +179 -0
  564. package/sensor/dist/ui-server/api/wire.d.ts.map +1 -0
  565. package/sensor/dist/ui-server/api/wire.js +231 -0
  566. package/sensor/dist/ui-server/api/wire.js.map +1 -0
  567. package/sensor/dist/ui-server/assets.d.ts +40 -0
  568. package/sensor/dist/ui-server/assets.d.ts.map +1 -0
  569. package/sensor/dist/ui-server/assets.js +110 -0
  570. package/sensor/dist/ui-server/assets.js.map +1 -0
  571. package/sensor/dist/ui-server/constants.d.ts +32 -0
  572. package/sensor/dist/ui-server/constants.d.ts.map +1 -0
  573. package/sensor/dist/ui-server/constants.js +35 -0
  574. package/sensor/dist/ui-server/constants.js.map +1 -0
  575. package/sensor/dist/ui-server/highlight/index.d.ts +113 -0
  576. package/sensor/dist/ui-server/highlight/index.d.ts.map +1 -0
  577. package/sensor/dist/ui-server/highlight/index.js +307 -0
  578. package/sensor/dist/ui-server/highlight/index.js.map +1 -0
  579. package/sensor/dist/ui-server/highlight/languages.d.ts +36 -0
  580. package/sensor/dist/ui-server/highlight/languages.d.ts.map +1 -0
  581. package/sensor/dist/ui-server/highlight/languages.js +50 -0
  582. package/sensor/dist/ui-server/highlight/languages.js.map +1 -0
  583. package/sensor/dist/ui-server/index.d.ts +92 -0
  584. package/sensor/dist/ui-server/index.d.ts.map +1 -0
  585. package/sensor/dist/ui-server/index.js +399 -0
  586. package/sensor/dist/ui-server/index.js.map +1 -0
  587. package/sensor/dist/ui-server/open-browser.d.ts +31 -0
  588. package/sensor/dist/ui-server/open-browser.d.ts.map +1 -0
  589. package/sensor/dist/ui-server/open-browser.js +79 -0
  590. package/sensor/dist/ui-server/open-browser.js.map +1 -0
  591. package/sensor/dist/ui-server/security.d.ts +127 -0
  592. package/sensor/dist/ui-server/security.d.ts.map +1 -0
  593. package/sensor/dist/ui-server/security.js +332 -0
  594. package/sensor/dist/ui-server/security.js.map +1 -0
  595. package/sensor/dist/ui-server/static.d.ts +45 -0
  596. package/sensor/dist/ui-server/static.d.ts.map +1 -0
  597. package/sensor/dist/ui-server/static.js +165 -0
  598. package/sensor/dist/ui-server/static.js.map +1 -0
  599. package/sensor/dist/utils.d.ts +14 -2
  600. package/sensor/dist/utils.d.ts.map +1 -1
  601. package/sensor/dist/utils.js +25 -10
  602. package/sensor/dist/utils.js.map +1 -1
  603. package/src/sensor-adapter.mjs +5 -1
@@ -45,21 +45,41 @@ exports.ReferenceResolver = void 0;
45
45
  exports.createResolver = createResolver;
46
46
  const fs = __importStar(require("fs"));
47
47
  const path = __importStar(require("path"));
48
+ const synthesis_stage_1 = require("../db/synthesis-stage");
49
+ const types_1 = require("./types");
48
50
  const name_matcher_1 = require("./name-matcher");
51
+ const cpp_macro_visibility_1 = require("./cpp-macro-visibility");
52
+ const cpp_constructor_1 = require("./cpp-constructor");
53
+ const swift_type_visibility_1 = require("./swift-type-visibility");
49
54
  const import_resolver_1 = require("./import-resolver");
50
55
  const resolver_pool_1 = require("./resolver-pool");
56
+ const alias_binding_1 = require("./alias-binding");
51
57
  const frameworks_1 = require("./frameworks");
52
58
  const callback_synthesizer_1 = require("./callback-synthesizer");
53
59
  const cooperative_yield_1 = require("./cooperative-yield");
60
+ const file_limits_1 = require("../file-limits");
54
61
  const path_aliases_1 = require("./path-aliases");
55
62
  const go_module_1 = require("./go-module");
56
63
  const workspace_packages_1 = require("./workspace-packages");
57
64
  const errors_1 = require("../errors");
65
+ const utils_1 = require("../utils");
58
66
  const lru_cache_1 = require("./lru-cache");
67
+ const js_builtins_1 = require("./js-builtins");
59
68
  /** Node kinds that can declare supertypes (extends/implements). */
60
69
  const SUPERTYPE_BEARING_KINDS = new Set([
61
70
  'class', 'struct', 'interface', 'trait', 'protocol', 'enum',
62
71
  ]);
72
+ /**
73
+ * The only edges resolving a reference reads (getSupertypes' walk). The batch
74
+ * loop commits a batch that made any of these before the next batch fans out;
75
+ * its other edges land while that batch resolves. A resolution strategy that
76
+ * reads another edge kind must be added here.
77
+ */
78
+ const RESOLUTION_READ_EDGE_KINDS = ['implements', 'extends'];
79
+ // SUPERTYPE_TARGET_KINDS (the kinds an extends/implements edge may TARGET)
80
+ // lives in ./types — the name-matcher needs the same set to restrict its
81
+ // candidate pool before ranking. It is deliberately wider than
82
+ // SUPERTYPE_BEARING_KINDS above, which is about the DECLARING side.
63
83
  /**
64
84
  * Languages whose chained static-factory/fluent calls defer to the conformance
65
85
  * second pass. Dotted-receiver languages resolve via matchDottedCallChain; the
@@ -109,13 +129,6 @@ function resolveCacheLimit() {
109
129
  // Re-export types
110
130
  __exportStar(require("./types"), exports);
111
131
  // Pre-built Sets for O(1) built-in lookups (allocated once, shared across all instances)
112
- const JS_BUILT_INS = new Set([
113
- 'console', 'window', 'document', 'global', 'process',
114
- 'Promise', 'Array', 'Object', 'String', 'Number', 'Boolean',
115
- 'Date', 'Math', 'JSON', 'RegExp', 'Error', 'Map', 'Set',
116
- 'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval',
117
- 'fetch', 'require', 'module', 'exports', '__dirname', '__filename',
118
- ]);
119
132
  const REACT_HOOKS = new Set([
120
133
  'useState', 'useEffect', 'useContext', 'useReducer', 'useCallback',
121
134
  'useMemo', 'useRef', 'useLayoutEffect', 'useImperativeHandle', 'useDebugValue',
@@ -236,8 +249,9 @@ class ReferenceResolver {
236
249
  context;
237
250
  frameworks = [];
238
251
  // Chained static-factory/fluent call refs the first pass couldn't resolve,
239
- // collected in-memory (the batched resolver deletes unresolved refs from the
240
- // DB, so they can't be re-read). Drained by resolveChainedCallsViaConformance
252
+ // collected in-memory and left pending in the DB until the post-pass
253
+ // finishes, so a restart can recover the queue (#1577). Drained by
254
+ // resolveChainedCallsViaConformance
241
255
  // once implements/extends edges exist, to resolve methods on a supertype the
242
256
  // receiver conforms to (#750).
243
257
  deferredChainRefs = [];
@@ -246,6 +260,7 @@ class ReferenceResolver {
246
260
  // same reason as deferredChainRefs and drained by
247
261
  // resolveDeferredThisMemberRefs once implements/extends edges exist (#808).
248
262
  deferredThisMemberRefs = [];
263
+ deferredRowIds = new Set();
249
264
  // Per-`.razor`/`.cshtml`-file `@using` namespace set (own directives + folder
250
265
  // `_Imports.razor`, cascading to the project root). Used to disambiguate a
251
266
  // markup type ref to the right C# namespace.
@@ -261,6 +276,12 @@ class ReferenceResolver {
261
276
  lowerNameCache; // lower(name) → nodes cache
262
277
  qualifiedNameCache; // qualified_name → nodes cache
263
278
  fileLinesCache; // file → split lines cache
279
+ // id → node for the resolver's own point reads. Every resolved reference
280
+ // re-reads its target a few times (kind gate, language gate, alias
281
+ // following, edge creation) and targets recur ~5× on large repos; the query
282
+ // layer's cache is too small for that working set. Same stable window as the
283
+ // name caches above; absent ids are not cached.
284
+ nodeByIdCache;
264
285
  methodMatchCache; // lang\0Type::method → matching method nodes
265
286
  // Per-(language, methodName) owner index for getMethodMatches: buckets a
266
287
  // method name's candidates by their qualifiedName's last two segments so a
@@ -297,6 +318,8 @@ class ReferenceResolver {
297
318
  // resolution pass (same lifetime assumption as nameCache); clearCaches() resets
298
319
  // it between passes. Callers must treat the returned array as read-only.
299
320
  nodesByKindCache = new Map();
321
+ // Filesystem existence probes behind context.fileExists (paths not in knownFiles).
322
+ fileExistsMemo = new Map();
300
323
  knownNames = null; // all known symbol names for fast pre-filtering
301
324
  knownFiles = null;
302
325
  cachesWarmed = false;
@@ -325,6 +348,7 @@ class ReferenceResolver {
325
348
  // Split-lines arrays are heavier than content strings; refs arrive
326
349
  // file-ordered, so a small cache still hits nearly always.
327
350
  this.fileLinesCache = new lru_cache_1.LRUCache(contentLimit);
351
+ this.nodeByIdCache = new lru_cache_1.LRUCache(Math.max(limit * 4, 20_000));
328
352
  this.methodMatchCache = new lru_cache_1.LRUCache(limit);
329
353
  this.context = this.createContext();
330
354
  }
@@ -403,6 +427,16 @@ class ReferenceResolver {
403
427
  this.knownNames = names;
404
428
  this.cachesWarmed = true;
405
429
  }
430
+ /** `queries.getNodeById` through the resolver's own id → node cache. */
431
+ nodeById(id) {
432
+ const cached = this.nodeByIdCache.get(id);
433
+ if (cached !== undefined)
434
+ return cached;
435
+ const node = this.queries.getNodeById(id);
436
+ if (node)
437
+ this.nodeByIdCache.set(id, node);
438
+ return node;
439
+ }
406
440
  /**
407
441
  * Clear internal caches
408
442
  */
@@ -415,11 +449,13 @@ class ReferenceResolver {
415
449
  this.lowerNameCache.clear();
416
450
  this.qualifiedNameCache.clear();
417
451
  this.fileLinesCache.clear();
452
+ this.nodeByIdCache.clear();
418
453
  this.methodMatchCache.clear();
419
454
  this.methodOwnerIndexCache.clear();
420
455
  this.supertypeMemo.clear();
421
456
  this.supertypeGen++;
422
457
  this.nodesByKindCache.clear();
458
+ this.fileExistsMemo.clear();
423
459
  this.knownNames = null;
424
460
  this.knownFiles = null;
425
461
  this.cachesWarmed = false;
@@ -428,6 +464,8 @@ class ReferenceResolver {
428
464
  if (this.context) {
429
465
  (0, import_resolver_1.clearImportResolverMemos)(this.context);
430
466
  (0, name_matcher_1.clearNameMatcherMemos)(this.context);
467
+ (0, cpp_macro_visibility_1.clearCppMacroVisibility)(this.context);
468
+ (0, swift_type_visibility_1.clearSwiftTypeVisibility)(this.context);
431
469
  }
432
470
  }
433
471
  /** `readFile` through the LRU content cache (null = read failed, also cached). */
@@ -437,6 +475,14 @@ class ReferenceResolver {
437
475
  }
438
476
  const fullPath = path.join(this.projectRoot, filePath);
439
477
  try {
478
+ // Import resolvers may follow package metadata to an archive (`file:*.har`,
479
+ // for example). Reject anything extraction would not accept before UTF-8
480
+ // decoding can multiply a large binary blob into gigabytes of V8 heap.
481
+ const stats = fs.statSync(fullPath);
482
+ if (!stats.isFile() || stats.size > file_limits_1.MAX_SOURCE_FILE_SIZE_BYTES) {
483
+ this.fileCache.set(filePath, null);
484
+ return null;
485
+ }
440
486
  const content = fs.readFileSync(fullPath, 'utf-8');
441
487
  this.fileCache.set(filePath, content);
442
488
  return content;
@@ -447,17 +493,49 @@ class ReferenceResolver {
447
493
  return null;
448
494
  }
449
495
  }
496
+ /**
497
+ * `readFileCached(filePath)?.includes(needle)` for an ASCII needle, searched
498
+ * in the raw bytes: an ASCII byte sequence survives UTF-8 decoding
499
+ * unchanged, and decoding is most of reading a file nobody keeps.
500
+ */
501
+ fileContains(filePath, needle) {
502
+ if (this.fileCache.has(filePath))
503
+ return this.fileCache.get(filePath)?.includes(needle) ?? false;
504
+ const fullPath = path.join(this.projectRoot, filePath);
505
+ try {
506
+ const stats = fs.statSync(fullPath);
507
+ if (!stats.isFile() || stats.size > file_limits_1.MAX_SOURCE_FILE_SIZE_BYTES)
508
+ return false;
509
+ return fs.readFileSync(fullPath).includes(needle);
510
+ }
511
+ catch {
512
+ return false;
513
+ }
514
+ }
450
515
  /**
451
516
  * Create the resolution context
452
517
  */
453
518
  createContext() {
454
519
  return {
520
+ resolveImport: (ref) => (0, import_resolver_1.resolveViaImport)(ref, this.context),
455
521
  getNodesInFile: (filePath) => {
456
522
  if (!this.nodeCache.has(filePath)) {
457
523
  this.nodeCache.set(filePath, this.queries.getNodesByFile(filePath));
458
524
  }
459
525
  return this.nodeCache.get(filePath);
460
526
  },
527
+ fileHasExportedNode: (filePath) => {
528
+ const cached = this.nodeCache.get(filePath);
529
+ return cached !== undefined ? cached.some((n) => n.isExported) : this.queries.fileHasExportedNode(filePath);
530
+ },
531
+ getExportedNodesInFile: (filePath) => {
532
+ const cached = this.nodeCache.get(filePath);
533
+ return cached !== undefined ? cached.filter((n) => n.isExported) : this.queries.getExportedNodesByFile(filePath);
534
+ },
535
+ getNodesInFileNamed: (filePath, name) => {
536
+ const cached = this.nodeCache.get(filePath);
537
+ return cached !== undefined ? cached.filter((n) => n.name === name) : this.queries.getNodesByFileAndName(filePath, name);
538
+ },
461
539
  getNodesByName: (name) => {
462
540
  const cached = this.nameCache.get(name);
463
541
  if (cached !== undefined)
@@ -488,7 +566,7 @@ class ReferenceResolver {
488
566
  for (const m of candidates) {
489
567
  if (m.kind !== 'method')
490
568
  continue;
491
- if (m.language !== language)
569
+ if (!(0, name_matcher_1.sameLanguageFamily)(m.language, language))
492
570
  continue;
493
571
  const qn = m.qualifiedName;
494
572
  if (qn === want || qn.endsWith(`::${want}`))
@@ -515,7 +593,7 @@ class ReferenceResolver {
515
593
  for (const m of candidates) {
516
594
  if (m.kind !== 'method')
517
595
  continue;
518
- if (m.language !== language)
596
+ if (!(0, name_matcher_1.sameLanguageFamily)(m.language, language))
519
597
  continue;
520
598
  const qn = m.qualifiedName;
521
599
  const i2 = qn.lastIndexOf('::');
@@ -565,17 +643,40 @@ class ReferenceResolver {
565
643
  return true;
566
644
  }
567
645
  }
568
- // Fall back to filesystem for files not yet indexed
569
- const fullPath = path.join(this.projectRoot, filePath);
570
- try {
571
- return fs.existsSync(fullPath);
572
- }
573
- catch (error) {
574
- (0, errors_1.logDebug)('Error checking file existence', { filePath, error: String(error) });
575
- return false;
646
+ // Fall back to filesystem for files not yet indexed. `path.join` does
647
+ // not clamp, and relative-import resolution hands us paths carrying
648
+ // `../` segments, so the probe has to be contained (#1631): a path
649
+ // outside the root can never be an indexed project file, and the
650
+ // `knownFiles` check above already answered for everything that is.
651
+ // Lexical containment only: this is a per-candidate hot path, and the
652
+ // symlink half of `validatePathWithinRoot` costs two `realpathSync`
653
+ // calls per probe (~70x slower here). It would also be wrong to apply
654
+ // — indexing deliberately follows in-root symlinks whose targets live
655
+ // outside the root (#935), so only the `../` escape is refused.
656
+ // Memoized: import resolution probes the same candidate paths (every
657
+ // extension of a specifier) from every file that imports it, and the
658
+ // tree does not change within a resolution pass (same window as the
659
+ // file-content cache; dropped by clearCaches).
660
+ const probed = this.fileExistsMemo.get(filePath);
661
+ if (probed !== undefined)
662
+ return probed;
663
+ const fullPath = (0, utils_1.lexicalPathWithinRoot)(this.projectRoot, filePath);
664
+ let exists = false;
665
+ if (fullPath !== null) {
666
+ try {
667
+ exists = fs.existsSync(fullPath);
668
+ }
669
+ catch (error) {
670
+ (0, errors_1.logDebug)('Error checking file existence', { filePath, error: String(error) });
671
+ }
576
672
  }
673
+ if (this.fileExistsMemo.size >= 200_000)
674
+ this.fileExistsMemo.clear();
675
+ this.fileExistsMemo.set(filePath, exists);
676
+ return exists;
577
677
  },
578
678
  readFile: (filePath) => this.readFileCached(filePath),
679
+ fileContains: (filePath, needle) => this.fileContains(filePath, needle),
579
680
  getFileLines: (filePath) => {
580
681
  const cached = this.fileLinesCache.get(filePath);
581
682
  if (cached !== undefined)
@@ -616,7 +717,7 @@ class ReferenceResolver {
616
717
  return result;
617
718
  },
618
719
  getNodeById: (id) => {
619
- return this.queries.getNodeById(id);
720
+ return this.nodeById(id);
620
721
  },
621
722
  getSupertypes: (typeName, language) => {
622
723
  // Union the `implements`/`extends` targets of every same-named type node.
@@ -633,7 +734,9 @@ class ReferenceResolver {
633
734
  return hit.supers;
634
735
  const typeNodes = this.context
635
736
  .getNodesByName(typeName)
636
- .filter((n) => SUPERTYPE_BEARING_KINDS.has(n.kind) && n.language === language);
737
+ // Scala singletons can inherit members even though they cannot be parents.
738
+ .filter((n) => n.language === language && (SUPERTYPE_BEARING_KINDS.has(n.kind) ||
739
+ (n.language === 'scala' && n.kind === 'module')));
637
740
  let supers;
638
741
  if (typeNodes.length === 0) {
639
742
  supers = [];
@@ -641,11 +744,20 @@ class ReferenceResolver {
641
744
  else {
642
745
  const supertypes = new Set();
643
746
  for (const tn of typeNodes) {
644
- for (const edge of this.queries.getOutgoingEdges(tn.id, ['implements', 'extends'])) {
645
- const target = this.queries.getNodeById(edge.target);
747
+ for (const edge of this.queries.getOutgoingEdges(tn.id, RESOLUTION_READ_EDGE_KINDS)) {
748
+ const target = this.nodeById(edge.target);
646
749
  if (target?.name && target.name !== typeName)
647
750
  supertypes.add(target.name);
648
751
  }
752
+ // A Swift conformance to a type the project only extends (SwiftUI's
753
+ // `View`) resolves to nothing — the extension is not the type — yet
754
+ // the members its extensions add are still the conformer's.
755
+ if (language === 'swift') {
756
+ for (const name of (0, swift_type_visibility_1.swiftExtendedConformances)(tn, this.context)) {
757
+ if (name !== typeName)
758
+ supertypes.add(name);
759
+ }
760
+ }
649
761
  }
650
762
  supers = [...supertypes];
651
763
  }
@@ -716,6 +828,7 @@ class ReferenceResolver {
716
828
  resolveAll(unresolvedRefs, onProgress) {
717
829
  // Pre-load all nodes into memory for fast lookups
718
830
  this.warmCaches();
831
+ this.advanceSupertypeGeneration();
719
832
  const resolved = [];
720
833
  const unresolved = [];
721
834
  const byMethod = {};
@@ -863,9 +976,48 @@ class ReferenceResolver {
863
976
  return false;
864
977
  }
865
978
  /**
866
- * Resolve a single reference
979
+ * Resolve a single reference.
980
+ *
981
+ * Thin decorator over `resolveOneInner` so every strategy — framework,
982
+ * import, name-match, chain, CFML component path — passes through the
983
+ * inheritance target-kind gate at ONE seam. Filtering inside the
984
+ * name-matcher would have covered `matchByExactName` only.
985
+ * Calls that land on an alias binding then forward once to the callable
986
+ * the alias names (see ./alias-binding), regardless of the strategy.
867
987
  */
868
988
  resolveOne(ref) {
989
+ // A C/C++ "call" whose name is a function-like macro visible in this
990
+ // translation unit is a macro expansion, not a call — it must never bind
991
+ // to a same-named function in another file (#1838).
992
+ if ((0, cpp_macro_visibility_1.isVisibleCppMacro)(ref, this.context))
993
+ return null;
994
+ // A Swift type reference never lands on an `extension X {}` node, nor on a
995
+ // nested type it cannot name bare (see ./swift-type-visibility).
996
+ const candidate = (0, swift_type_visibility_1.gateSwiftTypeTarget)(this.gateTargetKind(this.resolveOneInner(ref), ref), ref, this.context);
997
+ const resolved = candidate?.resolvedBy === 'framework'
998
+ ? this.gateFrameworkLanguage(candidate, ref)
999
+ : this.gateLanguage(candidate, ref);
1000
+ if (!resolved || ref.referenceKind !== 'calls')
1001
+ return resolved;
1002
+ const target = this.nodeById(resolved.targetNodeId);
1003
+ if (!target)
1004
+ return resolved;
1005
+ const dot = ref.referenceName.lastIndexOf('.');
1006
+ const memberName = dot >= 0 ? ref.referenceName.slice(dot + 1) : null;
1007
+ const forwarded = (0, alias_binding_1.resolveAliasBinding)(target, memberName, this.context);
1008
+ if (!forwarded || forwarded.id === resolved.targetNodeId)
1009
+ return resolved;
1010
+ return this.gateLanguage({
1011
+ ...resolved,
1012
+ targetNodeId: forwarded.id,
1013
+ confidence: Math.min(resolved.confidence, 0.85),
1014
+ }, ref);
1015
+ }
1016
+ resolveOneInner(ref) {
1017
+ // A local C++ object construction (`T obj(args)`, ref `ns::T::T/1`)
1018
+ // resolves ONLY to a constructor of the lexically nearest `T` (#1839).
1019
+ if ((0, cpp_constructor_1.isCppConstructorRef)(ref))
1020
+ return (0, cpp_constructor_1.matchCppConstructor)(ref, this.context);
869
1021
  // Skip built-in/external references
870
1022
  if (this.isBuiltInOrExternal(ref)) {
871
1023
  return null;
@@ -895,9 +1047,13 @@ class ReferenceResolver {
895
1047
  // indexed under the bare name, so the existence check strips the dot.
896
1048
  // Nix static path imports (`import ./x.nix`) name a FILE, not a symbol —
897
1049
  // they bypass the symbol-existence check and resolve via resolveViaImport.
898
- const existenceName = ref.language === 'arkts' && ref.referenceName.startsWith('.')
1050
+ let existenceName = ref.language === 'arkts' && ref.referenceName.startsWith('.')
899
1051
  ? ref.referenceName.slice(1)
900
1052
  : ref.referenceName;
1053
+ // Erlang refs carry the call-site arity (`f/1`, `mod::f/2` — #1610); the
1054
+ // name index stores bare names, so existence is checked arity-less.
1055
+ if (ref.language === 'erlang')
1056
+ existenceName = existenceName.replace(/\/\d{1,3}$/, '');
901
1057
  const tPre = this.profileStages ? process.hrtime.bigint() : 0n;
902
1058
  const preFilterPass = (0, import_resolver_1.isNixPathImportRef)(ref) ||
903
1059
  this.hasAnyPossibleMatch(existenceName) ||
@@ -906,7 +1062,7 @@ class ReferenceResolver {
906
1062
  if (this.profileStages)
907
1063
  this.stageAdd('preFilter', ref, preFilterPass, tPre);
908
1064
  if (!preFilterPass) {
909
- return null;
1065
+ return this.gateLanguage((0, name_matcher_1.matchJsStoreBindingCall)(ref, this.context), ref);
910
1066
  }
911
1067
  // Function-as-value refs (#756) get a dedicated, strictly-gated path:
912
1068
  // import-based resolution first (an imported callback resolves through its
@@ -919,9 +1075,12 @@ class ReferenceResolver {
919
1075
  if (ref.referenceName.startsWith('this.')) {
920
1076
  return this.gateLanguage(this.resolveThisMemberFnRef(ref), ref);
921
1077
  }
1078
+ if ((ref.language === 'python' || ref.language === 'go') && ref.referenceName.includes('.')) {
1079
+ return this.gateLanguage((0, name_matcher_1.matchFunctionRef)(ref, this.context), ref);
1080
+ }
922
1081
  const viaImport = this.gateLanguage((0, import_resolver_1.resolveViaImport)(ref, this.context), ref);
923
1082
  if (viaImport) {
924
- const target = this.queries.getNodeById(viaImport.targetNodeId);
1083
+ const target = this.nodeById(viaImport.targetNodeId);
925
1084
  if (target &&
926
1085
  (target.kind === 'function' ||
927
1086
  target.kind === 'method' ||
@@ -963,12 +1122,16 @@ class ReferenceResolver {
963
1122
  if (razorResult)
964
1123
  return razorResult;
965
1124
  }
1125
+ // An explicit PHP class import owns its static calls, including an
1126
+ // unavailable method. Do not let same-name fallbacks change the receiver
1127
+ // to an unrelated Service/Repository type (#1545).
1128
+ const phpStaticImport = (0, import_resolver_1.resolvePhpImportedStaticCall)(ref, this.context);
1129
+ if (phpStaticImport !== undefined)
1130
+ return this.gateLanguage(phpStaticImport, ref);
966
1131
  const candidates = [];
967
1132
  // Strategy 1: Try framework-specific resolution. Cross-language bridges
968
1133
  // are deliberately preserved (Drupal `routing.yml` → PHP controller, RN
969
- // JS → native `calls`) — `gateFrameworkLanguage` only drops a type/import
970
- // edge between two KNOWN families (see its doc), never a `calls` bridge or
971
- // a config↔code edge.
1134
+ // JS → native `calls`); other code references obey the shared family gate.
972
1135
  const tFw = this.profileStages ? process.hrtime.bigint() : 0n;
973
1136
  let fwEarly = null;
974
1137
  for (const framework of this.frameworks) {
@@ -985,7 +1148,21 @@ class ReferenceResolver {
985
1148
  this.stageAdd('frameworks', ref, fwEarly !== null, tFw);
986
1149
  if (fwEarly)
987
1150
  return fwEarly;
1151
+ // A retained untyped chain supplies effect/call-site evidence only. In
1152
+ // particular, importing its root does not make the root its call target.
1153
+ if ((0, name_matcher_1.isUnresolvedJsMemberCall)(ref))
1154
+ return null;
988
1155
  // Strategy 2: Try import-based resolution
1156
+ // A TS/JS/Python call-receiver chain (`useStore.getState().reset`, #1683)
1157
+ // names the ROOT's import, not the method's: letting resolveViaImport see
1158
+ // it binds the call to the imported store constant and the method is
1159
+ // never looked up. The name-matcher owns the chain shape for these
1160
+ // languages — the Java/Kotlin/C++ chains keep their existing path.
1161
+ if (ref.referenceKind === 'calls' &&
1162
+ CHAIN_SHAPE.test(ref.referenceName) &&
1163
+ (ref.language === 'typescript' || ref.language === 'javascript' || ref.language === 'tsx' || ref.language === 'jsx' || ref.language === 'python')) {
1164
+ return this.gateLanguage((0, name_matcher_1.matchReference)(ref, this.context), ref);
1165
+ }
989
1166
  const tImp = this.profileStages ? process.hrtime.bigint() : 0n;
990
1167
  const importResult = this.gateLanguage((0, import_resolver_1.resolveViaImport)(ref, this.context), ref);
991
1168
  if (this.profileStages)
@@ -1022,8 +1199,15 @@ class ReferenceResolver {
1022
1199
  // matcher would link each `mkOption` call to whichever file's inherit
1023
1200
  // binding it happened to pick. Same-file matches only.
1024
1201
  if (nameResult) {
1025
- const target = this.queries.getNodeById(nameResult.targetNodeId);
1026
- if (ref.language === 'nix') {
1202
+ const target = this.nodeById(nameResult.targetNodeId);
1203
+ // A definition its language makes file-local — a C `static`, a Kotlin
1204
+ // `private fun`, a Go unexported name in another package, a Rust
1205
+ // non-`pub` item outside its module subtree — cannot be what a name in
1206
+ // another file means, whichever strategy chose it (#1730).
1207
+ if (target && !(0, name_matcher_1.isVisibleAcrossFiles)(target, ref, this.context)) {
1208
+ nameResult = null;
1209
+ }
1210
+ else if (ref.language === 'nix') {
1027
1211
  if (!target || target.filePath !== ref.filePath) {
1028
1212
  nameResult = null;
1029
1213
  }
@@ -1071,7 +1255,7 @@ class ReferenceResolver {
1071
1255
  if (ref.referenceKind === 'calls' &&
1072
1256
  CHAIN_LANGUAGES.has(ref.language) &&
1073
1257
  CHAIN_SHAPE.test(ref.referenceName)) {
1074
- this.deferredChainRefs.push(ref);
1258
+ this.deferReference(ref, this.deferredChainRefs);
1075
1259
  }
1076
1260
  else if (
1077
1261
  // PHP `$this->prop->method()` (encoded `this->prop.method`): its method
@@ -1080,7 +1264,7 @@ class ReferenceResolver {
1080
1264
  ref.referenceKind === 'calls' &&
1081
1265
  ref.language === 'php' &&
1082
1266
  PHP_PROP_SHAPE.test(ref.referenceName)) {
1083
- this.deferredChainRefs.push(ref);
1267
+ this.deferReference(ref, this.deferredChainRefs);
1084
1268
  }
1085
1269
  return null;
1086
1270
  }
@@ -1091,43 +1275,53 @@ class ReferenceResolver {
1091
1275
  * Create edges from resolved references
1092
1276
  */
1093
1277
  createEdges(resolved) {
1094
- return resolved.map((ref) => {
1278
+ return resolved.flatMap((ref) => {
1095
1279
  // `function_ref` (#756) is internal-only: it persists as a `references`
1096
1280
  // edge (the registration site depends on the callback), distinguishable
1097
1281
  // by metadata.resolvedBy === 'function-ref'. callers/impact already
1098
1282
  // traverse `references`, so registration sites surface with no
1099
1283
  // graph-layer changes.
1100
- let kind = ref.original.referenceKind === 'function_ref' ? 'references' : ref.original.referenceKind;
1284
+ let kind = ref.edgeKind ??
1285
+ (ref.original.referenceKind === 'function_ref' ? 'references' : ref.original.referenceKind);
1101
1286
  // Promote "extends" to "implements" when a class/struct targets an interface
1102
1287
  if (kind === 'extends') {
1103
- const targetNode = this.queries.getNodeById(ref.targetNodeId);
1288
+ const targetNode = this.nodeById(ref.targetNodeId);
1104
1289
  if (targetNode && (targetNode.kind === 'interface' || targetNode.kind === 'protocol')) {
1105
- const sourceNode = this.queries.getNodeById(ref.original.fromNodeId);
1290
+ const sourceNode = this.nodeById(ref.original.fromNodeId);
1106
1291
  if (sourceNode && sourceNode.kind !== 'interface' && sourceNode.kind !== 'protocol') {
1107
1292
  kind = 'implements';
1108
1293
  }
1109
1294
  }
1110
1295
  }
1111
1296
  // Promote "calls" to "instantiates" when the resolved target is a
1112
- // class/struct. Languages without a `new` keyword (Python, Ruby)
1297
+ // class/struct/union. Languages without a `new` keyword (Python, Ruby)
1113
1298
  // express instantiation as `Foo()` — extraction can't tell that
1114
1299
  // apart from a function call without symbol info, but resolution
1115
1300
  // can: if `Foo` resolves to a class, the call IS an instantiation.
1116
1301
  if (kind === 'calls') {
1117
- const targetNode = this.queries.getNodeById(ref.targetNodeId);
1118
- if (targetNode && (targetNode.kind === 'class' || targetNode.kind === 'struct')) {
1302
+ const targetNode = this.nodeById(ref.targetNodeId);
1303
+ if (targetNode &&
1304
+ (targetNode.kind === 'class' || targetNode.kind === 'struct' || targetNode.kind === 'union')) {
1119
1305
  kind = 'instantiates';
1120
1306
  }
1121
1307
  }
1122
- return {
1308
+ // One reference can name several targets — a navigation whose
1309
+ // destination is a conditional reaches every arm. Each becomes its own
1310
+ // edge, sharing this resolution's kind and confidence.
1311
+ const targets = [
1312
+ { targetNodeId: ref.targetNodeId, metadata: ref.metadata },
1313
+ ...(ref.alsoTargets ?? []),
1314
+ ];
1315
+ return targets.map((t) => ({
1123
1316
  source: ref.original.fromNodeId,
1124
- target: ref.targetNodeId,
1317
+ target: t.targetNodeId,
1125
1318
  kind,
1126
1319
  line: ref.original.line,
1127
1320
  column: ref.original.column,
1128
1321
  confidence: ref.confidence,
1129
1322
  resolvedBy: ref.resolvedBy,
1130
1323
  metadata: {
1324
+ ...(t.metadata ?? {}),
1131
1325
  confidence: ref.confidence,
1132
1326
  resolvedBy: ref.resolvedBy,
1133
1327
  // The ORIGINAL reference text (and kind, when edge-kind promotion
@@ -1153,7 +1347,7 @@ class ReferenceResolver {
1153
1347
  ...(ref.original.bindingForm !== undefined ? { binding: ref.original.bindingForm } : {}),
1154
1348
  ...(ref.original.importedName !== undefined ? { importedName: ref.original.importedName } : {}),
1155
1349
  },
1156
- };
1350
+ }));
1157
1351
  });
1158
1352
  }
1159
1353
  /**
@@ -1202,10 +1396,25 @@ class ReferenceResolver {
1202
1396
  }
1203
1397
  return { byRowId, legacyKeys };
1204
1398
  }
1399
+ /** A deferred attempt is unfinished work, not a final failure (#1577). */
1400
+ nonDeferredFailures(unresolved) {
1401
+ return unresolved.filter((ref) => ref.rowId == null || !this.deferredRowIds.has(ref.rowId));
1402
+ }
1403
+ deferReference(ref, queue) {
1404
+ queue.push(ref);
1405
+ if (ref.rowId != null)
1406
+ this.deferredRowIds.add(ref.rowId);
1407
+ }
1205
1408
  /**
1206
1409
  * Resolve and persist edges to database
1207
1410
  */
1208
1411
  resolveAndPersist(unresolvedRefs, onProgress) {
1412
+ const prerequisites = unresolvedRefs.filter(ReferenceResolver.isPrerequisite);
1413
+ if (prerequisites.length > 0 && prerequisites.length < unresolvedRefs.length) {
1414
+ const first = this.resolveAndPersist(prerequisites, (current) => onProgress?.(current, unresolvedRefs.length));
1415
+ const rest = this.resolveAndPersist(unresolvedRefs.filter((ref) => !ReferenceResolver.isPrerequisite(ref)), (current) => onProgress?.(prerequisites.length + current, unresolvedRefs.length));
1416
+ return ReferenceResolver.mergeResults(first, rest);
1417
+ }
1209
1418
  const result = this.resolveAll(unresolvedRefs, onProgress);
1210
1419
  // Create edges from resolved references
1211
1420
  const edges = this.createEdges(result.resolved);
@@ -1229,7 +1438,7 @@ class ReferenceResolver {
1229
1438
  // is still 'pending', so any pending row at rest belongs to an
1230
1439
  // interrupted run and the sweep can key off the pending count.
1231
1440
  if (result.unresolved.length > 0) {
1232
- const { byRowId, legacyKeys } = ReferenceResolver.partitionFailedCleanup(result.unresolved);
1441
+ const { byRowId, legacyKeys } = ReferenceResolver.partitionFailedCleanup(this.nonDeferredFailures(result.unresolved));
1233
1442
  this.queries.markReferencesFailedByRowIds(byRowId);
1234
1443
  this.queries.markReferencesFailed(legacyKeys);
1235
1444
  }
@@ -1245,8 +1454,18 @@ class ReferenceResolver {
1245
1454
  * a large edit lands many popular symbol names at once.
1246
1455
  */
1247
1456
  async resolveAndPersistListYielding(refs) {
1457
+ const prerequisites = refs.filter(ReferenceResolver.isPrerequisite);
1458
+ if (prerequisites.length > 0 && prerequisites.length < refs.length) {
1459
+ const first = await this.resolveAndPersistListYielding(prerequisites);
1460
+ const rest = await this.resolveAndPersistListYielding(refs.filter((ref) => !ReferenceResolver.isPrerequisite(ref)));
1461
+ return ReferenceResolver.mergeResults(first, rest);
1462
+ }
1248
1463
  const maybeYield = (0, cooperative_yield_1.createYielder)();
1249
1464
  const result = await this.resolveBatchYielding(refs, maybeYield);
1465
+ await this.persistResolutionResult(result, maybeYield);
1466
+ return result;
1467
+ }
1468
+ async persistResolutionResult(result, maybeYield) {
1250
1469
  const PERSIST_CHUNK = 1000;
1251
1470
  const edges = this.createEdges(result.resolved);
1252
1471
  for (let i = 0; i < edges.length; i += PERSIST_CHUNK) {
@@ -1262,7 +1481,7 @@ class ReferenceResolver {
1262
1481
  this.queries.deleteSpecificResolvedReferences(resolvedCleanup.legacyKeys.slice(i, i + PERSIST_CHUNK));
1263
1482
  await maybeYield();
1264
1483
  }
1265
- const failedCleanup = ReferenceResolver.partitionFailedCleanup(result.unresolved);
1484
+ const failedCleanup = ReferenceResolver.partitionFailedCleanup(this.nonDeferredFailures(result.unresolved));
1266
1485
  for (let i = 0; i < failedCleanup.byRowId.length; i += PERSIST_CHUNK) {
1267
1486
  this.queries.markReferencesFailedByRowIds(failedCleanup.byRowId.slice(i, i + PERSIST_CHUNK));
1268
1487
  await maybeYield();
@@ -1271,7 +1490,43 @@ class ReferenceResolver {
1271
1490
  this.queries.markReferencesFailed(failedCleanup.legacyKeys.slice(i, i + PERSIST_CHUNK));
1272
1491
  await maybeYield();
1273
1492
  }
1274
- return result;
1493
+ return edges.length;
1494
+ }
1495
+ /** Finalize the durable queue only AFTER its edges have been inserted. */
1496
+ async persistDeferredReferences(deferred, resolved) {
1497
+ for (const ref of deferred)
1498
+ if (ref.rowId != null)
1499
+ this.deferredRowIds.delete(ref.rowId);
1500
+ const matched = new Set(resolved.map((ref) => ref.original));
1501
+ const unresolved = deferred.filter((ref) => !matched.has(ref));
1502
+ const count = await this.persistResolutionResult({
1503
+ resolved,
1504
+ unresolved,
1505
+ stats: { total: deferred.length, resolved: resolved.length, unresolved: unresolved.length, byMethod: {} },
1506
+ }, (0, cooperative_yield_1.createYielder)());
1507
+ if (count > 0)
1508
+ this.clearCaches();
1509
+ return count;
1510
+ }
1511
+ /** Same two phases as the bounded DB reader: persist wiring before calls. */
1512
+ static isPrerequisite(ref) {
1513
+ return ref.referenceKind === 'imports' || ref.referenceKind === 'extends' || ref.referenceKind === 'implements';
1514
+ }
1515
+ static mergeResults(first, rest) {
1516
+ const byMethod = { ...first.stats.byMethod };
1517
+ for (const [method, count] of Object.entries(rest.stats.byMethod)) {
1518
+ byMethod[method] = (byMethod[method] ?? 0) + count;
1519
+ }
1520
+ return {
1521
+ resolved: first.resolved.concat(rest.resolved),
1522
+ unresolved: first.unresolved.concat(rest.unresolved),
1523
+ stats: {
1524
+ total: first.stats.total + rest.stats.total,
1525
+ resolved: first.stats.resolved + rest.stats.resolved,
1526
+ unresolved: first.stats.unresolved + rest.stats.unresolved,
1527
+ byMethod,
1528
+ },
1529
+ };
1275
1530
  }
1276
1531
  /**
1277
1532
  * Second resolution pass for chained static-factory / fluent calls whose
@@ -1315,14 +1570,7 @@ class ReferenceResolver {
1315
1570
  resolved.push(match);
1316
1571
  await maybeYield();
1317
1572
  }
1318
- if (resolved.length === 0)
1319
- return 0;
1320
- const edges = this.createEdges(resolved);
1321
- if (edges.length > 0) {
1322
- this.queries.insertEdges(edges);
1323
- this.clearCaches();
1324
- }
1325
- return edges.length;
1573
+ return this.persistDeferredReferences(deferred, resolved);
1326
1574
  }
1327
1575
  /**
1328
1576
  * Resolve one batch with a yield checkpoint between EVERY ref so the #850
@@ -1478,6 +1726,7 @@ class ReferenceResolver {
1478
1726
  unresolved.push(ref);
1479
1727
  }
1480
1728
  }
1729
+ this.deferredRowIds.clear(); // the admission side now owns both queues
1481
1730
  return {
1482
1731
  resolved,
1483
1732
  unresolved,
@@ -1500,8 +1749,10 @@ class ReferenceResolver {
1500
1749
  * would have.
1501
1750
  */
1502
1751
  appendDeferredFromWorkers(deferredChain, deferredThisMember) {
1503
- this.deferredChainRefs.push(...deferredChain);
1504
- this.deferredThisMemberRefs.push(...deferredThisMember);
1752
+ for (const ref of deferredChain)
1753
+ this.deferReference(ref, this.deferredChainRefs);
1754
+ for (const ref of deferredThisMember)
1755
+ this.deferReference(ref, this.deferredThisMemberRefs);
1505
1756
  }
1506
1757
  /**
1507
1758
  * Resolve and persist in batches to keep memory bounded.
@@ -1520,7 +1771,7 @@ class ReferenceResolver {
1520
1771
  // the valve's timer-driven passive passes stay perpetually partial against
1521
1772
  // the pool's continuous reads, which is how a kernel-scale resolution grew
1522
1773
  // a 22GB WAL on a 4.6GB DB (migration plan §7a.1).
1523
- parallel) {
1774
+ parallel, synthesize = true) {
1524
1775
  // Resolution runs on the indexer's MAIN thread, and the #850 liveness
1525
1776
  // watchdog SIGKILLs a process whose event loop stalls past its window (60s
1526
1777
  // by default). A single dense batch's resolveAll — or the synthesis pass
@@ -1675,8 +1926,26 @@ class ReferenceResolver {
1675
1926
  }
1676
1927
  try {
1677
1928
  try {
1929
+ // Orphans retain interruption/re-extraction order, not clean-index order.
1930
+ // A caller can precede its imports or supertypes by many batches (#1577).
1931
+ // Drain those prerequisites first, then start a fresh keyset cursor over
1932
+ // the remaining kinds. The disjoint filters let us prefetch across the
1933
+ // phase boundary before cleanup without re-reading the current batch.
1934
+ let prerequisites = true;
1935
+ let afterRowId = 0;
1936
+ const readNextBatch = () => {
1937
+ let next = this.queries.getUnresolvedReferencesBatchAfter(afterRowId, batchSize, prerequisites);
1938
+ if (next.length === 0 && prerequisites) {
1939
+ prerequisites = false;
1940
+ afterRowId = 0;
1941
+ next = this.queries.getUnresolvedReferencesBatchAfter(afterRowId, batchSize, prerequisites);
1942
+ }
1943
+ if (next.length > 0)
1944
+ afterRowId = next[next.length - 1].rowId;
1945
+ return next;
1946
+ };
1678
1947
  tLp = Date.now();
1679
- let batch = this.queries.getUnresolvedReferencesBatchAfter(0, batchSize);
1948
+ let batch = readNextBatch();
1680
1949
  lp('read', tLp);
1681
1950
  let inFlight = batch.length > 0 ? beginBatch(batch) : null;
1682
1951
  while (batch.length > 0 && inFlight) {
@@ -1686,7 +1955,7 @@ class ReferenceResolver {
1686
1955
  // enumeration yields the following batch (keyset — OFFSET re-walked the
1687
1956
  // accumulated failed prefix every read, 54.6s at kernel scale, §7a.2).
1688
1957
  tLp = Date.now();
1689
- const nextBatch = this.queries.getUnresolvedReferencesBatchAfter(batch[batch.length - 1].rowId, batchSize);
1958
+ const nextBatch = readNextBatch();
1690
1959
  lp('read', tLp);
1691
1960
  const tBatch = Date.now();
1692
1961
  const result = await settleBatch(inFlight, batch);
@@ -1759,27 +2028,36 @@ class ReferenceResolver {
1759
2028
  // the remainder idempotently on the next run/sweep (#1187).
1760
2029
  const PERSIST_CHUNK = 1000;
1761
2030
  const tPersist = Date.now();
1762
- // Persist edges BEFORE fanning out the next batch: later batches read
1763
- // this batch's edges — resolveMethodOnType walks supertype chains over
1764
- // `extends`/`implements` edges that earlier batches resolved, so a
1765
- // receiver typed as a subclass only reaches a method declared on its
1766
- // base class if those edges are visible. (Validated on dubbo: fanning
1767
- // out first downgraded exactly those supertype-method resolutions from
1768
- // the 0.9 typed-receiver path to the 0.65 word-overlap fallback.)
2031
+ // A batch that made `extends`/`implements` edges persists them BEFORE
2032
+ // fanning out the next batch: later batches read them —
2033
+ // resolveMethodOnType walks supertype chains over edges that earlier
2034
+ // batches resolved, so a receiver typed as a subclass only reaches a
2035
+ // method declared on its base class if those edges are visible.
2036
+ // (Validated on dubbo: fanning out first downgraded exactly those
2037
+ // supertype-method resolutions from the 0.9 typed-receiver path to the
2038
+ // 0.65 word-overlap fallback.) They are the only edges resolution reads
2039
+ // (RESOLUTION_READ_EDGE_KINDS), so a batch that made none — every batch
2040
+ // after the prerequisite phase readNextBatch drains first — fans the
2041
+ // next batch out now and inserts while it resolves: the same writes in
2042
+ // the same order, and nothing the workers read differs.
1769
2043
  tLp = Date.now();
1770
2044
  const edges = this.createEdges(result.resolved);
1771
2045
  lp('createEdges', tLp);
2046
+ const readEdge = edges.some((e) => RESOLUTION_READ_EDGE_KINDS.includes(e.kind));
2047
+ let nextInFlight = !readEdge && nextBatch.length > 0 ? beginBatch(nextBatch) : null;
1772
2048
  tLp = Date.now();
1773
2049
  for (let i = 0; i < edges.length; i += PERSIST_CHUNK) {
1774
2050
  this.queries.insertEdges(edges.slice(i, i + PERSIST_CHUNK));
1775
2051
  await maybeYield();
1776
2052
  }
1777
2053
  lp('insertEdges', tLp);
1778
- // NOW fan the next batch out — workers see exactly the edge state the
1779
- // sequential baseline would (every batch ≤ this one committed), while
1780
- // the main thread spends the REST of the persist (ref deletes + failed
1781
- // parking below) overlapped with their resolution — the double-buffer.
1782
- const nextInFlight = nextBatch.length > 0 ? beginBatch(nextBatch) : null;
2054
+ // NOW fan the next batch out (if not already) — workers see exactly the
2055
+ // edge state the sequential baseline would (every batch ≤ this one
2056
+ // committed), while the main thread spends the REST of the persist (ref
2057
+ // deletes + failed parking below) overlapped with their resolution —
2058
+ // the double-buffer.
2059
+ if (!nextInFlight && nextBatch.length > 0)
2060
+ nextInFlight = beginBatch(nextBatch);
1783
2061
  // Clean up resolved refs so they don't appear in the next batch —
1784
2062
  // by row id, so a same-key sibling ref in a LATER batch (same caller
1785
2063
  // calling the same callee at another line) is left pending for its own
@@ -1801,7 +2079,9 @@ class ReferenceResolver {
1801
2079
  // only see pending rows) but stay retryable when a later sync adds a
1802
2080
  // symbol that could satisfy them (#1240).
1803
2081
  tLp = Date.now();
1804
- const failedCleanup = ReferenceResolver.partitionFailedCleanup(result.unresolved);
2082
+ const failures = this.nonDeferredFailures(result.unresolved);
2083
+ const deferredCount = result.unresolved.length - failures.length;
2084
+ const failedCleanup = ReferenceResolver.partitionFailedCleanup(failures);
1805
2085
  for (let i = 0; i < failedCleanup.byRowId.length; i += PERSIST_CHUNK) {
1806
2086
  removedThisBatch += this.queries.markReferencesFailedByRowIds(failedCleanup.byRowId.slice(i, i + PERSIST_CHUNK));
1807
2087
  await maybeYield();
@@ -1831,17 +2111,11 @@ class ReferenceResolver {
1831
2111
  // first 5000 refs are all external/stdlib calls, resolution stopped at
1832
2112
  // batch one and left the rest of the table as permanent orphans (#1187).
1833
2113
  // The count-based guard below catches the true no-progress case.
1834
- // Non-progress guard (defense-in-depth). Each iteration enumerates from
1835
- // the head of the pending set, so the PENDING population MUST shrink
1836
- // every iteration — resolved refs are deleted and unresolvable ones are
1837
- // marked failed above, and both leave the pending set the batch reader
1838
- // sees. If it didn't shrink, a resolver returned a match whose
1839
- // `original.referenceName` differs from the stored row, so the keyed
1840
- // delete/update no-ops, and we'd re-read + re-resolve + re-insert the
1841
- // same rows forever (the runaway that grew a 99-file repo to 5M edges /
1842
- // 1.4 GB before the Go-fallback fix). Stop rather than grow the graph
1843
- // without bound. (An in-flight prefetched batch is abandoned unsettled —
1844
- // fan-out has no side effects until settleBatch appends its results.)
2114
+ // Non-progress guard (defense-in-depth). Ordinary attempts must leave
2115
+ // the pending set; a mismatched original reference can make legacy-key
2116
+ // cleanup a no-op. Keep the guard against that broken persistence even
2117
+ // though keyset pagination now advances independently of row cleanup.
2118
+ // An abandoned prefetched batch has no side effects until settleBatch.
1845
2119
  // Non-progress signal, now O(1): `changes` summed across this batch's
1846
2120
  // deletes + failed-parks is the DIRECT evidence the guard's old count
1847
2121
  // diff inferred — a resolver returning a mismatched name makes the keyed
@@ -1851,7 +2125,9 @@ class ReferenceResolver {
1851
2125
  // runs only on the suspicious path (claimed-work batch removed nothing —
1852
2126
  // e.g. every row was a sibling a legacy-key sweep already consumed),
1853
2127
  // where it arbitrates stop-vs-continue exactly as before.
1854
- if (removedThisBatch <= 0 && batch.length > 0) {
2128
+ // Deferred refs legitimately remain pending for the post-pass. The
2129
+ // keyset cursor advances past them; they must not trigger this guard.
2130
+ if (removedThisBatch + deferredCount <= 0 && batch.length > 0) {
1855
2131
  tLp = Date.now();
1856
2132
  const remaining = this.queries.getUnresolvedReferencesCount();
1857
2133
  lp('countGuard', tLp);
@@ -1888,6 +2164,21 @@ class ReferenceResolver {
1888
2164
  await bp;
1889
2165
  }
1890
2166
  }
2167
+ // Indexes the bulk-edge window's end deferred: built once, while the pool
2168
+ // is busy with synthesis when it is, and in any case before this returns.
2169
+ let deferredBuilt = !bulkEdgesActive || !parallel?.bulkEdgeLoad?.deferred;
2170
+ const buildDeferredIndexes = () => {
2171
+ if (deferredBuilt)
2172
+ return;
2173
+ deferredBuilt = true;
2174
+ const tDeferred = Date.now();
2175
+ try {
2176
+ parallel.bulkEdgeLoad.deferred();
2177
+ }
2178
+ catch { /* healed by schema.sql on the next open, like a crash in the window */ }
2179
+ if (process.env.LATTICE_SENSOR_SYNTH_TIMINGS)
2180
+ console.error(`[phase-timing] deferred-edge-index: ${Date.now() - tDeferred}ms`);
2181
+ };
1891
2182
  // Dynamic-edge synthesis: now that all base `calls` edges are persisted,
1892
2183
  // synthesize observer/callback dispatch edges (dispatcher → registered
1893
2184
  // callbacks) that static parsing leaves out. Best-effort — never fail the
@@ -1897,11 +2188,13 @@ class ReferenceResolver {
1897
2188
  // loop. See docs/design/callback-edge-synthesis.md.
1898
2189
  const tSynth = Date.now();
1899
2190
  try {
1900
- aggregateStats.byMethod['callback-synthesis'] = await (0, callback_synthesizer_1.synthesizeCallbackEdges)(this.queries, this.context, onSynthesisProgress, pool, parallel?.backpressure);
2191
+ if (synthesize)
2192
+ aggregateStats.byMethod['callback-synthesis'] = await (0, callback_synthesizer_1.synthesizeCallbackEdges)(this.queries, this.context, onSynthesisProgress, pool, parallel?.backpressure, buildDeferredIndexes);
1901
2193
  }
1902
2194
  catch {
1903
2195
  // synthesis is additive and optional; ignore failures
1904
2196
  }
2197
+ buildDeferredIndexes();
1905
2198
  if (process.env.LATTICE_SENSOR_SYNTH_TIMINGS)
1906
2199
  console.error(`[phase-timing] callback-synthesis: ${Date.now() - tSynth}ms`);
1907
2200
  }
@@ -1920,12 +2213,63 @@ class ReferenceResolver {
1920
2213
  stats: aggregateStats,
1921
2214
  };
1922
2215
  }
2216
+ /** Replace synthesis only after every base-resolution pass has finished. */
2217
+ async refreshSynthesis(dbPath, onProgress, backpressure) {
2218
+ this.clearCaches();
2219
+ const stage = new synthesis_stage_1.SynthesisStage(dbPath);
2220
+ try {
2221
+ const fresh = new ReferenceResolver(this.projectRoot, stage.queries);
2222
+ const count = await (0, callback_synthesizer_1.synthesizeCallbackEdges)(stage.queries, fresh.context, onProgress, null, backpressure);
2223
+ await stage.publish(backpressure);
2224
+ return count;
2225
+ }
2226
+ finally {
2227
+ stage.close();
2228
+ this.clearCaches();
2229
+ }
2230
+ }
1923
2231
  /**
1924
2232
  * Get detected frameworks
1925
2233
  */
1926
2234
  getDetectedFrameworks() {
1927
2235
  return this.frameworks.map((f) => f.name);
1928
2236
  }
2237
+ /**
2238
+ * True when `receiver` is a local name bound by an import that resolves to a
2239
+ * file IN THIS PROJECT — the only case where letting a python
2240
+ * built-in-method name through the filter is safe (#1681).
2241
+ *
2242
+ * Asking only whether SOME import bound the local name is not enough: every
2243
+ * import produces a mapping, stdlib and PyPI included, so that would also be
2244
+ * true for `os`, `requests`, `np`. Opening the filter for them lets
2245
+ * resolveViaImport find no project file, fall through to bare-name matching,
2246
+ * and bind `os.remove(p)` to whatever project method happens to be named
2247
+ * `remove` — reintroducing, through its own escape hatch, the fabricated-edge
2248
+ * class this filter exists to prevent.
2249
+ *
2250
+ * Resolving the specifier is the same question resolveViaImport will ask
2251
+ * next, so a receiver that passes here is one the qualified path can actually
2252
+ * serve; anything else stays a silent miss rather than a wrong edge.
2253
+ */
2254
+ isPythonProjectModule(ref, receiver) {
2255
+ for (const imp of this.context.getImportMappings(ref.filePath, ref.language)) {
2256
+ if (imp.localName !== receiver)
2257
+ continue;
2258
+ // `import pkg.mod` / `import pkg.mod as m` binds the module `source`
2259
+ // names. `from pkg import mod` binds `pkg.mod`, and `from . import mod`
2260
+ // binds `.mod` — join without doubling the dot that makes `.` mean the
2261
+ // current package.
2262
+ const specifier = imp.isNamespace
2263
+ ? imp.source
2264
+ : imp.source.endsWith('.')
2265
+ ? `${imp.source}${imp.exportedName}`
2266
+ : `${imp.source}.${imp.exportedName}`;
2267
+ if ((0, import_resolver_1.resolveImportPath)(specifier, ref.filePath, ref.language, this.context)) {
2268
+ return true;
2269
+ }
2270
+ }
2271
+ return false;
2272
+ }
1929
2273
  /**
1930
2274
  * Check if reference is to a built-in or external symbol
1931
2275
  */
@@ -1934,7 +2278,7 @@ class ReferenceResolver {
1934
2278
  const isJsTs = ref.language === 'typescript' || ref.language === 'javascript'
1935
2279
  || ref.language === 'tsx' || ref.language === 'jsx' || ref.language === 'arkts';
1936
2280
  // JavaScript/TypeScript built-ins
1937
- if (isJsTs && JS_BUILT_INS.has(name)) {
2281
+ if (isJsTs && js_builtins_1.JS_BUILT_INS.has(name)) {
1938
2282
  return true;
1939
2283
  }
1940
2284
  // ArkTS resource-reference intrinsics — `$r('app.string.x')` /
@@ -1968,10 +2312,27 @@ class ReferenceResolver {
1968
2312
  }
1969
2313
  // Filter built-in methods on non-class receivers
1970
2314
  // (e.g., items.append where items is a local list variable)
1971
- // But allow if the capitalized receiver matches a known codebase class
2315
+ // But allow if the capitalized receiver matches a known codebase class,
2316
+ // OR the receiver is itself an imported project module — a module can
2317
+ // export a top-level function sharing a common collection-method name
2318
+ // (`ledger.append`, `from . import ledger`), and that call is a real
2319
+ // project dependency, not `list.append` (#1681). Without this, the
2320
+ // qualified ref never reaches resolveViaImport / resolvePythonModuleMember.
1972
2321
  if (PYTHON_BUILT_IN_METHODS.has(method)) {
2322
+ // A module-scope collection binding is stronger evidence than a
2323
+ // coincidentally matching class name (#1652). Only use this file's
2324
+ // binding: an unrelated module may reuse the receiver for a collection.
2325
+ const isCollection = this.context.getNodesByName(receiver).some((node) => node.language === 'python' && node.filePath === ref.filePath &&
2326
+ (node.kind === 'variable' || node.kind === 'constant') &&
2327
+ node.qualifiedName === receiver &&
2328
+ /^=\s*(?:[\[{]|(?:dict|list|set|tuple|frozenset)\s*\(|\(\s*\)|\([^()]*,)/.test(node.signature ?? ''));
2329
+ if (isCollection)
2330
+ return true;
1973
2331
  const capitalized = receiver.charAt(0).toUpperCase() + receiver.slice(1);
1974
- if (!this.knownNames?.has(capitalized)) {
2332
+ const isKnownClass = this.context.getNodesByName(capitalized).some((node) => node.language === 'python' &&
2333
+ (node.kind === 'class' || node.kind === 'struct' || node.kind === 'interface'));
2334
+ const isProjectModule = !isKnownClass && this.isPythonProjectModule(ref, receiver);
2335
+ if (!isKnownClass && !isProjectModule) {
1975
2336
  return true;
1976
2337
  }
1977
2338
  }
@@ -1979,9 +2340,8 @@ class ReferenceResolver {
1979
2340
  // A bare name colliding with a builtin method (index, get, update, count…)
1980
2341
  // is only a builtin when NOTHING in the codebase declares it. A declared
1981
2342
  // symbol with that exact name — e.g. a Flask/FastAPI view `def index()` or
1982
- // `def get()` — is a real reference target. Mirrors the knownNames guard on
1983
- // the dotted branch above; without it, every handler named after a builtin
1984
- // method silently loses its route→handler edge.
2343
+ // `def get()` — is a real reference target. Without this guard, every
2344
+ // handler named after a builtin method silently loses its route→handler edge.
1985
2345
  if (PYTHON_BUILT_IN_METHODS.has(name) && !this.knownNames?.has(name)) {
1986
2346
  return true;
1987
2347
  }
@@ -2032,28 +2392,16 @@ class ReferenceResolver {
2032
2392
  * Get file path from node ID
2033
2393
  */
2034
2394
  getFilePathFromNodeId(nodeId) {
2035
- const node = this.queries.getNodeById(nodeId);
2395
+ const node = this.nodeById(nodeId);
2036
2396
  return node?.filePath || '';
2037
2397
  }
2038
2398
  /**
2039
2399
  * Get language from node ID
2040
2400
  */
2041
2401
  getLanguageFromNodeId(nodeId) {
2042
- const node = this.queries.getNodeById(nodeId);
2402
+ const node = this.nodeById(nodeId);
2043
2403
  return node?.language || 'unknown';
2044
2404
  }
2045
- /**
2046
- * Drop an import/name-strategy resolution that crosses a language family.
2047
- * Two regimes (mirrors `applyLanguageGate`'s candidate filter):
2048
- * - `references` (type usage): STRICT — a `Type.member` static read names a
2049
- * same-family type, never a coincidentally same-named symbol in another
2050
- * language. Drops any non-same-family target.
2051
- * - `imports` (import binding / `#include`): both-known — a C++ `#include
2052
- * "X.h"` must not resolve to a same-named ObjC header on another platform
2053
- * (basename collision), but a singleton-family / SFC language (`vue` →
2054
- * `.ts`) importing across is left alone.
2055
- * Applies to the import (strategy 2) + name-match (strategy 3) results.
2056
- */
2057
2405
  /**
2058
2406
  * Collect the `@using` namespaces in scope for a `.razor`/`.cshtml` file: its
2059
2407
  * own `@using` directives plus every `_Imports.razor` from the file's folder up
@@ -2211,7 +2559,7 @@ class ReferenceResolver {
2211
2559
  const member = ref.referenceName.slice('this.'.length);
2212
2560
  if (!member)
2213
2561
  return null;
2214
- const fromNode = this.queries.getNodeById(ref.fromNodeId);
2562
+ const fromNode = this.nodeById(ref.fromNodeId);
2215
2563
  if (!fromNode)
2216
2564
  return null;
2217
2565
  // A hook declared at class-body level (Ruby `before_action :authenticate`)
@@ -2236,7 +2584,7 @@ class ReferenceResolver {
2236
2584
  // Not on the class itself — possibly INHERITED. implements/extends
2237
2585
  // edges don't exist yet in this pass, so retry in the supertype pass
2238
2586
  // (resolveDeferredThisMemberRefs) instead of giving up.
2239
- this.deferredThisMemberRefs.push(ref);
2587
+ this.deferReference(ref, this.deferredThisMemberRefs);
2240
2588
  return null;
2241
2589
  }
2242
2590
  const target = candidates.reduce((a, b) => (a.startLine <= b.startLine ? a : b));
@@ -2267,10 +2615,41 @@ class ReferenceResolver {
2267
2615
  // periodically so the #850 liveness watchdog heartbeat can fire (#1091).
2268
2616
  const maybeYield = (0, cooperative_yield_1.createYielder)();
2269
2617
  const resolved = [];
2618
+ // Refs share supertypes (every `this.dispose` walks the same chain), and
2619
+ // nothing is written until the loop ends: read each type's supertype
2620
+ // edges, and each supertype's callable members by name, once.
2621
+ const supertypeEdges = new Map();
2622
+ const callableMembers = new Map();
2623
+ const supertypesOf = (id) => {
2624
+ let edges = supertypeEdges.get(id);
2625
+ if (!edges) {
2626
+ edges = this.queries.getOutgoingEdges(id, ['implements', 'extends']);
2627
+ supertypeEdges.set(id, edges);
2628
+ }
2629
+ return edges;
2630
+ };
2631
+ const callableMembersOf = (id) => {
2632
+ let byName = callableMembers.get(id);
2633
+ if (!byName) {
2634
+ byName = new Map();
2635
+ for (const c of this.queries.getOutgoingEdges(id, ['contains'])) {
2636
+ const m = this.nodeById(c.target);
2637
+ if (!m || (m.kind !== 'function' && m.kind !== 'method'))
2638
+ continue;
2639
+ const list = byName.get(m.name);
2640
+ if (list)
2641
+ list.push(m);
2642
+ else
2643
+ byName.set(m.name, [m]);
2644
+ }
2645
+ callableMembers.set(id, byName);
2646
+ }
2647
+ return byName;
2648
+ };
2270
2649
  for (const ref of deferred) {
2271
2650
  await maybeYield();
2272
2651
  const member = ref.referenceName.slice('this.'.length);
2273
- const fromNode = this.queries.getNodeById(ref.fromNodeId);
2652
+ const fromNode = this.nodeById(ref.fromNodeId);
2274
2653
  if (!fromNode || !member)
2275
2654
  continue;
2276
2655
  // Class-body-level hooks (Ruby) attribute to the CLASS node itself.
@@ -2310,24 +2689,18 @@ class ReferenceResolver {
2310
2689
  for (let depth = 0; depth < 5 && frontierNodes.length > 0 && !target; depth++) {
2311
2690
  const next = [];
2312
2691
  for (const typeNode of frontierNodes) {
2313
- for (const edge of this.queries.getOutgoingEdges(typeNode.id, ['implements', 'extends'])) {
2314
- const superNode = this.queries.getNodeById(edge.target);
2692
+ for (const edge of supertypesOf(typeNode.id)) {
2693
+ const superNode = this.nodeById(edge.target);
2315
2694
  if (!superNode || seenNodes.has(superNode.id))
2316
2695
  continue;
2317
2696
  seenNodes.add(superNode.id);
2318
2697
  if (!SUPERTYPE_BEARING_KINDS.has(superNode.kind))
2319
2698
  continue;
2320
2699
  // Member lookup anchored on the supertype's contains edges.
2321
- for (const c of this.queries.getOutgoingEdges(superNode.id, ['contains'])) {
2322
- const m = this.queries.getNodeById(c.target);
2323
- if (m &&
2324
- m.name === member &&
2325
- (m.kind === 'function' || m.kind === 'method') &&
2326
- (0, name_matcher_1.sameLanguageFamily)(m.language, ref.language)) {
2327
- target = m;
2328
- break;
2329
- }
2330
- }
2700
+ target =
2701
+ callableMembersOf(superNode.id)
2702
+ .get(member)
2703
+ ?.find((m) => (0, name_matcher_1.sameLanguageFamily)(m.language, ref.language)) ?? null;
2331
2704
  if (target)
2332
2705
  break;
2333
2706
  next.push(superNode);
@@ -2346,47 +2719,99 @@ class ReferenceResolver {
2346
2719
  });
2347
2720
  }
2348
2721
  }
2349
- if (resolved.length === 0)
2350
- return 0;
2351
- const edges = this.createEdges(resolved);
2352
- if (edges.length > 0) {
2353
- this.queries.insertEdges(edges);
2354
- this.clearCaches();
2355
- }
2356
- return edges.length;
2722
+ return this.persistDeferredReferences(deferred, resolved);
2357
2723
  }
2358
- gateLanguage(result, ref) {
2724
+ /**
2725
+ * Drop a resolution whose target cannot be what the reference names.
2726
+ * Applied at the `resolveOne` seam so it covers every strategy uniformly —
2727
+ * framework, import, name-match, chain, CFML component path.
2728
+ *
2729
+ * For `imports`: the target must be importable. A member that only exists
2730
+ * inside a type never is.
2731
+ *
2732
+ * For `extends`/`implements`, it cannot be describing a real supertype when:
2733
+ *
2734
+ * 1. The target's kind can never be a supertype (an enum member, a method,
2735
+ * a variable). `matchByExactName` additionally narrows its candidate
2736
+ * pool by the same set, so a legitimate supertype outranks a same-named
2737
+ * non-type rather than merely losing its edge.
2738
+ * 2. The name is imported from outside the repo, so NO local node is the
2739
+ * referent. Without this, filtering by kind alone just relocates the
2740
+ * false edge onto the next same-named local type.
2741
+ *
2742
+ * One exception to (1): a TypeScript VALUE that shares its name with a type
2743
+ * in the same file. `export const IFoo = createDecorator<IFoo>('foo')` beside
2744
+ * `export interface IFoo` is how VS Code declares every service, and an
2745
+ * import of `IFoo` resolves to the file with both — a strategy that takes the
2746
+ * first export of that name gets the value. The strategy found the right
2747
+ * file and name; the type declared there is the supertype, so the edge moves
2748
+ * to it rather than being dropped (dropping it lost ~900 `implements` edges
2749
+ * on vscode).
2750
+ *
2751
+ * Otherwise this only ever REMOVES an edge, never adds one. A dropped ref
2752
+ * stays in `unresolved_refs` as `failed`, which is the honest record for a
2753
+ * supertype that lives outside the repo — silent beats wrong.
2754
+ */
2755
+ gateTargetKind(result, ref) {
2359
2756
  if (!result)
2360
2757
  return result;
2361
- const tgt = this.getLanguageFromNodeId(result.targetNodeId);
2362
- if (!tgt || !ref.language)
2758
+ // A `#define` is a value, never a callee (#1838): a macro defined only in
2759
+ // an unrelated file is not what `NAME(x)` here expands to either.
2760
+ if (ref.referenceKind === 'calls') {
2761
+ const target = this.nodeById(result.targetNodeId);
2762
+ if (target?.kind === 'constant' && types_1.CPP_DEFINE_SIGNATURE.test(target.signature ?? ''))
2763
+ return null;
2764
+ }
2765
+ // An `imports` reference names something importable — never a member that
2766
+ // only exists inside a type.
2767
+ if (ref.referenceKind === 'imports') {
2768
+ const target = this.nodeById(result.targetNodeId);
2769
+ return target && !(0, types_1.isImportableKind)(target.kind) ? null : result;
2770
+ }
2771
+ if (!(0, types_1.isInheritanceRef)(ref))
2363
2772
  return result;
2364
- if ((ref.referenceKind === 'references' || ref.referenceKind === 'function_ref') && !(0, name_matcher_1.sameLanguageFamily)(tgt, ref.language))
2365
- return null;
2366
- if (ref.referenceKind === 'imports' && (0, name_matcher_1.crossesKnownFamily)(tgt, ref.language))
2773
+ const target = this.nodeById(result.targetNodeId);
2774
+ if (target && !(0, types_1.isSupertypeTarget)(target)) {
2775
+ const type = this.sameNamedTypeOfValue(target);
2776
+ if (!type)
2777
+ return null;
2778
+ result = { ...result, targetNodeId: type.id };
2779
+ }
2780
+ if ((0, import_resolver_1.isBoundToOutOfRepoImport)(ref, this.context))
2367
2781
  return null;
2368
2782
  return result;
2369
2783
  }
2784
+ /** The one supertype-kind node a TypeScript value shares its name and file with. */
2785
+ sameNamedTypeOfValue(value) {
2786
+ if (value.kind !== 'constant' && value.kind !== 'variable')
2787
+ return null;
2788
+ if (value.language !== 'typescript' && value.language !== 'tsx')
2789
+ return null;
2790
+ const types = this.context
2791
+ .getNodesInFile(value.filePath)
2792
+ .filter((n) => n.name === value.name && (0, types_1.isSupertypeTarget)(n));
2793
+ return types.length === 1 ? types[0] : null;
2794
+ }
2795
+ gateLanguage(result, ref) {
2796
+ if (!result)
2797
+ return result;
2798
+ return (0, name_matcher_1.gateLanguageMatch)(result, ref, this.context);
2799
+ }
2370
2800
  /**
2371
- * Drop a FRAMEWORK-strategy resolution that crosses two *known* language
2372
- * families for a type-usage (`references`) or import-binding (`imports`)
2373
- * edge. The framework strategy is intentionally ungated for cross-language
2374
- * bridges, but those legitimate bridges are either `calls` edges (RN/Expo
2375
- * JS → native) or config↔code edges whose config side (`yaml`/`blade`/…) is
2376
- * not a known programming-language family. A `references`/`imports` edge
2377
- * between two *known* families is always a coincidental name collision — the
2378
- * React/Svelte/Vue PascalCase component resolvers name-match `getNodesByName`
2379
- * without a language check, so a TS `<TestRunner>` ref happily matched a
2380
- * Kotlin `class TestRunner`. Gating only the both-known-cross-family case
2381
- * lets config bridges and `calls` bridges through untouched.
2801
+ * Framework calls carry bridge evidence (RN/Expo JS → native). Other
2802
+ * framework results obey the same code-family boundary as name matches;
2803
+ * markup/config transitions remain open.
2382
2804
  */
2383
2805
  gateFrameworkLanguage(result, ref) {
2384
2806
  if (!result)
2385
2807
  return result;
2386
- if (ref.referenceKind !== 'references' && ref.referenceKind !== 'imports')
2808
+ if (ref.referenceKind === 'calls')
2387
2809
  return result;
2388
2810
  const tgt = this.getLanguageFromNodeId(result.targetNodeId);
2389
- if (tgt && ref.language && (0, name_matcher_1.crossesKnownFamily)(tgt, ref.language))
2811
+ // Package imports cannot target prose found by a framework's name lookup.
2812
+ if (ref.referenceKind === 'imports' && tgt === 'markdown' && ref.language !== 'markdown')
2813
+ return null;
2814
+ if (tgt && ref.language && (0, name_matcher_1.crossesCodeBoundary)(tgt, ref.language))
2390
2815
  return null;
2391
2816
  return result;
2392
2817
  }