@stupidloud/codegraph 0.8.1 → 0.9.9

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 (341) hide show
  1. package/README.md +319 -152
  2. package/dist/bin/codegraph.d.ts +4 -0
  3. package/dist/bin/codegraph.d.ts.map +1 -1
  4. package/dist/bin/codegraph.js +354 -90
  5. package/dist/bin/codegraph.js.map +1 -1
  6. package/dist/bin/node-version-check.d.ts +17 -0
  7. package/dist/bin/node-version-check.d.ts.map +1 -1
  8. package/dist/bin/node-version-check.js +37 -0
  9. package/dist/bin/node-version-check.js.map +1 -1
  10. package/dist/config.d.ts.map +1 -1
  11. package/dist/config.js +1 -11
  12. package/dist/config.js.map +1 -1
  13. package/dist/context/formatter.d.ts.map +1 -1
  14. package/dist/context/formatter.js +25 -6
  15. package/dist/context/formatter.js.map +1 -1
  16. package/dist/context/index.d.ts +22 -0
  17. package/dist/context/index.d.ts.map +1 -1
  18. package/dist/context/index.js +257 -6
  19. package/dist/context/index.js.map +1 -1
  20. package/dist/context/markers.d.ts +19 -0
  21. package/dist/context/markers.d.ts.map +1 -0
  22. package/dist/context/markers.js +22 -0
  23. package/dist/context/markers.js.map +1 -0
  24. package/dist/db/index.d.ts +30 -1
  25. package/dist/db/index.d.ts.map +1 -1
  26. package/dist/db/index.js +75 -25
  27. package/dist/db/index.js.map +1 -1
  28. package/dist/db/queries.d.ts +104 -0
  29. package/dist/db/queries.d.ts.map +1 -1
  30. package/dist/db/queries.js +328 -31
  31. package/dist/db/queries.js.map +1 -1
  32. package/dist/db/sqlite-adapter.d.ts +24 -23
  33. package/dist/db/sqlite-adapter.d.ts.map +1 -1
  34. package/dist/db/sqlite-adapter.js +54 -174
  35. package/dist/db/sqlite-adapter.js.map +1 -1
  36. package/dist/directory.d.ts.map +1 -1
  37. package/dist/directory.js +6 -20
  38. package/dist/directory.js.map +1 -1
  39. package/dist/extraction/generated-detection.d.ts +30 -0
  40. package/dist/extraction/generated-detection.d.ts.map +1 -0
  41. package/dist/extraction/generated-detection.js +80 -0
  42. package/dist/extraction/generated-detection.js.map +1 -0
  43. package/dist/extraction/grammars.d.ts +23 -1
  44. package/dist/extraction/grammars.d.ts.map +1 -1
  45. package/dist/extraction/grammars.js +107 -3
  46. package/dist/extraction/grammars.js.map +1 -1
  47. package/dist/extraction/index.d.ts +22 -14
  48. package/dist/extraction/index.d.ts.map +1 -1
  49. package/dist/extraction/index.js +272 -183
  50. package/dist/extraction/index.js.map +1 -1
  51. package/dist/extraction/languages/c-cpp.d.ts.map +1 -1
  52. package/dist/extraction/languages/c-cpp.js +45 -0
  53. package/dist/extraction/languages/c-cpp.js.map +1 -1
  54. package/dist/extraction/languages/csharp.d.ts.map +1 -1
  55. package/dist/extraction/languages/csharp.js +2 -1
  56. package/dist/extraction/languages/csharp.js.map +1 -1
  57. package/dist/extraction/languages/go.d.ts.map +1 -1
  58. package/dist/extraction/languages/go.js +18 -2
  59. package/dist/extraction/languages/go.js.map +1 -1
  60. package/dist/extraction/languages/index.d.ts.map +1 -1
  61. package/dist/extraction/languages/index.js +6 -0
  62. package/dist/extraction/languages/index.js.map +1 -1
  63. package/dist/extraction/languages/java.d.ts.map +1 -1
  64. package/dist/extraction/languages/java.js +6 -0
  65. package/dist/extraction/languages/java.js.map +1 -1
  66. package/dist/extraction/languages/kotlin.d.ts.map +1 -1
  67. package/dist/extraction/languages/kotlin.js +6 -0
  68. package/dist/extraction/languages/kotlin.js.map +1 -1
  69. package/dist/extraction/languages/lua.d.ts +3 -0
  70. package/dist/extraction/languages/lua.d.ts.map +1 -0
  71. package/dist/extraction/languages/lua.js +150 -0
  72. package/dist/extraction/languages/lua.js.map +1 -0
  73. package/dist/extraction/languages/luau.d.ts +3 -0
  74. package/dist/extraction/languages/luau.d.ts.map +1 -0
  75. package/dist/extraction/languages/luau.js +37 -0
  76. package/dist/extraction/languages/luau.js.map +1 -0
  77. package/dist/extraction/languages/objc.d.ts +3 -0
  78. package/dist/extraction/languages/objc.d.ts.map +1 -0
  79. package/dist/extraction/languages/objc.js +133 -0
  80. package/dist/extraction/languages/objc.js.map +1 -0
  81. package/dist/extraction/mybatis-extractor.d.ts +48 -0
  82. package/dist/extraction/mybatis-extractor.d.ts.map +1 -0
  83. package/dist/extraction/mybatis-extractor.js +198 -0
  84. package/dist/extraction/mybatis-extractor.js.map +1 -0
  85. package/dist/extraction/tree-sitter-types.d.ts +14 -0
  86. package/dist/extraction/tree-sitter-types.d.ts.map +1 -1
  87. package/dist/extraction/tree-sitter.d.ts +84 -0
  88. package/dist/extraction/tree-sitter.d.ts.map +1 -1
  89. package/dist/extraction/tree-sitter.js +715 -16
  90. package/dist/extraction/tree-sitter.js.map +1 -1
  91. package/dist/extraction/vue-extractor.d.ts +15 -0
  92. package/dist/extraction/vue-extractor.d.ts.map +1 -1
  93. package/dist/extraction/vue-extractor.js +88 -0
  94. package/dist/extraction/vue-extractor.js.map +1 -1
  95. package/dist/extraction/wasm/tree-sitter-lua.wasm +0 -0
  96. package/dist/extraction/wasm/tree-sitter-luau.wasm +0 -0
  97. package/dist/extraction/wasm-runtime-flags.d.ts +38 -0
  98. package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -0
  99. package/dist/extraction/wasm-runtime-flags.js +106 -0
  100. package/dist/extraction/wasm-runtime-flags.js.map +1 -0
  101. package/dist/graph/traversal.d.ts.map +1 -1
  102. package/dist/graph/traversal.js +76 -38
  103. package/dist/graph/traversal.js.map +1 -1
  104. package/dist/index.d.ts +77 -8
  105. package/dist/index.d.ts.map +1 -1
  106. package/dist/index.js +133 -19
  107. package/dist/index.js.map +1 -1
  108. package/dist/installer/config-writer.d.ts +7 -8
  109. package/dist/installer/config-writer.d.ts.map +1 -1
  110. package/dist/installer/config-writer.js +7 -27
  111. package/dist/installer/config-writer.js.map +1 -1
  112. package/dist/installer/index.d.ts +51 -16
  113. package/dist/installer/index.d.ts.map +1 -1
  114. package/dist/installer/index.js +120 -29
  115. package/dist/installer/index.js.map +1 -1
  116. package/dist/installer/instructions-template.d.ts +11 -21
  117. package/dist/installer/instructions-template.d.ts.map +1 -1
  118. package/dist/installer/instructions-template.js +12 -56
  119. package/dist/installer/instructions-template.js.map +1 -1
  120. package/dist/installer/targets/antigravity.d.ts +57 -0
  121. package/dist/installer/targets/antigravity.d.ts.map +1 -0
  122. package/dist/installer/targets/antigravity.js +308 -0
  123. package/dist/installer/targets/antigravity.js.map +1 -0
  124. package/dist/installer/targets/claude.d.ts +26 -1
  125. package/dist/installer/targets/claude.d.ts.map +1 -1
  126. package/dist/installer/targets/claude.js +118 -40
  127. package/dist/installer/targets/claude.js.map +1 -1
  128. package/dist/installer/targets/codex.d.ts.map +1 -1
  129. package/dist/installer/targets/codex.js +15 -13
  130. package/dist/installer/targets/codex.js.map +1 -1
  131. package/dist/installer/targets/cursor.d.ts.map +1 -1
  132. package/dist/installer/targets/cursor.js +61 -36
  133. package/dist/installer/targets/cursor.js.map +1 -1
  134. package/dist/installer/targets/gemini.d.ts +26 -0
  135. package/dist/installer/targets/gemini.d.ts.map +1 -0
  136. package/dist/installer/targets/gemini.js +167 -0
  137. package/dist/installer/targets/gemini.js.map +1 -0
  138. package/dist/installer/targets/hermes.d.ts +18 -0
  139. package/dist/installer/targets/hermes.d.ts.map +1 -0
  140. package/dist/installer/targets/hermes.js +359 -0
  141. package/dist/installer/targets/hermes.js.map +1 -0
  142. package/dist/installer/targets/kiro.d.ts +27 -0
  143. package/dist/installer/targets/kiro.d.ts.map +1 -0
  144. package/dist/installer/targets/kiro.js +178 -0
  145. package/dist/installer/targets/kiro.js.map +1 -0
  146. package/dist/installer/targets/opencode.d.ts.map +1 -1
  147. package/dist/installer/targets/opencode.js +15 -13
  148. package/dist/installer/targets/opencode.js.map +1 -1
  149. package/dist/installer/targets/registry.d.ts.map +1 -1
  150. package/dist/installer/targets/registry.js +8 -0
  151. package/dist/installer/targets/registry.js.map +1 -1
  152. package/dist/installer/targets/shared.d.ts.map +1 -1
  153. package/dist/installer/targets/shared.js +3 -2
  154. package/dist/installer/targets/shared.js.map +1 -1
  155. package/dist/installer/targets/types.d.ts +1 -16
  156. package/dist/installer/targets/types.d.ts.map +1 -1
  157. package/dist/mcp/daemon-paths.d.ts +46 -0
  158. package/dist/mcp/daemon-paths.d.ts.map +1 -0
  159. package/dist/mcp/daemon-paths.js +125 -0
  160. package/dist/mcp/daemon-paths.js.map +1 -0
  161. package/dist/mcp/daemon.d.ts +161 -0
  162. package/dist/mcp/daemon.d.ts.map +1 -0
  163. package/dist/mcp/daemon.js +403 -0
  164. package/dist/mcp/daemon.js.map +1 -0
  165. package/dist/mcp/engine.d.ts +105 -0
  166. package/dist/mcp/engine.d.ts.map +1 -0
  167. package/dist/mcp/engine.js +270 -0
  168. package/dist/mcp/engine.js.map +1 -0
  169. package/dist/mcp/index.d.ts +70 -52
  170. package/dist/mcp/index.d.ts.map +1 -1
  171. package/dist/mcp/index.js +355 -331
  172. package/dist/mcp/index.js.map +1 -1
  173. package/dist/mcp/proxy.d.ts +81 -0
  174. package/dist/mcp/proxy.d.ts.map +1 -0
  175. package/dist/mcp/proxy.js +510 -0
  176. package/dist/mcp/proxy.js.map +1 -0
  177. package/dist/mcp/server-instructions.d.ts +1 -1
  178. package/dist/mcp/server-instructions.d.ts.map +1 -1
  179. package/dist/mcp/server-instructions.js +21 -21
  180. package/dist/mcp/session.d.ts +77 -0
  181. package/dist/mcp/session.d.ts.map +1 -0
  182. package/dist/mcp/session.js +294 -0
  183. package/dist/mcp/session.js.map +1 -0
  184. package/dist/mcp/tools.d.ts +171 -15
  185. package/dist/mcp/tools.d.ts.map +1 -1
  186. package/dist/mcp/tools.js +1714 -298
  187. package/dist/mcp/tools.js.map +1 -1
  188. package/dist/mcp/transport.d.ts +111 -29
  189. package/dist/mcp/transport.d.ts.map +1 -1
  190. package/dist/mcp/transport.js +181 -71
  191. package/dist/mcp/transport.js.map +1 -1
  192. package/dist/mcp/version.d.ts +19 -0
  193. package/dist/mcp/version.d.ts.map +1 -0
  194. package/dist/mcp/version.js +71 -0
  195. package/dist/mcp/version.js.map +1 -0
  196. package/dist/resolution/callback-synthesizer.d.ts +10 -0
  197. package/dist/resolution/callback-synthesizer.d.ts.map +1 -0
  198. package/dist/resolution/callback-synthesizer.js +1300 -0
  199. package/dist/resolution/callback-synthesizer.js.map +1 -0
  200. package/dist/resolution/frameworks/csharp.d.ts.map +1 -1
  201. package/dist/resolution/frameworks/csharp.js +36 -8
  202. package/dist/resolution/frameworks/csharp.js.map +1 -1
  203. package/dist/resolution/frameworks/drupal.d.ts +51 -0
  204. package/dist/resolution/frameworks/drupal.d.ts.map +1 -0
  205. package/dist/resolution/frameworks/drupal.js +367 -0
  206. package/dist/resolution/frameworks/drupal.js.map +1 -0
  207. package/dist/resolution/frameworks/expo-modules.d.ts +3 -0
  208. package/dist/resolution/frameworks/expo-modules.d.ts.map +1 -0
  209. package/dist/resolution/frameworks/expo-modules.js +143 -0
  210. package/dist/resolution/frameworks/expo-modules.js.map +1 -0
  211. package/dist/resolution/frameworks/express.d.ts.map +1 -1
  212. package/dist/resolution/frameworks/express.js +102 -19
  213. package/dist/resolution/frameworks/express.js.map +1 -1
  214. package/dist/resolution/frameworks/fabric.d.ts +3 -0
  215. package/dist/resolution/frameworks/fabric.d.ts.map +1 -0
  216. package/dist/resolution/frameworks/fabric.js +354 -0
  217. package/dist/resolution/frameworks/fabric.js.map +1 -0
  218. package/dist/resolution/frameworks/go.d.ts.map +1 -1
  219. package/dist/resolution/frameworks/go.js +6 -3
  220. package/dist/resolution/frameworks/go.js.map +1 -1
  221. package/dist/resolution/frameworks/index.d.ts +6 -0
  222. package/dist/resolution/frameworks/index.d.ts.map +1 -1
  223. package/dist/resolution/frameworks/index.js +29 -1
  224. package/dist/resolution/frameworks/index.js.map +1 -1
  225. package/dist/resolution/frameworks/java.d.ts.map +1 -1
  226. package/dist/resolution/frameworks/java.js +339 -12
  227. package/dist/resolution/frameworks/java.js.map +1 -1
  228. package/dist/resolution/frameworks/laravel.d.ts.map +1 -1
  229. package/dist/resolution/frameworks/laravel.js +17 -8
  230. package/dist/resolution/frameworks/laravel.js.map +1 -1
  231. package/dist/resolution/frameworks/nestjs.d.ts.map +1 -1
  232. package/dist/resolution/frameworks/nestjs.js +324 -0
  233. package/dist/resolution/frameworks/nestjs.js.map +1 -1
  234. package/dist/resolution/frameworks/play.d.ts +19 -0
  235. package/dist/resolution/frameworks/play.d.ts.map +1 -0
  236. package/dist/resolution/frameworks/play.js +111 -0
  237. package/dist/resolution/frameworks/play.js.map +1 -0
  238. package/dist/resolution/frameworks/python.d.ts.map +1 -1
  239. package/dist/resolution/frameworks/python.js +134 -16
  240. package/dist/resolution/frameworks/python.js.map +1 -1
  241. package/dist/resolution/frameworks/react-native.d.ts +3 -0
  242. package/dist/resolution/frameworks/react-native.d.ts.map +1 -0
  243. package/dist/resolution/frameworks/react-native.js +360 -0
  244. package/dist/resolution/frameworks/react-native.js.map +1 -0
  245. package/dist/resolution/frameworks/react.d.ts.map +1 -1
  246. package/dist/resolution/frameworks/react.js +96 -3
  247. package/dist/resolution/frameworks/react.js.map +1 -1
  248. package/dist/resolution/frameworks/ruby.d.ts.map +1 -1
  249. package/dist/resolution/frameworks/ruby.js +106 -2
  250. package/dist/resolution/frameworks/ruby.js.map +1 -1
  251. package/dist/resolution/frameworks/rust.d.ts.map +1 -1
  252. package/dist/resolution/frameworks/rust.js +102 -5
  253. package/dist/resolution/frameworks/rust.js.map +1 -1
  254. package/dist/resolution/frameworks/swift-objc.d.ts +37 -0
  255. package/dist/resolution/frameworks/swift-objc.d.ts.map +1 -0
  256. package/dist/resolution/frameworks/swift-objc.js +252 -0
  257. package/dist/resolution/frameworks/swift-objc.js.map +1 -0
  258. package/dist/resolution/frameworks/swift.d.ts.map +1 -1
  259. package/dist/resolution/frameworks/swift.js +30 -6
  260. package/dist/resolution/frameworks/swift.js.map +1 -1
  261. package/dist/resolution/go-module.d.ts +26 -0
  262. package/dist/resolution/go-module.d.ts.map +1 -0
  263. package/dist/resolution/go-module.js +78 -0
  264. package/dist/resolution/go-module.js.map +1 -0
  265. package/dist/resolution/import-resolver.d.ts +28 -0
  266. package/dist/resolution/import-resolver.d.ts.map +1 -1
  267. package/dist/resolution/import-resolver.js +617 -5
  268. package/dist/resolution/import-resolver.js.map +1 -1
  269. package/dist/resolution/index.d.ts +11 -0
  270. package/dist/resolution/index.d.ts.map +1 -1
  271. package/dist/resolution/index.js +196 -10
  272. package/dist/resolution/index.js.map +1 -1
  273. package/dist/resolution/lru-cache.d.ts +24 -0
  274. package/dist/resolution/lru-cache.d.ts.map +1 -0
  275. package/dist/resolution/lru-cache.js +62 -0
  276. package/dist/resolution/lru-cache.js.map +1 -0
  277. package/dist/resolution/name-matcher.d.ts.map +1 -1
  278. package/dist/resolution/name-matcher.js +212 -0
  279. package/dist/resolution/name-matcher.js.map +1 -1
  280. package/dist/resolution/swift-objc-bridge.d.ts +134 -0
  281. package/dist/resolution/swift-objc-bridge.d.ts.map +1 -0
  282. package/dist/resolution/swift-objc-bridge.js +256 -0
  283. package/dist/resolution/swift-objc-bridge.js.map +1 -0
  284. package/dist/resolution/types.d.ts +44 -0
  285. package/dist/resolution/types.d.ts.map +1 -1
  286. package/dist/resolution/workspace-packages.d.ts +48 -0
  287. package/dist/resolution/workspace-packages.d.ts.map +1 -0
  288. package/dist/resolution/workspace-packages.js +208 -0
  289. package/dist/resolution/workspace-packages.js.map +1 -0
  290. package/dist/search/query-utils.d.ts +18 -0
  291. package/dist/search/query-utils.d.ts.map +1 -1
  292. package/dist/search/query-utils.js +30 -0
  293. package/dist/search/query-utils.js.map +1 -1
  294. package/dist/sync/git-hooks.d.ts.map +1 -1
  295. package/dist/sync/git-hooks.js +2 -0
  296. package/dist/sync/git-hooks.js.map +1 -1
  297. package/dist/sync/index.d.ts +3 -1
  298. package/dist/sync/index.d.ts.map +1 -1
  299. package/dist/sync/index.js +8 -1
  300. package/dist/sync/index.js.map +1 -1
  301. package/dist/sync/watcher.d.ts +214 -12
  302. package/dist/sync/watcher.d.ts.map +1 -1
  303. package/dist/sync/watcher.js +467 -55
  304. package/dist/sync/watcher.js.map +1 -1
  305. package/dist/sync/worktree.d.ts +54 -0
  306. package/dist/sync/worktree.d.ts.map +1 -0
  307. package/dist/sync/worktree.js +137 -0
  308. package/dist/sync/worktree.js.map +1 -0
  309. package/dist/types.d.ts +9 -1
  310. package/dist/types.d.ts.map +1 -1
  311. package/dist/types.js +14 -0
  312. package/dist/types.js.map +1 -1
  313. package/dist/utils.js +1 -1
  314. package/package.json +2 -2
  315. package/scripts/add-lang/bench.sh +60 -0
  316. package/scripts/add-lang/check-grammar.mjs +75 -0
  317. package/scripts/add-lang/dump-ast.mjs +103 -0
  318. package/scripts/add-lang/verify-extraction.mjs +70 -0
  319. package/scripts/agent-eval/arms-F.sh +21 -0
  320. package/scripts/agent-eval/arms-matrix.sh +37 -0
  321. package/scripts/agent-eval/bench-readme.sh +28 -0
  322. package/scripts/agent-eval/bench-why-repo.sh +22 -0
  323. package/scripts/agent-eval/block-read-hook.sh +19 -0
  324. package/scripts/agent-eval/hook-settings.json +15 -0
  325. package/scripts/agent-eval/itrun.sh +24 -11
  326. package/scripts/agent-eval/parse-arms.mjs +116 -0
  327. package/scripts/agent-eval/parse-bench-readme.mjs +84 -0
  328. package/scripts/agent-eval/probe-context.mjs +21 -0
  329. package/scripts/agent-eval/probe-explore.mjs +40 -0
  330. package/scripts/agent-eval/probe-node.mjs +20 -0
  331. package/scripts/agent-eval/probe-sweep.mjs +119 -0
  332. package/scripts/agent-eval/probe-trace.mjs +20 -0
  333. package/scripts/agent-eval/run-arms.sh +56 -0
  334. package/scripts/agent-eval/seq-matrix.mjs +137 -0
  335. package/scripts/build-bundle.sh +118 -0
  336. package/scripts/npm-sdk.js +75 -0
  337. package/scripts/npm-shim.js +246 -0
  338. package/scripts/pack-npm.sh +119 -0
  339. package/scripts/prepare-release.mjs +270 -0
  340. package/scripts/patch-tree-sitter-dart.js +0 -112
  341. package/scripts/release.sh +0 -68
@@ -39,12 +39,17 @@ var __importStar = (this && this.__importStar) || (function () {
39
39
  })();
40
40
  Object.defineProperty(exports, "__esModule", { value: true });
41
41
  exports.resolveImportPath = resolveImportPath;
42
+ exports.clearCppIncludeDirCache = clearCppIncludeDirCache;
43
+ exports.loadCppIncludeDirs = loadCppIncludeDirs;
42
44
  exports.extractImportMappings = extractImportMappings;
43
45
  exports.clearImportMappingCache = clearImportMappingCache;
44
46
  exports.extractReExports = extractReExports;
47
+ exports.resolveJvmImport = resolveJvmImport;
45
48
  exports.resolveViaImport = resolveViaImport;
49
+ const fs = __importStar(require("fs"));
46
50
  const path = __importStar(require("path"));
47
51
  const path_aliases_1 = require("./path-aliases");
52
+ const workspace_packages_1 = require("./workspace-packages");
48
53
  /**
49
54
  * Extension resolution order by language
50
55
  */
@@ -53,13 +58,21 @@ const EXTENSION_RESOLUTION = {
53
58
  javascript: ['.js', '.jsx', '.mjs', '.cjs', '/index.js', '/index.jsx'],
54
59
  tsx: ['.tsx', '.ts', '.d.ts', '.js', '.jsx', '/index.tsx', '/index.ts', '/index.js'],
55
60
  jsx: ['.jsx', '.js', '/index.jsx', '/index.js'],
61
+ // SFC consumers import plain TS/JS, sibling components, and barrels
62
+ // (`./lib` → `./lib/index.ts`). Without a list, relative imports from a
63
+ // `.svelte`/`.vue` file resolve to nothing, so barrel callers vanish (#629).
64
+ svelte: ['.ts', '.js', '.svelte', '.tsx', '.jsx', '/index.ts', '/index.js', '/index.svelte'],
65
+ vue: ['.ts', '.js', '.vue', '.tsx', '.jsx', '/index.ts', '/index.js', '/index.vue'],
56
66
  python: ['.py', '/__init__.py'],
57
67
  go: ['.go'],
58
68
  rust: ['.rs', '/mod.rs'],
59
69
  java: ['.java'],
70
+ c: ['.h', '.c'],
71
+ cpp: ['.h', '.hpp', '.hxx', '.cpp', '.cc', '.cxx'],
60
72
  csharp: ['.cs'],
61
73
  php: ['.php'],
62
74
  ruby: ['.rb'],
75
+ objc: ['.h', '.m', '.mm'],
63
76
  };
64
77
  /**
65
78
  * Resolve an import path to an actual file
@@ -79,8 +92,53 @@ function resolveImportPath(importPath, fromFile, language, context) {
79
92
  return resolveRelativeImport(importPath, fromDir, language, context);
80
93
  }
81
94
  // Handle absolute/aliased imports (like @/ or src/)
82
- return resolveAliasedImport(importPath, projectRoot, language, context);
95
+ const aliased = resolveAliasedImport(importPath, projectRoot, language, context);
96
+ if (aliased)
97
+ return aliased;
98
+ // C/C++ include directory search: when neither relative nor aliased
99
+ // resolution found a match, search -I directories from
100
+ // compile_commands.json or heuristic probing.
101
+ if (language === 'c' || language === 'cpp') {
102
+ return resolveCppIncludePath(importPath, language, context);
103
+ }
104
+ return null;
83
105
  }
106
+ /**
107
+ * C and C++ standard library header names (without delimiters).
108
+ * Used by isExternalImport to filter system includes from resolution.
109
+ */
110
+ const C_CPP_STDLIB_HEADERS = new Set([
111
+ // C standard library headers
112
+ 'assert.h', 'complex.h', 'ctype.h', 'errno.h', 'fenv.h', 'float.h',
113
+ 'inttypes.h', 'iso646.h', 'limits.h', 'locale.h', 'math.h', 'setjmp.h',
114
+ 'signal.h', 'stdalign.h', 'stdarg.h', 'stdatomic.h', 'stdbool.h',
115
+ 'stddef.h', 'stdint.h', 'stdio.h', 'stdlib.h', 'stdnoreturn.h',
116
+ 'string.h', 'tgmath.h', 'threads.h', 'time.h', 'uchar.h', 'wchar.h',
117
+ 'wctype.h',
118
+ // C++ C-library wrappers (cname form)
119
+ 'cassert', 'ccomplex', 'cctype', 'cerrno', 'cfenv', 'cfloat',
120
+ 'cinttypes', 'ciso646', 'climits', 'clocale', 'cmath', 'csetjmp',
121
+ 'csignal', 'cstdalign', 'cstdarg', 'cstdbool', 'cstddef', 'cstdint',
122
+ 'cstdio', 'cstdlib', 'cstring', 'ctgmath', 'ctime', 'cuchar',
123
+ 'cwchar', 'cwctype',
124
+ // C++ STL headers
125
+ 'algorithm', 'any', 'array', 'atomic', 'barrier', 'bit', 'bitset',
126
+ 'charconv', 'chrono', 'codecvt', 'compare', 'complex', 'concepts',
127
+ 'condition_variable', 'coroutine', 'deque', 'exception', 'execution',
128
+ 'expected', 'filesystem', 'format', 'forward_list', 'fstream',
129
+ 'functional', 'future', 'generator', 'initializer_list', 'iomanip',
130
+ 'ios', 'iosfwd', 'iostream', 'istream', 'iterator', 'latch',
131
+ 'limits', 'list', 'locale', 'map', 'mdspan', 'memory', 'memory_resource',
132
+ 'mutex', 'new', 'numbers', 'numeric', 'optional', 'ostream', 'print',
133
+ 'queue', 'random', 'ranges', 'ratio', 'regex', 'scoped_allocator',
134
+ 'semaphore', 'set', 'shared_mutex', 'source_location', 'span',
135
+ 'spanstream', 'sstream', 'stack', 'stacktrace', 'stdexcept',
136
+ 'stdfloat', 'stop_token', 'streambuf', 'string', 'string_view',
137
+ 'strstream', 'syncstream', 'system_error', 'thread', 'tuple',
138
+ 'type_traits', 'typeindex', 'typeinfo', 'unordered_map',
139
+ 'unordered_set', 'utility', 'valarray', 'variant', 'vector',
140
+ 'version',
141
+ ]);
84
142
  /**
85
143
  * Check if an import is external (npm package, etc.)
86
144
  *
@@ -94,6 +152,14 @@ function isExternalImport(importPath, language, context) {
94
152
  if (importPath.startsWith('.')) {
95
153
  return false;
96
154
  }
155
+ // Workspace-member imports (`@scope/ui`, `@scope/ui/widgets`) are LOCAL to
156
+ // a monorepo even though they look like bare npm specifiers. Consult the
157
+ // workspace map first so they aren't misclassified as external (#629). The
158
+ // map is null for single-package repos, so this is a no-op there.
159
+ const workspaces = context?.getWorkspacePackages?.();
160
+ if (workspaces && (0, workspace_packages_1.resolveWorkspaceImport)(importPath, workspaces)) {
161
+ return false;
162
+ }
97
163
  // Common external patterns
98
164
  if (language === 'typescript' || language === 'javascript' || language === 'tsx' || language === 'jsx') {
99
165
  // Node built-ins
@@ -122,10 +188,35 @@ function isExternalImport(importPath, language, context) {
122
188
  }
123
189
  }
124
190
  if (language === 'go') {
125
- // Standard library or external packages
126
- if (!importPath.startsWith('.') && !importPath.includes('/internal/')) {
127
- return true;
191
+ // Relative imports (rare in idiomatic Go but the grammar allows them).
192
+ if (importPath.startsWith('.')) {
193
+ return false;
194
+ }
195
+ // In-module imports look like `<module-path>/sub/pkg` — local to
196
+ // this project. Without the module-path check we'd flag every
197
+ // cross-package call in a Go monorepo as external (issue #388).
198
+ const mod = context?.getGoModule?.();
199
+ if (mod && (importPath === mod.modulePath || importPath.startsWith(mod.modulePath + '/'))) {
200
+ return false;
128
201
  }
202
+ // `internal/` packages stay local even when go.mod is missing —
203
+ // preserves the pre-#388 escape hatch for repos without a parsed module path.
204
+ if (importPath.includes('/internal/')) {
205
+ return false;
206
+ }
207
+ // Anything else is the Go standard library or a third-party module.
208
+ return true;
209
+ }
210
+ if (language === 'c' || language === 'cpp') {
211
+ // C/C++ standard library headers — both C-style (<stdio.h>) and
212
+ // C++-style (<cstdio>, <vector>) forms. Checked against the import
213
+ // path (which the extractor strips of <> or "" delimiters).
214
+ if (C_CPP_STDLIB_HEADERS.has(importPath))
215
+ return true;
216
+ // C++ headers without .h extension (e.g. "vector", "string")
217
+ const withoutExt = importPath.replace(/\.h$/, '');
218
+ if (C_CPP_STDLIB_HEADERS.has(withoutExt))
219
+ return true;
129
220
  }
130
221
  return false;
131
222
  }
@@ -184,6 +275,18 @@ function resolveAliasedImport(importPath, projectRoot, language, context) {
184
275
  return hit;
185
276
  }
186
277
  }
278
+ // 1.5 Workspace packages (`@scope/ui/widgets` → `packages/ui/widgets`).
279
+ // Resolves a monorepo member import to the member's directory; the
280
+ // extension/index permutations below then find its barrel (#629).
281
+ const workspaces = context.getWorkspacePackages?.();
282
+ if (workspaces) {
283
+ const base = (0, workspace_packages_1.resolveWorkspaceImport)(importPath, workspaces);
284
+ if (base) {
285
+ const hit = tryWithExt(base);
286
+ if (hit)
287
+ return hit;
288
+ }
289
+ }
187
290
  // 2. Hard-coded fallback list. Kept for projects that use these
188
291
  // conventional aliases without declaring them in tsconfig.
189
292
  const fallbackAliases = {
@@ -204,6 +307,215 @@ function resolveAliasedImport(importPath, projectRoot, language, context) {
204
307
  // 3. Direct path.
205
308
  return tryWithExt(importPath);
206
309
  }
310
+ /**
311
+ * C/C++ include directory cache (keyed by project root).
312
+ * Loaded once per resolver instance, shared across calls.
313
+ */
314
+ const cppIncludeDirCache = new Map();
315
+ /**
316
+ * Clear the C/C++ include directory cache (call between indexing runs)
317
+ */
318
+ function clearCppIncludeDirCache() {
319
+ cppIncludeDirCache.clear();
320
+ }
321
+ /**
322
+ * Discover C/C++ include search directories for a project.
323
+ *
324
+ * Strategy:
325
+ * 1. Look for compile_commands.json (Clang compilation database) in the
326
+ * project root and common build subdirectories. Parse -I and -isystem
327
+ * flags from compiler commands.
328
+ * 2. If no compilation database is found, probe for common convention
329
+ * directories (include/, src/, lib/, api/) and top-level directories
330
+ * containing .h/.hpp files.
331
+ *
332
+ * Returns paths relative to projectRoot.
333
+ */
334
+ function loadCppIncludeDirs(projectRoot) {
335
+ const cached = cppIncludeDirCache.get(projectRoot);
336
+ if (cached !== undefined)
337
+ return cached;
338
+ const dirs = loadCppIncludeDirsFromCompileDB(projectRoot)
339
+ || loadCppIncludeDirsHeuristic(projectRoot);
340
+ cppIncludeDirCache.set(projectRoot, dirs);
341
+ return dirs;
342
+ }
343
+ /**
344
+ * Try to load include directories from compile_commands.json.
345
+ * Returns null if no compilation database is found (so the heuristic
346
+ * fallback can run). Returns an array (possibly empty) otherwise.
347
+ */
348
+ function loadCppIncludeDirsFromCompileDB(projectRoot) {
349
+ const candidates = [
350
+ path.join(projectRoot, 'compile_commands.json'),
351
+ path.join(projectRoot, 'build', 'compile_commands.json'),
352
+ path.join(projectRoot, 'cmake-build-debug', 'compile_commands.json'),
353
+ path.join(projectRoot, 'cmake-build-release', 'compile_commands.json'),
354
+ path.join(projectRoot, 'out', 'compile_commands.json'),
355
+ ];
356
+ let dbPath;
357
+ for (const c of candidates) {
358
+ try {
359
+ if (fs.existsSync(c)) {
360
+ dbPath = c;
361
+ break;
362
+ }
363
+ }
364
+ catch {
365
+ // ignore
366
+ }
367
+ }
368
+ if (!dbPath)
369
+ return null;
370
+ try {
371
+ const content = fs.readFileSync(dbPath, 'utf-8');
372
+ const entries = JSON.parse(content);
373
+ if (!Array.isArray(entries))
374
+ return null;
375
+ const dirSet = new Set();
376
+ for (const entry of entries) {
377
+ const dir = entry.directory || projectRoot;
378
+ const args = entry.arguments || (entry.command ? shlexSplit(entry.command) : []);
379
+ for (let i = 0; i < args.length; i++) {
380
+ const arg = args[i];
381
+ let includeDir;
382
+ // -I<dir> (no space)
383
+ if (arg.startsWith('-I') && arg.length > 2) {
384
+ includeDir = arg.substring(2);
385
+ }
386
+ // -isystem <dir> (space-separated)
387
+ else if ((arg === '-isystem' || arg === '-I') && i + 1 < args.length) {
388
+ includeDir = args[i + 1];
389
+ i++; // skip next arg
390
+ }
391
+ if (includeDir) {
392
+ // Normalize: resolve relative to the compilation directory
393
+ const absPath = path.isAbsolute(includeDir)
394
+ ? includeDir
395
+ : path.resolve(dir, includeDir);
396
+ const relPath = path.relative(projectRoot, absPath).replace(/\\/g, '/');
397
+ // Skip system directories and paths outside the project
398
+ // (relative paths starting with .. or absolute paths like
399
+ // /usr/include or C:\usr on Windows)
400
+ if (!relPath.startsWith('..') && relPath.length > 0 && !path.isAbsolute(relPath)) {
401
+ dirSet.add(relPath);
402
+ }
403
+ }
404
+ }
405
+ }
406
+ return Array.from(dirSet);
407
+ }
408
+ catch {
409
+ return null;
410
+ }
411
+ }
412
+ /**
413
+ * Minimal shlex-style split for compiler command strings.
414
+ * Handles double-quoted and single-quoted arguments.
415
+ */
416
+ function shlexSplit(cmd) {
417
+ const result = [];
418
+ let i = 0;
419
+ while (i < cmd.length) {
420
+ // Skip whitespace
421
+ while (i < cmd.length && /\s/.test(cmd[i]))
422
+ i++;
423
+ if (i >= cmd.length)
424
+ break;
425
+ const ch = cmd[i];
426
+ if (ch === '"') {
427
+ i++;
428
+ let arg = '';
429
+ while (i < cmd.length && cmd[i] !== '"') {
430
+ if (cmd[i] === '\\' && i + 1 < cmd.length) {
431
+ i++;
432
+ arg += cmd[i];
433
+ }
434
+ else {
435
+ arg += cmd[i];
436
+ }
437
+ i++;
438
+ }
439
+ i++; // closing quote
440
+ result.push(arg);
441
+ }
442
+ else if (ch === "'") {
443
+ i++;
444
+ let arg = '';
445
+ while (i < cmd.length && cmd[i] !== "'") {
446
+ arg += cmd[i];
447
+ i++;
448
+ }
449
+ i++; // closing quote
450
+ result.push(arg);
451
+ }
452
+ else {
453
+ let arg = '';
454
+ while (i < cmd.length && !/\s/.test(cmd[i])) {
455
+ arg += cmd[i];
456
+ i++;
457
+ }
458
+ result.push(arg);
459
+ }
460
+ }
461
+ return result;
462
+ }
463
+ /**
464
+ * Heuristic include directory discovery when no compile_commands.json exists.
465
+ * Checks common convention directories and scans top-level dirs for headers.
466
+ */
467
+ function loadCppIncludeDirsHeuristic(projectRoot) {
468
+ const dirs = [];
469
+ const conventionDirs = ['include', 'src', 'lib', 'api', 'inc'];
470
+ try {
471
+ const entries = fs.readdirSync(projectRoot, { withFileTypes: true });
472
+ for (const entry of entries) {
473
+ if (!entry.isDirectory())
474
+ continue;
475
+ const name = entry.name;
476
+ // Convention directories
477
+ if (conventionDirs.includes(name.toLowerCase())) {
478
+ dirs.push(name);
479
+ continue;
480
+ }
481
+ // Any top-level directory containing .h or .hpp files
482
+ try {
483
+ const subFiles = fs.readdirSync(path.join(projectRoot, name));
484
+ if (subFiles.some(f => /\.(h|hpp|hxx|hh)$/i.test(f))) {
485
+ dirs.push(name);
486
+ }
487
+ }
488
+ catch {
489
+ // ignore permission errors
490
+ }
491
+ }
492
+ }
493
+ catch {
494
+ // ignore
495
+ }
496
+ return dirs;
497
+ }
498
+ /**
499
+ * Resolve a C/C++ include path by searching include directories.
500
+ * Called as a fallback after relative and aliased resolution fail.
501
+ */
502
+ function resolveCppIncludePath(importPath, language, context) {
503
+ const includeDirs = context.getCppIncludeDirs?.() ?? [];
504
+ const extensions = EXTENSION_RESOLUTION[language] ?? [];
505
+ for (const dir of includeDirs) {
506
+ const normalizedDir = dir.replace(/\\/g, '/');
507
+ for (const ext of extensions) {
508
+ const candidate = normalizedDir + '/' + importPath + ext;
509
+ if (context.fileExists(candidate))
510
+ return candidate;
511
+ }
512
+ // Try as-is (already has extension)
513
+ const candidate = normalizedDir + '/' + importPath;
514
+ if (context.fileExists(candidate))
515
+ return candidate;
516
+ }
517
+ return null;
518
+ }
207
519
  /**
208
520
  * Extract import mappings from a file
209
521
  */
@@ -212,15 +524,32 @@ function extractImportMappings(_filePath, content, language) {
212
524
  if (language === 'typescript' || language === 'javascript' || language === 'tsx' || language === 'jsx') {
213
525
  mappings.push(...extractJSImports(content));
214
526
  }
527
+ else if (language === 'svelte' || language === 'vue') {
528
+ // Svelte/Vue single-file components import via plain ES6 inside their
529
+ // `<script>` block. Without this, a `.svelte`/`.vue` consumer produces
530
+ // zero import mappings, so `resolveViaImport` can't run and a barrel
531
+ // import (`import { Foo } from './lib'`) falls back to name-matching —
532
+ // which silently fails whenever the re-export alias differs from the
533
+ // component's real name, yielding a false 0 callers (#629). The ES6
534
+ // import regex only matches `import … from '…'`, so running it over the
535
+ // whole SFC (markup + styles included) is safe.
536
+ mappings.push(...extractJSImports(content));
537
+ }
215
538
  else if (language === 'python') {
216
539
  mappings.push(...extractPythonImports(content));
217
540
  }
218
541
  else if (language === 'go') {
219
542
  mappings.push(...extractGoImports(content));
220
543
  }
544
+ else if (language === 'java' || language === 'kotlin') {
545
+ mappings.push(...extractJavaImports(content));
546
+ }
221
547
  else if (language === 'php') {
222
548
  mappings.push(...extractPHPImports(content));
223
549
  }
550
+ else if (language === 'c' || language === 'cpp') {
551
+ mappings.push(...extractCppImports(content));
552
+ }
224
553
  return mappings;
225
554
  }
226
555
  /**
@@ -406,6 +735,50 @@ function extractGoImports(content) {
406
735
  }
407
736
  return mappings;
408
737
  }
738
+ /**
739
+ * Extract Java / Kotlin import mappings.
740
+ *
741
+ * Java/Kotlin imports carry the full qualified name of the imported
742
+ * symbol — `import com.example.dao.converter.FooConverter;` — which is
743
+ * exactly the disambiguation signal we need when two packages both
744
+ * declare a `FooConverter`. Pre-#314 the resolver had no Java branch
745
+ * here at all, so this mapping was empty and cross-module name
746
+ * collisions were resolved by file-path proximity (often wrongly).
747
+ *
748
+ * `import static com.example.Foo.bar;` is parsed as a local-name `bar`
749
+ * pointing at FQN `com.example.Foo.bar` so static-method call sites
750
+ * (`bar(...)`) can resolve through the same import lookup.
751
+ */
752
+ function extractJavaImports(content) {
753
+ const mappings = [];
754
+ // Strip line and block comments so `// import foo;` doesn't false-match.
755
+ const stripped = content
756
+ .replace(/\/\*[\s\S]*?\*\//g, '')
757
+ .replace(/\/\/[^\n]*/g, '');
758
+ // `import [static] <fqn>[.*];`
759
+ const re = /^\s*import\s+(static\s+)?([\w.]+(?:\.\*)?)\s*;/gm;
760
+ let match;
761
+ while ((match = re.exec(stripped)) !== null) {
762
+ const fqn = match[2];
763
+ // `import com.example.*;` — wildcard. We can't materialize a single
764
+ // local name; skip and let name-matching handle members reachable
765
+ // through the wildcard. (Future enhancement: enumerate package files.)
766
+ if (fqn.endsWith('.*'))
767
+ continue;
768
+ const parts = fqn.split('.');
769
+ const localName = parts[parts.length - 1];
770
+ if (!localName)
771
+ continue;
772
+ mappings.push({
773
+ localName,
774
+ exportedName: localName,
775
+ source: fqn,
776
+ isDefault: false,
777
+ isNamespace: false,
778
+ });
779
+ }
780
+ return mappings;
781
+ }
409
782
  /**
410
783
  * Extract PHP import mappings (use statements)
411
784
  */
@@ -427,6 +800,34 @@ function extractPHPImports(content) {
427
800
  }
428
801
  return mappings;
429
802
  }
803
+ /**
804
+ * Extract C/C++ import mappings from #include directives.
805
+ *
806
+ * #include brings all symbols from the included header into scope
807
+ * (namespace import), so each mapping uses isNamespace: true and
808
+ * exportedName: '*'. The localName is set to the header's basename
809
+ * without extension so that symbol references like `MyClass` can
810
+ * match against any include that might provide it.
811
+ */
812
+ function extractCppImports(content) {
813
+ const mappings = [];
814
+ // Match both #include <...> and #include "..."
815
+ const includeRegex = /^\s*#\s*include\s+[<"]([^>"]+)[>"]/gm;
816
+ let match;
817
+ while ((match = includeRegex.exec(content)) !== null) {
818
+ const modulePath = match[1];
819
+ // Basename without extension for localName matching
820
+ const basename = modulePath.split('/').pop().replace(/\.(h|hpp|hxx|hh|inl|ipp|cxx|cc|cpp)$/, '');
821
+ mappings.push({
822
+ localName: basename || modulePath,
823
+ exportedName: '*',
824
+ source: modulePath,
825
+ isDefault: false,
826
+ isNamespace: true,
827
+ });
828
+ }
829
+ return mappings;
830
+ }
430
831
  // Cache import mappings per file to avoid re-reading and re-parsing
431
832
  const importMappingCache = new Map();
432
833
  /**
@@ -434,6 +835,7 @@ const importMappingCache = new Map();
434
835
  */
435
836
  function clearImportMappingCache() {
436
837
  importMappingCache.clear();
838
+ cppIncludeDirCache.clear();
437
839
  }
438
840
  /**
439
841
  * Strip JS line + block comments from `content` while preserving
@@ -556,12 +958,89 @@ function extractReExports(content, language) {
556
958
  /**
557
959
  * Resolve a reference using import mappings
558
960
  */
961
+ /**
962
+ * JVM (Java / Kotlin) imports use fully-qualified names (`import
963
+ * com.example.foo.Bar`) decoupled from filenames, so the JS/Python
964
+ * style filesystem path lookup misses them whenever the file isn't
965
+ * named after its primary symbol (Kotlin `Utils.kt` exporting `Bar`,
966
+ * top-level fns, extension fns). Resolve them through the
967
+ * `qualifiedName` index instead — populated by the package_header /
968
+ * package_declaration namespace wrappers in the extractor.
969
+ */
970
+ function resolveJvmImport(ref, context) {
971
+ if (ref.referenceKind !== 'imports')
972
+ return null;
973
+ if (ref.language !== 'java' && ref.language !== 'kotlin')
974
+ return null;
975
+ const fqn = ref.referenceName;
976
+ const lastDot = fqn.lastIndexOf('.');
977
+ if (lastDot <= 0)
978
+ return null;
979
+ const pkg = fqn.substring(0, lastDot);
980
+ const sym = fqn.substring(lastDot + 1);
981
+ // Wildcard imports (`com.example.*`) deliberately punt to name-matcher.
982
+ if (sym === '*')
983
+ return null;
984
+ const candidates = context.getNodesByQualifiedName(`${pkg}::${sym}`);
985
+ if (candidates.length === 0)
986
+ return null;
987
+ return {
988
+ original: ref,
989
+ targetNodeId: candidates[0].id,
990
+ confidence: 0.95,
991
+ resolvedBy: 'import',
992
+ };
993
+ }
559
994
  function resolveViaImport(ref, context) {
995
+ // C/C++ #include references — resolve directly to the included file
996
+ // (file→file edge), bypassing symbol lookup. The extractor emits these
997
+ // with `referenceKind: 'imports'` and `referenceName: <include path>`
998
+ // (e.g. "uint256.h" or "common/args.h"). Without this branch the
999
+ // include-dir scan path inside resolveImportPath never produces an
1000
+ // edge — resolveViaImport's symbol lookup below would search the
1001
+ // resolved file for a symbol named like the file extension and fail.
1002
+ if ((ref.language === 'c' || ref.language === 'cpp') && ref.referenceKind === 'imports') {
1003
+ const resolvedPath = resolveImportPath(ref.referenceName, ref.filePath, ref.language, context);
1004
+ if (!resolvedPath)
1005
+ return null;
1006
+ const basename = resolvedPath.split('/').pop();
1007
+ const fileNodes = context.getNodesByName(basename).filter((n) => n.kind === 'file');
1008
+ const fileNode = fileNodes.find((n) => n.filePath === resolvedPath);
1009
+ if (fileNode) {
1010
+ return {
1011
+ original: ref,
1012
+ targetNodeId: fileNode.id,
1013
+ confidence: 0.9,
1014
+ resolvedBy: 'import',
1015
+ };
1016
+ }
1017
+ return null;
1018
+ }
560
1019
  // Use cached import mappings (avoids re-reading and re-parsing per ref)
561
1020
  const imports = context.getImportMappings(ref.filePath, ref.language);
562
1021
  if (imports.length === 0 && !context.readFile(ref.filePath)) {
563
1022
  return null;
564
1023
  }
1024
+ // Go cross-package calls: `pkga.FuncX(...)` extracts to referenceName
1025
+ // `pkga.FuncX` and the import `github.com/example/myproject/pkga`
1026
+ // maps to a *package directory* containing one or more .go files.
1027
+ // The generic file-based lookup below can't follow that — issue #388.
1028
+ if (ref.language === 'go') {
1029
+ const goResult = resolveGoCrossPackageReference(ref, imports, context);
1030
+ if (goResult)
1031
+ return goResult;
1032
+ }
1033
+ // Java / Kotlin: imports are FQNs (`import com.example.Foo;`) — no
1034
+ // resolvable file path the JS/TS-style chain below could follow. Look
1035
+ // up the symbol by name and filter to the candidate whose file path
1036
+ // matches the imported FQN. This is the disambiguation signal that
1037
+ // breaks the same-name class collision the path-proximity matcher
1038
+ // can't resolve (issue #314).
1039
+ if (ref.language === 'java' || ref.language === 'kotlin') {
1040
+ const javaResult = resolveJavaImportedReference(ref, imports, context);
1041
+ if (javaResult)
1042
+ return javaResult;
1043
+ }
565
1044
  // Check if the reference name matches any import
566
1045
  for (const imp of imports) {
567
1046
  if (imp.localName === ref.referenceName || ref.referenceName.startsWith(imp.localName + '.')) {
@@ -586,6 +1065,132 @@ function resolveViaImport(ref, context) {
586
1065
  }
587
1066
  return null;
588
1067
  }
1068
+ /**
1069
+ * Resolve a Java/Kotlin reference whose receiver is the simple name of
1070
+ * an imported FQN: `Foo.bar(...)` where `import com.example.Foo;`. The
1071
+ * imported FQN converts to a file-path suffix (`com/example/Foo.java`
1072
+ * or `.kt`) which uniquely identifies the right symbol when multiple
1073
+ * classes share the same simple name.
1074
+ *
1075
+ * Also handles bare references to the imported class itself
1076
+ * (`new Foo()` extraction emits `Foo` as a `references`/`instantiates`
1077
+ * ref) and `import static <Foo>.bar` style imports of a single member.
1078
+ */
1079
+ function resolveJavaImportedReference(ref, imports, context) {
1080
+ if (imports.length === 0)
1081
+ return null;
1082
+ const ext = ref.language === 'kotlin' ? '.kt' : '.java';
1083
+ for (const imp of imports) {
1084
+ const matchesBare = imp.localName === ref.referenceName;
1085
+ const matchesQualified = ref.referenceName.startsWith(imp.localName + '.');
1086
+ if (!matchesBare && !matchesQualified)
1087
+ continue;
1088
+ // Convert FQN to a file-path suffix. `com.example.Foo` ->
1089
+ // `com/example/Foo.java` (or `.kt`). The actual file may live
1090
+ // under any source root (`src/main/java/`, `src/`, etc.), so match
1091
+ // by suffix rather than exact path.
1092
+ const fqnPath = imp.source.replace(/\./g, '/') + ext;
1093
+ // Which symbol name to look up: the class itself, or a member.
1094
+ const memberName = matchesBare
1095
+ ? imp.localName
1096
+ : ref.referenceName.substring(imp.localName.length + 1);
1097
+ const candidates = context.getNodesByName(memberName);
1098
+ for (const node of candidates) {
1099
+ if (node.language !== ref.language)
1100
+ continue;
1101
+ const fp = node.filePath.replace(/\\/g, '/');
1102
+ if (fp.endsWith(fqnPath) || fp.endsWith('/' + fqnPath)) {
1103
+ return {
1104
+ original: ref,
1105
+ targetNodeId: node.id,
1106
+ confidence: 0.9,
1107
+ resolvedBy: 'import',
1108
+ };
1109
+ }
1110
+ }
1111
+ // `import static com.example.Foo.bar;` — the FQN's tail is the
1112
+ // member name, the part before is the owner class. Look up the
1113
+ // member named `<imp.localName>` (e.g. `bar`) and prefer the
1114
+ // candidate whose file matches the parent FQN's path.
1115
+ if (matchesBare) {
1116
+ const dot = imp.source.lastIndexOf('.');
1117
+ if (dot > 0) {
1118
+ const ownerFqn = imp.source.substring(0, dot);
1119
+ const ownerPath = ownerFqn.replace(/\./g, '/') + ext;
1120
+ for (const node of candidates) {
1121
+ if (node.language !== ref.language)
1122
+ continue;
1123
+ const fp = node.filePath.replace(/\\/g, '/');
1124
+ if (fp.endsWith(ownerPath) || fp.endsWith('/' + ownerPath)) {
1125
+ return {
1126
+ original: ref,
1127
+ targetNodeId: node.id,
1128
+ confidence: 0.9,
1129
+ resolvedBy: 'import',
1130
+ };
1131
+ }
1132
+ }
1133
+ }
1134
+ }
1135
+ }
1136
+ return null;
1137
+ }
1138
+ /**
1139
+ * Resolve a Go cross-package qualified reference (`pkga.FuncX`) by matching
1140
+ * the package alias against an in-module import, stripping the module prefix
1141
+ * to a project-relative directory, and locating the exported symbol in any
1142
+ * `.go` file under that directory. Returns `null` for stdlib / third-party
1143
+ * imports (no `go.mod`-relative match) so the rest of `resolveViaImport`
1144
+ * can still try the file-based path.
1145
+ */
1146
+ function resolveGoCrossPackageReference(ref, imports, context) {
1147
+ const mod = context.getGoModule?.();
1148
+ if (!mod)
1149
+ return null;
1150
+ // Qualified call: receiver before `.`, member after. A bare reference
1151
+ // (no dot) is a same-file/in-package call — handled elsewhere.
1152
+ const dotIdx = ref.referenceName.indexOf('.');
1153
+ if (dotIdx <= 0)
1154
+ return null;
1155
+ const receiver = ref.referenceName.substring(0, dotIdx);
1156
+ const memberName = ref.referenceName.substring(dotIdx + 1);
1157
+ if (!memberName)
1158
+ return null;
1159
+ for (const imp of imports) {
1160
+ if (imp.localName !== receiver)
1161
+ continue;
1162
+ // Only in-module imports map to a known directory.
1163
+ if (imp.source !== mod.modulePath && !imp.source.startsWith(mod.modulePath + '/')) {
1164
+ continue;
1165
+ }
1166
+ const pkgDir = imp.source === mod.modulePath
1167
+ ? ''
1168
+ : imp.source.substring(mod.modulePath.length + 1);
1169
+ // Look up the member by name and pick the candidate whose file lives
1170
+ // directly in the package directory. Match the immediate parent dir
1171
+ // exactly so a call to `pkga.FuncX` doesn't accidentally land on a
1172
+ // `FuncX` declared in `pkga/subpkg/`.
1173
+ const candidates = context.getNodesByName(memberName);
1174
+ for (const node of candidates) {
1175
+ if (node.language !== 'go')
1176
+ continue;
1177
+ if (!node.isExported)
1178
+ continue;
1179
+ const fp = node.filePath.replace(/\\/g, '/');
1180
+ const lastSlash = fp.lastIndexOf('/');
1181
+ const fileDir = lastSlash >= 0 ? fp.substring(0, lastSlash) : '';
1182
+ if (fileDir === pkgDir) {
1183
+ return {
1184
+ original: ref,
1185
+ targetNodeId: node.id,
1186
+ confidence: 0.9,
1187
+ resolvedBy: 'import',
1188
+ };
1189
+ }
1190
+ }
1191
+ }
1192
+ return null;
1193
+ }
589
1194
  /** Recursive depth cap for re-export chain following. Real codebases
590
1195
  * rarely chain barrels more than 2–3 deep; 8 is a generous safety
591
1196
  * net that still bounds worst-case work. */
@@ -609,7 +1214,14 @@ function findExportedSymbol(filePath, want, language, context, visited, depth =
609
1214
  const nodesInFile = context.getNodesInFile(filePath);
610
1215
  // 1. Direct hit: the symbol is declared in this file.
611
1216
  if (want.isDefault) {
612
- const direct = nodesInFile.find((n) => n.isExported && (n.kind === 'function' || n.kind === 'class'));
1217
+ // Svelte/Vue single-file components ARE the module's default export,
1218
+ // but are extracted as kind 'component' (not function/class). Prefer
1219
+ // the component node; fall back to an exported function/class for the
1220
+ // `.ts`/`.tsx` `export default fn`/`class` case. Without the component
1221
+ // branch, an `export { default as X } from './X.svelte'` barrel never
1222
+ // resolves and the component shows a false 0 callers (#629).
1223
+ const direct = nodesInFile.find((n) => n.isExported && n.kind === 'component') ??
1224
+ nodesInFile.find((n) => n.isExported && (n.kind === 'function' || n.kind === 'class'));
613
1225
  if (direct)
614
1226
  return direct;
615
1227
  }