@optave/codegraph 3.5.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (346) hide show
  1. package/README.md +47 -21
  2. package/dist/ast-analysis/engine.d.ts.map +1 -1
  3. package/dist/ast-analysis/engine.js +119 -127
  4. package/dist/ast-analysis/engine.js.map +1 -1
  5. package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
  6. package/dist/ast-analysis/visitors/ast-store-visitor.js +14 -1
  7. package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
  8. package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
  9. package/dist/ast-analysis/visitors/complexity-visitor.js +11 -13
  10. package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
  11. package/dist/db/connection.d.ts +12 -2
  12. package/dist/db/connection.d.ts.map +1 -1
  13. package/dist/db/connection.js +81 -53
  14. package/dist/db/connection.js.map +1 -1
  15. package/dist/db/index.d.ts +1 -1
  16. package/dist/db/index.d.ts.map +1 -1
  17. package/dist/db/index.js +1 -1
  18. package/dist/db/index.js.map +1 -1
  19. package/dist/db/migrations.d.ts.map +1 -1
  20. package/dist/db/migrations.js +38 -32
  21. package/dist/db/migrations.js.map +1 -1
  22. package/dist/domain/analysis/context.d.ts.map +1 -1
  23. package/dist/domain/analysis/context.js +51 -66
  24. package/dist/domain/analysis/context.js.map +1 -1
  25. package/dist/domain/analysis/dependencies.d.ts.map +1 -1
  26. package/dist/domain/analysis/dependencies.js +62 -70
  27. package/dist/domain/analysis/dependencies.js.map +1 -1
  28. package/dist/domain/analysis/diff-impact.d.ts +9 -7
  29. package/dist/domain/analysis/diff-impact.d.ts.map +1 -1
  30. package/dist/domain/analysis/exports.d.ts.map +1 -1
  31. package/dist/domain/analysis/exports.js +29 -33
  32. package/dist/domain/analysis/exports.js.map +1 -1
  33. package/dist/domain/analysis/fn-impact.d.ts +15 -17
  34. package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
  35. package/dist/domain/analysis/fn-impact.js +35 -65
  36. package/dist/domain/analysis/fn-impact.js.map +1 -1
  37. package/dist/domain/analysis/module-map.d.ts.map +1 -1
  38. package/dist/domain/analysis/module-map.js +91 -6
  39. package/dist/domain/analysis/module-map.js.map +1 -1
  40. package/dist/domain/analysis/query-helpers.d.ts +20 -0
  41. package/dist/domain/analysis/query-helpers.d.ts.map +1 -0
  42. package/dist/domain/analysis/query-helpers.js +27 -0
  43. package/dist/domain/analysis/query-helpers.js.map +1 -0
  44. package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
  45. package/dist/domain/graph/builder/helpers.js +15 -9
  46. package/dist/domain/graph/builder/helpers.js.map +1 -1
  47. package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
  48. package/dist/domain/graph/builder/incremental.js +3 -2
  49. package/dist/domain/graph/builder/incremental.js.map +1 -1
  50. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
  51. package/dist/domain/graph/builder/pipeline.js +69 -3
  52. package/dist/domain/graph/builder/pipeline.js.map +1 -1
  53. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
  54. package/dist/domain/graph/builder/stages/build-edges.js +7 -51
  55. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
  56. package/dist/domain/graph/builder/stages/build-structure.d.ts.map +1 -1
  57. package/dist/domain/graph/builder/stages/build-structure.js +7 -5
  58. package/dist/domain/graph/builder/stages/build-structure.js.map +1 -1
  59. package/dist/domain/graph/builder/stages/collect-files.js +2 -2
  60. package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
  61. package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
  62. package/dist/domain/graph/builder/stages/detect-changes.js +2 -2
  63. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
  64. package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
  65. package/dist/domain/graph/builder/stages/finalize.js +124 -105
  66. package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
  67. package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
  68. package/dist/domain/graph/builder/stages/insert-nodes.js +28 -15
  69. package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
  70. package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
  71. package/dist/domain/graph/builder/stages/resolve-imports.js +3 -2
  72. package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
  73. package/dist/domain/graph/resolve.d.ts +0 -4
  74. package/dist/domain/graph/resolve.d.ts.map +1 -1
  75. package/dist/domain/graph/resolve.js +32 -48
  76. package/dist/domain/graph/resolve.js.map +1 -1
  77. package/dist/domain/graph/watcher.d.ts.map +1 -1
  78. package/dist/domain/graph/watcher.js +12 -12
  79. package/dist/domain/graph/watcher.js.map +1 -1
  80. package/dist/domain/parser.d.ts +1 -1
  81. package/dist/domain/parser.d.ts.map +1 -1
  82. package/dist/domain/parser.js +206 -101
  83. package/dist/domain/parser.js.map +1 -1
  84. package/dist/domain/search/search/cli-formatter.d.ts.map +1 -1
  85. package/dist/domain/search/search/cli-formatter.js +88 -83
  86. package/dist/domain/search/search/cli-formatter.js.map +1 -1
  87. package/dist/extractors/bash.d.ts +6 -0
  88. package/dist/extractors/bash.d.ts.map +1 -0
  89. package/dist/extractors/bash.js +91 -0
  90. package/dist/extractors/bash.js.map +1 -0
  91. package/dist/extractors/c.d.ts +6 -0
  92. package/dist/extractors/c.d.ts.map +1 -0
  93. package/dist/extractors/c.js +204 -0
  94. package/dist/extractors/c.js.map +1 -0
  95. package/dist/extractors/cpp.d.ts +6 -0
  96. package/dist/extractors/cpp.d.ts.map +1 -0
  97. package/dist/extractors/cpp.js +283 -0
  98. package/dist/extractors/cpp.js.map +1 -0
  99. package/dist/extractors/csharp.d.ts.map +1 -1
  100. package/dist/extractors/csharp.js +42 -54
  101. package/dist/extractors/csharp.js.map +1 -1
  102. package/dist/extractors/dart.d.ts +6 -0
  103. package/dist/extractors/dart.d.ts.map +1 -0
  104. package/dist/extractors/dart.js +277 -0
  105. package/dist/extractors/dart.js.map +1 -0
  106. package/dist/extractors/elixir.d.ts +9 -0
  107. package/dist/extractors/elixir.d.ts.map +1 -0
  108. package/dist/extractors/elixir.js +223 -0
  109. package/dist/extractors/elixir.js.map +1 -0
  110. package/dist/extractors/go.d.ts.map +1 -1
  111. package/dist/extractors/go.js +126 -130
  112. package/dist/extractors/go.js.map +1 -1
  113. package/dist/extractors/haskell.d.ts +8 -0
  114. package/dist/extractors/haskell.d.ts.map +1 -0
  115. package/dist/extractors/haskell.js +217 -0
  116. package/dist/extractors/haskell.js.map +1 -0
  117. package/dist/extractors/hcl.js +6 -6
  118. package/dist/extractors/hcl.js.map +1 -1
  119. package/dist/extractors/helpers.d.ts +32 -1
  120. package/dist/extractors/helpers.d.ts.map +1 -1
  121. package/dist/extractors/helpers.js +74 -0
  122. package/dist/extractors/helpers.js.map +1 -1
  123. package/dist/extractors/index.d.ts +12 -0
  124. package/dist/extractors/index.d.ts.map +1 -1
  125. package/dist/extractors/index.js +12 -0
  126. package/dist/extractors/index.js.map +1 -1
  127. package/dist/extractors/java.d.ts.map +1 -1
  128. package/dist/extractors/java.js +32 -47
  129. package/dist/extractors/java.js.map +1 -1
  130. package/dist/extractors/javascript.d.ts.map +1 -1
  131. package/dist/extractors/javascript.js +306 -292
  132. package/dist/extractors/javascript.js.map +1 -1
  133. package/dist/extractors/kotlin.d.ts +6 -0
  134. package/dist/extractors/kotlin.d.ts.map +1 -0
  135. package/dist/extractors/kotlin.js +275 -0
  136. package/dist/extractors/kotlin.js.map +1 -0
  137. package/dist/extractors/lua.d.ts +6 -0
  138. package/dist/extractors/lua.d.ts.map +1 -0
  139. package/dist/extractors/lua.js +162 -0
  140. package/dist/extractors/lua.js.map +1 -0
  141. package/dist/extractors/ocaml.d.ts +6 -0
  142. package/dist/extractors/ocaml.d.ts.map +1 -0
  143. package/dist/extractors/ocaml.js +236 -0
  144. package/dist/extractors/ocaml.js.map +1 -0
  145. package/dist/extractors/php.d.ts.map +1 -1
  146. package/dist/extractors/php.js +39 -44
  147. package/dist/extractors/php.js.map +1 -1
  148. package/dist/extractors/python.d.ts.map +1 -1
  149. package/dist/extractors/python.js +75 -93
  150. package/dist/extractors/python.js.map +1 -1
  151. package/dist/extractors/ruby.js +6 -13
  152. package/dist/extractors/ruby.js.map +1 -1
  153. package/dist/extractors/rust.d.ts.map +1 -1
  154. package/dist/extractors/rust.js +58 -83
  155. package/dist/extractors/rust.js.map +1 -1
  156. package/dist/extractors/scala.d.ts +6 -0
  157. package/dist/extractors/scala.d.ts.map +1 -0
  158. package/dist/extractors/scala.js +269 -0
  159. package/dist/extractors/scala.js.map +1 -0
  160. package/dist/extractors/swift.d.ts +6 -0
  161. package/dist/extractors/swift.d.ts.map +1 -0
  162. package/dist/extractors/swift.js +275 -0
  163. package/dist/extractors/swift.js.map +1 -0
  164. package/dist/extractors/zig.d.ts +9 -0
  165. package/dist/extractors/zig.d.ts.map +1 -0
  166. package/dist/extractors/zig.js +276 -0
  167. package/dist/extractors/zig.js.map +1 -0
  168. package/dist/features/ast.d.ts +2 -0
  169. package/dist/features/ast.d.ts.map +1 -1
  170. package/dist/features/ast.js +9 -24
  171. package/dist/features/ast.js.map +1 -1
  172. package/dist/features/audit.d.ts.map +1 -1
  173. package/dist/features/audit.js +17 -21
  174. package/dist/features/audit.js.map +1 -1
  175. package/dist/features/branch-compare.d.ts.map +1 -1
  176. package/dist/features/branch-compare.js +47 -3
  177. package/dist/features/branch-compare.js.map +1 -1
  178. package/dist/features/cfg.d.ts +7 -1
  179. package/dist/features/cfg.d.ts.map +1 -1
  180. package/dist/features/cfg.js +72 -61
  181. package/dist/features/cfg.js.map +1 -1
  182. package/dist/features/check.d.ts.map +1 -1
  183. package/dist/features/check.js +79 -62
  184. package/dist/features/check.js.map +1 -1
  185. package/dist/features/complexity-query.d.ts.map +1 -1
  186. package/dist/features/complexity-query.js +142 -137
  187. package/dist/features/complexity-query.js.map +1 -1
  188. package/dist/features/complexity.d.ts +7 -1
  189. package/dist/features/complexity.d.ts.map +1 -1
  190. package/dist/features/complexity.js +62 -1
  191. package/dist/features/complexity.js.map +1 -1
  192. package/dist/features/dataflow.d.ts +7 -1
  193. package/dist/features/dataflow.d.ts.map +1 -1
  194. package/dist/features/dataflow.js +356 -188
  195. package/dist/features/dataflow.js.map +1 -1
  196. package/dist/features/graph-enrichment.d.ts.map +1 -1
  197. package/dist/features/graph-enrichment.js +117 -104
  198. package/dist/features/graph-enrichment.js.map +1 -1
  199. package/dist/features/sequence.d.ts.map +1 -1
  200. package/dist/features/sequence.js +25 -4
  201. package/dist/features/sequence.js.map +1 -1
  202. package/dist/features/structure-query.d.ts.map +1 -1
  203. package/dist/features/structure-query.js +29 -4
  204. package/dist/features/structure-query.js.map +1 -1
  205. package/dist/features/structure.d.ts.map +1 -1
  206. package/dist/features/structure.js +35 -15
  207. package/dist/features/structure.js.map +1 -1
  208. package/dist/graph/algorithms/leiden/adapter.d.ts.map +1 -1
  209. package/dist/graph/algorithms/leiden/adapter.js +88 -73
  210. package/dist/graph/algorithms/leiden/adapter.js.map +1 -1
  211. package/dist/graph/algorithms/leiden/index.js +43 -28
  212. package/dist/graph/algorithms/leiden/index.js.map +1 -1
  213. package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
  214. package/dist/graph/algorithms/leiden/optimiser.js +90 -104
  215. package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
  216. package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -1
  217. package/dist/graph/algorithms/leiden/partition.js +89 -106
  218. package/dist/graph/algorithms/leiden/partition.js.map +1 -1
  219. package/dist/graph/model.d.ts +2 -0
  220. package/dist/graph/model.d.ts.map +1 -1
  221. package/dist/graph/model.js +20 -8
  222. package/dist/graph/model.js.map +1 -1
  223. package/dist/infrastructure/config.d.ts +0 -8
  224. package/dist/infrastructure/config.d.ts.map +1 -1
  225. package/dist/infrastructure/config.js +73 -62
  226. package/dist/infrastructure/config.js.map +1 -1
  227. package/dist/infrastructure/registry.d.ts +0 -8
  228. package/dist/infrastructure/registry.d.ts.map +1 -1
  229. package/dist/infrastructure/registry.js +12 -14
  230. package/dist/infrastructure/registry.js.map +1 -1
  231. package/dist/mcp/server.d.ts.map +1 -1
  232. package/dist/mcp/server.js +45 -36
  233. package/dist/mcp/server.js.map +1 -1
  234. package/dist/presentation/audit.d.ts.map +1 -1
  235. package/dist/presentation/audit.js +61 -57
  236. package/dist/presentation/audit.js.map +1 -1
  237. package/dist/presentation/branch-compare.d.ts.map +1 -1
  238. package/dist/presentation/branch-compare.js +56 -38
  239. package/dist/presentation/branch-compare.js.map +1 -1
  240. package/dist/presentation/check.d.ts.map +1 -1
  241. package/dist/presentation/check.js +30 -32
  242. package/dist/presentation/check.js.map +1 -1
  243. package/dist/presentation/colors.d.ts.map +1 -1
  244. package/dist/presentation/colors.js +2 -0
  245. package/dist/presentation/colors.js.map +1 -1
  246. package/dist/presentation/complexity.d.ts.map +1 -1
  247. package/dist/presentation/complexity.js +25 -19
  248. package/dist/presentation/complexity.js.map +1 -1
  249. package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
  250. package/dist/presentation/queries-cli/exports.js +15 -15
  251. package/dist/presentation/queries-cli/exports.js.map +1 -1
  252. package/dist/presentation/queries-cli/impact.d.ts.map +1 -1
  253. package/dist/presentation/queries-cli/impact.js +29 -19
  254. package/dist/presentation/queries-cli/impact.js.map +1 -1
  255. package/dist/types.d.ts +182 -7
  256. package/dist/types.d.ts.map +1 -1
  257. package/grammars/tree-sitter-bash.wasm +0 -0
  258. package/grammars/tree-sitter-c.wasm +0 -0
  259. package/grammars/tree-sitter-cpp.wasm +0 -0
  260. package/grammars/tree-sitter-dart.wasm +0 -0
  261. package/grammars/tree-sitter-elixir.wasm +0 -0
  262. package/grammars/tree-sitter-haskell.wasm +0 -0
  263. package/grammars/tree-sitter-kotlin.wasm +0 -0
  264. package/grammars/tree-sitter-lua.wasm +0 -0
  265. package/grammars/tree-sitter-ocaml.wasm +0 -0
  266. package/grammars/tree-sitter-scala.wasm +0 -0
  267. package/grammars/tree-sitter-swift.wasm +0 -0
  268. package/grammars/tree-sitter-zig.wasm +0 -0
  269. package/package.json +19 -7
  270. package/src/ast-analysis/engine.ts +147 -138
  271. package/src/ast-analysis/visitors/ast-store-visitor.ts +15 -2
  272. package/src/ast-analysis/visitors/complexity-visitor.ts +11 -11
  273. package/src/db/connection.ts +90 -59
  274. package/src/db/index.ts +1 -0
  275. package/src/db/migrations.ts +36 -32
  276. package/src/domain/analysis/context.ts +73 -75
  277. package/src/domain/analysis/dependencies.ts +78 -68
  278. package/src/domain/analysis/exports.ts +45 -34
  279. package/src/domain/analysis/fn-impact.ts +67 -64
  280. package/src/domain/analysis/module-map.ts +103 -8
  281. package/src/domain/analysis/query-helpers.ts +35 -0
  282. package/src/domain/graph/builder/helpers.ts +12 -6
  283. package/src/domain/graph/builder/incremental.ts +3 -2
  284. package/src/domain/graph/builder/pipeline.ts +71 -3
  285. package/src/domain/graph/builder/stages/build-edges.ts +10 -75
  286. package/src/domain/graph/builder/stages/build-structure.ts +9 -7
  287. package/src/domain/graph/builder/stages/collect-files.ts +2 -2
  288. package/src/domain/graph/builder/stages/detect-changes.ts +7 -2
  289. package/src/domain/graph/builder/stages/finalize.ts +159 -125
  290. package/src/domain/graph/builder/stages/insert-nodes.ts +32 -21
  291. package/src/domain/graph/builder/stages/resolve-imports.ts +3 -2
  292. package/src/domain/graph/resolve.ts +34 -46
  293. package/src/domain/graph/watcher.ts +12 -14
  294. package/src/domain/parser.ts +222 -97
  295. package/src/domain/search/search/cli-formatter.ts +121 -94
  296. package/src/extractors/bash.ts +97 -0
  297. package/src/extractors/c.ts +212 -0
  298. package/src/extractors/cpp.ts +298 -0
  299. package/src/extractors/csharp.ts +53 -56
  300. package/src/extractors/dart.ts +304 -0
  301. package/src/extractors/elixir.ts +251 -0
  302. package/src/extractors/go.ts +152 -134
  303. package/src/extractors/haskell.ts +235 -0
  304. package/src/extractors/hcl.ts +6 -6
  305. package/src/extractors/helpers.ts +93 -1
  306. package/src/extractors/index.ts +12 -0
  307. package/src/extractors/java.ts +43 -48
  308. package/src/extractors/javascript.ts +328 -281
  309. package/src/extractors/kotlin.ts +293 -0
  310. package/src/extractors/lua.ts +169 -0
  311. package/src/extractors/ocaml.ts +259 -0
  312. package/src/extractors/php.ts +46 -40
  313. package/src/extractors/python.ts +81 -104
  314. package/src/extractors/ruby.ts +6 -13
  315. package/src/extractors/rust.ts +65 -85
  316. package/src/extractors/scala.ts +285 -0
  317. package/src/extractors/swift.ts +293 -0
  318. package/src/extractors/zig.ts +294 -0
  319. package/src/features/ast.ts +10 -25
  320. package/src/features/audit.ts +24 -20
  321. package/src/features/branch-compare.ts +51 -4
  322. package/src/features/cfg.ts +113 -65
  323. package/src/features/check.ts +90 -74
  324. package/src/features/complexity-query.ts +181 -163
  325. package/src/features/complexity.ts +64 -1
  326. package/src/features/dataflow.ts +462 -217
  327. package/src/features/graph-enrichment.ts +161 -117
  328. package/src/features/sequence.ts +27 -4
  329. package/src/features/structure-query.ts +43 -4
  330. package/src/features/structure.ts +50 -22
  331. package/src/graph/algorithms/leiden/adapter.ts +126 -71
  332. package/src/graph/algorithms/leiden/index.ts +67 -28
  333. package/src/graph/algorithms/leiden/optimiser.ts +114 -105
  334. package/src/graph/algorithms/leiden/partition.ts +131 -98
  335. package/src/graph/model.ts +19 -7
  336. package/src/infrastructure/config.ts +60 -58
  337. package/src/infrastructure/registry.ts +17 -14
  338. package/src/mcp/server.ts +46 -37
  339. package/src/presentation/audit.ts +72 -67
  340. package/src/presentation/branch-compare.ts +54 -50
  341. package/src/presentation/check.ts +34 -34
  342. package/src/presentation/colors.ts +2 -0
  343. package/src/presentation/complexity.ts +39 -33
  344. package/src/presentation/queries-cli/exports.ts +17 -17
  345. package/src/presentation/queries-cli/impact.ts +30 -22
  346. package/src/types.ts +195 -7
@@ -1,5 +1,5 @@
1
1
  import { debug } from '../infrastructure/logger.js';
2
- import { findChild, MAX_WALK_DEPTH, nodeEndLine } from './helpers.js';
2
+ import { findChild, findParentNode, MAX_WALK_DEPTH, nodeEndLine, setTypeMapEntry, } from './helpers.js';
3
3
  /** Built-in globals that start with uppercase but are not user-defined types. */
4
4
  const BUILTIN_GLOBALS = new Set([
5
5
  'Math',
@@ -67,6 +67,176 @@ export function extractSymbols(tree, _filePath, query) {
67
67
  return extractSymbolsWalk(tree);
68
68
  }
69
69
  // ── Query-based extraction (fast path) ──────────────────────────────────────
70
+ /** Handle function_declaration capture. */
71
+ function handleFnCapture(c, definitions) {
72
+ const fnChildren = extractParameters(c.fn_node);
73
+ definitions.push({
74
+ name: c.fn_name.text,
75
+ kind: 'function',
76
+ line: c.fn_node.startPosition.row + 1,
77
+ endLine: nodeEndLine(c.fn_node),
78
+ children: fnChildren.length > 0 ? fnChildren : undefined,
79
+ });
80
+ }
81
+ /** Handle variable_declarator with arrow_function / function_expression capture. */
82
+ function handleVarFnCapture(c, definitions) {
83
+ const declNode = c.varfn_name.parent?.parent;
84
+ const line = declNode ? declNode.startPosition.row + 1 : c.varfn_name.startPosition.row + 1;
85
+ const varFnChildren = extractParameters(c.varfn_value);
86
+ definitions.push({
87
+ name: c.varfn_name.text,
88
+ kind: 'function',
89
+ line,
90
+ endLine: nodeEndLine(c.varfn_value),
91
+ children: varFnChildren.length > 0 ? varFnChildren : undefined,
92
+ });
93
+ }
94
+ /** Handle class_declaration capture. */
95
+ function handleClassCapture(c, definitions, classes) {
96
+ const className = c.cls_name.text;
97
+ const startLine = c.cls_node.startPosition.row + 1;
98
+ const clsChildren = extractClassProperties(c.cls_node);
99
+ definitions.push({
100
+ name: className,
101
+ kind: 'class',
102
+ line: startLine,
103
+ endLine: nodeEndLine(c.cls_node),
104
+ children: clsChildren.length > 0 ? clsChildren : undefined,
105
+ });
106
+ const heritage = c.cls_node.childForFieldName('heritage') || findChild(c.cls_node, 'class_heritage');
107
+ if (heritage) {
108
+ const superName = extractSuperclass(heritage);
109
+ if (superName)
110
+ classes.push({ name: className, extends: superName, line: startLine });
111
+ const implementsList = extractImplements(heritage);
112
+ for (const iface of implementsList) {
113
+ classes.push({ name: className, implements: iface, line: startLine });
114
+ }
115
+ }
116
+ }
117
+ /** Handle method_definition capture. */
118
+ function handleMethodCapture(c, definitions) {
119
+ const methName = c.meth_name.text;
120
+ const parentClass = findParentClass(c.meth_node);
121
+ const fullName = parentClass ? `${parentClass}.${methName}` : methName;
122
+ const methChildren = extractParameters(c.meth_node);
123
+ const methVis = extractVisibility(c.meth_node);
124
+ definitions.push({
125
+ name: fullName,
126
+ kind: 'method',
127
+ line: c.meth_node.startPosition.row + 1,
128
+ endLine: nodeEndLine(c.meth_node),
129
+ children: methChildren.length > 0 ? methChildren : undefined,
130
+ visibility: methVis,
131
+ });
132
+ }
133
+ /** Handle export_statement capture. */
134
+ function handleExportCapture(c, exps, imports) {
135
+ const exportLine = c.exp_node.startPosition.row + 1;
136
+ const decl = c.exp_node.childForFieldName('declaration');
137
+ if (decl) {
138
+ const declType = decl.type;
139
+ const kindMap = {
140
+ function_declaration: 'function',
141
+ class_declaration: 'class',
142
+ interface_declaration: 'interface',
143
+ type_alias_declaration: 'type',
144
+ };
145
+ const kind = kindMap[declType];
146
+ if (kind) {
147
+ const n = decl.childForFieldName('name');
148
+ if (n)
149
+ exps.push({ name: n.text, kind: kind, line: exportLine });
150
+ }
151
+ }
152
+ const source = c.exp_node.childForFieldName('source') || findChild(c.exp_node, 'string');
153
+ if (source && !decl) {
154
+ const modPath = source.text.replace(/['"]/g, '');
155
+ const reexportNames = extractImportNames(c.exp_node);
156
+ const nodeText = c.exp_node.text;
157
+ const isWildcard = nodeText.includes('export *') || nodeText.includes('export*');
158
+ imports.push({
159
+ source: modPath,
160
+ names: reexportNames,
161
+ line: exportLine,
162
+ reexport: true,
163
+ wildcardReexport: isWildcard && reexportNames.length === 0,
164
+ });
165
+ }
166
+ }
167
+ /** Dispatch a single query match to the appropriate handler. */
168
+ function dispatchQueryMatch(c, definitions, calls, imports, classes, exps) {
169
+ if (c.fn_node) {
170
+ handleFnCapture(c, definitions);
171
+ }
172
+ else if (c.varfn_name) {
173
+ handleVarFnCapture(c, definitions);
174
+ }
175
+ else if (c.cls_node) {
176
+ handleClassCapture(c, definitions, classes);
177
+ }
178
+ else if (c.meth_node) {
179
+ handleMethodCapture(c, definitions);
180
+ }
181
+ else if (c.iface_node) {
182
+ const ifaceName = c.iface_name.text;
183
+ definitions.push({
184
+ name: ifaceName,
185
+ kind: 'interface',
186
+ line: c.iface_node.startPosition.row + 1,
187
+ endLine: nodeEndLine(c.iface_node),
188
+ });
189
+ const body = c.iface_node.childForFieldName('body') ||
190
+ findChild(c.iface_node, 'interface_body') ||
191
+ findChild(c.iface_node, 'object_type');
192
+ if (body)
193
+ extractInterfaceMethods(body, ifaceName, definitions);
194
+ }
195
+ else if (c.type_node) {
196
+ definitions.push({
197
+ name: c.type_name.text,
198
+ kind: 'type',
199
+ line: c.type_node.startPosition.row + 1,
200
+ endLine: nodeEndLine(c.type_node),
201
+ });
202
+ }
203
+ else if (c.imp_node) {
204
+ const isTypeOnly = c.imp_node.text.startsWith('import type');
205
+ const modPath = c.imp_source.text.replace(/['"]/g, '');
206
+ const names = extractImportNames(c.imp_node);
207
+ imports.push({
208
+ source: modPath,
209
+ names,
210
+ line: c.imp_node.startPosition.row + 1,
211
+ typeOnly: isTypeOnly,
212
+ });
213
+ }
214
+ else if (c.exp_node) {
215
+ handleExportCapture(c, exps, imports);
216
+ }
217
+ else if (c.callfn_node) {
218
+ calls.push({
219
+ name: c.callfn_name.text,
220
+ line: c.callfn_node.startPosition.row + 1,
221
+ });
222
+ }
223
+ else if (c.callmem_node) {
224
+ const callInfo = extractCallInfo(c.callmem_fn, c.callmem_node);
225
+ if (callInfo)
226
+ calls.push(callInfo);
227
+ const cbDef = extractCallbackDefinition(c.callmem_node, c.callmem_fn);
228
+ if (cbDef)
229
+ definitions.push(cbDef);
230
+ }
231
+ else if (c.callsub_node) {
232
+ const callInfo = extractCallInfo(c.callsub_fn, c.callsub_node);
233
+ if (callInfo)
234
+ calls.push(callInfo);
235
+ }
236
+ else if (c.assign_node) {
237
+ handleCommonJSAssignment(c.assign_left, c.assign_right, c.assign_node, imports);
238
+ }
239
+ }
70
240
  function extractSymbolsQuery(tree, query) {
71
241
  const definitions = [];
72
242
  const calls = [];
@@ -80,165 +250,7 @@ function extractSymbolsQuery(tree, query) {
80
250
  const c = Object.create(null);
81
251
  for (const cap of match.captures)
82
252
  c[cap.name] = cap.node;
83
- if (c.fn_node) {
84
- // function_declaration
85
- const fnChildren = extractParameters(c.fn_node);
86
- definitions.push({
87
- name: c.fn_name.text,
88
- kind: 'function',
89
- line: c.fn_node.startPosition.row + 1,
90
- endLine: nodeEndLine(c.fn_node),
91
- children: fnChildren.length > 0 ? fnChildren : undefined,
92
- });
93
- }
94
- else if (c.varfn_name) {
95
- // variable_declarator with arrow_function / function_expression
96
- const declNode = c.varfn_name.parent?.parent;
97
- const line = declNode ? declNode.startPosition.row + 1 : c.varfn_name.startPosition.row + 1;
98
- const varFnChildren = extractParameters(c.varfn_value);
99
- definitions.push({
100
- name: c.varfn_name.text,
101
- kind: 'function',
102
- line,
103
- endLine: nodeEndLine(c.varfn_value),
104
- children: varFnChildren.length > 0 ? varFnChildren : undefined,
105
- });
106
- }
107
- else if (c.cls_node) {
108
- // class_declaration
109
- const className = c.cls_name.text;
110
- const startLine = c.cls_node.startPosition.row + 1;
111
- const clsChildren = extractClassProperties(c.cls_node);
112
- definitions.push({
113
- name: className,
114
- kind: 'class',
115
- line: startLine,
116
- endLine: nodeEndLine(c.cls_node),
117
- children: clsChildren.length > 0 ? clsChildren : undefined,
118
- });
119
- const heritage = c.cls_node.childForFieldName('heritage') || findChild(c.cls_node, 'class_heritage');
120
- if (heritage) {
121
- const superName = extractSuperclass(heritage);
122
- if (superName)
123
- classes.push({ name: className, extends: superName, line: startLine });
124
- const implementsList = extractImplements(heritage);
125
- for (const iface of implementsList) {
126
- classes.push({ name: className, implements: iface, line: startLine });
127
- }
128
- }
129
- }
130
- else if (c.meth_node) {
131
- // method_definition
132
- const methName = c.meth_name.text;
133
- const parentClass = findParentClass(c.meth_node);
134
- const fullName = parentClass ? `${parentClass}.${methName}` : methName;
135
- const methChildren = extractParameters(c.meth_node);
136
- const methVis = extractVisibility(c.meth_node);
137
- definitions.push({
138
- name: fullName,
139
- kind: 'method',
140
- line: c.meth_node.startPosition.row + 1,
141
- endLine: nodeEndLine(c.meth_node),
142
- children: methChildren.length > 0 ? methChildren : undefined,
143
- visibility: methVis,
144
- });
145
- }
146
- else if (c.iface_node) {
147
- // interface_declaration (TS/TSX only)
148
- const ifaceName = c.iface_name.text;
149
- definitions.push({
150
- name: ifaceName,
151
- kind: 'interface',
152
- line: c.iface_node.startPosition.row + 1,
153
- endLine: nodeEndLine(c.iface_node),
154
- });
155
- const body = c.iface_node.childForFieldName('body') ||
156
- findChild(c.iface_node, 'interface_body') ||
157
- findChild(c.iface_node, 'object_type');
158
- if (body)
159
- extractInterfaceMethods(body, ifaceName, definitions);
160
- }
161
- else if (c.type_node) {
162
- // type_alias_declaration (TS/TSX only)
163
- definitions.push({
164
- name: c.type_name.text,
165
- kind: 'type',
166
- line: c.type_node.startPosition.row + 1,
167
- endLine: nodeEndLine(c.type_node),
168
- });
169
- }
170
- else if (c.imp_node) {
171
- // import_statement
172
- const isTypeOnly = c.imp_node.text.startsWith('import type');
173
- const modPath = c.imp_source.text.replace(/['"]/g, '');
174
- const names = extractImportNames(c.imp_node);
175
- imports.push({
176
- source: modPath,
177
- names,
178
- line: c.imp_node.startPosition.row + 1,
179
- typeOnly: isTypeOnly,
180
- });
181
- }
182
- else if (c.exp_node) {
183
- // export_statement
184
- const exportLine = c.exp_node.startPosition.row + 1;
185
- const decl = c.exp_node.childForFieldName('declaration');
186
- if (decl) {
187
- const declType = decl.type;
188
- const kindMap = {
189
- function_declaration: 'function',
190
- class_declaration: 'class',
191
- interface_declaration: 'interface',
192
- type_alias_declaration: 'type',
193
- };
194
- const kind = kindMap[declType];
195
- if (kind) {
196
- const n = decl.childForFieldName('name');
197
- if (n)
198
- exps.push({ name: n.text, kind: kind, line: exportLine });
199
- }
200
- }
201
- const source = c.exp_node.childForFieldName('source') || findChild(c.exp_node, 'string');
202
- if (source && !decl) {
203
- const modPath = source.text.replace(/['"]/g, '');
204
- const reexportNames = extractImportNames(c.exp_node);
205
- const nodeText = c.exp_node.text;
206
- const isWildcard = nodeText.includes('export *') || nodeText.includes('export*');
207
- imports.push({
208
- source: modPath,
209
- names: reexportNames,
210
- line: exportLine,
211
- reexport: true,
212
- wildcardReexport: isWildcard && reexportNames.length === 0,
213
- });
214
- }
215
- }
216
- else if (c.callfn_node) {
217
- // call_expression with identifier function
218
- calls.push({
219
- name: c.callfn_name.text,
220
- line: c.callfn_node.startPosition.row + 1,
221
- });
222
- }
223
- else if (c.callmem_node) {
224
- // call_expression with member_expression function
225
- const callInfo = extractCallInfo(c.callmem_fn, c.callmem_node);
226
- if (callInfo)
227
- calls.push(callInfo);
228
- const cbDef = extractCallbackDefinition(c.callmem_node, c.callmem_fn);
229
- if (cbDef)
230
- definitions.push(cbDef);
231
- }
232
- else if (c.callsub_node) {
233
- // call_expression with subscript_expression function
234
- const callInfo = extractCallInfo(c.callsub_fn, c.callsub_node);
235
- if (callInfo)
236
- calls.push(callInfo);
237
- }
238
- else if (c.assign_node) {
239
- // CommonJS: module.exports = require(...) / module.exports = { ...require(...) }
240
- handleCommonJSAssignment(c.assign_left, c.assign_right, c.assign_node, imports);
241
- }
253
+ dispatchQueryMatch(c, definitions, calls, imports, classes, exps);
242
254
  }
243
255
  // Extract top-level constants via targeted walk (query patterns don't cover these)
244
256
  extractConstantsWalk(tree.rootNode, definitions);
@@ -350,45 +362,41 @@ function handleCommonJSAssignment(left, right, node, imports) {
350
362
  const leftText = left.text;
351
363
  if (!leftText.startsWith('module.exports') && leftText !== 'exports')
352
364
  return;
353
- const rightType = right.type;
354
365
  const assignLine = node.startPosition.row + 1;
355
- if (rightType === 'call_expression') {
356
- const fn = right.childForFieldName('function');
357
- const args = right.childForFieldName('arguments') || findChild(right, 'arguments');
358
- if (fn && fn.text === 'require' && args) {
359
- const strArg = findChild(args, 'string');
360
- if (strArg) {
361
- imports.push({
362
- source: strArg.text.replace(/['"]/g, ''),
363
- names: [],
364
- line: assignLine,
365
- reexport: true,
366
- wildcardReexport: true,
367
- });
368
- }
366
+ // module.exports = require("…") — direct re-export
367
+ if (right.type === 'call_expression') {
368
+ extractRequireReexport(right, assignLine, imports);
369
+ }
370
+ // module.exports = { ...require("…") } — spread re-export
371
+ if (right.type === 'object') {
372
+ extractSpreadRequireReexports(right, assignLine, imports);
373
+ }
374
+ }
375
+ /** Extract a direct `require()` re-export from a call_expression. */
376
+ function extractRequireReexport(callExpr, line, imports) {
377
+ const fn = callExpr.childForFieldName('function');
378
+ const args = callExpr.childForFieldName('arguments') || findChild(callExpr, 'arguments');
379
+ if (fn && fn.text === 'require' && args) {
380
+ const strArg = findChild(args, 'string');
381
+ if (strArg) {
382
+ imports.push({
383
+ source: strArg.text.replace(/['"]/g, ''),
384
+ names: [],
385
+ line,
386
+ reexport: true,
387
+ wildcardReexport: true,
388
+ });
369
389
  }
370
390
  }
371
- if (rightType === 'object') {
372
- for (let ci = 0; ci < right.childCount; ci++) {
373
- const child = right.child(ci);
374
- if (child && child.type === 'spread_element') {
375
- const spreadExpr = child.child(1) || child.childForFieldName('value');
376
- if (spreadExpr && spreadExpr.type === 'call_expression') {
377
- const fn2 = spreadExpr.childForFieldName('function');
378
- const args2 = spreadExpr.childForFieldName('arguments') || findChild(spreadExpr, 'arguments');
379
- if (fn2 && fn2.text === 'require' && args2) {
380
- const strArg2 = findChild(args2, 'string');
381
- if (strArg2) {
382
- imports.push({
383
- source: strArg2.text.replace(/['"]/g, ''),
384
- names: [],
385
- line: assignLine,
386
- reexport: true,
387
- wildcardReexport: true,
388
- });
389
- }
390
- }
391
- }
391
+ }
392
+ /** Extract `...require()` re-exports from spread elements inside an object literal. */
393
+ function extractSpreadRequireReexports(objectNode, line, imports) {
394
+ for (let ci = 0; ci < objectNode.childCount; ci++) {
395
+ const child = objectNode.child(ci);
396
+ if (child && child.type === 'spread_element') {
397
+ const spreadExpr = child.child(1) || child.childForFieldName('value');
398
+ if (spreadExpr && spreadExpr.type === 'call_expression') {
399
+ extractRequireReexport(spreadExpr, line, imports);
392
400
  }
393
401
  }
394
402
  }
@@ -896,59 +904,15 @@ function extractNewExprTypeName(newExprNode) {
896
904
  * Higher-confidence entries take priority when the same variable is seen twice.
897
905
  */
898
906
  function extractTypeMapWalk(rootNode, typeMap) {
899
- function setIfHigher(name, type, confidence) {
900
- const existing = typeMap.get(name);
901
- if (!existing || confidence > existing.confidence) {
902
- typeMap.set(name, { type, confidence });
903
- }
904
- }
905
907
  function walk(node, depth) {
906
908
  if (depth >= MAX_WALK_DEPTH)
907
909
  return;
908
910
  const t = node.type;
909
911
  if (t === 'variable_declarator') {
910
- const nameN = node.childForFieldName('name');
911
- if (nameN && nameN.type === 'identifier') {
912
- const typeAnno = findChild(node, 'type_annotation');
913
- if (typeAnno) {
914
- const typeName = extractSimpleTypeName(typeAnno);
915
- if (typeName)
916
- setIfHigher(nameN.text, typeName, 0.9);
917
- }
918
- const valueN = node.childForFieldName('value');
919
- if (valueN) {
920
- // Constructor: const x = new Foo() → confidence 1.0
921
- if (valueN.type === 'new_expression') {
922
- const ctorType = extractNewExprTypeName(valueN);
923
- if (ctorType)
924
- setIfHigher(nameN.text, ctorType, 1.0);
925
- }
926
- // Factory method: const x = Foo.create() → confidence 0.7
927
- else if (valueN.type === 'call_expression') {
928
- const fn = valueN.childForFieldName('function');
929
- if (fn && fn.type === 'member_expression') {
930
- const obj = fn.childForFieldName('object');
931
- if (obj && obj.type === 'identifier') {
932
- const objName = obj.text;
933
- if (objName[0] !== objName[0].toLowerCase() && !BUILTIN_GLOBALS.has(objName)) {
934
- setIfHigher(nameN.text, objName, 0.7);
935
- }
936
- }
937
- }
938
- }
939
- }
940
- }
912
+ handleVarDeclaratorTypeMap(node, typeMap);
941
913
  }
942
914
  else if (t === 'required_parameter' || t === 'optional_parameter') {
943
- const nameNode = node.childForFieldName('pattern') || node.childForFieldName('left') || node.child(0);
944
- if (nameNode && nameNode.type === 'identifier') {
945
- const typeAnno = findChild(node, 'type_annotation');
946
- if (typeAnno) {
947
- const typeName = extractSimpleTypeName(typeAnno);
948
- if (typeName)
949
- setIfHigher(nameNode.text, typeName, 0.9);
950
- }
951
- }
915
+ handleParamTypeMap(node, typeMap);
952
916
  }
953
917
  for (let i = 0; i < node.childCount; i++) {
954
918
  walk(node.child(i), depth + 1);
@@ -956,6 +920,53 @@ function extractTypeMapWalk(rootNode, typeMap) {
956
920
  }
957
921
  walk(rootNode, 0);
958
922
  }
923
+ /** Extract type info from a variable_declarator: type annotation, constructor, or factory. */
924
+ function handleVarDeclaratorTypeMap(node, typeMap) {
925
+ const nameN = node.childForFieldName('name');
926
+ if (!nameN || nameN.type !== 'identifier')
927
+ return;
928
+ // Type annotation: const x: Foo = …
929
+ const typeAnno = findChild(node, 'type_annotation');
930
+ if (typeAnno) {
931
+ const typeName = extractSimpleTypeName(typeAnno);
932
+ if (typeName)
933
+ setTypeMapEntry(typeMap, nameN.text, typeName, 0.9);
934
+ }
935
+ const valueN = node.childForFieldName('value');
936
+ if (!valueN)
937
+ return;
938
+ // Constructor: const x = new Foo() → confidence 1.0
939
+ if (valueN.type === 'new_expression') {
940
+ const ctorType = extractNewExprTypeName(valueN);
941
+ if (ctorType)
942
+ setTypeMapEntry(typeMap, nameN.text, ctorType, 1.0);
943
+ }
944
+ // Factory method: const x = Foo.create() → confidence 0.7
945
+ else if (valueN.type === 'call_expression') {
946
+ const fn = valueN.childForFieldName('function');
947
+ if (fn && fn.type === 'member_expression') {
948
+ const obj = fn.childForFieldName('object');
949
+ if (obj && obj.type === 'identifier') {
950
+ const objName = obj.text;
951
+ if (objName[0] !== objName[0].toLowerCase() && !BUILTIN_GLOBALS.has(objName)) {
952
+ setTypeMapEntry(typeMap, nameN.text, objName, 0.7);
953
+ }
954
+ }
955
+ }
956
+ }
957
+ }
958
+ /** Extract type info from a required_parameter or optional_parameter. */
959
+ function handleParamTypeMap(node, typeMap) {
960
+ const nameNode = node.childForFieldName('pattern') || node.childForFieldName('left') || node.child(0);
961
+ if (!nameNode || nameNode.type !== 'identifier')
962
+ return;
963
+ const typeAnno = findChild(node, 'type_annotation');
964
+ if (typeAnno) {
965
+ const typeName = extractSimpleTypeName(typeAnno);
966
+ if (typeName)
967
+ setTypeMapEntry(typeMap, nameNode.text, typeName, 0.9);
968
+ }
969
+ }
959
970
  function extractReceiverName(objNode) {
960
971
  if (!objNode)
961
972
  return undefined;
@@ -970,49 +981,60 @@ function extractCallInfo(fn, callNode) {
970
981
  return { name: fn.text, line: callNode.startPosition.row + 1 };
971
982
  }
972
983
  if (fnType === 'member_expression') {
973
- const obj = fn.childForFieldName('object');
974
- const prop = fn.childForFieldName('property');
975
- if (!prop)
976
- return null;
977
- const callLine = callNode.startPosition.row + 1;
978
- const propText = prop.text;
979
- if (propText === 'call' || propText === 'apply' || propText === 'bind') {
980
- if (obj && obj.type === 'identifier')
981
- return { name: obj.text, line: callLine, dynamic: true };
982
- if (obj && obj.type === 'member_expression') {
983
- const innerProp = obj.childForFieldName('property');
984
- if (innerProp)
985
- return { name: innerProp.text, line: callLine, dynamic: true };
986
- }
984
+ return extractMemberExprCallInfo(fn, callNode);
985
+ }
986
+ if (fnType === 'subscript_expression') {
987
+ return extractSubscriptCallInfo(fn, callNode);
988
+ }
989
+ return null;
990
+ }
991
+ /** Extract call info from a member_expression function node (obj.method()). */
992
+ function extractMemberExprCallInfo(fn, callNode) {
993
+ const obj = fn.childForFieldName('object');
994
+ const prop = fn.childForFieldName('property');
995
+ if (!prop)
996
+ return null;
997
+ const callLine = callNode.startPosition.row + 1;
998
+ const propText = prop.text;
999
+ // .call()/.apply()/.bind() — dynamic invocation
1000
+ if (propText === 'call' || propText === 'apply' || propText === 'bind') {
1001
+ if (obj && obj.type === 'identifier')
1002
+ return { name: obj.text, line: callLine, dynamic: true };
1003
+ if (obj && obj.type === 'member_expression') {
1004
+ const innerProp = obj.childForFieldName('property');
1005
+ if (innerProp)
1006
+ return { name: innerProp.text, line: callLine, dynamic: true };
987
1007
  }
988
- const propType = prop.type;
989
- if (propType === 'string' || propType === 'string_fragment') {
990
- const methodName = propText.replace(/['"]/g, '');
991
- if (methodName) {
992
- const receiver = extractReceiverName(obj);
993
- return { name: methodName, line: callLine, dynamic: true, receiver };
994
- }
1008
+ }
1009
+ // Computed property: obj["method"]()
1010
+ const propType = prop.type;
1011
+ if (propType === 'string' || propType === 'string_fragment') {
1012
+ const methodName = propText.replace(/['"]/g, '');
1013
+ if (methodName) {
1014
+ const receiver = extractReceiverName(obj);
1015
+ return { name: methodName, line: callLine, dynamic: true, receiver };
995
1016
  }
996
- const receiver = extractReceiverName(obj);
997
- return { name: propText, line: callLine, receiver };
998
1017
  }
999
- if (fnType === 'subscript_expression') {
1000
- const obj = fn.childForFieldName('object');
1001
- const index = fn.childForFieldName('index');
1002
- if (index) {
1003
- const indexType = index.type;
1004
- if (indexType === 'string' || indexType === 'template_string') {
1005
- const methodName = index.text.replace(/['"`]/g, '');
1006
- if (methodName && !methodName.includes('$')) {
1007
- const receiver = extractReceiverName(obj);
1008
- return {
1009
- name: methodName,
1010
- line: callNode.startPosition.row + 1,
1011
- dynamic: true,
1012
- receiver,
1013
- };
1014
- }
1015
- }
1018
+ const receiver = extractReceiverName(obj);
1019
+ return { name: propText, line: callLine, receiver };
1020
+ }
1021
+ /** Extract call info from a subscript_expression function node (obj["method"]()). */
1022
+ function extractSubscriptCallInfo(fn, callNode) {
1023
+ const obj = fn.childForFieldName('object');
1024
+ const index = fn.childForFieldName('index');
1025
+ if (!index)
1026
+ return null;
1027
+ const indexType = index.type;
1028
+ if (indexType === 'string' || indexType === 'template_string') {
1029
+ const methodName = index.text.replace(/['"`]/g, '');
1030
+ if (methodName && !methodName.includes('$')) {
1031
+ const receiver = extractReceiverName(obj);
1032
+ return {
1033
+ name: methodName,
1034
+ line: callNode.startPosition.row + 1,
1035
+ dynamic: true,
1036
+ receiver,
1037
+ };
1016
1038
  }
1017
1039
  }
1018
1040
  return null;
@@ -1149,17 +1171,9 @@ function extractSuperclass(heritage) {
1149
1171
  }
1150
1172
  return null;
1151
1173
  }
1174
+ const JS_CLASS_TYPES = ['class_declaration', 'class'];
1152
1175
  function findParentClass(node) {
1153
- let current = node.parent;
1154
- while (current) {
1155
- const t = current.type;
1156
- if (t === 'class_declaration' || t === 'class') {
1157
- const nameNode = current.childForFieldName('name');
1158
- return nameNode ? nameNode.text : null;
1159
- }
1160
- current = current.parent;
1161
- }
1162
- return null;
1176
+ return findParentNode(node, JS_CLASS_TYPES);
1163
1177
  }
1164
1178
  function extractImportNames(node) {
1165
1179
  const names = [];