@optave/codegraph 3.7.0 → 3.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (401) hide show
  1. package/README.md +28 -16
  2. package/dist/ast-analysis/engine.d.ts.map +1 -1
  3. package/dist/ast-analysis/engine.js +195 -30
  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/rules/javascript.d.ts.map +1 -1
  10. package/dist/ast-analysis/rules/javascript.js +0 -1
  11. package/dist/ast-analysis/rules/javascript.js.map +1 -1
  12. package/dist/ast-analysis/shared.d.ts.map +1 -1
  13. package/dist/ast-analysis/shared.js +24 -19
  14. package/dist/ast-analysis/shared.js.map +1 -1
  15. package/dist/ast-analysis/visitor-utils.d.ts.map +1 -1
  16. package/dist/ast-analysis/visitor-utils.js +55 -39
  17. package/dist/ast-analysis/visitor-utils.js.map +1 -1
  18. package/dist/ast-analysis/visitor.d.ts.map +1 -1
  19. package/dist/ast-analysis/visitor.js +91 -70
  20. package/dist/ast-analysis/visitor.js.map +1 -1
  21. package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
  22. package/dist/ast-analysis/visitors/ast-store-visitor.js +52 -129
  23. package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
  24. package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
  25. package/dist/ast-analysis/visitors/complexity-visitor.js +32 -39
  26. package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
  27. package/dist/ast-analysis/visitors/dataflow-visitor.d.ts.map +1 -1
  28. package/dist/ast-analysis/visitors/dataflow-visitor.js +57 -38
  29. package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
  30. package/dist/cli/commands/ast.js +2 -2
  31. package/dist/cli/commands/ast.js.map +1 -1
  32. package/dist/cli/commands/watch.d.ts.map +1 -1
  33. package/dist/cli/commands/watch.js +16 -2
  34. package/dist/cli/commands/watch.js.map +1 -1
  35. package/dist/db/connection.d.ts.map +1 -1
  36. package/dist/db/connection.js +29 -26
  37. package/dist/db/connection.js.map +1 -1
  38. package/dist/db/query-builder.d.ts.map +1 -1
  39. package/dist/db/query-builder.js +16 -5
  40. package/dist/db/query-builder.js.map +1 -1
  41. package/dist/db/repository/base.d.ts +10 -0
  42. package/dist/db/repository/base.d.ts.map +1 -1
  43. package/dist/db/repository/base.js +17 -0
  44. package/dist/db/repository/base.js.map +1 -1
  45. package/dist/db/repository/native-repository.d.ts +6 -1
  46. package/dist/db/repository/native-repository.d.ts.map +1 -1
  47. package/dist/db/repository/native-repository.js +77 -1
  48. package/dist/db/repository/native-repository.js.map +1 -1
  49. package/dist/db/repository/nodes.d.ts.map +1 -1
  50. package/dist/db/repository/nodes.js +8 -4
  51. package/dist/db/repository/nodes.js.map +1 -1
  52. package/dist/db/repository/sqlite-repository.d.ts +3 -0
  53. package/dist/db/repository/sqlite-repository.d.ts.map +1 -1
  54. package/dist/db/repository/sqlite-repository.js +26 -0
  55. package/dist/db/repository/sqlite-repository.js.map +1 -1
  56. package/dist/domain/analysis/brief.d.ts.map +1 -1
  57. package/dist/domain/analysis/brief.js +13 -17
  58. package/dist/domain/analysis/brief.js.map +1 -1
  59. package/dist/domain/analysis/context.d.ts.map +1 -1
  60. package/dist/domain/analysis/context.js +14 -11
  61. package/dist/domain/analysis/context.js.map +1 -1
  62. package/dist/domain/analysis/dependencies.d.ts.map +1 -1
  63. package/dist/domain/analysis/dependencies.js +53 -52
  64. package/dist/domain/analysis/dependencies.js.map +1 -1
  65. package/dist/domain/analysis/fn-impact.d.ts +2 -7
  66. package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
  67. package/dist/domain/analysis/fn-impact.js +33 -31
  68. package/dist/domain/analysis/fn-impact.js.map +1 -1
  69. package/dist/domain/analysis/implementations.d.ts.map +1 -1
  70. package/dist/domain/analysis/implementations.js +11 -19
  71. package/dist/domain/analysis/implementations.js.map +1 -1
  72. package/dist/domain/analysis/module-map.d.ts.map +1 -1
  73. package/dist/domain/analysis/module-map.js +55 -76
  74. package/dist/domain/analysis/module-map.js.map +1 -1
  75. package/dist/domain/analysis/query-helpers.d.ts +7 -0
  76. package/dist/domain/analysis/query-helpers.d.ts.map +1 -1
  77. package/dist/domain/analysis/query-helpers.js +15 -1
  78. package/dist/domain/analysis/query-helpers.js.map +1 -1
  79. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
  80. package/dist/domain/graph/builder/pipeline.js +315 -43
  81. package/dist/domain/graph/builder/pipeline.js.map +1 -1
  82. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
  83. package/dist/domain/graph/builder/stages/build-edges.js +106 -1
  84. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
  85. package/dist/domain/graph/builder/stages/collect-files.d.ts.map +1 -1
  86. package/dist/domain/graph/builder/stages/collect-files.js +17 -5
  87. package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
  88. package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
  89. package/dist/domain/graph/builder/stages/detect-changes.js +99 -51
  90. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
  91. package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
  92. package/dist/domain/graph/builder/stages/finalize.js +34 -7
  93. package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
  94. package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
  95. package/dist/domain/graph/builder/stages/insert-nodes.js +50 -26
  96. package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
  97. package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
  98. package/dist/domain/graph/builder/stages/resolve-imports.js +95 -84
  99. package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
  100. package/dist/domain/graph/cycles.d.ts +6 -0
  101. package/dist/domain/graph/cycles.d.ts.map +1 -1
  102. package/dist/domain/graph/cycles.js +114 -22
  103. package/dist/domain/graph/cycles.js.map +1 -1
  104. package/dist/domain/graph/resolve.js +1 -1
  105. package/dist/domain/graph/resolve.js.map +1 -1
  106. package/dist/domain/graph/watcher.d.ts +2 -0
  107. package/dist/domain/graph/watcher.d.ts.map +1 -1
  108. package/dist/domain/graph/watcher.js +170 -75
  109. package/dist/domain/graph/watcher.js.map +1 -1
  110. package/dist/domain/parser.d.ts +1 -6
  111. package/dist/domain/parser.d.ts.map +1 -1
  112. package/dist/domain/parser.js +101 -32
  113. package/dist/domain/parser.js.map +1 -1
  114. package/dist/domain/search/generator.js +1 -1
  115. package/dist/domain/search/generator.js.map +1 -1
  116. package/dist/domain/search/models.d.ts +4 -3
  117. package/dist/domain/search/models.d.ts.map +1 -1
  118. package/dist/domain/search/models.js +18 -5
  119. package/dist/domain/search/models.js.map +1 -1
  120. package/dist/domain/search/search/hybrid.d.ts.map +1 -1
  121. package/dist/domain/search/search/hybrid.js +29 -18
  122. package/dist/domain/search/search/hybrid.js.map +1 -1
  123. package/dist/extractors/clojure.d.ts +12 -0
  124. package/dist/extractors/clojure.d.ts.map +1 -0
  125. package/dist/extractors/clojure.js +245 -0
  126. package/dist/extractors/clojure.js.map +1 -0
  127. package/dist/extractors/cuda.d.ts +11 -0
  128. package/dist/extractors/cuda.d.ts.map +1 -0
  129. package/dist/extractors/cuda.js +302 -0
  130. package/dist/extractors/cuda.js.map +1 -0
  131. package/dist/extractors/erlang.d.ts +14 -0
  132. package/dist/extractors/erlang.d.ts.map +1 -0
  133. package/dist/extractors/erlang.js +239 -0
  134. package/dist/extractors/erlang.js.map +1 -0
  135. package/dist/extractors/fsharp.d.ts +13 -0
  136. package/dist/extractors/fsharp.d.ts.map +1 -0
  137. package/dist/extractors/fsharp.js +218 -0
  138. package/dist/extractors/fsharp.js.map +1 -0
  139. package/dist/extractors/gleam.d.ts +14 -0
  140. package/dist/extractors/gleam.d.ts.map +1 -0
  141. package/dist/extractors/gleam.js +229 -0
  142. package/dist/extractors/gleam.js.map +1 -0
  143. package/dist/extractors/go.js +36 -33
  144. package/dist/extractors/go.js.map +1 -1
  145. package/dist/extractors/groovy.d.ts +10 -0
  146. package/dist/extractors/groovy.d.ts.map +1 -0
  147. package/dist/extractors/groovy.js +304 -0
  148. package/dist/extractors/groovy.js.map +1 -0
  149. package/dist/extractors/helpers.d.ts.map +1 -1
  150. package/dist/extractors/helpers.js +40 -29
  151. package/dist/extractors/helpers.js.map +1 -1
  152. package/dist/extractors/index.d.ts +11 -0
  153. package/dist/extractors/index.d.ts.map +1 -1
  154. package/dist/extractors/index.js +11 -0
  155. package/dist/extractors/index.js.map +1 -1
  156. package/dist/extractors/java.js +58 -46
  157. package/dist/extractors/java.js.map +1 -1
  158. package/dist/extractors/javascript.js +46 -45
  159. package/dist/extractors/javascript.js.map +1 -1
  160. package/dist/extractors/julia.d.ts +16 -0
  161. package/dist/extractors/julia.d.ts.map +1 -0
  162. package/dist/extractors/julia.js +287 -0
  163. package/dist/extractors/julia.js.map +1 -0
  164. package/dist/extractors/kotlin.js +84 -78
  165. package/dist/extractors/kotlin.js.map +1 -1
  166. package/dist/extractors/objc.d.ts +9 -0
  167. package/dist/extractors/objc.d.ts.map +1 -0
  168. package/dist/extractors/objc.js +406 -0
  169. package/dist/extractors/objc.js.map +1 -0
  170. package/dist/extractors/ocaml.js +74 -0
  171. package/dist/extractors/ocaml.js.map +1 -1
  172. package/dist/extractors/python.js +29 -24
  173. package/dist/extractors/python.js.map +1 -1
  174. package/dist/extractors/r.d.ts +13 -0
  175. package/dist/extractors/r.d.ts.map +1 -0
  176. package/dist/extractors/r.js +251 -0
  177. package/dist/extractors/r.js.map +1 -0
  178. package/dist/extractors/rust.js +41 -32
  179. package/dist/extractors/rust.js.map +1 -1
  180. package/dist/extractors/solidity.d.ts +9 -0
  181. package/dist/extractors/solidity.d.ts.map +1 -0
  182. package/dist/extractors/solidity.js +365 -0
  183. package/dist/extractors/solidity.js.map +1 -0
  184. package/dist/extractors/swift.js +83 -81
  185. package/dist/extractors/swift.js.map +1 -1
  186. package/dist/extractors/verilog.d.ts +9 -0
  187. package/dist/extractors/verilog.d.ts.map +1 -0
  188. package/dist/extractors/verilog.js +286 -0
  189. package/dist/extractors/verilog.js.map +1 -0
  190. package/dist/extractors/zig.js +58 -60
  191. package/dist/extractors/zig.js.map +1 -1
  192. package/dist/features/ast.d.ts +16 -14
  193. package/dist/features/ast.d.ts.map +1 -1
  194. package/dist/features/ast.js +84 -83
  195. package/dist/features/ast.js.map +1 -1
  196. package/dist/features/audit.d.ts.map +1 -1
  197. package/dist/features/audit.js +8 -6
  198. package/dist/features/audit.js.map +1 -1
  199. package/dist/features/branch-compare.d.ts.map +1 -1
  200. package/dist/features/branch-compare.js +69 -72
  201. package/dist/features/branch-compare.js.map +1 -1
  202. package/dist/features/communities.d.ts.map +1 -1
  203. package/dist/features/communities.js +19 -7
  204. package/dist/features/communities.js.map +1 -1
  205. package/dist/features/complexity.d.ts.map +1 -1
  206. package/dist/features/complexity.js +120 -125
  207. package/dist/features/complexity.js.map +1 -1
  208. package/dist/features/dataflow.d.ts.map +1 -1
  209. package/dist/features/dataflow.js +136 -137
  210. package/dist/features/dataflow.js.map +1 -1
  211. package/dist/features/flow.d.ts.map +1 -1
  212. package/dist/features/flow.js +84 -79
  213. package/dist/features/flow.js.map +1 -1
  214. package/dist/features/structure-query.d.ts.map +1 -1
  215. package/dist/features/structure-query.js +69 -65
  216. package/dist/features/structure-query.js.map +1 -1
  217. package/dist/graph/algorithms/bfs.d.ts +2 -0
  218. package/dist/graph/algorithms/bfs.d.ts.map +1 -1
  219. package/dist/graph/algorithms/bfs.js +27 -0
  220. package/dist/graph/algorithms/bfs.js.map +1 -1
  221. package/dist/graph/algorithms/centrality.d.ts +2 -0
  222. package/dist/graph/algorithms/centrality.d.ts.map +1 -1
  223. package/dist/graph/algorithms/centrality.js +28 -0
  224. package/dist/graph/algorithms/centrality.js.map +1 -1
  225. package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
  226. package/dist/graph/algorithms/leiden/optimiser.js +70 -55
  227. package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
  228. package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -1
  229. package/dist/graph/algorithms/leiden/partition.js +288 -266
  230. package/dist/graph/algorithms/leiden/partition.js.map +1 -1
  231. package/dist/graph/algorithms/louvain.d.ts +3 -4
  232. package/dist/graph/algorithms/louvain.d.ts.map +1 -1
  233. package/dist/graph/algorithms/louvain.js +29 -0
  234. package/dist/graph/algorithms/louvain.js.map +1 -1
  235. package/dist/graph/algorithms/shortest-path.d.ts +2 -0
  236. package/dist/graph/algorithms/shortest-path.d.ts.map +1 -1
  237. package/dist/graph/algorithms/shortest-path.js +18 -1
  238. package/dist/graph/algorithms/shortest-path.js.map +1 -1
  239. package/dist/graph/model.d.ts.map +1 -1
  240. package/dist/graph/model.js +5 -1
  241. package/dist/graph/model.js.map +1 -1
  242. package/dist/infrastructure/config.d.ts.map +1 -1
  243. package/dist/infrastructure/config.js +6 -4
  244. package/dist/infrastructure/config.js.map +1 -1
  245. package/dist/infrastructure/suppress.d.ts +25 -0
  246. package/dist/infrastructure/suppress.d.ts.map +1 -0
  247. package/dist/infrastructure/suppress.js +43 -0
  248. package/dist/infrastructure/suppress.js.map +1 -0
  249. package/dist/mcp/server.d.ts.map +1 -1
  250. package/dist/mcp/server.js +29 -24
  251. package/dist/mcp/server.js.map +1 -1
  252. package/dist/presentation/dataflow.d.ts.map +1 -1
  253. package/dist/presentation/dataflow.js +47 -38
  254. package/dist/presentation/dataflow.js.map +1 -1
  255. package/dist/presentation/diff-impact-mermaid.d.ts.map +1 -1
  256. package/dist/presentation/diff-impact-mermaid.js +60 -51
  257. package/dist/presentation/diff-impact-mermaid.js.map +1 -1
  258. package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
  259. package/dist/presentation/queries-cli/exports.js +20 -14
  260. package/dist/presentation/queries-cli/exports.js.map +1 -1
  261. package/dist/presentation/queries-cli/impact.d.ts.map +1 -1
  262. package/dist/presentation/queries-cli/impact.js +15 -13
  263. package/dist/presentation/queries-cli/impact.js.map +1 -1
  264. package/dist/presentation/queries-cli/inspect.d.ts.map +1 -1
  265. package/dist/presentation/queries-cli/inspect.js +101 -79
  266. package/dist/presentation/queries-cli/inspect.js.map +1 -1
  267. package/dist/presentation/queries-cli/overview.d.ts.map +1 -1
  268. package/dist/presentation/queries-cli/overview.js +25 -16
  269. package/dist/presentation/queries-cli/overview.js.map +1 -1
  270. package/dist/presentation/queries-cli/path.js +26 -20
  271. package/dist/presentation/queries-cli/path.js.map +1 -1
  272. package/dist/presentation/result-formatter.d.ts +10 -0
  273. package/dist/presentation/result-formatter.d.ts.map +1 -1
  274. package/dist/presentation/result-formatter.js +16 -1
  275. package/dist/presentation/result-formatter.js.map +1 -1
  276. package/dist/presentation/viewer.d.ts.map +1 -1
  277. package/dist/presentation/viewer.js +18 -12
  278. package/dist/presentation/viewer.js.map +1 -1
  279. package/dist/shared/errors.d.ts +5 -0
  280. package/dist/shared/errors.d.ts.map +1 -1
  281. package/dist/shared/errors.js +5 -0
  282. package/dist/shared/errors.js.map +1 -1
  283. package/dist/shared/hierarchy.d.ts +8 -2
  284. package/dist/shared/hierarchy.d.ts.map +1 -1
  285. package/dist/shared/hierarchy.js +42 -1
  286. package/dist/shared/hierarchy.js.map +1 -1
  287. package/dist/shared/normalize.d.ts +6 -1
  288. package/dist/shared/normalize.d.ts.map +1 -1
  289. package/dist/shared/normalize.js +20 -12
  290. package/dist/shared/normalize.js.map +1 -1
  291. package/dist/shared/paginate.d.ts +0 -9
  292. package/dist/shared/paginate.d.ts.map +1 -1
  293. package/dist/shared/paginate.js +0 -15
  294. package/dist/shared/paginate.js.map +1 -1
  295. package/dist/types.d.ts +129 -3
  296. package/dist/types.d.ts.map +1 -1
  297. package/grammars/tree-sitter-clojure.wasm +0 -0
  298. package/grammars/tree-sitter-cuda.wasm +0 -0
  299. package/grammars/tree-sitter-erlang.wasm +0 -0
  300. package/grammars/tree-sitter-fsharp.wasm +0 -0
  301. package/grammars/tree-sitter-gleam.wasm +0 -0
  302. package/grammars/tree-sitter-groovy.wasm +0 -0
  303. package/grammars/tree-sitter-julia.wasm +0 -0
  304. package/grammars/tree-sitter-objc.wasm +0 -0
  305. package/grammars/tree-sitter-ocaml_interface.wasm +0 -0
  306. package/grammars/tree-sitter-r.wasm +0 -0
  307. package/grammars/tree-sitter-solidity.wasm +0 -0
  308. package/grammars/tree-sitter-verilog.wasm +0 -0
  309. package/package.json +18 -7
  310. package/src/ast-analysis/engine.ts +245 -42
  311. package/src/ast-analysis/metrics.ts +33 -11
  312. package/src/ast-analysis/rules/javascript.ts +0 -1
  313. package/src/ast-analysis/shared.ts +33 -24
  314. package/src/ast-analysis/visitor-utils.ts +52 -32
  315. package/src/ast-analysis/visitor.ts +132 -71
  316. package/src/ast-analysis/visitors/ast-store-visitor.ts +49 -119
  317. package/src/ast-analysis/visitors/complexity-visitor.ts +35 -40
  318. package/src/ast-analysis/visitors/dataflow-visitor.ts +87 -43
  319. package/src/cli/commands/ast.ts +2 -2
  320. package/src/cli/commands/watch.ts +16 -2
  321. package/src/db/connection.ts +29 -28
  322. package/src/db/query-builder.ts +15 -3
  323. package/src/db/repository/base.ts +20 -0
  324. package/src/db/repository/native-repository.ts +79 -1
  325. package/src/db/repository/nodes.ts +13 -8
  326. package/src/db/repository/sqlite-repository.ts +29 -0
  327. package/src/domain/analysis/brief.ts +15 -25
  328. package/src/domain/analysis/context.ts +17 -10
  329. package/src/domain/analysis/dependencies.ts +67 -76
  330. package/src/domain/analysis/fn-impact.ts +36 -43
  331. package/src/domain/analysis/implementations.ts +11 -17
  332. package/src/domain/analysis/module-map.ts +58 -92
  333. package/src/domain/analysis/query-helpers.ts +18 -1
  334. package/src/domain/graph/builder/pipeline.ts +366 -41
  335. package/src/domain/graph/builder/stages/build-edges.ts +162 -1
  336. package/src/domain/graph/builder/stages/collect-files.ts +18 -7
  337. package/src/domain/graph/builder/stages/detect-changes.ts +110 -56
  338. package/src/domain/graph/builder/stages/finalize.ts +41 -11
  339. package/src/domain/graph/builder/stages/insert-nodes.ts +75 -39
  340. package/src/domain/graph/builder/stages/resolve-imports.ts +122 -100
  341. package/src/domain/graph/cycles.ts +110 -23
  342. package/src/domain/graph/resolve.ts +1 -1
  343. package/src/domain/graph/watcher.ts +202 -96
  344. package/src/domain/parser.ts +122 -28
  345. package/src/domain/search/generator.ts +1 -1
  346. package/src/domain/search/models.ts +17 -4
  347. package/src/domain/search/search/hybrid.ts +69 -51
  348. package/src/extractors/clojure.ts +273 -0
  349. package/src/extractors/cuda.ts +316 -0
  350. package/src/extractors/erlang.ts +252 -0
  351. package/src/extractors/fsharp.ts +253 -0
  352. package/src/extractors/gleam.ts +246 -0
  353. package/src/extractors/go.ts +43 -33
  354. package/src/extractors/groovy.ts +332 -0
  355. package/src/extractors/helpers.ts +37 -23
  356. package/src/extractors/index.ts +11 -0
  357. package/src/extractors/java.ts +66 -47
  358. package/src/extractors/javascript.ts +45 -46
  359. package/src/extractors/julia.ts +318 -0
  360. package/src/extractors/kotlin.ts +84 -77
  361. package/src/extractors/objc.ts +431 -0
  362. package/src/extractors/ocaml.ts +78 -0
  363. package/src/extractors/python.ts +31 -25
  364. package/src/extractors/r.ts +253 -0
  365. package/src/extractors/rust.ts +37 -29
  366. package/src/extractors/solidity.ts +394 -0
  367. package/src/extractors/swift.ts +81 -80
  368. package/src/extractors/verilog.ts +315 -0
  369. package/src/extractors/zig.ts +58 -61
  370. package/src/features/ast.ts +131 -112
  371. package/src/features/audit.ts +8 -6
  372. package/src/features/branch-compare.ts +105 -79
  373. package/src/features/communities.ts +25 -10
  374. package/src/features/complexity.ts +171 -134
  375. package/src/features/dataflow.ts +165 -175
  376. package/src/features/flow.ts +129 -92
  377. package/src/features/structure-query.ts +79 -64
  378. package/src/graph/algorithms/bfs.ts +34 -0
  379. package/src/graph/algorithms/centrality.ts +30 -0
  380. package/src/graph/algorithms/leiden/optimiser.ts +99 -55
  381. package/src/graph/algorithms/leiden/partition.ts +359 -294
  382. package/src/graph/algorithms/louvain.ts +31 -4
  383. package/src/graph/algorithms/shortest-path.ts +20 -1
  384. package/src/graph/model.ts +6 -1
  385. package/src/infrastructure/config.ts +6 -4
  386. package/src/infrastructure/suppress.ts +47 -0
  387. package/src/mcp/server.ts +53 -37
  388. package/src/presentation/dataflow.ts +50 -44
  389. package/src/presentation/diff-impact-mermaid.ts +104 -62
  390. package/src/presentation/queries-cli/exports.ts +21 -13
  391. package/src/presentation/queries-cli/impact.ts +15 -13
  392. package/src/presentation/queries-cli/inspect.ts +100 -81
  393. package/src/presentation/queries-cli/overview.ts +26 -16
  394. package/src/presentation/queries-cli/path.ts +33 -25
  395. package/src/presentation/result-formatter.ts +19 -1
  396. package/src/presentation/viewer.ts +42 -14
  397. package/src/shared/errors.ts +6 -0
  398. package/src/shared/hierarchy.ts +50 -2
  399. package/src/shared/normalize.ts +31 -12
  400. package/src/shared/paginate.ts +0 -17
  401. package/src/types.ts +138 -3
@@ -328,34 +328,7 @@ function extractConstantsWalk(node: TreeSitterNode, definitions: Definition[]):
328
328
  if (inner) declNode = inner;
329
329
  }
330
330
 
331
- const t = declNode.type;
332
- if (t === 'lexical_declaration' || t === 'variable_declaration') {
333
- if (declNode.text.startsWith('const ')) {
334
- for (let j = 0; j < declNode.childCount; j++) {
335
- const declarator = declNode.child(j);
336
- if (!declarator || declarator.type !== 'variable_declarator') continue;
337
- const nameN = declarator.childForFieldName('name');
338
- const valueN = declarator.childForFieldName('value');
339
- if (!nameN || nameN.type !== 'identifier' || !valueN) continue;
340
- // Skip functions — already captured by query patterns
341
- const valType = valueN.type;
342
- if (
343
- valType === 'arrow_function' ||
344
- valType === 'function_expression' ||
345
- valType === 'function'
346
- )
347
- continue;
348
- if (isConstantValue(valueN)) {
349
- definitions.push({
350
- name: nameN.text,
351
- kind: 'constant',
352
- line: declNode.startPosition.row + 1,
353
- endLine: nodeEndLine(declNode),
354
- });
355
- }
356
- }
357
- }
358
- }
331
+ extractConstDeclarators(declNode, definitions);
359
332
 
360
333
  // Recurse into non-function, non-export-statement children (blocks, if-statements, etc.)
361
334
  if (child.type !== 'export_statement') {
@@ -364,6 +337,33 @@ function extractConstantsWalk(node: TreeSitterNode, definitions: Definition[]):
364
337
  }
365
338
  }
366
339
 
340
+ /** Extract constant definitions from a `const` declaration node. */
341
+ function extractConstDeclarators(declNode: TreeSitterNode, definitions: Definition[]): void {
342
+ const t = declNode.type;
343
+ if (t !== 'lexical_declaration' && t !== 'variable_declaration') return;
344
+ if (!declNode.text.startsWith('const ')) return;
345
+
346
+ for (let j = 0; j < declNode.childCount; j++) {
347
+ const declarator = declNode.child(j);
348
+ if (!declarator || declarator.type !== 'variable_declarator') continue;
349
+ const nameN = declarator.childForFieldName('name');
350
+ const valueN = declarator.childForFieldName('value');
351
+ if (!nameN || nameN.type !== 'identifier' || !valueN) continue;
352
+ // Skip functions — already captured by query patterns
353
+ const valType = valueN.type;
354
+ if (valType === 'arrow_function' || valType === 'function_expression' || valType === 'function')
355
+ continue;
356
+ if (isConstantValue(valueN)) {
357
+ definitions.push({
358
+ name: nameN.text,
359
+ kind: 'constant',
360
+ line: declNode.startPosition.row + 1,
361
+ endLine: nodeEndLine(declNode),
362
+ });
363
+ }
364
+ }
365
+ }
366
+
367
367
  /**
368
368
  * Recursive walk to find dynamic import() calls.
369
369
  * Query patterns match call_expression with identifier/member_expression/subscript_expression
@@ -678,24 +678,7 @@ function handleCallExpr(node: TreeSitterNode, ctx: ExtractorOutput): void {
678
678
  const fn = node.childForFieldName('function');
679
679
  if (!fn) return;
680
680
  if (fn.type === 'import') {
681
- const args = node.childForFieldName('arguments') || findChild(node, 'arguments');
682
- if (args) {
683
- const strArg = findChild(args, 'string');
684
- if (strArg) {
685
- const modPath = strArg.text.replace(/['"]/g, '');
686
- const names = extractDynamicImportNames(node);
687
- ctx.imports.push({
688
- source: modPath,
689
- names,
690
- line: node.startPosition.row + 1,
691
- dynamicImport: true,
692
- });
693
- } else {
694
- debug(
695
- `Skipping non-static dynamic import() at line ${node.startPosition.row + 1} (template literal or variable)`,
696
- );
697
- }
698
- }
681
+ handleDynamicImportCall(node, ctx.imports);
699
682
  } else {
700
683
  const callInfo = extractCallInfo(fn, node);
701
684
  if (callInfo) ctx.calls.push(callInfo);
@@ -706,6 +689,22 @@ function handleCallExpr(node: TreeSitterNode, ctx: ExtractorOutput): void {
706
689
  }
707
690
  }
708
691
 
692
+ /** Handle a dynamic import() call expression and add to imports if static. */
693
+ function handleDynamicImportCall(node: TreeSitterNode, imports: Import[]): void {
694
+ const args = node.childForFieldName('arguments') || findChild(node, 'arguments');
695
+ if (!args) return;
696
+ const strArg = findChild(args, 'string');
697
+ if (strArg) {
698
+ const modPath = strArg.text.replace(/['"]/g, '');
699
+ const names = extractDynamicImportNames(node);
700
+ imports.push({ source: modPath, names, line: node.startPosition.row + 1, dynamicImport: true });
701
+ } else {
702
+ debug(
703
+ `Skipping non-static dynamic import() at line ${node.startPosition.row + 1} (template literal or variable)`,
704
+ );
705
+ }
706
+ }
707
+
709
708
  function handleImportStmt(node: TreeSitterNode, ctx: ExtractorOutput): void {
710
709
  const isTypeOnly = node.text.startsWith('import type');
711
710
  const source = node.childForFieldName('source') || findChild(node, 'string');
@@ -0,0 +1,318 @@
1
+ import type { ExtractorOutput, SubDeclaration, TreeSitterNode, TreeSitterTree } from '../types.js';
2
+ import { findChild, nodeEndLine } from './helpers.js';
3
+
4
+ /**
5
+ * Extract symbols from Julia files.
6
+ *
7
+ * tree-sitter-julia grammar notes:
8
+ * - function_definition: `function name(params)...end`
9
+ * - assignment: `name(params) = expr` (short form), LHS is call_expression
10
+ * - struct_definition: `struct TypeHead...end`, name is in type_head
11
+ * - module_definition: `module Name...end`
12
+ * - import_statement / using_statement
13
+ * - macro_definition: `macro name(params)...end`
14
+ * - abstract_definition: `abstract type Name end`
15
+ * - call_expression: function calls
16
+ */
17
+ export function extractJuliaSymbols(tree: TreeSitterTree, _filePath: string): ExtractorOutput {
18
+ const ctx: ExtractorOutput = {
19
+ definitions: [],
20
+ calls: [],
21
+ imports: [],
22
+ classes: [],
23
+ exports: [],
24
+ typeMap: new Map(),
25
+ };
26
+
27
+ walkJuliaNode(tree.rootNode, ctx, null);
28
+ return ctx;
29
+ }
30
+
31
+ function walkJuliaNode(
32
+ node: TreeSitterNode,
33
+ ctx: ExtractorOutput,
34
+ currentModule: string | null,
35
+ ): void {
36
+ let nextModule = currentModule;
37
+
38
+ switch (node.type) {
39
+ case 'module_definition':
40
+ nextModule = handleModuleDef(node, ctx);
41
+ break;
42
+ case 'function_definition':
43
+ handleFunctionDef(node, ctx, currentModule);
44
+ break;
45
+ case 'assignment':
46
+ handleAssignment(node, ctx, currentModule);
47
+ break;
48
+ case 'struct_definition':
49
+ handleStructDef(node, ctx);
50
+ break;
51
+ case 'abstract_definition':
52
+ handleAbstractDef(node, ctx);
53
+ break;
54
+ case 'macro_definition':
55
+ handleMacroDef(node, ctx, currentModule);
56
+ break;
57
+ case 'import_statement':
58
+ case 'using_statement':
59
+ handleImport(node, ctx);
60
+ break;
61
+ case 'call_expression':
62
+ handleCall(node, ctx);
63
+ break;
64
+ }
65
+
66
+ for (let i = 0; i < node.childCount; i++) {
67
+ const child = node.child(i);
68
+ if (child) walkJuliaNode(child, ctx, nextModule);
69
+ }
70
+ }
71
+
72
+ function handleModuleDef(node: TreeSitterNode, ctx: ExtractorOutput): string | null {
73
+ const nameNode = node.childForFieldName('name') || findChild(node, 'identifier');
74
+ if (!nameNode) return null;
75
+
76
+ ctx.definitions.push({
77
+ name: nameNode.text,
78
+ kind: 'module',
79
+ line: node.startPosition.row + 1,
80
+ endLine: nodeEndLine(node),
81
+ });
82
+
83
+ return nameNode.text;
84
+ }
85
+
86
+ function handleFunctionDef(
87
+ node: TreeSitterNode,
88
+ ctx: ExtractorOutput,
89
+ currentModule: string | null,
90
+ ): void {
91
+ // function_definition may have a call_expression child as the signature
92
+ const callSig = findChild(node, 'call_expression');
93
+ if (callSig) {
94
+ const funcNameNode = callSig.child(0);
95
+ if (funcNameNode) {
96
+ const name = currentModule ? `${currentModule}.${funcNameNode.text}` : funcNameNode.text;
97
+ const params = extractJuliaParams(callSig);
98
+ ctx.definitions.push({
99
+ name,
100
+ kind: 'function',
101
+ line: node.startPosition.row + 1,
102
+ endLine: nodeEndLine(node),
103
+ children: params.length > 0 ? params : undefined,
104
+ });
105
+ return;
106
+ }
107
+ }
108
+
109
+ // Fallback: look for identifier directly
110
+ const nameNode = node.childForFieldName('name') || findChild(node, 'identifier');
111
+ if (!nameNode) return;
112
+
113
+ const name = currentModule ? `${currentModule}.${nameNode.text}` : nameNode.text;
114
+ ctx.definitions.push({
115
+ name,
116
+ kind: 'function',
117
+ line: node.startPosition.row + 1,
118
+ endLine: nodeEndLine(node),
119
+ });
120
+ }
121
+
122
+ function handleAssignment(
123
+ node: TreeSitterNode,
124
+ ctx: ExtractorOutput,
125
+ currentModule: string | null,
126
+ ): void {
127
+ // assignment: LHS operator RHS
128
+ // Short function form: add(x, y) = x + y → LHS is call_expression
129
+ const lhs = node.child(0);
130
+ if (!lhs) return;
131
+
132
+ if (lhs.type === 'call_expression') {
133
+ const funcNameNode = lhs.child(0);
134
+ if (!funcNameNode) return;
135
+
136
+ const name = currentModule ? `${currentModule}.${funcNameNode.text}` : funcNameNode.text;
137
+ const params = extractJuliaParams(lhs);
138
+
139
+ ctx.definitions.push({
140
+ name,
141
+ kind: 'function',
142
+ line: node.startPosition.row + 1,
143
+ endLine: nodeEndLine(node),
144
+ children: params.length > 0 ? params : undefined,
145
+ });
146
+ }
147
+ }
148
+
149
+ function handleStructDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
150
+ // struct_definition: struct type_head fields... end
151
+ const typeHead = findChild(node, 'type_head');
152
+ const nameNode = typeHead
153
+ ? (findChild(typeHead, 'identifier') ?? typeHead)
154
+ : findChild(node, 'identifier');
155
+ if (!nameNode) return;
156
+
157
+ const children: SubDeclaration[] = [];
158
+ // Fields are typed_expression children of struct_definition
159
+ for (let i = 0; i < node.childCount; i++) {
160
+ const child = node.child(i);
161
+ if (!child) continue;
162
+ if (child.type === 'typed_expression') {
163
+ const fieldName = findChild(child, 'identifier');
164
+ if (fieldName) {
165
+ children.push({
166
+ name: fieldName.text,
167
+ kind: 'property',
168
+ line: child.startPosition.row + 1,
169
+ });
170
+ }
171
+ }
172
+ // Plain identifier fields (no type annotation)
173
+ if (child.type === 'identifier' && child !== nameNode && typeHead && child !== typeHead) {
174
+ children.push({ name: child.text, kind: 'property', line: child.startPosition.row + 1 });
175
+ }
176
+ }
177
+
178
+ // Check for supertype in type_head (Point <: AbstractPoint)
179
+ if (typeHead) {
180
+ const subtypeExpr = findChild(typeHead, 'subtype_expression');
181
+ if (subtypeExpr) {
182
+ // Find the supertype identifier
183
+ for (let i = 0; i < subtypeExpr.childCount; i++) {
184
+ const child = subtypeExpr.child(i);
185
+ if (child?.type === 'identifier' && i > 0) {
186
+ ctx.classes.push({
187
+ name: nameNode.text,
188
+ extends: child.text,
189
+ line: node.startPosition.row + 1,
190
+ });
191
+ }
192
+ }
193
+ }
194
+ }
195
+
196
+ ctx.definitions.push({
197
+ name: nameNode.text,
198
+ kind: 'struct',
199
+ line: node.startPosition.row + 1,
200
+ endLine: nodeEndLine(node),
201
+ children: children.length > 0 ? children : undefined,
202
+ });
203
+ }
204
+
205
+ function handleAbstractDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
206
+ const nameNode = node.childForFieldName('name') || findChild(node, 'identifier');
207
+ if (!nameNode) return;
208
+
209
+ ctx.definitions.push({
210
+ name: nameNode.text,
211
+ kind: 'type',
212
+ line: node.startPosition.row + 1,
213
+ endLine: nodeEndLine(node),
214
+ });
215
+ }
216
+
217
+ function handleMacroDef(
218
+ node: TreeSitterNode,
219
+ ctx: ExtractorOutput,
220
+ currentModule: string | null,
221
+ ): void {
222
+ const nameNode = node.childForFieldName('name') || findChild(node, 'identifier');
223
+ if (!nameNode) return;
224
+
225
+ const name = currentModule ? `${currentModule}.@${nameNode.text}` : `@${nameNode.text}`;
226
+ ctx.definitions.push({
227
+ name,
228
+ kind: 'function',
229
+ line: node.startPosition.row + 1,
230
+ endLine: nodeEndLine(node),
231
+ });
232
+ }
233
+
234
+ function handleImport(node: TreeSitterNode, ctx: ExtractorOutput): void {
235
+ const names: string[] = [];
236
+ let source = '';
237
+
238
+ for (let i = 0; i < node.childCount; i++) {
239
+ const child = node.child(i);
240
+ if (!child) continue;
241
+ if (
242
+ child.type === 'identifier' ||
243
+ child.type === 'scoped_identifier' ||
244
+ child.type === 'selected_import'
245
+ ) {
246
+ if (!source) source = child.text;
247
+ names.push(child.text.split('.').pop() || child.text);
248
+ }
249
+ }
250
+
251
+ if (source) {
252
+ ctx.imports.push({
253
+ source,
254
+ names: names.length > 0 ? names : [source],
255
+ line: node.startPosition.row + 1,
256
+ });
257
+ }
258
+ }
259
+
260
+ function handleCall(node: TreeSitterNode, ctx: ExtractorOutput): void {
261
+ // Don't record if parent is assignment LHS (that's a function definition)
262
+ if (node.parent?.type === 'assignment' && node === node.parent.child(0)) return;
263
+ // Don't record if parent is function_definition (that's a signature)
264
+ if (node.parent?.type === 'function_definition') return;
265
+
266
+ const funcNode = node.child(0);
267
+ if (!funcNode) return;
268
+
269
+ if (funcNode.type === 'identifier') {
270
+ ctx.calls.push({ name: funcNode.text, line: node.startPosition.row + 1 });
271
+ } else if (funcNode.type === 'field_expression' || funcNode.type === 'scoped_identifier') {
272
+ const parts = funcNode.text.split('.');
273
+ if (parts.length >= 2) {
274
+ ctx.calls.push({
275
+ name: parts[parts.length - 1]!,
276
+ receiver: parts.slice(0, -1).join('.'),
277
+ line: node.startPosition.row + 1,
278
+ });
279
+ } else {
280
+ ctx.calls.push({ name: funcNode.text, line: node.startPosition.row + 1 });
281
+ }
282
+ }
283
+ }
284
+
285
+ function extractJuliaParams(callExpr: TreeSitterNode): SubDeclaration[] {
286
+ const params: SubDeclaration[] = [];
287
+ const argList = findChild(callExpr, 'argument_list') || findChild(callExpr, 'tuple_expression');
288
+ if (!argList) return params;
289
+
290
+ for (let i = 0; i < argList.childCount; i++) {
291
+ const child = argList.child(i);
292
+ if (!child) continue;
293
+ if (child.type === 'identifier') {
294
+ params.push({ name: child.text, kind: 'parameter', line: child.startPosition.row + 1 });
295
+ }
296
+ if (child.type === 'typed_parameter' || child.type === 'typed_expression') {
297
+ const nameNode = findChild(child, 'identifier');
298
+ if (nameNode) {
299
+ params.push({
300
+ name: nameNode.text,
301
+ kind: 'parameter',
302
+ line: child.startPosition.row + 1,
303
+ });
304
+ }
305
+ }
306
+ if (child.type === 'optional_parameter' || child.type === 'default_parameter') {
307
+ const nameNode = findChild(child, 'identifier');
308
+ if (nameNode) {
309
+ params.push({
310
+ name: nameNode.text,
311
+ kind: 'parameter',
312
+ line: child.startPosition.row + 1,
313
+ });
314
+ }
315
+ }
316
+ }
317
+ return params;
318
+ }
@@ -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
  }