@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
@@ -0,0 +1,293 @@
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 Kotlin files.
12
+ */
13
+ export function extractKotlinSymbols(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
+ walkKotlinNode(tree.rootNode, ctx);
24
+ return ctx;
25
+ }
26
+
27
+ function walkKotlinNode(node: TreeSitterNode, ctx: ExtractorOutput): void {
28
+ switch (node.type) {
29
+ case 'class_declaration':
30
+ handleKotlinClassDecl(node, ctx);
31
+ break;
32
+ case 'object_declaration':
33
+ handleKotlinObjectDecl(node, ctx);
34
+ break;
35
+ case 'function_declaration':
36
+ handleKotlinFunctionDecl(node, ctx);
37
+ break;
38
+ case 'import_header':
39
+ handleKotlinImport(node, ctx);
40
+ break;
41
+ case 'call_expression':
42
+ handleKotlinCallExpression(node, ctx);
43
+ break;
44
+ case 'navigation_expression':
45
+ handleKotlinNavExpression(node, ctx);
46
+ break;
47
+ }
48
+
49
+ for (let i = 0; i < node.childCount; i++) {
50
+ const child = node.child(i);
51
+ if (child) walkKotlinNode(child, ctx);
52
+ }
53
+ }
54
+
55
+ // ── Walk-path per-node-type handlers ────────────────────────────────────────
56
+
57
+ function hasKeywordChild(node: TreeSitterNode, keyword: string): boolean {
58
+ for (let i = 0; i < node.childCount; i++) {
59
+ const child = node.child(i);
60
+ if (child && child.text === keyword) return true;
61
+ }
62
+ return false;
63
+ }
64
+
65
+ function hasModifier(node: TreeSitterNode, keyword: string): boolean {
66
+ for (let i = 0; i < node.childCount; i++) {
67
+ const child = node.child(i);
68
+ if (!child) continue;
69
+ if (child.type === 'modifiers' && child.text.includes(keyword)) return true;
70
+ }
71
+ return false;
72
+ }
73
+
74
+ function handleKotlinClassDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
75
+ const isInterface = hasKeywordChild(node, 'interface');
76
+ const isEnum = hasModifier(node, 'enum');
77
+
78
+ const nameNode = findChild(node, 'type_identifier');
79
+ if (!nameNode) return;
80
+ const name = nameNode.text;
81
+
82
+ const kind = isInterface ? 'interface' : isEnum ? 'enum' : 'class';
83
+
84
+ const children: SubDeclaration[] = [];
85
+ if (isEnum) {
86
+ // Enum entries are inside class_body
87
+ const body = findChild(node, 'class_body');
88
+ if (body) {
89
+ for (let i = 0; i < body.childCount; i++) {
90
+ const child = body.child(i);
91
+ if (child && child.type === 'enum_entry') {
92
+ const entryName = findChild(child, 'simple_identifier');
93
+ if (entryName) {
94
+ children.push({
95
+ name: entryName.text,
96
+ kind: 'constant',
97
+ line: child.startPosition.row + 1,
98
+ });
99
+ }
100
+ }
101
+ }
102
+ }
103
+ } else {
104
+ // Extract properties from class_body
105
+ const body = findChild(node, 'class_body');
106
+ if (body) {
107
+ for (let i = 0; i < body.childCount; i++) {
108
+ const child = body.child(i);
109
+ if (child && child.type === 'property_declaration') {
110
+ const propName = findChild(child, 'variable_declaration');
111
+ if (propName) {
112
+ const id = findChild(propName, 'simple_identifier');
113
+ if (id) {
114
+ children.push({
115
+ name: id.text,
116
+ kind: 'property',
117
+ line: child.startPosition.row + 1,
118
+ visibility: extractModifierVisibility(child),
119
+ });
120
+ }
121
+ }
122
+ }
123
+ }
124
+ }
125
+ }
126
+
127
+ ctx.definitions.push({
128
+ name,
129
+ kind,
130
+ line: node.startPosition.row + 1,
131
+ endLine: nodeEndLine(node),
132
+ children: children.length > 0 ? children : undefined,
133
+ });
134
+
135
+ // Methods inside class_body
136
+ const body = findChild(node, 'class_body');
137
+ if (body) {
138
+ for (let i = 0; i < body.childCount; i++) {
139
+ const child = body.child(i);
140
+ if (child && child.type === 'function_declaration') {
141
+ const methName = findChild(child, 'simple_identifier');
142
+ if (methName) {
143
+ ctx.definitions.push({
144
+ name: `${name}.${methName.text}`,
145
+ kind: 'method',
146
+ line: child.startPosition.row + 1,
147
+ endLine: child.endPosition.row + 1,
148
+ visibility: extractModifierVisibility(child),
149
+ });
150
+ }
151
+ }
152
+ }
153
+ }
154
+
155
+ // Inheritance: delegation_specifier nodes are DIRECT children
156
+ for (let i = 0; i < node.childCount; i++) {
157
+ const child = node.child(i);
158
+ if (!child || child.type !== 'delegation_specifier') continue;
159
+
160
+ // constructor_invocation > user_type > type_identifier (extends)
161
+ const ctorInvocation = findChild(child, 'constructor_invocation');
162
+ if (ctorInvocation) {
163
+ const userType = findChild(ctorInvocation, 'user_type');
164
+ if (userType) {
165
+ const typeId = findChild(userType, 'type_identifier');
166
+ if (typeId) {
167
+ ctx.classes.push({
168
+ name,
169
+ extends: typeId.text,
170
+ line: node.startPosition.row + 1,
171
+ });
172
+ }
173
+ }
174
+ continue;
175
+ }
176
+
177
+ // user_type > type_identifier (implements)
178
+ const userType = findChild(child, 'user_type');
179
+ if (userType) {
180
+ const typeId = findChild(userType, 'type_identifier');
181
+ if (typeId) {
182
+ ctx.classes.push({
183
+ name,
184
+ implements: typeId.text,
185
+ line: node.startPosition.row + 1,
186
+ });
187
+ }
188
+ }
189
+ }
190
+ }
191
+
192
+ function handleKotlinObjectDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
193
+ const nameNode = findChild(node, 'type_identifier');
194
+ if (!nameNode) return;
195
+ ctx.definitions.push({
196
+ name: nameNode.text,
197
+ kind: 'class',
198
+ line: node.startPosition.row + 1,
199
+ endLine: nodeEndLine(node),
200
+ });
201
+
202
+ // Methods inside object body
203
+ const body = findChild(node, 'class_body');
204
+ if (body) {
205
+ for (let i = 0; i < body.childCount; i++) {
206
+ const child = body.child(i);
207
+ if (child && child.type === 'function_declaration') {
208
+ const methName = findChild(child, 'simple_identifier');
209
+ if (methName) {
210
+ ctx.definitions.push({
211
+ name: `${nameNode.text}.${methName.text}`,
212
+ kind: 'method',
213
+ line: child.startPosition.row + 1,
214
+ endLine: child.endPosition.row + 1,
215
+ visibility: extractModifierVisibility(child),
216
+ });
217
+ }
218
+ }
219
+ }
220
+ }
221
+ }
222
+
223
+ function handleKotlinFunctionDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
224
+ // Skip methods already emitted by class/object handlers
225
+ if (
226
+ node.parent?.type === 'class_body' &&
227
+ (node.parent.parent?.type === 'class_declaration' ||
228
+ node.parent.parent?.type === 'object_declaration')
229
+ ) {
230
+ return;
231
+ }
232
+ const nameNode = findChild(node, 'simple_identifier');
233
+ if (!nameNode) return;
234
+ const params = extractKotlinParameters(node);
235
+ ctx.definitions.push({
236
+ name: nameNode.text,
237
+ kind: 'function',
238
+ line: node.startPosition.row + 1,
239
+ endLine: nodeEndLine(node),
240
+ children: params.length > 0 ? params : undefined,
241
+ visibility: extractModifierVisibility(node),
242
+ });
243
+ }
244
+
245
+ function handleKotlinImport(node: TreeSitterNode, ctx: ExtractorOutput): void {
246
+ const identNode = findChild(node, 'identifier');
247
+ if (!identNode) return;
248
+ const fullPath = identNode.text;
249
+ const lastName = fullPath.split('.').pop() ?? fullPath;
250
+ ctx.imports.push({
251
+ source: fullPath,
252
+ names: [lastName],
253
+ line: node.startPosition.row + 1,
254
+ kotlinImport: true,
255
+ });
256
+ }
257
+
258
+ function handleKotlinCallExpression(node: TreeSitterNode, ctx: ExtractorOutput): void {
259
+ const funcNode = node.child(0);
260
+ if (!funcNode) return;
261
+ if (funcNode.type === 'simple_identifier') {
262
+ ctx.calls.push({ name: funcNode.text, line: node.startPosition.row + 1 });
263
+ }
264
+ }
265
+
266
+ function handleKotlinNavExpression(node: TreeSitterNode, ctx: ExtractorOutput): void {
267
+ // navigation_expression: expr . identifier — only emit if parent is call_expression
268
+ if (node.parent?.type !== 'call_expression') return;
269
+ const lastChild = node.child(node.childCount - 1);
270
+ const firstChild = node.child(0);
271
+ if (lastChild && lastChild.type === 'simple_identifier' && firstChild) {
272
+ const call: Call = { name: lastChild.text, line: node.startPosition.row + 1 };
273
+ call.receiver = firstChild.text;
274
+ ctx.calls.push(call);
275
+ }
276
+ }
277
+
278
+ // ── Child extraction helpers ────────────────────────────────────────────────
279
+
280
+ function extractKotlinParameters(funcNode: TreeSitterNode): SubDeclaration[] {
281
+ const params: SubDeclaration[] = [];
282
+ const paramList = findChild(funcNode, 'function_value_parameters');
283
+ if (!paramList) return params;
284
+ for (let i = 0; i < paramList.childCount; i++) {
285
+ const param = paramList.child(i);
286
+ if (!param || param.type !== 'parameter') continue;
287
+ const nameNode = findChild(param, 'simple_identifier');
288
+ if (nameNode) {
289
+ params.push({ name: nameNode.text, kind: 'parameter', line: param.startPosition.row + 1 });
290
+ }
291
+ }
292
+ return params;
293
+ }
@@ -0,0 +1,169 @@
1
+ import type {
2
+ Call,
3
+ ExtractorOutput,
4
+ SubDeclaration,
5
+ TreeSitterNode,
6
+ TreeSitterTree,
7
+ } from '../types.js';
8
+ import { findChild, nodeEndLine } from './helpers.js';
9
+
10
+ /**
11
+ * Extract symbols from Lua files.
12
+ */
13
+ export function extractLuaSymbols(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
+ walkLuaNode(tree.rootNode, ctx);
24
+ return ctx;
25
+ }
26
+
27
+ function walkLuaNode(node: TreeSitterNode, ctx: ExtractorOutput): void {
28
+ switch (node.type) {
29
+ case 'function_declaration':
30
+ handleLuaFunctionDecl(node, ctx);
31
+ break;
32
+ case 'variable_declaration':
33
+ handleLuaVariableDecl(node, ctx);
34
+ break;
35
+ case 'function_call':
36
+ handleLuaFunctionCall(node, ctx);
37
+ break;
38
+ }
39
+
40
+ for (let i = 0; i < node.childCount; i++) {
41
+ const child = node.child(i);
42
+ if (child) walkLuaNode(child, ctx);
43
+ }
44
+ }
45
+
46
+ function handleLuaFunctionDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
47
+ const nameNode = node.childForFieldName('name');
48
+ if (!nameNode) return;
49
+
50
+ let name: string;
51
+ let kind: 'function' | 'method' = 'function';
52
+
53
+ if (nameNode.type === 'method_index_expression') {
54
+ const table = nameNode.childForFieldName('table');
55
+ const method = nameNode.childForFieldName('method');
56
+ if (table && method) {
57
+ name = `${table.text}.${method.text}`;
58
+ kind = 'method';
59
+ } else {
60
+ name = nameNode.text;
61
+ }
62
+ } else if (nameNode.type === 'dot_index_expression') {
63
+ const table = nameNode.childForFieldName('table');
64
+ const field = nameNode.childForFieldName('field');
65
+ if (table && field) {
66
+ name = `${table.text}.${field.text}`;
67
+ kind = 'method';
68
+ } else {
69
+ name = nameNode.text;
70
+ }
71
+ } else {
72
+ name = nameNode.text;
73
+ }
74
+
75
+ const params = extractLuaParams(node);
76
+
77
+ ctx.definitions.push({
78
+ name,
79
+ kind,
80
+ line: node.startPosition.row + 1,
81
+ endLine: nodeEndLine(node),
82
+ children: params.length > 0 ? params : undefined,
83
+ });
84
+ }
85
+
86
+ function extractLuaParams(funcNode: TreeSitterNode): SubDeclaration[] {
87
+ const params: SubDeclaration[] = [];
88
+ const paramList = funcNode.childForFieldName('parameters');
89
+ if (!paramList) return params;
90
+
91
+ for (let i = 0; i < paramList.childCount; i++) {
92
+ const param = paramList.child(i);
93
+ if (!param || param.type !== 'identifier') continue;
94
+ params.push({ name: param.text, kind: 'parameter', line: param.startPosition.row + 1 });
95
+ }
96
+ return params;
97
+ }
98
+
99
+ function handleLuaVariableDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
100
+ // Check for require calls in the assignment
101
+ const assignment = findChild(node, 'assignment_statement');
102
+ if (assignment) {
103
+ checkForRequire(assignment, ctx);
104
+ }
105
+ }
106
+
107
+ function checkForRequire(node: TreeSitterNode, ctx: ExtractorOutput): void {
108
+ for (let i = 0; i < node.childCount; i++) {
109
+ const child = node.child(i);
110
+ if (!child) continue;
111
+ if (child.type === 'function_call') {
112
+ const nameNode = child.childForFieldName('name');
113
+ if (nameNode && nameNode.type === 'identifier' && nameNode.text === 'require') {
114
+ const args = child.childForFieldName('arguments');
115
+ if (args) {
116
+ const strArg = findChild(args, 'string');
117
+ if (strArg) {
118
+ const source = strArg.text.replace(/^['"]|['"]$/g, '');
119
+ ctx.imports.push({
120
+ source,
121
+ names: ['require'],
122
+ line: child.startPosition.row + 1,
123
+ });
124
+ }
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ function handleLuaFunctionCall(node: TreeSitterNode, ctx: ExtractorOutput): void {
132
+ const nameNode = node.childForFieldName('name');
133
+ if (!nameNode) return;
134
+
135
+ // Check for require() as import
136
+ if (nameNode.type === 'identifier' && nameNode.text === 'require') {
137
+ const args = node.childForFieldName('arguments');
138
+ if (args) {
139
+ const strArg = findChild(args, 'string');
140
+ if (strArg) {
141
+ const source = strArg.text.replace(/^['"]|['"]$/g, '');
142
+ ctx.imports.push({
143
+ source,
144
+ names: ['require'],
145
+ line: node.startPosition.row + 1,
146
+ });
147
+ return;
148
+ }
149
+ }
150
+ }
151
+
152
+ const call: Call = { name: '', line: node.startPosition.row + 1 };
153
+
154
+ if (nameNode.type === 'method_index_expression') {
155
+ const table = nameNode.childForFieldName('table');
156
+ const method = nameNode.childForFieldName('method');
157
+ if (method) call.name = method.text;
158
+ if (table) call.receiver = table.text;
159
+ } else if (nameNode.type === 'dot_index_expression') {
160
+ const table = nameNode.childForFieldName('table');
161
+ const field = nameNode.childForFieldName('field');
162
+ if (field) call.name = field.text;
163
+ if (table) call.receiver = table.text;
164
+ } else {
165
+ call.name = nameNode.text;
166
+ }
167
+
168
+ if (call.name) ctx.calls.push(call);
169
+ }