@optave/codegraph 3.8.0 → 3.9.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 (310) hide show
  1. package/README.md +13 -8
  2. package/dist/ast-analysis/engine.d.ts.map +1 -1
  3. package/dist/ast-analysis/engine.js +137 -86
  4. package/dist/ast-analysis/engine.js.map +1 -1
  5. package/dist/ast-analysis/metrics.d.ts +0 -3
  6. package/dist/ast-analysis/metrics.d.ts.map +1 -1
  7. package/dist/ast-analysis/metrics.js +30 -13
  8. package/dist/ast-analysis/metrics.js.map +1 -1
  9. package/dist/ast-analysis/shared.d.ts.map +1 -1
  10. package/dist/ast-analysis/shared.js +24 -19
  11. package/dist/ast-analysis/shared.js.map +1 -1
  12. package/dist/ast-analysis/visitor-utils.d.ts.map +1 -1
  13. package/dist/ast-analysis/visitor-utils.js +55 -39
  14. package/dist/ast-analysis/visitor-utils.js.map +1 -1
  15. package/dist/ast-analysis/visitor.d.ts.map +1 -1
  16. package/dist/ast-analysis/visitor.js +91 -70
  17. package/dist/ast-analysis/visitor.js.map +1 -1
  18. package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
  19. package/dist/ast-analysis/visitors/ast-store-visitor.js +54 -58
  20. package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
  21. package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
  22. package/dist/ast-analysis/visitors/complexity-visitor.js +81 -39
  23. package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
  24. package/dist/ast-analysis/visitors/dataflow-visitor.d.ts.map +1 -1
  25. package/dist/ast-analysis/visitors/dataflow-visitor.js +57 -38
  26. package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
  27. package/dist/cli/commands/branch-compare.d.ts.map +1 -1
  28. package/dist/cli/commands/branch-compare.js +4 -0
  29. package/dist/cli/commands/branch-compare.js.map +1 -1
  30. package/dist/cli/commands/diff-impact.d.ts.map +1 -1
  31. package/dist/cli/commands/diff-impact.js +2 -1
  32. package/dist/cli/commands/diff-impact.js.map +1 -1
  33. package/dist/cli/commands/info.d.ts.map +1 -1
  34. package/dist/cli/commands/info.js +3 -2
  35. package/dist/cli/commands/info.js.map +1 -1
  36. package/dist/cli/commands/watch.d.ts.map +1 -1
  37. package/dist/cli/commands/watch.js +16 -2
  38. package/dist/cli/commands/watch.js.map +1 -1
  39. package/dist/db/connection.d.ts.map +1 -1
  40. package/dist/db/connection.js +29 -26
  41. package/dist/db/connection.js.map +1 -1
  42. package/dist/db/query-builder.d.ts.map +1 -1
  43. package/dist/db/query-builder.js +16 -5
  44. package/dist/db/query-builder.js.map +1 -1
  45. package/dist/db/repository/base.d.ts +16 -0
  46. package/dist/db/repository/base.d.ts.map +1 -1
  47. package/dist/db/repository/base.js +31 -0
  48. package/dist/db/repository/base.js.map +1 -1
  49. package/dist/db/repository/native-repository.d.ts +7 -1
  50. package/dist/db/repository/native-repository.d.ts.map +1 -1
  51. package/dist/db/repository/native-repository.js +100 -1
  52. package/dist/db/repository/native-repository.js.map +1 -1
  53. package/dist/db/repository/nodes.d.ts.map +1 -1
  54. package/dist/db/repository/nodes.js +8 -4
  55. package/dist/db/repository/nodes.js.map +1 -1
  56. package/dist/db/repository/sqlite-repository.d.ts +4 -0
  57. package/dist/db/repository/sqlite-repository.d.ts.map +1 -1
  58. package/dist/db/repository/sqlite-repository.js +51 -0
  59. package/dist/db/repository/sqlite-repository.js.map +1 -1
  60. package/dist/domain/analysis/brief.d.ts.map +1 -1
  61. package/dist/domain/analysis/brief.js +13 -17
  62. package/dist/domain/analysis/brief.js.map +1 -1
  63. package/dist/domain/analysis/context.d.ts.map +1 -1
  64. package/dist/domain/analysis/context.js +14 -11
  65. package/dist/domain/analysis/context.js.map +1 -1
  66. package/dist/domain/analysis/dependencies.d.ts.map +1 -1
  67. package/dist/domain/analysis/dependencies.js +64 -59
  68. package/dist/domain/analysis/dependencies.js.map +1 -1
  69. package/dist/domain/analysis/fn-impact.d.ts +2 -7
  70. package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
  71. package/dist/domain/analysis/fn-impact.js +33 -31
  72. package/dist/domain/analysis/fn-impact.js.map +1 -1
  73. package/dist/domain/analysis/implementations.d.ts.map +1 -1
  74. package/dist/domain/analysis/implementations.js +11 -19
  75. package/dist/domain/analysis/implementations.js.map +1 -1
  76. package/dist/domain/analysis/module-map.d.ts.map +1 -1
  77. package/dist/domain/analysis/module-map.js +55 -76
  78. package/dist/domain/analysis/module-map.js.map +1 -1
  79. package/dist/domain/analysis/query-helpers.d.ts +7 -0
  80. package/dist/domain/analysis/query-helpers.d.ts.map +1 -1
  81. package/dist/domain/analysis/query-helpers.js +15 -1
  82. package/dist/domain/analysis/query-helpers.js.map +1 -1
  83. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
  84. package/dist/domain/graph/builder/pipeline.js +352 -107
  85. package/dist/domain/graph/builder/pipeline.js.map +1 -1
  86. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
  87. package/dist/domain/graph/builder/stages/build-edges.js +49 -18
  88. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
  89. package/dist/domain/graph/builder/stages/detect-changes.js +2 -2
  90. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
  91. package/dist/domain/graph/builder/stages/finalize.js +2 -2
  92. package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
  93. package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
  94. package/dist/domain/graph/builder/stages/insert-nodes.js +32 -21
  95. package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
  96. package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
  97. package/dist/domain/graph/builder/stages/resolve-imports.js +95 -84
  98. package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
  99. package/dist/domain/graph/cycles.d.ts +6 -0
  100. package/dist/domain/graph/cycles.d.ts.map +1 -1
  101. package/dist/domain/graph/cycles.js +114 -22
  102. package/dist/domain/graph/cycles.js.map +1 -1
  103. package/dist/domain/graph/resolve.js +1 -1
  104. package/dist/domain/graph/resolve.js.map +1 -1
  105. package/dist/domain/graph/watcher.d.ts +2 -0
  106. package/dist/domain/graph/watcher.d.ts.map +1 -1
  107. package/dist/domain/graph/watcher.js +170 -75
  108. package/dist/domain/graph/watcher.js.map +1 -1
  109. package/dist/domain/parser.d.ts +3 -4
  110. package/dist/domain/parser.d.ts.map +1 -1
  111. package/dist/domain/parser.js +141 -89
  112. package/dist/domain/parser.js.map +1 -1
  113. package/dist/domain/search/generator.js +1 -1
  114. package/dist/domain/search/generator.js.map +1 -1
  115. package/dist/domain/search/models.d.ts +4 -3
  116. package/dist/domain/search/models.d.ts.map +1 -1
  117. package/dist/domain/search/models.js +23 -8
  118. package/dist/domain/search/models.js.map +1 -1
  119. package/dist/domain/search/search/hybrid.d.ts.map +1 -1
  120. package/dist/domain/search/search/hybrid.js +29 -18
  121. package/dist/domain/search/search/hybrid.js.map +1 -1
  122. package/dist/extractors/go.js +36 -33
  123. package/dist/extractors/go.js.map +1 -1
  124. package/dist/extractors/helpers.d.ts.map +1 -1
  125. package/dist/extractors/helpers.js +40 -29
  126. package/dist/extractors/helpers.js.map +1 -1
  127. package/dist/extractors/java.js +58 -46
  128. package/dist/extractors/java.js.map +1 -1
  129. package/dist/extractors/javascript.js +65 -54
  130. package/dist/extractors/javascript.js.map +1 -1
  131. package/dist/extractors/kotlin.js +84 -78
  132. package/dist/extractors/kotlin.js.map +1 -1
  133. package/dist/extractors/python.js +29 -24
  134. package/dist/extractors/python.js.map +1 -1
  135. package/dist/extractors/rust.js +41 -32
  136. package/dist/extractors/rust.js.map +1 -1
  137. package/dist/extractors/solidity.js +58 -67
  138. package/dist/extractors/solidity.js.map +1 -1
  139. package/dist/extractors/swift.js +83 -81
  140. package/dist/extractors/swift.js.map +1 -1
  141. package/dist/extractors/zig.js +58 -60
  142. package/dist/extractors/zig.js.map +1 -1
  143. package/dist/features/ast.d.ts +16 -14
  144. package/dist/features/ast.d.ts.map +1 -1
  145. package/dist/features/ast.js +83 -81
  146. package/dist/features/ast.js.map +1 -1
  147. package/dist/features/audit.d.ts.map +1 -1
  148. package/dist/features/audit.js +8 -6
  149. package/dist/features/audit.js.map +1 -1
  150. package/dist/features/branch-compare.d.ts.map +1 -1
  151. package/dist/features/branch-compare.js +69 -72
  152. package/dist/features/branch-compare.js.map +1 -1
  153. package/dist/features/communities.d.ts.map +1 -1
  154. package/dist/features/communities.js +19 -7
  155. package/dist/features/communities.js.map +1 -1
  156. package/dist/features/complexity.d.ts.map +1 -1
  157. package/dist/features/complexity.js +120 -125
  158. package/dist/features/complexity.js.map +1 -1
  159. package/dist/features/dataflow.d.ts.map +1 -1
  160. package/dist/features/dataflow.js +136 -137
  161. package/dist/features/dataflow.js.map +1 -1
  162. package/dist/features/flow.d.ts.map +1 -1
  163. package/dist/features/flow.js +84 -79
  164. package/dist/features/flow.js.map +1 -1
  165. package/dist/features/structure-query.d.ts.map +1 -1
  166. package/dist/features/structure-query.js +69 -65
  167. package/dist/features/structure-query.js.map +1 -1
  168. package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
  169. package/dist/graph/algorithms/leiden/optimiser.js +70 -55
  170. package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
  171. package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -1
  172. package/dist/graph/algorithms/leiden/partition.js +288 -266
  173. package/dist/graph/algorithms/leiden/partition.js.map +1 -1
  174. package/dist/graph/model.d.ts.map +1 -1
  175. package/dist/graph/model.js +5 -1
  176. package/dist/graph/model.js.map +1 -1
  177. package/dist/infrastructure/config.d.ts.map +1 -1
  178. package/dist/infrastructure/config.js +6 -4
  179. package/dist/infrastructure/config.js.map +1 -1
  180. package/dist/infrastructure/suppress.d.ts +25 -0
  181. package/dist/infrastructure/suppress.d.ts.map +1 -0
  182. package/dist/infrastructure/suppress.js +43 -0
  183. package/dist/infrastructure/suppress.js.map +1 -0
  184. package/dist/mcp/server.d.ts.map +1 -1
  185. package/dist/mcp/server.js +29 -24
  186. package/dist/mcp/server.js.map +1 -1
  187. package/dist/presentation/dataflow.d.ts.map +1 -1
  188. package/dist/presentation/dataflow.js +47 -38
  189. package/dist/presentation/dataflow.js.map +1 -1
  190. package/dist/presentation/diff-impact-mermaid.d.ts.map +1 -1
  191. package/dist/presentation/diff-impact-mermaid.js +60 -51
  192. package/dist/presentation/diff-impact-mermaid.js.map +1 -1
  193. package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
  194. package/dist/presentation/queries-cli/exports.js +20 -14
  195. package/dist/presentation/queries-cli/exports.js.map +1 -1
  196. package/dist/presentation/queries-cli/impact.d.ts.map +1 -1
  197. package/dist/presentation/queries-cli/impact.js +15 -13
  198. package/dist/presentation/queries-cli/impact.js.map +1 -1
  199. package/dist/presentation/queries-cli/inspect.d.ts.map +1 -1
  200. package/dist/presentation/queries-cli/inspect.js +101 -79
  201. package/dist/presentation/queries-cli/inspect.js.map +1 -1
  202. package/dist/presentation/queries-cli/overview.d.ts.map +1 -1
  203. package/dist/presentation/queries-cli/overview.js +25 -16
  204. package/dist/presentation/queries-cli/overview.js.map +1 -1
  205. package/dist/presentation/queries-cli/path.js +26 -20
  206. package/dist/presentation/queries-cli/path.js.map +1 -1
  207. package/dist/presentation/result-formatter.d.ts +10 -0
  208. package/dist/presentation/result-formatter.d.ts.map +1 -1
  209. package/dist/presentation/result-formatter.js +16 -1
  210. package/dist/presentation/result-formatter.js.map +1 -1
  211. package/dist/presentation/viewer.d.ts.map +1 -1
  212. package/dist/presentation/viewer.js +18 -12
  213. package/dist/presentation/viewer.js.map +1 -1
  214. package/dist/shared/errors.d.ts +5 -0
  215. package/dist/shared/errors.d.ts.map +1 -1
  216. package/dist/shared/errors.js +5 -0
  217. package/dist/shared/errors.js.map +1 -1
  218. package/dist/shared/hierarchy.d.ts +8 -2
  219. package/dist/shared/hierarchy.d.ts.map +1 -1
  220. package/dist/shared/hierarchy.js +42 -1
  221. package/dist/shared/hierarchy.js.map +1 -1
  222. package/dist/shared/normalize.d.ts +6 -1
  223. package/dist/shared/normalize.d.ts.map +1 -1
  224. package/dist/shared/normalize.js +20 -12
  225. package/dist/shared/normalize.js.map +1 -1
  226. package/dist/shared/paginate.d.ts +0 -9
  227. package/dist/shared/paginate.d.ts.map +1 -1
  228. package/dist/shared/paginate.js +0 -15
  229. package/dist/shared/paginate.js.map +1 -1
  230. package/dist/types.d.ts +12 -5
  231. package/dist/types.d.ts.map +1 -1
  232. package/grammars/tree-sitter-erlang.wasm +0 -0
  233. package/grammars/tree-sitter-gleam.wasm +0 -0
  234. package/package.json +9 -9
  235. package/src/ast-analysis/engine.ts +176 -104
  236. package/src/ast-analysis/metrics.ts +33 -11
  237. package/src/ast-analysis/shared.ts +33 -24
  238. package/src/ast-analysis/visitor-utils.ts +52 -32
  239. package/src/ast-analysis/visitor.ts +132 -71
  240. package/src/ast-analysis/visitors/ast-store-visitor.ts +53 -50
  241. package/src/ast-analysis/visitors/complexity-visitor.ts +89 -40
  242. package/src/ast-analysis/visitors/dataflow-visitor.ts +87 -43
  243. package/src/cli/commands/branch-compare.ts +4 -0
  244. package/src/cli/commands/diff-impact.ts +2 -1
  245. package/src/cli/commands/info.ts +3 -2
  246. package/src/cli/commands/watch.ts +16 -2
  247. package/src/db/connection.ts +29 -28
  248. package/src/db/query-builder.ts +15 -3
  249. package/src/db/repository/base.ts +34 -0
  250. package/src/db/repository/native-repository.ts +104 -1
  251. package/src/db/repository/nodes.ts +13 -8
  252. package/src/db/repository/sqlite-repository.ts +55 -0
  253. package/src/domain/analysis/brief.ts +15 -25
  254. package/src/domain/analysis/context.ts +17 -10
  255. package/src/domain/analysis/dependencies.ts +77 -81
  256. package/src/domain/analysis/fn-impact.ts +36 -43
  257. package/src/domain/analysis/implementations.ts +11 -17
  258. package/src/domain/analysis/module-map.ts +58 -92
  259. package/src/domain/analysis/query-helpers.ts +18 -1
  260. package/src/domain/graph/builder/pipeline.ts +409 -99
  261. package/src/domain/graph/builder/stages/build-edges.ts +45 -19
  262. package/src/domain/graph/builder/stages/detect-changes.ts +2 -2
  263. package/src/domain/graph/builder/stages/finalize.ts +2 -2
  264. package/src/domain/graph/builder/stages/insert-nodes.ts +59 -34
  265. package/src/domain/graph/builder/stages/resolve-imports.ts +122 -100
  266. package/src/domain/graph/cycles.ts +110 -23
  267. package/src/domain/graph/resolve.ts +1 -1
  268. package/src/domain/graph/watcher.ts +202 -96
  269. package/src/domain/parser.ts +143 -89
  270. package/src/domain/search/generator.ts +1 -1
  271. package/src/domain/search/models.ts +26 -7
  272. package/src/domain/search/search/hybrid.ts +69 -51
  273. package/src/extractors/go.ts +43 -33
  274. package/src/extractors/helpers.ts +37 -23
  275. package/src/extractors/java.ts +66 -47
  276. package/src/extractors/javascript.ts +66 -54
  277. package/src/extractors/kotlin.ts +84 -77
  278. package/src/extractors/python.ts +31 -25
  279. package/src/extractors/rust.ts +37 -29
  280. package/src/extractors/solidity.ts +57 -61
  281. package/src/extractors/swift.ts +81 -80
  282. package/src/extractors/zig.ts +58 -61
  283. package/src/features/ast.ts +130 -110
  284. package/src/features/audit.ts +8 -6
  285. package/src/features/branch-compare.ts +105 -79
  286. package/src/features/communities.ts +25 -10
  287. package/src/features/complexity.ts +171 -134
  288. package/src/features/dataflow.ts +165 -175
  289. package/src/features/flow.ts +129 -92
  290. package/src/features/structure-query.ts +79 -64
  291. package/src/graph/algorithms/leiden/optimiser.ts +99 -55
  292. package/src/graph/algorithms/leiden/partition.ts +359 -294
  293. package/src/graph/model.ts +6 -1
  294. package/src/infrastructure/config.ts +6 -4
  295. package/src/infrastructure/suppress.ts +47 -0
  296. package/src/mcp/server.ts +53 -37
  297. package/src/presentation/dataflow.ts +50 -44
  298. package/src/presentation/diff-impact-mermaid.ts +104 -62
  299. package/src/presentation/queries-cli/exports.ts +21 -13
  300. package/src/presentation/queries-cli/impact.ts +15 -13
  301. package/src/presentation/queries-cli/inspect.ts +100 -81
  302. package/src/presentation/queries-cli/overview.ts +26 -16
  303. package/src/presentation/queries-cli/path.ts +33 -25
  304. package/src/presentation/result-formatter.ts +19 -1
  305. package/src/presentation/viewer.ts +42 -14
  306. package/src/shared/errors.ts +6 -0
  307. package/src/shared/hierarchy.ts +50 -2
  308. package/src/shared/normalize.ts +31 -12
  309. package/src/shared/paginate.ts +0 -17
  310. package/src/types.ts +26 -5
@@ -81,48 +81,7 @@ function handleKotlinClassDecl(node: TreeSitterNode, ctx: ExtractorOutput): void
81
81
 
82
82
  const kind = isInterface ? 'interface' : isEnum ? 'enum' : 'class';
83
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
- }
84
+ const children = isEnum ? collectKotlinEnumEntries(node) : collectKotlinProperties(node);
126
85
 
127
86
  ctx.definitions.push({
128
87
  name,
@@ -132,27 +91,79 @@ function handleKotlinClassDecl(node: TreeSitterNode, ctx: ExtractorOutput): void
132
91
  children: children.length > 0 ? children : undefined,
133
92
  });
134
93
 
135
- // Methods inside class_body
94
+ collectKotlinMethods(node, name, ctx);
95
+ collectKotlinInheritance(node, name, ctx);
96
+ }
97
+
98
+ /** Collect enum constant entries from a class_body. */
99
+ function collectKotlinEnumEntries(node: TreeSitterNode): SubDeclaration[] {
100
+ const entries: SubDeclaration[] = [];
136
101
  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
- }
102
+ if (!body) return entries;
103
+ for (let i = 0; i < body.childCount; i++) {
104
+ const child = body.child(i);
105
+ if (!child || child.type !== 'enum_entry') continue;
106
+ const entryName = findChild(child, 'simple_identifier');
107
+ if (entryName) {
108
+ entries.push({
109
+ name: entryName.text,
110
+ kind: 'constant',
111
+ line: child.startPosition.row + 1,
112
+ });
152
113
  }
153
114
  }
115
+ return entries;
116
+ }
117
+
118
+ /** Collect property declarations from a class_body. */
119
+ function collectKotlinProperties(node: TreeSitterNode): SubDeclaration[] {
120
+ const props: SubDeclaration[] = [];
121
+ const body = findChild(node, 'class_body');
122
+ if (!body) return props;
123
+ for (let i = 0; i < body.childCount; i++) {
124
+ const child = body.child(i);
125
+ if (!child || child.type !== 'property_declaration') continue;
126
+ const varDecl = findChild(child, 'variable_declaration');
127
+ if (!varDecl) continue;
128
+ const id = findChild(varDecl, 'simple_identifier');
129
+ if (id) {
130
+ props.push({
131
+ name: id.text,
132
+ kind: 'property',
133
+ line: child.startPosition.row + 1,
134
+ visibility: extractModifierVisibility(child),
135
+ });
136
+ }
137
+ }
138
+ return props;
139
+ }
140
+
141
+ /** Collect method declarations from a class_body. */
142
+ function collectKotlinMethods(node: TreeSitterNode, className: string, ctx: ExtractorOutput): void {
143
+ const body = findChild(node, 'class_body');
144
+ if (!body) return;
145
+ for (let i = 0; i < body.childCount; i++) {
146
+ const child = body.child(i);
147
+ if (!child || child.type !== 'function_declaration') continue;
148
+ const methName = findChild(child, 'simple_identifier');
149
+ if (methName) {
150
+ ctx.definitions.push({
151
+ name: `${className}.${methName.text}`,
152
+ kind: 'method',
153
+ line: child.startPosition.row + 1,
154
+ endLine: child.endPosition.row + 1,
155
+ visibility: extractModifierVisibility(child),
156
+ });
157
+ }
158
+ }
159
+ }
154
160
 
155
- // Inheritance: delegation_specifier nodes are DIRECT children
161
+ /** Collect inheritance relationships from delegation_specifier children. */
162
+ function collectKotlinInheritance(
163
+ node: TreeSitterNode,
164
+ className: string,
165
+ ctx: ExtractorOutput,
166
+ ): void {
156
167
  for (let i = 0; i < node.childCount; i++) {
157
168
  const child = node.child(i);
158
169
  if (!child || child.type !== 'delegation_specifier') continue;
@@ -161,30 +172,26 @@ function handleKotlinClassDecl(node: TreeSitterNode, ctx: ExtractorOutput): void
161
172
  const ctorInvocation = findChild(child, 'constructor_invocation');
162
173
  if (ctorInvocation) {
163
174
  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
- }
175
+ const typeId = userType ? findChild(userType, 'type_identifier') : null;
176
+ if (typeId) {
177
+ ctx.classes.push({
178
+ name: className,
179
+ extends: typeId.text,
180
+ line: node.startPosition.row + 1,
181
+ });
173
182
  }
174
183
  continue;
175
184
  }
176
185
 
177
186
  // user_type > type_identifier (implements)
178
187
  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
+ const typeId = userType ? findChild(userType, 'type_identifier') : null;
189
+ if (typeId) {
190
+ ctx.classes.push({
191
+ name: className,
192
+ implements: typeId.text,
193
+ line: node.startPosition.row + 1,
194
+ });
188
195
  }
189
196
  }
190
197
  }
@@ -245,35 +245,41 @@ function extractPythonParameters(fnNode: TreeSitterNode): SubDeclaration[] {
245
245
  for (let i = 0; i < paramsNode.childCount; i++) {
246
246
  const child = paramsNode.child(i);
247
247
  if (!child) continue;
248
- const t = child.type;
249
- if (t === 'identifier') {
250
- params.push({ name: child.text, kind: 'parameter', line: child.startPosition.row + 1 });
251
- } else if (
252
- t === 'typed_parameter' ||
253
- t === 'default_parameter' ||
254
- t === 'typed_default_parameter'
255
- ) {
256
- const nameNode = child.childForFieldName('name') || child.child(0);
257
- if (nameNode && nameNode.type === 'identifier') {
258
- params.push({
259
- name: nameNode.text,
260
- kind: 'parameter',
261
- line: child.startPosition.row + 1,
262
- });
263
- }
264
- } else if (t === 'list_splat_pattern' || t === 'dictionary_splat_pattern') {
265
- for (let j = 0; j < child.childCount; j++) {
266
- const inner = child.child(j);
267
- if (inner && inner.type === 'identifier') {
268
- params.push({ name: inner.text, kind: 'parameter', line: child.startPosition.row + 1 });
269
- break;
270
- }
271
- }
272
- }
248
+ const param = extractSinglePyParam(child);
249
+ if (param) params.push(param);
273
250
  }
274
251
  return params;
275
252
  }
276
253
 
254
+ /** Extract a single parameter declaration from a parameter node. */
255
+ function extractSinglePyParam(child: TreeSitterNode): SubDeclaration | null {
256
+ const t = child.type;
257
+ if (t === 'identifier') {
258
+ return { name: child.text, kind: 'parameter', line: child.startPosition.row + 1 };
259
+ }
260
+ if (t === 'typed_parameter' || t === 'default_parameter' || t === 'typed_default_parameter') {
261
+ const nameNode = child.childForFieldName('name') || child.child(0);
262
+ if (nameNode && nameNode.type === 'identifier') {
263
+ return { name: nameNode.text, kind: 'parameter', line: child.startPosition.row + 1 };
264
+ }
265
+ }
266
+ if (t === 'list_splat_pattern' || t === 'dictionary_splat_pattern') {
267
+ return extractSplatParam(child);
268
+ }
269
+ return null;
270
+ }
271
+
272
+ /** Extract the identifier name from a *args or **kwargs splat pattern. */
273
+ function extractSplatParam(node: TreeSitterNode): SubDeclaration | null {
274
+ for (let j = 0; j < node.childCount; j++) {
275
+ const inner = node.child(j);
276
+ if (inner && inner.type === 'identifier') {
277
+ return { name: inner.text, kind: 'parameter', line: node.startPosition.row + 1 };
278
+ }
279
+ }
280
+ return null;
281
+ }
282
+
277
283
  /** Extract class-level assignment properties from expression statements. */
278
284
  function extractClassAssignment(
279
285
  child: TreeSitterNode,
@@ -138,19 +138,22 @@ function handleRustTraitItem(node: TreeSitterNode, ctx: ExtractorOutput): void {
138
138
  endLine: nodeEndLine(node),
139
139
  });
140
140
  const body = node.childForFieldName('body');
141
- if (body) {
142
- for (let i = 0; i < body.childCount; i++) {
143
- const child = body.child(i);
144
- if (child && (child.type === 'function_signature_item' || child.type === 'function_item')) {
145
- const methName = child.childForFieldName('name');
146
- if (methName) {
147
- ctx.definitions.push({
148
- name: `${nameNode.text}.${methName.text}`,
149
- kind: 'method',
150
- line: child.startPosition.row + 1,
151
- endLine: child.endPosition.row + 1,
152
- });
153
- }
141
+ if (body) extractTraitMethods(body, nameNode.text, ctx);
142
+ }
143
+
144
+ /** Extract method signatures/definitions from a trait body. */
145
+ function extractTraitMethods(body: TreeSitterNode, traitName: string, ctx: ExtractorOutput): void {
146
+ for (let i = 0; i < body.childCount; i++) {
147
+ const child = body.child(i);
148
+ if (child && (child.type === 'function_signature_item' || child.type === 'function_item')) {
149
+ const methName = child.childForFieldName('name');
150
+ if (methName) {
151
+ ctx.definitions.push({
152
+ name: `${traitName}.${methName.text}`,
153
+ kind: 'method',
154
+ line: child.startPosition.row + 1,
155
+ endLine: child.endPosition.row + 1,
156
+ });
154
157
  }
155
158
  }
156
159
  }
@@ -185,25 +188,30 @@ function handleRustUseDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
185
188
  function handleRustCallExpr(node: TreeSitterNode, ctx: ExtractorOutput): void {
186
189
  const fn = node.childForFieldName('function');
187
190
  if (!fn) return;
188
- if (fn.type === 'identifier') {
189
- ctx.calls.push({ name: fn.text, line: node.startPosition.row + 1 });
190
- } else if (fn.type === 'field_expression') {
191
+ const call = extractRustCallInfo(fn, node.startPosition.row + 1);
192
+ if (call) ctx.calls.push(call);
193
+ }
194
+
195
+ /** Extract call info from a Rust call function node. */
196
+ function extractRustCallInfo(fn: TreeSitterNode, line: number): Call | null {
197
+ if (fn.type === 'identifier') return { name: fn.text, line };
198
+ if (fn.type === 'field_expression') {
191
199
  const field = fn.childForFieldName('field');
192
- if (field) {
193
- const value = fn.childForFieldName('value');
194
- const call: Call = { name: field.text, line: node.startPosition.row + 1 };
195
- if (value) call.receiver = value.text;
196
- ctx.calls.push(call);
197
- }
198
- } else if (fn.type === 'scoped_identifier') {
200
+ if (!field) return null;
201
+ const value = fn.childForFieldName('value');
202
+ const call: Call = { name: field.text, line };
203
+ if (value) call.receiver = value.text;
204
+ return call;
205
+ }
206
+ if (fn.type === 'scoped_identifier') {
199
207
  const name = fn.childForFieldName('name');
200
- if (name) {
201
- const path = fn.childForFieldName('path');
202
- const call: Call = { name: name.text, line: node.startPosition.row + 1 };
203
- if (path) call.receiver = path.text;
204
- ctx.calls.push(call);
205
- }
208
+ if (!name) return null;
209
+ const path = fn.childForFieldName('path');
210
+ const call: Call = { name: name.text, line };
211
+ if (path) call.receiver = path.text;
212
+ return call;
206
213
  }
214
+ return null;
207
215
  }
208
216
 
209
217
  function handleRustMacroInvocation(node: TreeSitterNode, ctx: ExtractorOutput): void {
@@ -97,60 +97,8 @@ function handleContractDecl(
97
97
  if (!nameNode) return;
98
98
  const name = nameNode.text;
99
99
 
100
- const members: SubDeclaration[] = [];
101
100
  const body = node.childForFieldName('body') || findChild(node, 'contract_body');
102
- if (body) {
103
- for (let i = 0; i < body.childCount; i++) {
104
- const child = body.child(i);
105
- if (!child) continue;
106
- if (child.type === 'function_definition') {
107
- const fnName = child.childForFieldName('name');
108
- if (fnName) {
109
- members.push({ name: fnName.text, kind: 'method', line: child.startPosition.row + 1 });
110
- }
111
- } else if (child.type === 'state_variable_declaration') {
112
- const varName = child.childForFieldName('name');
113
- if (varName) {
114
- members.push({
115
- name: varName.text,
116
- kind: 'property',
117
- line: child.startPosition.row + 1,
118
- visibility: extractSolVisibility(child),
119
- });
120
- }
121
- } else if (child.type === 'event_definition') {
122
- const evName = child.childForFieldName('name');
123
- if (evName) {
124
- members.push({
125
- name: evName.text,
126
- kind: 'property',
127
- decorators: ['event'],
128
- line: child.startPosition.row + 1,
129
- });
130
- }
131
- } else if (child.type === 'error_declaration') {
132
- const errName = child.childForFieldName('name');
133
- if (errName) {
134
- members.push({
135
- name: errName.text,
136
- kind: 'property',
137
- decorators: ['error'],
138
- line: child.startPosition.row + 1,
139
- });
140
- }
141
- } else if (child.type === 'modifier_definition') {
142
- const modName = child.childForFieldName('name');
143
- if (modName) {
144
- members.push({
145
- name: modName.text,
146
- kind: 'method',
147
- decorators: ['modifier'],
148
- line: child.startPosition.row + 1,
149
- });
150
- }
151
- }
152
- }
153
- }
101
+ const members = body ? extractContractMembers(body) : [];
154
102
 
155
103
  ctx.definitions.push({
156
104
  name,
@@ -160,15 +108,63 @@ function handleContractDecl(
160
108
  children: members.length > 0 ? members : undefined,
161
109
  });
162
110
 
163
- // Inheritance
111
+ extractInheritance(node, name, ctx);
112
+ }
113
+
114
+ /** Extract member declarations from a contract body node. */
115
+ function extractContractMembers(body: TreeSitterNode): SubDeclaration[] {
116
+ const members: SubDeclaration[] = [];
117
+ for (let i = 0; i < body.childCount; i++) {
118
+ const child = body.child(i);
119
+ if (!child) continue;
120
+ const member = extractContractMember(child);
121
+ if (member) members.push(member);
122
+ }
123
+ return members;
124
+ }
125
+
126
+ /** Map a single contract body child to a SubDeclaration, or null if not a recognized member. */
127
+ function extractContractMember(child: TreeSitterNode): SubDeclaration | null {
128
+ const line = child.startPosition.row + 1;
129
+ switch (child.type) {
130
+ case 'function_definition': {
131
+ const fnName = child.childForFieldName('name');
132
+ return fnName ? { name: fnName.text, kind: 'method', line } : null;
133
+ }
134
+ case 'state_variable_declaration': {
135
+ const varName = child.childForFieldName('name');
136
+ return varName
137
+ ? { name: varName.text, kind: 'property', line, visibility: extractSolVisibility(child) }
138
+ : null;
139
+ }
140
+ case 'event_definition': {
141
+ const evName = child.childForFieldName('name');
142
+ return evName ? { name: evName.text, kind: 'property', decorators: ['event'], line } : null;
143
+ }
144
+ case 'error_declaration': {
145
+ const errName = child.childForFieldName('name');
146
+ return errName ? { name: errName.text, kind: 'property', decorators: ['error'], line } : null;
147
+ }
148
+ case 'modifier_definition': {
149
+ const modName = child.childForFieldName('name');
150
+ return modName
151
+ ? { name: modName.text, kind: 'method', decorators: ['modifier'], line }
152
+ : null;
153
+ }
154
+ default:
155
+ return null;
156
+ }
157
+ }
158
+
159
+ /** Extract inheritance (extends) relationships from a contract node. */
160
+ function extractInheritance(node: TreeSitterNode, name: string, ctx: ExtractorOutput): void {
164
161
  const inheritance = findChild(node, 'inheritance_specifier');
165
- if (inheritance) {
166
- for (let i = 0; i < inheritance.childCount; i++) {
167
- const child = inheritance.child(i);
168
- if (!child) continue;
169
- if (child.type === 'user_defined_type' || child.type === 'identifier') {
170
- ctx.classes.push({ name, extends: child.text, line: node.startPosition.row + 1 });
171
- }
162
+ if (!inheritance) return;
163
+ for (let i = 0; i < inheritance.childCount; i++) {
164
+ const child = inheritance.child(i);
165
+ if (!child) continue;
166
+ if (child.type === 'user_defined_type' || child.type === 'identifier') {
167
+ ctx.classes.push({ name, extends: child.text, line: node.startPosition.row + 1 });
172
168
  }
173
169
  }
174
170
  }
@@ -73,49 +73,7 @@ function handleSwiftClassDecl(node: TreeSitterNode, ctx: ExtractorOutput): void
73
73
 
74
74
  const kind = isEnum ? 'enum' : isStruct ? 'struct' : 'class';
75
75
 
76
- const children: SubDeclaration[] = [];
77
-
78
- if (isEnum) {
79
- // Enum cases: enum_entry > simple_identifier, inside enum_class_body
80
- const body = findChild(node, 'enum_class_body');
81
- if (body) {
82
- for (let i = 0; i < body.childCount; i++) {
83
- const child = body.child(i);
84
- if (child && child.type === 'enum_entry') {
85
- const entryName = findChild(child, 'simple_identifier');
86
- if (entryName) {
87
- children.push({
88
- name: entryName.text,
89
- kind: 'constant',
90
- line: child.startPosition.row + 1,
91
- });
92
- }
93
- }
94
- }
95
- }
96
- } else {
97
- // Extract properties from class_body
98
- const body = findChild(node, 'class_body');
99
- if (body) {
100
- for (let i = 0; i < body.childCount; i++) {
101
- const child = body.child(i);
102
- if (child && child.type === 'property_declaration') {
103
- const pattern = findChild(child, 'pattern');
104
- if (pattern) {
105
- const propName = findChild(pattern, 'simple_identifier');
106
- if (propName) {
107
- children.push({
108
- name: propName.text,
109
- kind: 'property',
110
- line: child.startPosition.row + 1,
111
- visibility: extractModifierVisibility(child),
112
- });
113
- }
114
- }
115
- }
116
- }
117
- }
118
- }
76
+ const children = isEnum ? collectSwiftEnumEntries(node) : collectSwiftProperties(node);
119
77
 
120
78
  ctx.definitions.push({
121
79
  name,
@@ -125,52 +83,95 @@ function handleSwiftClassDecl(node: TreeSitterNode, ctx: ExtractorOutput): void
125
83
  children: children.length > 0 ? children : undefined,
126
84
  });
127
85
 
128
- // Methods inside class_body or enum_class_body
86
+ collectSwiftMethods(node, name, ctx);
87
+ collectSwiftInheritance(node, name, ctx);
88
+ }
89
+
90
+ /** Collect enum constant entries from an enum_class_body. */
91
+ function collectSwiftEnumEntries(node: TreeSitterNode): SubDeclaration[] {
92
+ const entries: SubDeclaration[] = [];
93
+ const body = findChild(node, 'enum_class_body');
94
+ if (!body) return entries;
95
+ for (let i = 0; i < body.childCount; i++) {
96
+ const child = body.child(i);
97
+ if (!child || child.type !== 'enum_entry') continue;
98
+ const entryName = findChild(child, 'simple_identifier');
99
+ if (entryName) {
100
+ entries.push({
101
+ name: entryName.text,
102
+ kind: 'constant',
103
+ line: child.startPosition.row + 1,
104
+ });
105
+ }
106
+ }
107
+ return entries;
108
+ }
109
+
110
+ /** Collect property declarations from a class_body. */
111
+ function collectSwiftProperties(node: TreeSitterNode): SubDeclaration[] {
112
+ const props: SubDeclaration[] = [];
113
+ const body = findChild(node, 'class_body');
114
+ if (!body) return props;
115
+ for (let i = 0; i < body.childCount; i++) {
116
+ const child = body.child(i);
117
+ if (!child || child.type !== 'property_declaration') continue;
118
+ const pattern = findChild(child, 'pattern');
119
+ if (!pattern) continue;
120
+ const propName = findChild(pattern, 'simple_identifier');
121
+ if (propName) {
122
+ props.push({
123
+ name: propName.text,
124
+ kind: 'property',
125
+ line: child.startPosition.row + 1,
126
+ visibility: extractModifierVisibility(child),
127
+ });
128
+ }
129
+ }
130
+ return props;
131
+ }
132
+
133
+ /** Collect method declarations from class_body or enum_class_body. */
134
+ function collectSwiftMethods(node: TreeSitterNode, className: string, ctx: ExtractorOutput): void {
129
135
  const body = findChild(node, 'class_body') || findChild(node, 'enum_class_body');
130
- if (body) {
131
- for (let i = 0; i < body.childCount; i++) {
132
- const child = body.child(i);
133
- if (child && child.type === 'function_declaration') {
134
- const methName = findChild(child, 'simple_identifier');
135
- if (methName) {
136
- ctx.definitions.push({
137
- name: `${name}.${methName.text}`,
138
- kind: 'method',
139
- line: child.startPosition.row + 1,
140
- endLine: child.endPosition.row + 1,
141
- visibility: extractModifierVisibility(child),
142
- });
143
- }
144
- }
136
+ if (!body) return;
137
+ for (let i = 0; i < body.childCount; i++) {
138
+ const child = body.child(i);
139
+ if (!child || child.type !== 'function_declaration') continue;
140
+ const methName = findChild(child, 'simple_identifier');
141
+ if (methName) {
142
+ ctx.definitions.push({
143
+ name: `${className}.${methName.text}`,
144
+ kind: 'method',
145
+ line: child.startPosition.row + 1,
146
+ endLine: child.endPosition.row + 1,
147
+ visibility: extractModifierVisibility(child),
148
+ });
145
149
  }
146
150
  }
151
+ }
147
152
 
148
- // Inheritance: inheritance_specifier nodes are DIRECT children of class_declaration
149
- // First specifier is the superclass (extends), rest are protocol conformances (implements)
153
+ /** Collect inheritance from inheritance_specifier children. First = extends, rest = implements. */
154
+ function collectSwiftInheritance(
155
+ node: TreeSitterNode,
156
+ className: string,
157
+ ctx: ExtractorOutput,
158
+ ): void {
150
159
  let first = true;
151
160
  for (let i = 0; i < node.childCount; i++) {
152
161
  const child = node.child(i);
153
162
  if (!child || child.type !== 'inheritance_specifier') continue;
154
- // inheritance_specifier > user_type > type_identifier
155
163
  const userType = findChild(child, 'user_type');
156
- if (userType) {
157
- const typeId = findChild(userType, 'type_identifier');
158
- if (typeId) {
159
- if (first) {
160
- ctx.classes.push({
161
- name,
162
- extends: typeId.text,
163
- line: node.startPosition.row + 1,
164
- });
165
- first = false;
166
- } else {
167
- ctx.classes.push({
168
- name,
169
- implements: typeId.text,
170
- line: node.startPosition.row + 1,
171
- });
172
- }
173
- }
164
+ const typeId = userType ? findChild(userType, 'type_identifier') : null;
165
+ if (!typeId) continue;
166
+ if (first) {
167
+ ctx.classes.push({ name: className, extends: typeId.text, line: node.startPosition.row + 1 });
168
+ first = false;
169
+ } else {
170
+ ctx.classes.push({
171
+ name: className,
172
+ implements: typeId.text,
173
+ line: node.startPosition.row + 1,
174
+ });
174
175
  }
175
176
  }
176
177
  }