@optave/codegraph 3.5.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (346) hide show
  1. package/README.md +47 -21
  2. package/dist/ast-analysis/engine.d.ts.map +1 -1
  3. package/dist/ast-analysis/engine.js +119 -127
  4. package/dist/ast-analysis/engine.js.map +1 -1
  5. package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
  6. package/dist/ast-analysis/visitors/ast-store-visitor.js +14 -1
  7. package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
  8. package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
  9. package/dist/ast-analysis/visitors/complexity-visitor.js +11 -13
  10. package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
  11. package/dist/db/connection.d.ts +12 -2
  12. package/dist/db/connection.d.ts.map +1 -1
  13. package/dist/db/connection.js +81 -53
  14. package/dist/db/connection.js.map +1 -1
  15. package/dist/db/index.d.ts +1 -1
  16. package/dist/db/index.d.ts.map +1 -1
  17. package/dist/db/index.js +1 -1
  18. package/dist/db/index.js.map +1 -1
  19. package/dist/db/migrations.d.ts.map +1 -1
  20. package/dist/db/migrations.js +38 -32
  21. package/dist/db/migrations.js.map +1 -1
  22. package/dist/domain/analysis/context.d.ts.map +1 -1
  23. package/dist/domain/analysis/context.js +51 -66
  24. package/dist/domain/analysis/context.js.map +1 -1
  25. package/dist/domain/analysis/dependencies.d.ts.map +1 -1
  26. package/dist/domain/analysis/dependencies.js +62 -70
  27. package/dist/domain/analysis/dependencies.js.map +1 -1
  28. package/dist/domain/analysis/diff-impact.d.ts +9 -7
  29. package/dist/domain/analysis/diff-impact.d.ts.map +1 -1
  30. package/dist/domain/analysis/exports.d.ts.map +1 -1
  31. package/dist/domain/analysis/exports.js +29 -33
  32. package/dist/domain/analysis/exports.js.map +1 -1
  33. package/dist/domain/analysis/fn-impact.d.ts +15 -17
  34. package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
  35. package/dist/domain/analysis/fn-impact.js +35 -65
  36. package/dist/domain/analysis/fn-impact.js.map +1 -1
  37. package/dist/domain/analysis/module-map.d.ts.map +1 -1
  38. package/dist/domain/analysis/module-map.js +91 -6
  39. package/dist/domain/analysis/module-map.js.map +1 -1
  40. package/dist/domain/analysis/query-helpers.d.ts +20 -0
  41. package/dist/domain/analysis/query-helpers.d.ts.map +1 -0
  42. package/dist/domain/analysis/query-helpers.js +27 -0
  43. package/dist/domain/analysis/query-helpers.js.map +1 -0
  44. package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
  45. package/dist/domain/graph/builder/helpers.js +15 -9
  46. package/dist/domain/graph/builder/helpers.js.map +1 -1
  47. package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
  48. package/dist/domain/graph/builder/incremental.js +3 -2
  49. package/dist/domain/graph/builder/incremental.js.map +1 -1
  50. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
  51. package/dist/domain/graph/builder/pipeline.js +69 -3
  52. package/dist/domain/graph/builder/pipeline.js.map +1 -1
  53. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
  54. package/dist/domain/graph/builder/stages/build-edges.js +7 -51
  55. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
  56. package/dist/domain/graph/builder/stages/build-structure.d.ts.map +1 -1
  57. package/dist/domain/graph/builder/stages/build-structure.js +7 -5
  58. package/dist/domain/graph/builder/stages/build-structure.js.map +1 -1
  59. package/dist/domain/graph/builder/stages/collect-files.js +2 -2
  60. package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
  61. package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
  62. package/dist/domain/graph/builder/stages/detect-changes.js +2 -2
  63. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
  64. package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
  65. package/dist/domain/graph/builder/stages/finalize.js +124 -105
  66. package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
  67. package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
  68. package/dist/domain/graph/builder/stages/insert-nodes.js +28 -15
  69. package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
  70. package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
  71. package/dist/domain/graph/builder/stages/resolve-imports.js +3 -2
  72. package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
  73. package/dist/domain/graph/resolve.d.ts +0 -4
  74. package/dist/domain/graph/resolve.d.ts.map +1 -1
  75. package/dist/domain/graph/resolve.js +32 -48
  76. package/dist/domain/graph/resolve.js.map +1 -1
  77. package/dist/domain/graph/watcher.d.ts.map +1 -1
  78. package/dist/domain/graph/watcher.js +12 -12
  79. package/dist/domain/graph/watcher.js.map +1 -1
  80. package/dist/domain/parser.d.ts +1 -1
  81. package/dist/domain/parser.d.ts.map +1 -1
  82. package/dist/domain/parser.js +206 -101
  83. package/dist/domain/parser.js.map +1 -1
  84. package/dist/domain/search/search/cli-formatter.d.ts.map +1 -1
  85. package/dist/domain/search/search/cli-formatter.js +88 -83
  86. package/dist/domain/search/search/cli-formatter.js.map +1 -1
  87. package/dist/extractors/bash.d.ts +6 -0
  88. package/dist/extractors/bash.d.ts.map +1 -0
  89. package/dist/extractors/bash.js +91 -0
  90. package/dist/extractors/bash.js.map +1 -0
  91. package/dist/extractors/c.d.ts +6 -0
  92. package/dist/extractors/c.d.ts.map +1 -0
  93. package/dist/extractors/c.js +204 -0
  94. package/dist/extractors/c.js.map +1 -0
  95. package/dist/extractors/cpp.d.ts +6 -0
  96. package/dist/extractors/cpp.d.ts.map +1 -0
  97. package/dist/extractors/cpp.js +283 -0
  98. package/dist/extractors/cpp.js.map +1 -0
  99. package/dist/extractors/csharp.d.ts.map +1 -1
  100. package/dist/extractors/csharp.js +42 -54
  101. package/dist/extractors/csharp.js.map +1 -1
  102. package/dist/extractors/dart.d.ts +6 -0
  103. package/dist/extractors/dart.d.ts.map +1 -0
  104. package/dist/extractors/dart.js +277 -0
  105. package/dist/extractors/dart.js.map +1 -0
  106. package/dist/extractors/elixir.d.ts +9 -0
  107. package/dist/extractors/elixir.d.ts.map +1 -0
  108. package/dist/extractors/elixir.js +223 -0
  109. package/dist/extractors/elixir.js.map +1 -0
  110. package/dist/extractors/go.d.ts.map +1 -1
  111. package/dist/extractors/go.js +126 -130
  112. package/dist/extractors/go.js.map +1 -1
  113. package/dist/extractors/haskell.d.ts +8 -0
  114. package/dist/extractors/haskell.d.ts.map +1 -0
  115. package/dist/extractors/haskell.js +217 -0
  116. package/dist/extractors/haskell.js.map +1 -0
  117. package/dist/extractors/hcl.js +6 -6
  118. package/dist/extractors/hcl.js.map +1 -1
  119. package/dist/extractors/helpers.d.ts +32 -1
  120. package/dist/extractors/helpers.d.ts.map +1 -1
  121. package/dist/extractors/helpers.js +74 -0
  122. package/dist/extractors/helpers.js.map +1 -1
  123. package/dist/extractors/index.d.ts +12 -0
  124. package/dist/extractors/index.d.ts.map +1 -1
  125. package/dist/extractors/index.js +12 -0
  126. package/dist/extractors/index.js.map +1 -1
  127. package/dist/extractors/java.d.ts.map +1 -1
  128. package/dist/extractors/java.js +32 -47
  129. package/dist/extractors/java.js.map +1 -1
  130. package/dist/extractors/javascript.d.ts.map +1 -1
  131. package/dist/extractors/javascript.js +306 -292
  132. package/dist/extractors/javascript.js.map +1 -1
  133. package/dist/extractors/kotlin.d.ts +6 -0
  134. package/dist/extractors/kotlin.d.ts.map +1 -0
  135. package/dist/extractors/kotlin.js +275 -0
  136. package/dist/extractors/kotlin.js.map +1 -0
  137. package/dist/extractors/lua.d.ts +6 -0
  138. package/dist/extractors/lua.d.ts.map +1 -0
  139. package/dist/extractors/lua.js +162 -0
  140. package/dist/extractors/lua.js.map +1 -0
  141. package/dist/extractors/ocaml.d.ts +6 -0
  142. package/dist/extractors/ocaml.d.ts.map +1 -0
  143. package/dist/extractors/ocaml.js +236 -0
  144. package/dist/extractors/ocaml.js.map +1 -0
  145. package/dist/extractors/php.d.ts.map +1 -1
  146. package/dist/extractors/php.js +39 -44
  147. package/dist/extractors/php.js.map +1 -1
  148. package/dist/extractors/python.d.ts.map +1 -1
  149. package/dist/extractors/python.js +75 -93
  150. package/dist/extractors/python.js.map +1 -1
  151. package/dist/extractors/ruby.js +6 -13
  152. package/dist/extractors/ruby.js.map +1 -1
  153. package/dist/extractors/rust.d.ts.map +1 -1
  154. package/dist/extractors/rust.js +58 -83
  155. package/dist/extractors/rust.js.map +1 -1
  156. package/dist/extractors/scala.d.ts +6 -0
  157. package/dist/extractors/scala.d.ts.map +1 -0
  158. package/dist/extractors/scala.js +269 -0
  159. package/dist/extractors/scala.js.map +1 -0
  160. package/dist/extractors/swift.d.ts +6 -0
  161. package/dist/extractors/swift.d.ts.map +1 -0
  162. package/dist/extractors/swift.js +275 -0
  163. package/dist/extractors/swift.js.map +1 -0
  164. package/dist/extractors/zig.d.ts +9 -0
  165. package/dist/extractors/zig.d.ts.map +1 -0
  166. package/dist/extractors/zig.js +276 -0
  167. package/dist/extractors/zig.js.map +1 -0
  168. package/dist/features/ast.d.ts +2 -0
  169. package/dist/features/ast.d.ts.map +1 -1
  170. package/dist/features/ast.js +9 -24
  171. package/dist/features/ast.js.map +1 -1
  172. package/dist/features/audit.d.ts.map +1 -1
  173. package/dist/features/audit.js +17 -21
  174. package/dist/features/audit.js.map +1 -1
  175. package/dist/features/branch-compare.d.ts.map +1 -1
  176. package/dist/features/branch-compare.js +47 -3
  177. package/dist/features/branch-compare.js.map +1 -1
  178. package/dist/features/cfg.d.ts +7 -1
  179. package/dist/features/cfg.d.ts.map +1 -1
  180. package/dist/features/cfg.js +72 -61
  181. package/dist/features/cfg.js.map +1 -1
  182. package/dist/features/check.d.ts.map +1 -1
  183. package/dist/features/check.js +79 -62
  184. package/dist/features/check.js.map +1 -1
  185. package/dist/features/complexity-query.d.ts.map +1 -1
  186. package/dist/features/complexity-query.js +142 -137
  187. package/dist/features/complexity-query.js.map +1 -1
  188. package/dist/features/complexity.d.ts +7 -1
  189. package/dist/features/complexity.d.ts.map +1 -1
  190. package/dist/features/complexity.js +62 -1
  191. package/dist/features/complexity.js.map +1 -1
  192. package/dist/features/dataflow.d.ts +7 -1
  193. package/dist/features/dataflow.d.ts.map +1 -1
  194. package/dist/features/dataflow.js +356 -188
  195. package/dist/features/dataflow.js.map +1 -1
  196. package/dist/features/graph-enrichment.d.ts.map +1 -1
  197. package/dist/features/graph-enrichment.js +117 -104
  198. package/dist/features/graph-enrichment.js.map +1 -1
  199. package/dist/features/sequence.d.ts.map +1 -1
  200. package/dist/features/sequence.js +25 -4
  201. package/dist/features/sequence.js.map +1 -1
  202. package/dist/features/structure-query.d.ts.map +1 -1
  203. package/dist/features/structure-query.js +29 -4
  204. package/dist/features/structure-query.js.map +1 -1
  205. package/dist/features/structure.d.ts.map +1 -1
  206. package/dist/features/structure.js +35 -15
  207. package/dist/features/structure.js.map +1 -1
  208. package/dist/graph/algorithms/leiden/adapter.d.ts.map +1 -1
  209. package/dist/graph/algorithms/leiden/adapter.js +88 -73
  210. package/dist/graph/algorithms/leiden/adapter.js.map +1 -1
  211. package/dist/graph/algorithms/leiden/index.js +43 -28
  212. package/dist/graph/algorithms/leiden/index.js.map +1 -1
  213. package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
  214. package/dist/graph/algorithms/leiden/optimiser.js +90 -104
  215. package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
  216. package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -1
  217. package/dist/graph/algorithms/leiden/partition.js +89 -106
  218. package/dist/graph/algorithms/leiden/partition.js.map +1 -1
  219. package/dist/graph/model.d.ts +2 -0
  220. package/dist/graph/model.d.ts.map +1 -1
  221. package/dist/graph/model.js +20 -8
  222. package/dist/graph/model.js.map +1 -1
  223. package/dist/infrastructure/config.d.ts +0 -8
  224. package/dist/infrastructure/config.d.ts.map +1 -1
  225. package/dist/infrastructure/config.js +73 -62
  226. package/dist/infrastructure/config.js.map +1 -1
  227. package/dist/infrastructure/registry.d.ts +0 -8
  228. package/dist/infrastructure/registry.d.ts.map +1 -1
  229. package/dist/infrastructure/registry.js +12 -14
  230. package/dist/infrastructure/registry.js.map +1 -1
  231. package/dist/mcp/server.d.ts.map +1 -1
  232. package/dist/mcp/server.js +45 -36
  233. package/dist/mcp/server.js.map +1 -1
  234. package/dist/presentation/audit.d.ts.map +1 -1
  235. package/dist/presentation/audit.js +61 -57
  236. package/dist/presentation/audit.js.map +1 -1
  237. package/dist/presentation/branch-compare.d.ts.map +1 -1
  238. package/dist/presentation/branch-compare.js +56 -38
  239. package/dist/presentation/branch-compare.js.map +1 -1
  240. package/dist/presentation/check.d.ts.map +1 -1
  241. package/dist/presentation/check.js +30 -32
  242. package/dist/presentation/check.js.map +1 -1
  243. package/dist/presentation/colors.d.ts.map +1 -1
  244. package/dist/presentation/colors.js +2 -0
  245. package/dist/presentation/colors.js.map +1 -1
  246. package/dist/presentation/complexity.d.ts.map +1 -1
  247. package/dist/presentation/complexity.js +25 -19
  248. package/dist/presentation/complexity.js.map +1 -1
  249. package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
  250. package/dist/presentation/queries-cli/exports.js +15 -15
  251. package/dist/presentation/queries-cli/exports.js.map +1 -1
  252. package/dist/presentation/queries-cli/impact.d.ts.map +1 -1
  253. package/dist/presentation/queries-cli/impact.js +29 -19
  254. package/dist/presentation/queries-cli/impact.js.map +1 -1
  255. package/dist/types.d.ts +182 -7
  256. package/dist/types.d.ts.map +1 -1
  257. package/grammars/tree-sitter-bash.wasm +0 -0
  258. package/grammars/tree-sitter-c.wasm +0 -0
  259. package/grammars/tree-sitter-cpp.wasm +0 -0
  260. package/grammars/tree-sitter-dart.wasm +0 -0
  261. package/grammars/tree-sitter-elixir.wasm +0 -0
  262. package/grammars/tree-sitter-haskell.wasm +0 -0
  263. package/grammars/tree-sitter-kotlin.wasm +0 -0
  264. package/grammars/tree-sitter-lua.wasm +0 -0
  265. package/grammars/tree-sitter-ocaml.wasm +0 -0
  266. package/grammars/tree-sitter-scala.wasm +0 -0
  267. package/grammars/tree-sitter-swift.wasm +0 -0
  268. package/grammars/tree-sitter-zig.wasm +0 -0
  269. package/package.json +19 -7
  270. package/src/ast-analysis/engine.ts +147 -138
  271. package/src/ast-analysis/visitors/ast-store-visitor.ts +15 -2
  272. package/src/ast-analysis/visitors/complexity-visitor.ts +11 -11
  273. package/src/db/connection.ts +90 -59
  274. package/src/db/index.ts +1 -0
  275. package/src/db/migrations.ts +36 -32
  276. package/src/domain/analysis/context.ts +73 -75
  277. package/src/domain/analysis/dependencies.ts +78 -68
  278. package/src/domain/analysis/exports.ts +45 -34
  279. package/src/domain/analysis/fn-impact.ts +67 -64
  280. package/src/domain/analysis/module-map.ts +103 -8
  281. package/src/domain/analysis/query-helpers.ts +35 -0
  282. package/src/domain/graph/builder/helpers.ts +12 -6
  283. package/src/domain/graph/builder/incremental.ts +3 -2
  284. package/src/domain/graph/builder/pipeline.ts +71 -3
  285. package/src/domain/graph/builder/stages/build-edges.ts +10 -75
  286. package/src/domain/graph/builder/stages/build-structure.ts +9 -7
  287. package/src/domain/graph/builder/stages/collect-files.ts +2 -2
  288. package/src/domain/graph/builder/stages/detect-changes.ts +7 -2
  289. package/src/domain/graph/builder/stages/finalize.ts +159 -125
  290. package/src/domain/graph/builder/stages/insert-nodes.ts +32 -21
  291. package/src/domain/graph/builder/stages/resolve-imports.ts +3 -2
  292. package/src/domain/graph/resolve.ts +34 -46
  293. package/src/domain/graph/watcher.ts +12 -14
  294. package/src/domain/parser.ts +222 -97
  295. package/src/domain/search/search/cli-formatter.ts +121 -94
  296. package/src/extractors/bash.ts +97 -0
  297. package/src/extractors/c.ts +212 -0
  298. package/src/extractors/cpp.ts +298 -0
  299. package/src/extractors/csharp.ts +53 -56
  300. package/src/extractors/dart.ts +304 -0
  301. package/src/extractors/elixir.ts +251 -0
  302. package/src/extractors/go.ts +152 -134
  303. package/src/extractors/haskell.ts +235 -0
  304. package/src/extractors/hcl.ts +6 -6
  305. package/src/extractors/helpers.ts +93 -1
  306. package/src/extractors/index.ts +12 -0
  307. package/src/extractors/java.ts +43 -48
  308. package/src/extractors/javascript.ts +328 -281
  309. package/src/extractors/kotlin.ts +293 -0
  310. package/src/extractors/lua.ts +169 -0
  311. package/src/extractors/ocaml.ts +259 -0
  312. package/src/extractors/php.ts +46 -40
  313. package/src/extractors/python.ts +81 -104
  314. package/src/extractors/ruby.ts +6 -13
  315. package/src/extractors/rust.ts +65 -85
  316. package/src/extractors/scala.ts +285 -0
  317. package/src/extractors/swift.ts +293 -0
  318. package/src/extractors/zig.ts +294 -0
  319. package/src/features/ast.ts +10 -25
  320. package/src/features/audit.ts +24 -20
  321. package/src/features/branch-compare.ts +51 -4
  322. package/src/features/cfg.ts +113 -65
  323. package/src/features/check.ts +90 -74
  324. package/src/features/complexity-query.ts +181 -163
  325. package/src/features/complexity.ts +64 -1
  326. package/src/features/dataflow.ts +462 -217
  327. package/src/features/graph-enrichment.ts +161 -117
  328. package/src/features/sequence.ts +27 -4
  329. package/src/features/structure-query.ts +43 -4
  330. package/src/features/structure.ts +50 -22
  331. package/src/graph/algorithms/leiden/adapter.ts +126 -71
  332. package/src/graph/algorithms/leiden/index.ts +67 -28
  333. package/src/graph/algorithms/leiden/optimiser.ts +114 -105
  334. package/src/graph/algorithms/leiden/partition.ts +131 -98
  335. package/src/graph/model.ts +19 -7
  336. package/src/infrastructure/config.ts +60 -58
  337. package/src/infrastructure/registry.ts +17 -14
  338. package/src/mcp/server.ts +46 -37
  339. package/src/presentation/audit.ts +72 -67
  340. package/src/presentation/branch-compare.ts +54 -50
  341. package/src/presentation/check.ts +34 -34
  342. package/src/presentation/colors.ts +2 -0
  343. package/src/presentation/complexity.ts +39 -33
  344. package/src/presentation/queries-cli/exports.ts +17 -17
  345. package/src/presentation/queries-cli/impact.ts +30 -22
  346. package/src/types.ts +195 -7
@@ -5,7 +5,14 @@ import type {
5
5
  TreeSitterNode,
6
6
  TreeSitterTree,
7
7
  } from '../types.js';
8
- import { findChild, MAX_WALK_DEPTH, nodeEndLine, rustVisibility } from './helpers.js';
8
+ import {
9
+ extractBodyMembers,
10
+ findParentNode,
11
+ MAX_WALK_DEPTH,
12
+ nodeEndLine,
13
+ rustVisibility,
14
+ setTypeMapEntry,
15
+ } from './helpers.js';
9
16
 
10
17
  /**
11
18
  * Extract symbols from Rust files.
@@ -206,16 +213,9 @@ function handleRustMacroInvocation(node: TreeSitterNode, ctx: ExtractorOutput):
206
213
  }
207
214
  }
208
215
 
216
+ const RUST_IMPL_TYPES = ['impl_item'] as const;
209
217
  function findCurrentImpl(node: TreeSitterNode): string | null {
210
- let current = node.parent;
211
- while (current) {
212
- if (current.type === 'impl_item') {
213
- const typeNode = current.childForFieldName('type');
214
- return typeNode ? typeNode.text : null;
215
- }
216
- current = current.parent;
217
- }
218
- return null;
218
+ return findParentNode(node, RUST_IMPL_TYPES, 'type');
219
219
  }
220
220
 
221
221
  // ── Child extraction helpers ────────────────────────────────────────────────
@@ -227,8 +227,7 @@ function extractRustParameters(paramListNode: TreeSitterNode | null): SubDeclara
227
227
  const param = paramListNode.child(i);
228
228
  if (!param) continue;
229
229
  if (param.type === 'self_parameter') {
230
- // Skip self parameters — matches native engine behaviour
231
- continue;
230
+ // Skip self — matches native engine behaviour
232
231
  } else if (param.type === 'parameter') {
233
232
  const pattern = param.childForFieldName('pattern');
234
233
  if (pattern) {
@@ -240,34 +239,16 @@ function extractRustParameters(paramListNode: TreeSitterNode | null): SubDeclara
240
239
  }
241
240
 
242
241
  function extractStructFields(structNode: TreeSitterNode): SubDeclaration[] {
243
- const fields: SubDeclaration[] = [];
244
- const fieldList =
245
- structNode.childForFieldName('body') || findChild(structNode, 'field_declaration_list');
246
- if (!fieldList) return fields;
247
- for (let i = 0; i < fieldList.childCount; i++) {
248
- const field = fieldList.child(i);
249
- if (!field || field.type !== 'field_declaration') continue;
250
- const nameNode = field.childForFieldName('name');
251
- if (nameNode) {
252
- fields.push({ name: nameNode.text, kind: 'property', line: field.startPosition.row + 1 });
253
- }
254
- }
255
- return fields;
242
+ return extractBodyMembers(
243
+ structNode,
244
+ ['body', 'field_declaration_list'],
245
+ 'field_declaration',
246
+ 'property',
247
+ );
256
248
  }
257
249
 
258
250
  function extractEnumVariants(enumNode: TreeSitterNode): SubDeclaration[] {
259
- const variants: SubDeclaration[] = [];
260
- const body = enumNode.childForFieldName('body') || findChild(enumNode, 'enum_variant_list');
261
- if (!body) return variants;
262
- for (let i = 0; i < body.childCount; i++) {
263
- const variant = body.child(i);
264
- if (!variant || variant.type !== 'enum_variant') continue;
265
- const nameNode = variant.childForFieldName('name');
266
- if (nameNode) {
267
- variants.push({ name: nameNode.text, kind: 'constant', line: variant.startPosition.row + 1 });
268
- }
269
- }
270
- return variants;
251
+ return extractBodyMembers(enumNode, ['body', 'enum_variant_list'], 'enum_variant', 'constant');
271
252
  }
272
253
 
273
254
  function extractRustTypeMap(node: TreeSitterNode, ctx: ExtractorOutput): void {
@@ -283,7 +264,7 @@ function extractRustTypeMapDepth(node: TreeSitterNode, ctx: ExtractorOutput, dep
283
264
  const typeNode = node.childForFieldName('type');
284
265
  if (pattern && pattern.type === 'identifier' && typeNode) {
285
266
  const typeName = extractRustTypeName(typeNode);
286
- if (typeName) ctx.typeMap?.set(pattern.text, { type: typeName, confidence: 0.9 });
267
+ if (typeName && ctx.typeMap) setTypeMapEntry(ctx.typeMap, pattern.text, typeName, 0.9);
287
268
  }
288
269
  }
289
270
 
@@ -295,7 +276,7 @@ function extractRustTypeMapDepth(node: TreeSitterNode, ctx: ExtractorOutput, dep
295
276
  const name = pattern.type === 'identifier' ? pattern.text : null;
296
277
  if (name && name !== 'self' && name !== '&self' && name !== '&mut self') {
297
278
  const typeName = extractRustTypeName(typeNode);
298
- if (typeName) ctx.typeMap?.set(name, { type: typeName, confidence: 0.9 });
279
+ if (typeName && ctx.typeMap) setTypeMapEntry(ctx.typeMap, name, typeName, 0.9);
299
280
  }
300
281
  }
301
282
  }
@@ -328,56 +309,55 @@ function extractRustTypeName(typeNode: TreeSitterNode): string | null {
328
309
  return null;
329
310
  }
330
311
 
331
- function extractRustUsePath(node: TreeSitterNode | null): { source: string; names: string[] }[] {
332
- if (!node) return [];
333
-
334
- if (node.type === 'use_list') {
335
- const results: { source: string; names: string[] }[] = [];
336
- for (let i = 0; i < node.childCount; i++) {
337
- results.push(...extractRustUsePath(node.child(i)));
312
+ /** Collect names from a scoped_use_list's list node. */
313
+ function collectScopedNames(listNode: TreeSitterNode): string[] {
314
+ const names: string[] = [];
315
+ for (let i = 0; i < listNode.childCount; i++) {
316
+ const child = listNode.child(i);
317
+ if (!child) continue;
318
+ if (child.type === 'identifier' || child.type === 'self') {
319
+ names.push(child.text);
320
+ } else if (child.type === 'use_as_clause') {
321
+ const name = (child.childForFieldName('alias') || child.childForFieldName('name'))?.text;
322
+ if (name) names.push(name);
338
323
  }
339
- return results;
340
324
  }
325
+ return names;
326
+ }
341
327
 
342
- if (node.type === 'scoped_use_list') {
343
- const pathNode = node.childForFieldName('path');
344
- const listNode = node.childForFieldName('list');
345
- const prefix = pathNode ? pathNode.text : '';
346
- if (listNode) {
347
- const names: string[] = [];
348
- for (let i = 0; i < listNode.childCount; i++) {
349
- const child = listNode.child(i);
350
- if (
351
- child &&
352
- (child.type === 'identifier' || child.type === 'use_as_clause' || child.type === 'self')
353
- ) {
354
- const name =
355
- child.type === 'use_as_clause'
356
- ? (child.childForFieldName('alias') || child.childForFieldName('name'))?.text
357
- : child.text;
358
- if (name) names.push(name);
359
- }
328
+ function extractRustUsePath(node: TreeSitterNode | null): { source: string; names: string[] }[] {
329
+ if (!node) return [];
330
+
331
+ switch (node.type) {
332
+ case 'use_list': {
333
+ const results: { source: string; names: string[] }[] = [];
334
+ for (let i = 0; i < node.childCount; i++) {
335
+ results.push(...extractRustUsePath(node.child(i)));
360
336
  }
361
- return [{ source: prefix, names }];
337
+ return results;
362
338
  }
363
- return [{ source: prefix, names: [] }];
364
- }
365
-
366
- if (node.type === 'use_as_clause') {
367
- const name = node.childForFieldName('alias') || node.childForFieldName('name');
368
- return [{ source: node.text, names: name ? [name.text] : [] }];
369
- }
370
-
371
- if (node.type === 'use_wildcard') {
372
- const pathNode = node.childForFieldName('path');
373
- return [{ source: pathNode ? pathNode.text : '*', names: ['*'] }];
374
- }
375
-
376
- if (node.type === 'scoped_identifier' || node.type === 'identifier') {
377
- const text = node.text;
378
- const lastName = text.split('::').pop() ?? text;
379
- return [{ source: text, names: [lastName] }];
339
+ case 'scoped_use_list': {
340
+ const pathNode = node.childForFieldName('path');
341
+ const listNode = node.childForFieldName('list');
342
+ const prefix = pathNode ? pathNode.text : '';
343
+ if (!listNode) return [{ source: prefix, names: [] }];
344
+ return [{ source: prefix, names: collectScopedNames(listNode) }];
345
+ }
346
+ case 'use_as_clause': {
347
+ const name = node.childForFieldName('alias') || node.childForFieldName('name');
348
+ return [{ source: node.text, names: name ? [name.text] : [] }];
349
+ }
350
+ case 'use_wildcard': {
351
+ const pathNode = node.childForFieldName('path');
352
+ return [{ source: pathNode ? pathNode.text : '*', names: ['*'] }];
353
+ }
354
+ case 'scoped_identifier':
355
+ case 'identifier': {
356
+ const text = node.text;
357
+ const lastName = text.split('::').pop() ?? text;
358
+ return [{ source: text, names: [lastName] }];
359
+ }
360
+ default:
361
+ return [];
380
362
  }
381
-
382
- return [];
383
363
  }
@@ -0,0 +1,285 @@
1
+ import type {
2
+ Call,
3
+ ExtractorOutput,
4
+ SubDeclaration,
5
+ TreeSitterNode,
6
+ TreeSitterTree,
7
+ } from '../types.js';
8
+ import { extractModifierVisibility, findChild, nodeEndLine } from './helpers.js';
9
+
10
+ /**
11
+ * Extract symbols from Scala files.
12
+ */
13
+ export function extractScalaSymbols(tree: TreeSitterTree, _filePath: string): ExtractorOutput {
14
+ const ctx: ExtractorOutput = {
15
+ definitions: [],
16
+ calls: [],
17
+ imports: [],
18
+ classes: [],
19
+ exports: [],
20
+ typeMap: new Map(),
21
+ };
22
+
23
+ walkScalaNode(tree.rootNode, ctx);
24
+ return ctx;
25
+ }
26
+
27
+ function walkScalaNode(node: TreeSitterNode, ctx: ExtractorOutput): void {
28
+ switch (node.type) {
29
+ case 'class_definition':
30
+ handleScalaClassDef(node, ctx);
31
+ break;
32
+ case 'trait_definition':
33
+ handleScalaTraitDef(node, ctx);
34
+ break;
35
+ case 'object_definition':
36
+ handleScalaObjectDef(node, ctx);
37
+ break;
38
+ case 'function_definition':
39
+ handleScalaFunctionDef(node, ctx);
40
+ break;
41
+ case 'import_declaration':
42
+ handleScalaImportDecl(node, ctx);
43
+ break;
44
+ case 'call_expression':
45
+ handleScalaCallExpression(node, ctx);
46
+ break;
47
+ case 'val_definition':
48
+ case 'var_definition':
49
+ handleScalaValVarDef(node, ctx);
50
+ break;
51
+ }
52
+
53
+ for (let i = 0; i < node.childCount; i++) {
54
+ const child = node.child(i);
55
+ if (child) walkScalaNode(child, ctx);
56
+ }
57
+ }
58
+
59
+ // ── Walk-path per-node-type handlers ────────────────────────────────────────
60
+
61
+ function handleScalaClassDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
62
+ const nameNode = node.childForFieldName('name');
63
+ if (!nameNode) return;
64
+ const name = nameNode.text;
65
+ const children = extractScalaBodyMembers(node, name, ctx);
66
+
67
+ ctx.definitions.push({
68
+ name,
69
+ kind: 'class',
70
+ line: node.startPosition.row + 1,
71
+ endLine: nodeEndLine(node),
72
+ children: children.length > 0 ? children : undefined,
73
+ });
74
+
75
+ extractScalaInheritance(node, name, ctx);
76
+ }
77
+
78
+ function handleScalaTraitDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
79
+ const nameNode = node.childForFieldName('name');
80
+ if (!nameNode) return;
81
+ const name = nameNode.text;
82
+ const children = extractScalaBodyMembers(node, name, ctx);
83
+
84
+ ctx.definitions.push({
85
+ name,
86
+ kind: 'interface',
87
+ line: node.startPosition.row + 1,
88
+ endLine: nodeEndLine(node),
89
+ children: children.length > 0 ? children : undefined,
90
+ });
91
+
92
+ extractScalaInheritance(node, name, ctx);
93
+ }
94
+
95
+ function handleScalaObjectDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
96
+ const nameNode = node.childForFieldName('name');
97
+ if (!nameNode) return;
98
+ const name = nameNode.text;
99
+ const children = extractScalaBodyMembers(node, name, ctx);
100
+
101
+ ctx.definitions.push({
102
+ name,
103
+ kind: 'class',
104
+ line: node.startPosition.row + 1,
105
+ endLine: nodeEndLine(node),
106
+ children: children.length > 0 ? children : undefined,
107
+ });
108
+
109
+ extractScalaInheritance(node, name, ctx);
110
+ }
111
+
112
+ function handleScalaFunctionDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
113
+ // Skip methods already emitted by class/trait/object handlers
114
+ if (node.parent?.type === 'template_body') {
115
+ const grandparent = node.parent.parent;
116
+ if (
117
+ grandparent &&
118
+ (grandparent.type === 'class_definition' ||
119
+ grandparent.type === 'trait_definition' ||
120
+ grandparent.type === 'object_definition')
121
+ ) {
122
+ return;
123
+ }
124
+ }
125
+ const nameNode = node.childForFieldName('name');
126
+ if (!nameNode) return;
127
+ const params = extractScalaParameters(node);
128
+ ctx.definitions.push({
129
+ name: nameNode.text,
130
+ kind: 'function',
131
+ line: node.startPosition.row + 1,
132
+ endLine: nodeEndLine(node),
133
+ children: params.length > 0 ? params : undefined,
134
+ visibility: extractModifierVisibility(node),
135
+ });
136
+ }
137
+
138
+ function handleScalaImportDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
139
+ // import_declaration has alternating `identifier` and `.` children directly (NO import_expression wrapper)
140
+ const parts: string[] = [];
141
+ for (let i = 0; i < node.childCount; i++) {
142
+ const child = node.child(i);
143
+ if (!child) continue;
144
+ if (child.type === 'identifier' || child.type === 'type_identifier') {
145
+ parts.push(child.text);
146
+ }
147
+ }
148
+ if (parts.length === 0) return;
149
+ const fullPath = parts.join('.');
150
+ const lastName = parts[parts.length - 1] ?? fullPath;
151
+ ctx.imports.push({
152
+ source: fullPath,
153
+ names: [lastName],
154
+ line: node.startPosition.row + 1,
155
+ scalaImport: true,
156
+ });
157
+ }
158
+
159
+ function handleScalaCallExpression(node: TreeSitterNode, ctx: ExtractorOutput): void {
160
+ const funcNode = node.childForFieldName('function');
161
+ if (!funcNode) return;
162
+ const call: Call = { name: '', line: node.startPosition.row + 1 };
163
+ if (funcNode.type === 'field_expression') {
164
+ const field = funcNode.childForFieldName('field');
165
+ const value = funcNode.childForFieldName('value');
166
+ if (field) call.name = field.text;
167
+ if (value) call.receiver = value.text;
168
+ } else {
169
+ call.name = funcNode.text;
170
+ }
171
+ if (call.name) ctx.calls.push(call);
172
+ }
173
+
174
+ function handleScalaValVarDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
175
+ // Only handle top-level vals/vars — skip class members and function-local bindings
176
+ if (node.parent?.type === 'template_body') return;
177
+ if (node.parent?.type === 'block' || node.parent?.type === 'indented_block') return;
178
+ const pattern = node.childForFieldName('pattern');
179
+ if (!pattern) return;
180
+ const nameNode = pattern.type === 'identifier' ? pattern : findChild(pattern, 'identifier');
181
+ if (!nameNode) return;
182
+ const kind = node.type === 'val_definition' ? 'constant' : 'variable';
183
+ ctx.definitions.push({
184
+ name: nameNode.text,
185
+ kind,
186
+ line: node.startPosition.row + 1,
187
+ endLine: nodeEndLine(node),
188
+ });
189
+ }
190
+
191
+ // ── Inheritance helpers ─────────────────────────────────────────────────────
192
+
193
+ function extractScalaInheritance(node: TreeSitterNode, name: string, ctx: ExtractorOutput): void {
194
+ const extendsClause = findChild(node, 'extends_clause');
195
+ if (!extendsClause) return;
196
+ let foundExtends = false;
197
+ for (let i = 0; i < extendsClause.childCount; i++) {
198
+ const child = extendsClause.child(i);
199
+ if (!child) continue;
200
+ if (
201
+ child.type === 'type_identifier' ||
202
+ child.type === 'generic_type' ||
203
+ child.type === 'identifier'
204
+ ) {
205
+ const typeName = child.type === 'generic_type' ? child.child(0)?.text : child.text;
206
+ if (!typeName) continue;
207
+ if (!foundExtends) {
208
+ ctx.classes.push({
209
+ name,
210
+ extends: typeName,
211
+ line: node.startPosition.row + 1,
212
+ });
213
+ foundExtends = true;
214
+ } else {
215
+ ctx.classes.push({
216
+ name,
217
+ implements: typeName,
218
+ line: node.startPosition.row + 1,
219
+ });
220
+ }
221
+ }
222
+ }
223
+ }
224
+
225
+ // ── Body member extraction ──────────────────────────────────────────────────
226
+
227
+ function extractScalaBodyMembers(
228
+ parentNode: TreeSitterNode,
229
+ parentName: string,
230
+ ctx: ExtractorOutput,
231
+ ): SubDeclaration[] {
232
+ const children: SubDeclaration[] = [];
233
+ const body = findChild(parentNode, 'template_body');
234
+ if (!body) return children;
235
+
236
+ for (let i = 0; i < body.childCount; i++) {
237
+ const member = body.child(i);
238
+ if (!member) continue;
239
+
240
+ if (member.type === 'function_definition') {
241
+ const methName = member.childForFieldName('name');
242
+ if (methName) {
243
+ ctx.definitions.push({
244
+ name: `${parentName}.${methName.text}`,
245
+ kind: 'method',
246
+ line: member.startPosition.row + 1,
247
+ endLine: member.endPosition.row + 1,
248
+ visibility: extractModifierVisibility(member),
249
+ });
250
+ }
251
+ } else if (member.type === 'val_definition' || member.type === 'var_definition') {
252
+ const pattern = member.childForFieldName('pattern');
253
+ if (pattern) {
254
+ const nameNode = pattern.type === 'identifier' ? pattern : findChild(pattern, 'identifier');
255
+ if (nameNode) {
256
+ children.push({
257
+ name: nameNode.text,
258
+ kind: 'property',
259
+ line: member.startPosition.row + 1,
260
+ visibility: extractModifierVisibility(member),
261
+ });
262
+ }
263
+ }
264
+ }
265
+ }
266
+
267
+ return children;
268
+ }
269
+
270
+ // ── Parameter extraction ────────────────────────────────────────────────────
271
+
272
+ function extractScalaParameters(funcNode: TreeSitterNode): SubDeclaration[] {
273
+ const params: SubDeclaration[] = [];
274
+ const paramList = findChild(funcNode, 'parameters');
275
+ if (!paramList) return params;
276
+ for (let i = 0; i < paramList.childCount; i++) {
277
+ const param = paramList.child(i);
278
+ if (!param || param.type !== 'parameter') continue;
279
+ const nameNode = findChild(param, 'identifier');
280
+ if (nameNode) {
281
+ params.push({ name: nameNode.text, kind: 'parameter', line: param.startPosition.row + 1 });
282
+ }
283
+ }
284
+ return params;
285
+ }