@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
@@ -0,0 +1,253 @@
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 F# files.
12
+ *
13
+ * tree-sitter-fsharp grammar notes:
14
+ * - named_module: top-level module declaration
15
+ * - function_declaration_left: LHS of `let name params = ...`
16
+ * - import_decl: `open Namespace`
17
+ * - type_definition > union_type_defn / record_type_defn
18
+ * - application_expression: function calls
19
+ */
20
+ export function extractFSharpSymbols(tree: TreeSitterTree, _filePath: string): ExtractorOutput {
21
+ const ctx: ExtractorOutput = {
22
+ definitions: [],
23
+ calls: [],
24
+ imports: [],
25
+ classes: [],
26
+ exports: [],
27
+ typeMap: new Map(),
28
+ };
29
+
30
+ walkFSharpNode(tree.rootNode, ctx, null);
31
+ return ctx;
32
+ }
33
+
34
+ function walkFSharpNode(
35
+ node: TreeSitterNode,
36
+ ctx: ExtractorOutput,
37
+ currentModule: string | null,
38
+ ): void {
39
+ let nextModule = currentModule;
40
+
41
+ switch (node.type) {
42
+ case 'named_module':
43
+ nextModule = handleNamedModule(node, ctx);
44
+ break;
45
+ case 'function_declaration_left':
46
+ handleFunctionDecl(node, ctx, currentModule);
47
+ break;
48
+ case 'type_definition':
49
+ handleTypeDef(node, ctx);
50
+ break;
51
+ case 'import_decl':
52
+ handleImportDecl(node, ctx);
53
+ break;
54
+ case 'application_expression':
55
+ handleApplication(node, ctx);
56
+ break;
57
+ case 'dot_expression':
58
+ handleDotExpression(node, ctx);
59
+ break;
60
+ }
61
+
62
+ for (let i = 0; i < node.childCount; i++) {
63
+ const child = node.child(i);
64
+ if (child) walkFSharpNode(child, ctx, nextModule);
65
+ }
66
+ }
67
+
68
+ function handleNamedModule(node: TreeSitterNode, ctx: ExtractorOutput): string | null {
69
+ const nameNode = findChild(node, 'long_identifier');
70
+ if (!nameNode) return null;
71
+
72
+ ctx.definitions.push({
73
+ name: nameNode.text,
74
+ kind: 'module',
75
+ line: node.startPosition.row + 1,
76
+ endLine: nodeEndLine(node),
77
+ });
78
+
79
+ return nameNode.text;
80
+ }
81
+
82
+ function handleFunctionDecl(
83
+ node: TreeSitterNode,
84
+ ctx: ExtractorOutput,
85
+ currentModule: string | null,
86
+ ): void {
87
+ // function_declaration_left: "add x y" — first child is the name identifier
88
+ const nameNode = findChild(node, 'identifier');
89
+ if (!nameNode) return;
90
+
91
+ // Avoid duplicates — the walk will also visit children
92
+ if (
93
+ ctx.definitions.some((d) => d.name === nameNode.text && d.line === node.startPosition.row + 1)
94
+ )
95
+ return;
96
+
97
+ const params = extractFSharpParams(node);
98
+ const name = currentModule ? `${currentModule}.${nameNode.text}` : nameNode.text;
99
+
100
+ ctx.definitions.push({
101
+ name,
102
+ kind: 'function',
103
+ line: node.startPosition.row + 1,
104
+ endLine: nodeEndLine(node.parent ?? node),
105
+ children: params.length > 0 ? params : undefined,
106
+ });
107
+ }
108
+
109
+ function extractFSharpParams(declLeft: TreeSitterNode): SubDeclaration[] {
110
+ const params: SubDeclaration[] = [];
111
+ const argPatterns = findChild(declLeft, 'argument_patterns');
112
+ if (!argPatterns) return params;
113
+
114
+ collectParamIdentifiers(argPatterns, params);
115
+ return params;
116
+ }
117
+
118
+ function collectParamIdentifiers(node: TreeSitterNode, params: SubDeclaration[]): void {
119
+ if (node.type === 'identifier') {
120
+ params.push({ name: node.text, kind: 'parameter', line: node.startPosition.row + 1 });
121
+ return;
122
+ }
123
+ for (let i = 0; i < node.childCount; i++) {
124
+ const child = node.child(i);
125
+ if (child) collectParamIdentifiers(child, params);
126
+ }
127
+ }
128
+
129
+ function handleTypeDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
130
+ // type_definition contains union_type_defn, record_type_defn, etc.
131
+ for (let i = 0; i < node.childCount; i++) {
132
+ const child = node.child(i);
133
+ if (!child) continue;
134
+
135
+ if (
136
+ child.type === 'union_type_defn' ||
137
+ child.type === 'record_type_defn' ||
138
+ child.type === 'type_abbreviation_defn' ||
139
+ child.type === 'class_type_defn' ||
140
+ child.type === 'interface_type_defn' ||
141
+ child.type === 'type_defn'
142
+ ) {
143
+ const nameNode = findChild(child, 'type_name');
144
+ const name = nameNode
145
+ ? (findChild(nameNode, 'identifier')?.text ?? nameNode.text)
146
+ : findChild(child, 'identifier')?.text;
147
+ if (!name) continue;
148
+
149
+ const kind = determineFSharpTypeKind(child);
150
+ const children: SubDeclaration[] = [];
151
+ extractFSharpTypeMembers(child, children);
152
+
153
+ ctx.definitions.push({
154
+ name,
155
+ kind,
156
+ line: child.startPosition.row + 1,
157
+ endLine: nodeEndLine(child),
158
+ children: children.length > 0 ? children : undefined,
159
+ });
160
+ }
161
+ }
162
+ }
163
+
164
+ function determineFSharpTypeKind(
165
+ typeDefn: TreeSitterNode,
166
+ ): 'class' | 'type' | 'record' | 'enum' | 'interface' {
167
+ switch (typeDefn.type) {
168
+ case 'union_type_defn':
169
+ return 'enum';
170
+ case 'record_type_defn':
171
+ return 'record';
172
+ case 'class_type_defn':
173
+ return 'class';
174
+ case 'interface_type_defn':
175
+ return 'interface';
176
+ default:
177
+ return 'type';
178
+ }
179
+ }
180
+
181
+ function extractFSharpTypeMembers(typeDefn: TreeSitterNode, children: SubDeclaration[]): void {
182
+ for (let i = 0; i < typeDefn.childCount; i++) {
183
+ const child = typeDefn.child(i);
184
+ if (!child) continue;
185
+
186
+ if (child.type === 'union_type_case') {
187
+ const nameNode = findChild(child, 'identifier');
188
+ if (nameNode) {
189
+ children.push({
190
+ name: nameNode.text,
191
+ kind: 'property',
192
+ line: child.startPosition.row + 1,
193
+ });
194
+ }
195
+ }
196
+ if (child.type === 'record_field') {
197
+ const nameNode = child.childForFieldName('name') || findChild(child, 'identifier');
198
+ if (nameNode) {
199
+ children.push({
200
+ name: nameNode.text,
201
+ kind: 'property',
202
+ line: child.startPosition.row + 1,
203
+ });
204
+ }
205
+ }
206
+ // Recurse into containers like union_type_cases
207
+ if (child.type === 'union_type_cases' || child.type === 'record_fields') {
208
+ extractFSharpTypeMembers(child, children);
209
+ }
210
+ }
211
+ }
212
+
213
+ function handleImportDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
214
+ const moduleNode = findChild(node, 'long_identifier');
215
+ if (!moduleNode) return;
216
+
217
+ const source = moduleNode.text;
218
+ ctx.imports.push({
219
+ source,
220
+ names: [source.split('.').pop() || source],
221
+ line: node.startPosition.row + 1,
222
+ });
223
+ }
224
+
225
+ function handleApplication(node: TreeSitterNode, ctx: ExtractorOutput): void {
226
+ const funcNode = node.child(0);
227
+ if (!funcNode) return;
228
+
229
+ if (funcNode.type === 'identifier' || funcNode.type === 'long_identifier') {
230
+ ctx.calls.push({ name: funcNode.text, line: node.startPosition.row + 1 });
231
+ } else if (funcNode.type === 'long_identifier_or_op') {
232
+ const id = findChild(funcNode, 'identifier') || findChild(funcNode, 'long_identifier');
233
+ if (id) ctx.calls.push({ name: id.text, line: node.startPosition.row + 1 });
234
+ }
235
+ }
236
+
237
+ function handleDotExpression(node: TreeSitterNode, ctx: ExtractorOutput): void {
238
+ const parts: string[] = [];
239
+ for (let i = 0; i < node.childCount; i++) {
240
+ const child = node.child(i);
241
+ if (child && (child.type === 'identifier' || child.type === 'long_identifier')) {
242
+ parts.push(child.text);
243
+ }
244
+ }
245
+ if (parts.length >= 2) {
246
+ const call: Call = {
247
+ name: parts[parts.length - 1]!,
248
+ receiver: parts.slice(0, -1).join('.'),
249
+ line: node.startPosition.row + 1,
250
+ };
251
+ ctx.calls.push(call);
252
+ }
253
+ }
@@ -0,0 +1,246 @@
1
+ import type {
2
+ Call,
3
+ ExtractorOutput,
4
+ SubDeclaration,
5
+ TreeSitterNode,
6
+ TreeSitterTree,
7
+ } from '../types.js';
8
+ import { findChild, nodeEndLine, stripQuotes } from './helpers.js';
9
+
10
+ /**
11
+ * Extract symbols from Gleam files.
12
+ *
13
+ * Gleam tree-sitter grammar (gleam-lang/tree-sitter-gleam) notes:
14
+ * - Functions: function with name, parameters, body fields
15
+ * - Types: type_definition with name, constructors
16
+ * - Type aliases: type_alias
17
+ * - Imports: import with module, unqualified_imports
18
+ * - External functions: external_function
19
+ * - Constants: constant
20
+ */
21
+ export function extractGleamSymbols(tree: TreeSitterTree, _filePath: string): ExtractorOutput {
22
+ const ctx: ExtractorOutput = {
23
+ definitions: [],
24
+ calls: [],
25
+ imports: [],
26
+ classes: [],
27
+ exports: [],
28
+ typeMap: new Map(),
29
+ };
30
+
31
+ walkGleamNode(tree.rootNode, ctx);
32
+ return ctx;
33
+ }
34
+
35
+ function walkGleamNode(node: TreeSitterNode, ctx: ExtractorOutput): void {
36
+ switch (node.type) {
37
+ case 'function':
38
+ handleFunction(node, ctx);
39
+ break;
40
+ case 'type_definition':
41
+ handleTypeDef(node, ctx);
42
+ break;
43
+ case 'type_alias':
44
+ handleTypeAlias(node, ctx);
45
+ break;
46
+ case 'import':
47
+ handleImport(node, ctx);
48
+ break;
49
+ case 'external_function':
50
+ handleExternalFunction(node, ctx);
51
+ break;
52
+ case 'constant':
53
+ handleConstant(node, ctx);
54
+ break;
55
+ case 'function_call':
56
+ case 'call':
57
+ handleCall(node, ctx);
58
+ break;
59
+ }
60
+
61
+ for (let i = 0; i < node.childCount; i++) {
62
+ const child = node.child(i);
63
+ if (child) walkGleamNode(child, ctx);
64
+ }
65
+ }
66
+
67
+ function handleFunction(node: TreeSitterNode, ctx: ExtractorOutput): void {
68
+ const nameNode = node.childForFieldName('name') || findChild(node, 'identifier');
69
+ if (!nameNode) return;
70
+
71
+ const visibility = isPublic(node) ? 'public' : 'private';
72
+ const params = extractParams(node);
73
+
74
+ ctx.definitions.push({
75
+ name: nameNode.text,
76
+ kind: 'function',
77
+ line: node.startPosition.row + 1,
78
+ endLine: nodeEndLine(node),
79
+ visibility,
80
+ children: params.length > 0 ? params : undefined,
81
+ });
82
+ }
83
+
84
+ function handleExternalFunction(node: TreeSitterNode, ctx: ExtractorOutput): void {
85
+ const nameNode = node.childForFieldName('name') || findChild(node, 'identifier');
86
+ if (!nameNode) return;
87
+
88
+ ctx.definitions.push({
89
+ name: nameNode.text,
90
+ kind: 'function',
91
+ line: node.startPosition.row + 1,
92
+ endLine: nodeEndLine(node),
93
+ visibility: isPublic(node) ? 'public' : 'private',
94
+ });
95
+ }
96
+
97
+ function handleTypeDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
98
+ const nameNode = node.childForFieldName('name') || findChild(node, 'type_name');
99
+ if (!nameNode) return;
100
+
101
+ const children: SubDeclaration[] = [];
102
+ // Extract constructors
103
+ for (let i = 0; i < node.childCount; i++) {
104
+ const child = node.child(i);
105
+ if (!child) continue;
106
+ if (child.type === 'data_constructor' || child.type === 'type_constructor') {
107
+ const ctorName = child.childForFieldName('name') || findChild(child, 'constructor_name');
108
+ if (ctorName) {
109
+ children.push({ name: ctorName.text, kind: 'property', line: child.startPosition.row + 1 });
110
+ }
111
+ }
112
+ // Recurse into constructors block
113
+ if (child.type === 'data_constructors' || child.type === 'type_constructors') {
114
+ for (let j = 0; j < child.childCount; j++) {
115
+ const ctor = child.child(j);
116
+ if (!ctor) continue;
117
+ if (ctor.type === 'data_constructor' || ctor.type === 'type_constructor') {
118
+ const ctorName = ctor.childForFieldName('name') || findChild(ctor, 'constructor_name');
119
+ if (ctorName) {
120
+ children.push({
121
+ name: ctorName.text,
122
+ kind: 'property',
123
+ line: ctor.startPosition.row + 1,
124
+ });
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ ctx.definitions.push({
132
+ name: nameNode.text,
133
+ kind: 'type',
134
+ line: node.startPosition.row + 1,
135
+ endLine: nodeEndLine(node),
136
+ visibility: isPublic(node) ? 'public' : 'private',
137
+ children: children.length > 0 ? children : undefined,
138
+ });
139
+ }
140
+
141
+ function handleTypeAlias(node: TreeSitterNode, ctx: ExtractorOutput): void {
142
+ const nameNode = node.childForFieldName('name') || findChild(node, 'type_name');
143
+ if (!nameNode) return;
144
+
145
+ ctx.definitions.push({
146
+ name: nameNode.text,
147
+ kind: 'type',
148
+ line: node.startPosition.row + 1,
149
+ endLine: nodeEndLine(node),
150
+ visibility: isPublic(node) ? 'public' : 'private',
151
+ });
152
+ }
153
+
154
+ function handleConstant(node: TreeSitterNode, ctx: ExtractorOutput): void {
155
+ const nameNode = node.childForFieldName('name') || findChild(node, 'identifier');
156
+ if (!nameNode) return;
157
+
158
+ ctx.definitions.push({
159
+ name: nameNode.text,
160
+ kind: 'variable',
161
+ line: node.startPosition.row + 1,
162
+ endLine: nodeEndLine(node),
163
+ visibility: isPublic(node) ? 'public' : 'private',
164
+ });
165
+ }
166
+
167
+ function handleImport(node: TreeSitterNode, ctx: ExtractorOutput): void {
168
+ const moduleNode =
169
+ node.childForFieldName('module') || findChild(node, 'module') || findChild(node, 'string');
170
+ if (!moduleNode) return;
171
+
172
+ const source = stripQuotes(moduleNode.text);
173
+ const names: string[] = [];
174
+
175
+ // Check for unqualified imports
176
+ const unqualified = findChild(node, 'unqualified_imports');
177
+ if (unqualified) {
178
+ for (let i = 0; i < unqualified.childCount; i++) {
179
+ const item = unqualified.child(i);
180
+ if (item && (item.type === 'unqualified_import' || item.type === 'identifier')) {
181
+ const nameNode = item.childForFieldName('name') || item;
182
+ if (nameNode.type !== ',') names.push(nameNode.text);
183
+ }
184
+ }
185
+ }
186
+
187
+ // Check for alias (as)
188
+ const alias = node.childForFieldName('alias') || findChild(node, 'identifier');
189
+ if (alias && alias !== moduleNode) {
190
+ names.push(alias.text);
191
+ }
192
+
193
+ ctx.imports.push({
194
+ source,
195
+ names: names.length > 0 ? names : [source.split('/').pop() || source],
196
+ line: node.startPosition.row + 1,
197
+ });
198
+ }
199
+
200
+ function handleCall(node: TreeSitterNode, ctx: ExtractorOutput): void {
201
+ const funcNode = node.childForFieldName('function') || node.child(0);
202
+ if (!funcNode) return;
203
+
204
+ if (funcNode.type === 'identifier' || funcNode.type === 'variable') {
205
+ ctx.calls.push({ name: funcNode.text, line: node.startPosition.row + 1 });
206
+ } else if (funcNode.type === 'field_access' || funcNode.type === 'module_select') {
207
+ const field = funcNode.childForFieldName('field') || funcNode.childForFieldName('label');
208
+ const record = funcNode.child(0);
209
+ if (field) {
210
+ const call: Call = { name: field.text, line: node.startPosition.row + 1 };
211
+ if (record && record !== field) call.receiver = record.text;
212
+ ctx.calls.push(call);
213
+ }
214
+ }
215
+ }
216
+
217
+ function extractParams(funcNode: TreeSitterNode): SubDeclaration[] {
218
+ const params: SubDeclaration[] = [];
219
+ const paramsNode =
220
+ funcNode.childForFieldName('parameters') || findChild(funcNode, 'function_parameters');
221
+ if (!paramsNode) return params;
222
+
223
+ for (let i = 0; i < paramsNode.childCount; i++) {
224
+ const param = paramsNode.child(i);
225
+ if (!param) continue;
226
+ if (param.type === 'function_parameter' || param.type === 'parameter') {
227
+ const nameNode = param.childForFieldName('name') || findChild(param, 'identifier');
228
+ if (nameNode) {
229
+ params.push({ name: nameNode.text, kind: 'parameter', line: param.startPosition.row + 1 });
230
+ }
231
+ }
232
+ if (param.type === 'identifier') {
233
+ params.push({ name: param.text, kind: 'parameter', line: param.startPosition.row + 1 });
234
+ }
235
+ }
236
+ return params;
237
+ }
238
+
239
+ function isPublic(node: TreeSitterNode): boolean {
240
+ for (let i = 0; i < node.childCount; i++) {
241
+ const child = node.child(i);
242
+ if (!child) continue;
243
+ if (child.type === 'visibility_modifier' || child.text === 'pub') return true;
244
+ }
245
+ return false;
246
+ }
@@ -80,21 +80,9 @@ function handleGoFuncDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
80
80
 
81
81
  function handleGoMethodDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
82
82
  const nameNode = node.childForFieldName('name');
83
- const receiver = node.childForFieldName('receiver');
84
83
  if (!nameNode) return;
85
- let receiverType: string | null = null;
86
- if (receiver) {
87
- for (let i = 0; i < receiver.childCount; i++) {
88
- const param = receiver.child(i);
89
- if (!param) continue;
90
- const typeNode = param.childForFieldName('type');
91
- if (typeNode) {
92
- receiverType =
93
- typeNode.type === 'pointer_type' ? typeNode.text.replace(/^\*/, '') : typeNode.text;
94
- break;
95
- }
96
- }
97
- }
84
+ const receiver = node.childForFieldName('receiver');
85
+ const receiverType = receiver ? extractGoReceiverType(receiver) : null;
98
86
  const fullName = receiverType ? `${receiverType}.${nameNode.text}` : nameNode.text;
99
87
  const params = extractGoParameters(node.childForFieldName('parameters'));
100
88
  ctx.definitions.push({
@@ -107,6 +95,19 @@ function handleGoMethodDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
107
95
  });
108
96
  }
109
97
 
98
+ /** Extract the receiver type name from a method receiver parameter list. */
99
+ function extractGoReceiverType(receiver: TreeSitterNode): string | null {
100
+ for (let i = 0; i < receiver.childCount; i++) {
101
+ const param = receiver.child(i);
102
+ if (!param) continue;
103
+ const typeNode = param.childForFieldName('type');
104
+ if (typeNode) {
105
+ return typeNode.type === 'pointer_type' ? typeNode.text.replace(/^\*/, '') : typeNode.text;
106
+ }
107
+ }
108
+ return null;
109
+ }
110
+
110
111
  function handleGoTypeDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
111
112
  for (let i = 0; i < node.childCount; i++) {
112
113
  const spec = node.child(i);
@@ -403,13 +404,38 @@ function extractGoParameters(paramListNode: TreeSitterNode | null): SubDeclarati
403
404
  * This performs file-local matching (cross-file matching requires build-edges).
404
405
  */
405
406
  function matchGoStructuralInterfaces(ctx: ExtractorOutput): void {
407
+ const { interfaceMethods, structMethods, structLines } = collectGoMethodSets(ctx);
408
+
409
+ // Match: struct satisfies interface if it has all interface methods (name-only;
410
+ // signatures are not verified — treat as candidate match, not definitive).
411
+ // NOTE: embedded interfaces (type_elem nodes) are not resolved — composite
412
+ // interfaces like `type ReadWriter interface { Reader; Writer }` will have an
413
+ // empty method set and be silently excluded from matching.
414
+ for (const [structName, methods] of structMethods) {
415
+ for (const [ifaceName, ifaceMethods] of interfaceMethods) {
416
+ if (ifaceMethods.size > 0 && [...ifaceMethods].every((m) => methods.has(m))) {
417
+ ctx.classes.push({
418
+ name: structName,
419
+ implements: ifaceName,
420
+ line: structLines.get(structName) || 1,
421
+ });
422
+ }
423
+ }
424
+ }
425
+ }
426
+
427
+ /** Collect interface and struct method sets from definitions for structural matching. */
428
+ function collectGoMethodSets(ctx: ExtractorOutput): {
429
+ interfaceMethods: Map<string, Set<string>>;
430
+ structMethods: Map<string, Set<string>>;
431
+ structLines: Map<string, number>;
432
+ } {
406
433
  const interfaceMethods = new Map<string, Set<string>>();
407
434
  const structMethods = new Map<string, Set<string>>();
408
435
  const structLines = new Map<string, number>();
409
-
410
- // Collect interface and struct definitions
411
436
  const interfaceNames = new Set<string>();
412
437
  const structNames = new Set<string>();
438
+
413
439
  for (const def of ctx.definitions) {
414
440
  if (def.kind === 'interface') interfaceNames.add(def.name);
415
441
  if (def.kind === 'struct') {
@@ -418,7 +444,6 @@ function matchGoStructuralInterfaces(ctx: ExtractorOutput): void {
418
444
  }
419
445
  }
420
446
 
421
- // Collect methods grouped by receiver type
422
447
  for (const def of ctx.definitions) {
423
448
  if (def.kind !== 'method' || !def.name.includes('.')) continue;
424
449
  const dotIdx = def.name.indexOf('.');
@@ -435,22 +460,7 @@ function matchGoStructuralInterfaces(ctx: ExtractorOutput): void {
435
460
  }
436
461
  }
437
462
 
438
- // Match: struct satisfies interface if it has all interface methods (name-only;
439
- // signatures are not verified — treat as candidate match, not definitive).
440
- // NOTE: embedded interfaces (type_elem nodes) are not resolved — composite
441
- // interfaces like `type ReadWriter interface { Reader; Writer }` will have an
442
- // empty method set and be silently excluded from matching.
443
- for (const [structName, methods] of structMethods) {
444
- for (const [ifaceName, ifaceMethods] of interfaceMethods) {
445
- if (ifaceMethods.size > 0 && [...ifaceMethods].every((m) => methods.has(m))) {
446
- ctx.classes.push({
447
- name: structName,
448
- implements: ifaceName,
449
- line: structLines.get(structName) || 1,
450
- });
451
- }
452
- }
453
- }
463
+ return { interfaceMethods, structMethods, structLines };
454
464
  }
455
465
 
456
466
  function extractStructFields(structTypeNode: TreeSitterNode): SubDeclaration[] {