@optave/codegraph 3.10.0 → 3.11.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 (312) hide show
  1. package/README.md +40 -33
  2. package/dist/ast-analysis/engine.d.ts.map +1 -1
  3. package/dist/ast-analysis/engine.js +91 -60
  4. package/dist/ast-analysis/engine.js.map +1 -1
  5. package/dist/ast-analysis/rules/index.d.ts.map +1 -1
  6. package/dist/ast-analysis/rules/index.js +77 -0
  7. package/dist/ast-analysis/rules/index.js.map +1 -1
  8. package/dist/ast-analysis/visitor-utils.d.ts +3 -0
  9. package/dist/ast-analysis/visitor-utils.d.ts.map +1 -1
  10. package/dist/ast-analysis/visitor-utils.js +83 -49
  11. package/dist/ast-analysis/visitor-utils.js.map +1 -1
  12. package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
  13. package/dist/ast-analysis/visitors/ast-store-visitor.js +78 -62
  14. package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
  15. package/dist/ast-analysis/visitors/dataflow-visitor.d.ts.map +1 -1
  16. package/dist/ast-analysis/visitors/dataflow-visitor.js +61 -42
  17. package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
  18. package/dist/cli/commands/audit.js +1 -1
  19. package/dist/cli/commands/audit.js.map +1 -1
  20. package/dist/cli/commands/build.d.ts.map +1 -1
  21. package/dist/cli/commands/build.js +2 -0
  22. package/dist/cli/commands/build.js.map +1 -1
  23. package/dist/cli/commands/check.js +1 -1
  24. package/dist/cli/commands/check.js.map +1 -1
  25. package/dist/cli/commands/children.js +1 -1
  26. package/dist/cli/commands/children.js.map +1 -1
  27. package/dist/cli/commands/diff-impact.js +1 -1
  28. package/dist/cli/commands/diff-impact.js.map +1 -1
  29. package/dist/cli/commands/embed.d.ts.map +1 -1
  30. package/dist/cli/commands/embed.js +49 -4
  31. package/dist/cli/commands/embed.js.map +1 -1
  32. package/dist/cli/commands/roles.js +1 -1
  33. package/dist/cli/commands/roles.js.map +1 -1
  34. package/dist/cli/commands/structure.js +1 -1
  35. package/dist/cli/commands/structure.js.map +1 -1
  36. package/dist/cli/shared/options.js +1 -1
  37. package/dist/cli/shared/options.js.map +1 -1
  38. package/dist/db/connection.d.ts.map +1 -1
  39. package/dist/db/connection.js +8 -0
  40. package/dist/db/connection.js.map +1 -1
  41. package/dist/domain/analysis/dependencies.d.ts.map +1 -1
  42. package/dist/domain/analysis/dependencies.js +106 -80
  43. package/dist/domain/analysis/dependencies.js.map +1 -1
  44. package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
  45. package/dist/domain/analysis/fn-impact.js +77 -52
  46. package/dist/domain/analysis/fn-impact.js.map +1 -1
  47. package/dist/domain/analysis/module-map.d.ts.map +1 -1
  48. package/dist/domain/analysis/module-map.js +132 -121
  49. package/dist/domain/analysis/module-map.js.map +1 -1
  50. package/dist/domain/graph/builder/helpers.d.ts +4 -4
  51. package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
  52. package/dist/domain/graph/builder/helpers.js +47 -33
  53. package/dist/domain/graph/builder/helpers.js.map +1 -1
  54. package/dist/domain/graph/builder/incremental.d.ts +6 -6
  55. package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
  56. package/dist/domain/graph/builder/incremental.js +148 -99
  57. package/dist/domain/graph/builder/incremental.js.map +1 -1
  58. package/dist/domain/graph/builder/pipeline.d.ts +1 -0
  59. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
  60. package/dist/domain/graph/builder/pipeline.js +23 -637
  61. package/dist/domain/graph/builder/pipeline.js.map +1 -1
  62. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
  63. package/dist/domain/graph/builder/stages/build-edges.js +141 -98
  64. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
  65. package/dist/domain/graph/builder/stages/build-structure.d.ts.map +1 -1
  66. package/dist/domain/graph/builder/stages/build-structure.js +82 -65
  67. package/dist/domain/graph/builder/stages/build-structure.js.map +1 -1
  68. package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
  69. package/dist/domain/graph/builder/stages/detect-changes.js +84 -56
  70. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
  71. package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
  72. package/dist/domain/graph/builder/stages/finalize.js +60 -51
  73. package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
  74. package/dist/domain/graph/builder/stages/insert-nodes.d.ts +8 -6
  75. package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
  76. package/dist/domain/graph/builder/stages/insert-nodes.js +107 -122
  77. package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
  78. package/dist/domain/graph/builder/stages/native-db-lifecycle.d.ts +14 -0
  79. package/dist/domain/graph/builder/stages/native-db-lifecycle.d.ts.map +1 -0
  80. package/dist/domain/graph/builder/stages/native-db-lifecycle.js +77 -0
  81. package/dist/domain/graph/builder/stages/native-db-lifecycle.js.map +1 -0
  82. package/dist/domain/graph/builder/stages/native-orchestrator.d.ts +62 -0
  83. package/dist/domain/graph/builder/stages/native-orchestrator.d.ts.map +1 -0
  84. package/dist/domain/graph/builder/stages/native-orchestrator.js +747 -0
  85. package/dist/domain/graph/builder/stages/native-orchestrator.js.map +1 -0
  86. package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
  87. package/dist/domain/graph/builder/stages/resolve-imports.js +73 -22
  88. package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
  89. package/dist/domain/graph/cycles.d.ts +6 -4
  90. package/dist/domain/graph/cycles.d.ts.map +1 -1
  91. package/dist/domain/graph/cycles.js +50 -55
  92. package/dist/domain/graph/cycles.js.map +1 -1
  93. package/dist/domain/graph/journal.d.ts.map +1 -1
  94. package/dist/domain/graph/journal.js +89 -70
  95. package/dist/domain/graph/journal.js.map +1 -1
  96. package/dist/domain/graph/watcher.d.ts.map +1 -1
  97. package/dist/domain/graph/watcher.js +28 -20
  98. package/dist/domain/graph/watcher.js.map +1 -1
  99. package/dist/domain/parser.d.ts +12 -23
  100. package/dist/domain/parser.d.ts.map +1 -1
  101. package/dist/domain/parser.js +153 -80
  102. package/dist/domain/parser.js.map +1 -1
  103. package/dist/domain/search/generator.d.ts +3 -1
  104. package/dist/domain/search/generator.d.ts.map +1 -1
  105. package/dist/domain/search/generator.js +68 -45
  106. package/dist/domain/search/generator.js.map +1 -1
  107. package/dist/domain/search/models.d.ts +18 -0
  108. package/dist/domain/search/models.d.ts.map +1 -1
  109. package/dist/domain/search/models.js +72 -4
  110. package/dist/domain/search/models.js.map +1 -1
  111. package/dist/domain/search/search/hybrid.d.ts.map +1 -1
  112. package/dist/domain/search/search/hybrid.js +49 -40
  113. package/dist/domain/search/search/hybrid.js.map +1 -1
  114. package/dist/domain/search/search/semantic.d.ts.map +1 -1
  115. package/dist/domain/search/search/semantic.js +69 -49
  116. package/dist/domain/search/search/semantic.js.map +1 -1
  117. package/dist/domain/wasm-worker-entry.js +209 -137
  118. package/dist/domain/wasm-worker-entry.js.map +1 -1
  119. package/dist/extractors/c.js +25 -6
  120. package/dist/extractors/c.js.map +1 -1
  121. package/dist/extractors/cpp.js +47 -6
  122. package/dist/extractors/cpp.js.map +1 -1
  123. package/dist/extractors/cuda.js +90 -14
  124. package/dist/extractors/cuda.js.map +1 -1
  125. package/dist/extractors/elixir.js +108 -4
  126. package/dist/extractors/elixir.js.map +1 -1
  127. package/dist/extractors/erlang.js +56 -20
  128. package/dist/extractors/erlang.js.map +1 -1
  129. package/dist/extractors/fsharp.d.ts +7 -0
  130. package/dist/extractors/fsharp.d.ts.map +1 -1
  131. package/dist/extractors/fsharp.js +94 -0
  132. package/dist/extractors/fsharp.js.map +1 -1
  133. package/dist/extractors/gleam.d.ts.map +1 -1
  134. package/dist/extractors/gleam.js +29 -33
  135. package/dist/extractors/gleam.js.map +1 -1
  136. package/dist/extractors/groovy.js +41 -1
  137. package/dist/extractors/groovy.js.map +1 -1
  138. package/dist/extractors/haskell.js +48 -4
  139. package/dist/extractors/haskell.js.map +1 -1
  140. package/dist/extractors/helpers.d.ts +79 -1
  141. package/dist/extractors/helpers.d.ts.map +1 -1
  142. package/dist/extractors/helpers.js +137 -0
  143. package/dist/extractors/helpers.js.map +1 -1
  144. package/dist/extractors/java.d.ts.map +1 -1
  145. package/dist/extractors/java.js +37 -49
  146. package/dist/extractors/java.js.map +1 -1
  147. package/dist/extractors/javascript.d.ts.map +1 -1
  148. package/dist/extractors/javascript.js +44 -44
  149. package/dist/extractors/javascript.js.map +1 -1
  150. package/dist/extractors/julia.js +198 -74
  151. package/dist/extractors/julia.js.map +1 -1
  152. package/dist/extractors/kotlin.js +4 -0
  153. package/dist/extractors/kotlin.js.map +1 -1
  154. package/dist/extractors/objc.js +184 -47
  155. package/dist/extractors/objc.js.map +1 -1
  156. package/dist/extractors/python.js +7 -4
  157. package/dist/extractors/python.js.map +1 -1
  158. package/dist/extractors/r.d.ts.map +1 -1
  159. package/dist/extractors/r.js +103 -87
  160. package/dist/extractors/r.js.map +1 -1
  161. package/dist/extractors/scala.d.ts.map +1 -1
  162. package/dist/extractors/scala.js +18 -32
  163. package/dist/extractors/scala.js.map +1 -1
  164. package/dist/extractors/solidity.d.ts.map +1 -1
  165. package/dist/extractors/solidity.js +55 -69
  166. package/dist/extractors/solidity.js.map +1 -1
  167. package/dist/extractors/verilog.js +80 -15
  168. package/dist/extractors/verilog.js.map +1 -1
  169. package/dist/features/boundaries.d.ts.map +1 -1
  170. package/dist/features/boundaries.js +49 -39
  171. package/dist/features/boundaries.js.map +1 -1
  172. package/dist/features/cfg.d.ts.map +1 -1
  173. package/dist/features/cfg.js +90 -63
  174. package/dist/features/cfg.js.map +1 -1
  175. package/dist/features/check.d.ts.map +1 -1
  176. package/dist/features/check.js +43 -34
  177. package/dist/features/check.js.map +1 -1
  178. package/dist/features/cochange.d.ts.map +1 -1
  179. package/dist/features/cochange.js +68 -56
  180. package/dist/features/cochange.js.map +1 -1
  181. package/dist/features/complexity.d.ts.map +1 -1
  182. package/dist/features/complexity.js +105 -75
  183. package/dist/features/complexity.js.map +1 -1
  184. package/dist/features/dataflow.d.ts.map +1 -1
  185. package/dist/features/dataflow.js +37 -29
  186. package/dist/features/dataflow.js.map +1 -1
  187. package/dist/features/flow.d.ts.map +1 -1
  188. package/dist/features/flow.js +31 -22
  189. package/dist/features/flow.js.map +1 -1
  190. package/dist/features/graph-enrichment.d.ts.map +1 -1
  191. package/dist/features/graph-enrichment.js +77 -70
  192. package/dist/features/graph-enrichment.js.map +1 -1
  193. package/dist/features/owners.d.ts +17 -26
  194. package/dist/features/owners.d.ts.map +1 -1
  195. package/dist/features/owners.js +120 -109
  196. package/dist/features/owners.js.map +1 -1
  197. package/dist/features/sequence.d.ts.map +1 -1
  198. package/dist/features/sequence.js +59 -54
  199. package/dist/features/sequence.js.map +1 -1
  200. package/dist/features/structure-query.d.ts.map +1 -1
  201. package/dist/features/structure-query.js +60 -60
  202. package/dist/features/structure-query.js.map +1 -1
  203. package/dist/features/structure.js +28 -36
  204. package/dist/features/structure.js.map +1 -1
  205. package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
  206. package/dist/graph/algorithms/leiden/optimiser.js +100 -69
  207. package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
  208. package/dist/graph/classifiers/roles.d.ts.map +1 -1
  209. package/dist/graph/classifiers/roles.js +63 -59
  210. package/dist/graph/classifiers/roles.js.map +1 -1
  211. package/dist/infrastructure/config.d.ts +1 -1
  212. package/dist/infrastructure/config.d.ts.map +1 -1
  213. package/dist/infrastructure/config.js +1 -1
  214. package/dist/infrastructure/config.js.map +1 -1
  215. package/dist/mcp/tool-registry.d.ts.map +1 -1
  216. package/dist/mcp/tool-registry.js +4 -0
  217. package/dist/mcp/tool-registry.js.map +1 -1
  218. package/dist/mcp/tools/semantic-search.d.ts +1 -0
  219. package/dist/mcp/tools/semantic-search.d.ts.map +1 -1
  220. package/dist/mcp/tools/semantic-search.js +1 -0
  221. package/dist/mcp/tools/semantic-search.js.map +1 -1
  222. package/dist/presentation/cfg.d.ts.map +1 -1
  223. package/dist/presentation/cfg.js +44 -29
  224. package/dist/presentation/cfg.js.map +1 -1
  225. package/dist/presentation/flow.d.ts.map +1 -1
  226. package/dist/presentation/flow.js +58 -38
  227. package/dist/presentation/flow.js.map +1 -1
  228. package/dist/types.d.ts +16 -2
  229. package/dist/types.d.ts.map +1 -1
  230. package/grammars/tree-sitter-erlang.wasm +0 -0
  231. package/grammars/tree-sitter-fsharp.wasm +0 -0
  232. package/grammars/tree-sitter-fsharp_signature.wasm +0 -0
  233. package/grammars/tree-sitter-gleam.wasm +0 -0
  234. package/package.json +10 -10
  235. package/src/ast-analysis/engine.ts +145 -61
  236. package/src/ast-analysis/rules/index.ts +87 -0
  237. package/src/ast-analysis/visitor-utils.ts +86 -46
  238. package/src/ast-analysis/visitors/ast-store-visitor.ts +104 -69
  239. package/src/ast-analysis/visitors/dataflow-visitor.ts +86 -47
  240. package/src/cli/commands/audit.ts +1 -1
  241. package/src/cli/commands/build.ts +2 -0
  242. package/src/cli/commands/check.ts +1 -1
  243. package/src/cli/commands/children.ts +1 -1
  244. package/src/cli/commands/diff-impact.ts +1 -1
  245. package/src/cli/commands/embed.ts +54 -4
  246. package/src/cli/commands/roles.ts +1 -1
  247. package/src/cli/commands/structure.ts +1 -1
  248. package/src/cli/shared/options.ts +1 -1
  249. package/src/db/connection.ts +8 -0
  250. package/src/domain/analysis/dependencies.ts +166 -85
  251. package/src/domain/analysis/fn-impact.ts +120 -50
  252. package/src/domain/analysis/module-map.ts +175 -140
  253. package/src/domain/graph/builder/helpers.ts +85 -76
  254. package/src/domain/graph/builder/incremental.ts +223 -131
  255. package/src/domain/graph/builder/pipeline.ts +32 -785
  256. package/src/domain/graph/builder/stages/build-edges.ts +207 -142
  257. package/src/domain/graph/builder/stages/build-structure.ts +115 -82
  258. package/src/domain/graph/builder/stages/detect-changes.ts +107 -64
  259. package/src/domain/graph/builder/stages/finalize.ts +72 -70
  260. package/src/domain/graph/builder/stages/insert-nodes.ts +154 -120
  261. package/src/domain/graph/builder/stages/native-db-lifecycle.ts +74 -0
  262. package/src/domain/graph/builder/stages/native-orchestrator.ts +942 -0
  263. package/src/domain/graph/builder/stages/resolve-imports.ts +79 -25
  264. package/src/domain/graph/cycles.ts +51 -49
  265. package/src/domain/graph/journal.ts +84 -69
  266. package/src/domain/graph/watcher.ts +29 -25
  267. package/src/domain/parser.ts +170 -67
  268. package/src/domain/search/generator.ts +132 -74
  269. package/src/domain/search/models.ts +75 -4
  270. package/src/domain/search/search/hybrid.ts +53 -42
  271. package/src/domain/search/search/semantic.ts +105 -65
  272. package/src/domain/wasm-worker-entry.ts +243 -153
  273. package/src/extractors/c.ts +27 -8
  274. package/src/extractors/cpp.ts +50 -8
  275. package/src/extractors/cuda.ts +90 -16
  276. package/src/extractors/elixir.ts +103 -4
  277. package/src/extractors/erlang.ts +63 -20
  278. package/src/extractors/fsharp.ts +104 -0
  279. package/src/extractors/gleam.ts +40 -39
  280. package/src/extractors/groovy.ts +45 -1
  281. package/src/extractors/haskell.ts +45 -4
  282. package/src/extractors/helpers.ts +205 -1
  283. package/src/extractors/java.ts +42 -45
  284. package/src/extractors/javascript.ts +44 -43
  285. package/src/extractors/julia.ts +191 -77
  286. package/src/extractors/kotlin.ts +4 -0
  287. package/src/extractors/objc.ts +171 -47
  288. package/src/extractors/python.ts +5 -3
  289. package/src/extractors/r.ts +104 -82
  290. package/src/extractors/scala.ts +24 -36
  291. package/src/extractors/solidity.ts +59 -78
  292. package/src/extractors/verilog.ts +83 -15
  293. package/src/features/boundaries.ts +64 -46
  294. package/src/features/cfg.ts +145 -74
  295. package/src/features/check.ts +60 -43
  296. package/src/features/cochange.ts +95 -72
  297. package/src/features/complexity.ts +134 -79
  298. package/src/features/dataflow.ts +57 -34
  299. package/src/features/flow.ts +48 -24
  300. package/src/features/graph-enrichment.ts +105 -70
  301. package/src/features/owners.ts +186 -146
  302. package/src/features/sequence.ts +99 -69
  303. package/src/features/structure-query.ts +94 -79
  304. package/src/features/structure.ts +56 -56
  305. package/src/graph/algorithms/leiden/optimiser.ts +142 -87
  306. package/src/graph/classifiers/roles.ts +64 -54
  307. package/src/infrastructure/config.ts +1 -1
  308. package/src/mcp/tool-registry.ts +5 -0
  309. package/src/mcp/tools/semantic-search.ts +2 -0
  310. package/src/presentation/cfg.ts +48 -32
  311. package/src/presentation/flow.ts +100 -52
  312. package/src/types.ts +16 -1
@@ -1,5 +1,4 @@
1
1
  import type {
2
- Call,
3
2
  ExtractorOutput,
4
3
  SubDeclaration,
5
4
  TreeSitterNode,
@@ -9,10 +8,14 @@ import type {
9
8
  import {
10
9
  extractBodyMembers,
11
10
  extractModifierVisibility,
11
+ extractSimpleParameters,
12
12
  findChild,
13
13
  findParentNode,
14
14
  lastPathSegment,
15
15
  nodeEndLine,
16
+ nodeStartLine,
17
+ pushCall,
18
+ pushImport,
16
19
  } from './helpers.js';
17
20
 
18
21
  /**
@@ -78,7 +81,7 @@ function handleJavaClassDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
78
81
  ctx.definitions.push({
79
82
  name: nameNode.text,
80
83
  kind: 'class',
81
- line: node.startPosition.row + 1,
84
+ line: nodeStartLine(node),
82
85
  endLine: nodeEndLine(node),
83
86
  children: classChildren.length > 0 ? classChildren : undefined,
84
87
  });
@@ -87,7 +90,7 @@ function handleJavaClassDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
87
90
 
88
91
  const interfaces = node.childForFieldName('interfaces');
89
92
  if (interfaces) {
90
- extractJavaInterfaces(interfaces, nameNode.text, node.startPosition.row + 1, ctx);
93
+ extractJavaInterfaces(interfaces, nameNode.text, nodeStartLine(node), ctx);
91
94
  }
92
95
  }
93
96
 
@@ -101,7 +104,7 @@ function extractJavaSuperclass(
101
104
  if (!superclass) return;
102
105
  const superName = findJavaSuperTypeName(superclass);
103
106
  if (superName) {
104
- ctx.classes.push({ name: className, extends: superName, line: node.startPosition.row + 1 });
107
+ ctx.classes.push({ name: className, extends: superName, line: nodeStartLine(node) });
105
108
  }
106
109
  }
107
110
 
@@ -163,7 +166,7 @@ function handleJavaInterfaceDecl(node: TreeSitterNode, ctx: ExtractorOutput): vo
163
166
  ctx.definitions.push({
164
167
  name: nameNode.text,
165
168
  kind: 'interface',
166
- line: node.startPosition.row + 1,
169
+ line: nodeStartLine(node),
167
170
  endLine: nodeEndLine(node),
168
171
  });
169
172
  const body = node.childForFieldName('body');
@@ -184,8 +187,8 @@ function extractJavaInterfaceMethods(
184
187
  ctx.definitions.push({
185
188
  name: `${ifaceName}.${methName.text}`,
186
189
  kind: 'method',
187
- line: child.startPosition.row + 1,
188
- endLine: child.endPosition.row + 1,
190
+ line: nodeStartLine(child),
191
+ endLine: nodeEndLine(child),
189
192
  });
190
193
  }
191
194
  }
@@ -199,7 +202,7 @@ function handleJavaEnumDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
199
202
  ctx.definitions.push({
200
203
  name: nameNode.text,
201
204
  kind: 'enum',
202
- line: node.startPosition.row + 1,
205
+ line: nodeStartLine(node),
203
206
  endLine: nodeEndLine(node),
204
207
  children: enumChildren.length > 0 ? enumChildren : undefined,
205
208
  });
@@ -216,7 +219,7 @@ function handleJavaMethodDecl(node: TreeSitterNode, ctx: ExtractorOutput): void
216
219
  ctx.definitions.push({
217
220
  name: fullName,
218
221
  kind: 'method',
219
- line: node.startPosition.row + 1,
222
+ line: nodeStartLine(node),
220
223
  endLine: nodeEndLine(node),
221
224
  children: params.length > 0 ? params : undefined,
222
225
  visibility: extractModifierVisibility(node),
@@ -232,7 +235,7 @@ function handleJavaConstructorDecl(node: TreeSitterNode, ctx: ExtractorOutput):
232
235
  ctx.definitions.push({
233
236
  name: fullName,
234
237
  kind: 'method',
235
- line: node.startPosition.row + 1,
238
+ line: nodeStartLine(node),
236
239
  endLine: nodeEndLine(node),
237
240
  children: params.length > 0 ? params : undefined,
238
241
  visibility: extractModifierVisibility(node),
@@ -245,12 +248,7 @@ function handleJavaImportDecl(node: TreeSitterNode, ctx: ExtractorOutput): void
245
248
  if (child && (child.type === 'scoped_identifier' || child.type === 'identifier')) {
246
249
  const fullPath = child.text;
247
250
  const lastName = lastPathSegment(fullPath, '.');
248
- ctx.imports.push({
249
- source: fullPath,
250
- names: [lastName],
251
- line: node.startPosition.row + 1,
252
- javaImport: true,
253
- });
251
+ pushImport(ctx, node, fullPath, [lastName], { javaImport: true });
254
252
  }
255
253
  if (child && child.type === 'asterisk') {
256
254
  const lastImport = ctx.imports[ctx.imports.length - 1];
@@ -263,21 +261,25 @@ function handleJavaMethodInvocation(node: TreeSitterNode, ctx: ExtractorOutput):
263
261
  const nameNode = node.childForFieldName('name');
264
262
  if (!nameNode) return;
265
263
  const obj = node.childForFieldName('object');
266
- const call: Call = { name: nameNode.text, line: node.startPosition.row + 1 };
267
- if (obj) call.receiver = obj.text;
268
- ctx.calls.push(call);
264
+ pushCall(ctx, node, nameNode.text, obj ? { receiver: obj.text } : {});
269
265
  }
270
266
 
271
267
  function handleJavaLocalVarDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
272
268
  const typeNode = node.childForFieldName('type');
273
269
  if (!typeNode) return;
274
- const typeName = typeNode.type === 'generic_type' ? typeNode.child(0)?.text : typeNode.text;
270
+ const typeName = resolveJavaTypeText(typeNode);
275
271
  if (!typeName) return;
276
272
  for (let i = 0; i < node.childCount; i++) {
277
273
  const child = node.child(i);
278
274
  if (child?.type === 'variable_declarator') {
279
275
  const nameNode = child.childForFieldName('name');
280
- if (nameNode) ctx.typeMap?.set(nameNode.text, { type: typeName, confidence: 0.9 });
276
+ // Use direct Map.set (last-wins) for local variable declarations.
277
+ // Local variable types are method-scoped and should override any
278
+ // prior entry (e.g. a same-named constructor parameter). Using
279
+ // setTypeMapEntry (first-wins on tie) would let a constructor
280
+ // parameter type block a local variable's more-specific concrete type.
281
+ if (nameNode && ctx.typeMap)
282
+ ctx.typeMap.set(nameNode.text, { type: typeName, confidence: 0.9 });
281
283
  }
282
284
  }
283
285
  }
@@ -285,8 +287,17 @@ function handleJavaLocalVarDecl(node: TreeSitterNode, ctx: ExtractorOutput): voi
285
287
  function handleJavaObjectCreation(node: TreeSitterNode, ctx: ExtractorOutput): void {
286
288
  const typeNode = node.childForFieldName('type');
287
289
  if (!typeNode) return;
288
- const typeName = typeNode.type === 'generic_type' ? typeNode.child(0)?.text : typeNode.text;
289
- if (typeName) ctx.calls.push({ name: typeName, line: node.startPosition.row + 1 });
290
+ const typeName = resolveJavaTypeText(typeNode);
291
+ if (typeName) pushCall(ctx, node, typeName);
292
+ }
293
+
294
+ /**
295
+ * Resolve a Java type node's text, unwrapping `generic_type` to its base name.
296
+ * Used wherever we need the bare type identifier (local var decls, object
297
+ * creation, parameter types).
298
+ */
299
+ function resolveJavaTypeText(typeNode: TreeSitterNode): string | undefined {
300
+ return typeNode.type === 'generic_type' ? typeNode.child(0)?.text : typeNode.text;
290
301
  }
291
302
 
292
303
  const JAVA_PARENT_TYPES = [
@@ -300,31 +311,17 @@ function findJavaParentClass(node: TreeSitterNode): string | null {
300
311
 
301
312
  // ── Child extraction helpers ────────────────────────────────────────────────
302
313
 
314
+ const JAVA_PARAM_TYPES = ['formal_parameter', 'spread_parameter'] as const;
315
+
303
316
  function extractJavaParameters(
304
317
  paramListNode: TreeSitterNode | null,
305
318
  typeMap?: Map<string, TypeMapEntry>,
306
319
  ): SubDeclaration[] {
307
- const params: SubDeclaration[] = [];
308
- if (!paramListNode) return params;
309
- for (let i = 0; i < paramListNode.childCount; i++) {
310
- const param = paramListNode.child(i);
311
- if (!param) continue;
312
- if (param.type === 'formal_parameter' || param.type === 'spread_parameter') {
313
- const nameNode = param.childForFieldName('name');
314
- if (nameNode) {
315
- params.push({ name: nameNode.text, kind: 'parameter', line: param.startPosition.row + 1 });
316
- if (typeMap) {
317
- const typeNode = param.childForFieldName('type');
318
- if (typeNode) {
319
- const typeName =
320
- typeNode.type === 'generic_type' ? typeNode.child(0)?.text : typeNode.text;
321
- if (typeName) typeMap.set(nameNode.text, { type: typeName, confidence: 0.9 });
322
- }
323
- }
324
- }
325
- }
326
- }
327
- return params;
320
+ return extractSimpleParameters(paramListNode, {
321
+ paramTypes: JAVA_PARAM_TYPES,
322
+ typeMap,
323
+ resolveType: resolveJavaTypeText,
324
+ });
328
325
  }
329
326
 
330
327
  function extractClassFields(classNode: TreeSitterNode): SubDeclaration[] {
@@ -350,7 +347,7 @@ function extractFieldDeclarators(member: TreeSitterNode, fields: SubDeclaration[
350
347
  fields.push({
351
348
  name: nameNode.text,
352
349
  kind: 'property',
353
- line: member.startPosition.row + 1,
350
+ line: nodeStartLine(member),
354
351
  visibility: vis,
355
352
  });
356
353
  }
@@ -17,6 +17,7 @@ import {
17
17
  findParentNode,
18
18
  MAX_WALK_DEPTH,
19
19
  nodeEndLine,
20
+ nodeStartLine,
20
21
  setTypeMapEntry,
21
22
  } from './helpers.js';
22
23
 
@@ -99,7 +100,7 @@ function handleFnCapture(c: Record<string, TreeSitterNode>, definitions: Definit
99
100
  definitions.push({
100
101
  name: c.fn_name!.text,
101
102
  kind: 'function',
102
- line: c.fn_node!.startPosition.row + 1,
103
+ line: nodeStartLine(c.fn_node!),
103
104
  endLine: nodeEndLine(c.fn_node!),
104
105
  children: fnChildren.length > 0 ? fnChildren : undefined,
105
106
  });
@@ -108,7 +109,7 @@ function handleFnCapture(c: Record<string, TreeSitterNode>, definitions: Definit
108
109
  /** Handle variable_declarator with arrow_function / function_expression capture. */
109
110
  function handleVarFnCapture(c: Record<string, TreeSitterNode>, definitions: Definition[]): void {
110
111
  const declNode = c.varfn_name!.parent?.parent;
111
- const line = declNode ? declNode.startPosition.row + 1 : c.varfn_name!.startPosition.row + 1;
112
+ const line = declNode ? nodeStartLine(declNode) : nodeStartLine(c.varfn_name!);
112
113
  const varFnChildren = extractParameters(c.varfn_value!);
113
114
  definitions.push({
114
115
  name: c.varfn_name!.text,
@@ -126,7 +127,7 @@ function handleClassCapture(
126
127
  classes: ClassRelation[],
127
128
  ): void {
128
129
  const className = c.cls_name!.text;
129
- const startLine = c.cls_node!.startPosition.row + 1;
130
+ const startLine = nodeStartLine(c.cls_node!);
130
131
  const clsChildren = extractClassProperties(c.cls_node!);
131
132
  definitions.push({
132
133
  name: className,
@@ -157,7 +158,7 @@ function handleMethodCapture(c: Record<string, TreeSitterNode>, definitions: Def
157
158
  definitions.push({
158
159
  name: fullName,
159
160
  kind: 'method',
160
- line: c.meth_node!.startPosition.row + 1,
161
+ line: nodeStartLine(c.meth_node!),
161
162
  endLine: nodeEndLine(c.meth_node!),
162
163
  children: methChildren.length > 0 ? methChildren : undefined,
163
164
  visibility: methVis,
@@ -170,7 +171,7 @@ function handleExportCapture(
170
171
  exps: Export[],
171
172
  imports: Import[],
172
173
  ): void {
173
- const exportLine = c.exp_node!.startPosition.row + 1;
174
+ const exportLine = nodeStartLine(c.exp_node!);
174
175
  const decl = c.exp_node!.childForFieldName('declaration');
175
176
  if (decl) {
176
177
  const declType = decl.type;
@@ -211,7 +212,7 @@ function handleInterfaceCapture(
211
212
  definitions.push({
212
213
  name: ifaceName,
213
214
  kind: 'interface',
214
- line: ifaceNode.startPosition.row + 1,
215
+ line: nodeStartLine(ifaceNode),
215
216
  endLine: nodeEndLine(ifaceNode),
216
217
  });
217
218
  const body =
@@ -226,7 +227,7 @@ function handleTypeCapture(c: Record<string, TreeSitterNode>, definitions: Defin
226
227
  definitions.push({
227
228
  name: c.type_name!.text,
228
229
  kind: 'type',
229
- line: typeNode.startPosition.row + 1,
230
+ line: nodeStartLine(typeNode),
230
231
  endLine: nodeEndLine(typeNode),
231
232
  });
232
233
  }
@@ -239,7 +240,7 @@ function handleImportCapture(c: Record<string, TreeSitterNode>, imports: Import[
239
240
  imports.push({
240
241
  source: modPath,
241
242
  names,
242
- line: impNode.startPosition.row + 1,
243
+ line: nodeStartLine(impNode),
243
244
  typeOnly: isTypeOnly,
244
245
  });
245
246
  }
@@ -272,7 +273,7 @@ function dispatchQueryMatch(
272
273
  } else if (c.callfn_node) {
273
274
  calls.push({
274
275
  name: c.callfn_name!.text,
275
- line: c.callfn_node.startPosition.row + 1,
276
+ line: nodeStartLine(c.callfn_node),
276
277
  });
277
278
  calls.push(...extractCallbackReferenceCalls(c.callfn_node));
278
279
  } else if (c.callmem_node) {
@@ -288,7 +289,7 @@ function dispatchQueryMatch(
288
289
  } else if (c.newfn_node) {
289
290
  calls.push({
290
291
  name: c.newfn_name!.text,
291
- line: c.newfn_node.startPosition.row + 1,
292
+ line: nodeStartLine(c.newfn_node),
292
293
  });
293
294
  } else if (c.newmem_node) {
294
295
  const callInfo = extractCallInfo(c.newmem_fn!, c.newmem_node);
@@ -411,7 +412,7 @@ function extractDestructuredBindingsWalk(node: TreeSitterNode, definitions: Defi
411
412
  if (nameN && nameN.type === 'object_pattern') {
412
413
  extractDestructuredBindings(
413
414
  nameN,
414
- declNode.startPosition.row + 1,
415
+ nodeStartLine(declNode),
415
416
  nodeEndLine(declNode),
416
417
  definitions,
417
418
  );
@@ -445,7 +446,7 @@ function extractConstDeclarators(declNode: TreeSitterNode, definitions: Definiti
445
446
  definitions.push({
446
447
  name: nameN.text,
447
448
  kind: 'constant',
448
- line: declNode.startPosition.row + 1,
449
+ line: nodeStartLine(declNode),
449
450
  endLine: nodeEndLine(declNode),
450
451
  });
451
452
  }
@@ -470,12 +471,12 @@ function extractDynamicImportsWalk(node: TreeSitterNode, imports: Import[]): voi
470
471
  imports.push({
471
472
  source: modPath,
472
473
  names,
473
- line: node.startPosition.row + 1,
474
+ line: nodeStartLine(node),
474
475
  dynamicImport: true,
475
476
  });
476
477
  } else {
477
478
  debug(
478
- `Skipping non-static dynamic import() at line ${node.startPosition.row + 1} (template literal or variable)`,
479
+ `Skipping non-static dynamic import() at line ${nodeStartLine(node)} (template literal or variable)`,
479
480
  );
480
481
  }
481
482
  }
@@ -497,7 +498,7 @@ function handleCommonJSAssignment(
497
498
  const leftText = left.text;
498
499
  if (!leftText.startsWith('module.exports') && leftText !== 'exports') return;
499
500
 
500
- const assignLine = node.startPosition.row + 1;
501
+ const assignLine = nodeStartLine(node);
501
502
 
502
503
  // module.exports = require("…") — direct re-export
503
504
  if (right.type === 'call_expression') {
@@ -618,7 +619,7 @@ function handleFunctionDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
618
619
  ctx.definitions.push({
619
620
  name: nameNode.text,
620
621
  kind: 'function',
621
- line: node.startPosition.row + 1,
622
+ line: nodeStartLine(node),
622
623
  endLine: nodeEndLine(node),
623
624
  children: fnChildren.length > 0 ? fnChildren : undefined,
624
625
  });
@@ -629,7 +630,7 @@ function handleClassDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
629
630
  const nameNode = node.childForFieldName('name');
630
631
  if (!nameNode) return;
631
632
  const className = nameNode.text;
632
- const startLine = node.startPosition.row + 1;
633
+ const startLine = nodeStartLine(node);
633
634
  const clsChildren = extractClassProperties(node);
634
635
  ctx.definitions.push({
635
636
  name: className,
@@ -661,7 +662,7 @@ function handleMethodDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
661
662
  ctx.definitions.push({
662
663
  name: fullName,
663
664
  kind: 'method',
664
- line: node.startPosition.row + 1,
665
+ line: nodeStartLine(node),
665
666
  endLine: nodeEndLine(node),
666
667
  children: methChildren.length > 0 ? methChildren : undefined,
667
668
  visibility: methVis,
@@ -675,7 +676,7 @@ function handleInterfaceDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
675
676
  ctx.definitions.push({
676
677
  name: nameNode.text,
677
678
  kind: 'interface',
678
- line: node.startPosition.row + 1,
679
+ line: nodeStartLine(node),
679
680
  endLine: nodeEndLine(node),
680
681
  });
681
682
  const body =
@@ -693,7 +694,7 @@ function handleTypeAliasDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
693
694
  ctx.definitions.push({
694
695
  name: nameNode.text,
695
696
  kind: 'type',
696
- line: node.startPosition.row + 1,
697
+ line: nodeStartLine(node),
697
698
  endLine: nodeEndLine(node),
698
699
  });
699
700
  }
@@ -751,7 +752,7 @@ function handleVariableDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
751
752
  ctx.definitions.push({
752
753
  name: nameN.text,
753
754
  kind: 'function',
754
- line: node.startPosition.row + 1,
755
+ line: nodeStartLine(node),
755
756
  endLine: nodeEndLine(valueN),
756
757
  children: varFnChildren.length > 0 ? varFnChildren : undefined,
757
758
  });
@@ -759,7 +760,7 @@ function handleVariableDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
759
760
  ctx.definitions.push({
760
761
  name: nameN.text,
761
762
  kind: 'constant',
762
- line: node.startPosition.row + 1,
763
+ line: nodeStartLine(node),
763
764
  endLine: nodeEndLine(node),
764
765
  });
765
766
  } else if (isConst && nameN.type === 'object_pattern' && !hasFunctionScopeAncestor(node)) {
@@ -772,7 +773,7 @@ function handleVariableDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
772
773
  // handle_var_decl (Rust path) — skips bindings inside function bodies.
773
774
  extractDestructuredBindings(
774
775
  nameN,
775
- node.startPosition.row + 1,
776
+ nodeStartLine(node),
776
777
  nodeEndLine(node),
777
778
  ctx.definitions,
778
779
  );
@@ -797,7 +798,7 @@ function handleEnumDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
797
798
  enumChildren.push({
798
799
  name: mName.text,
799
800
  kind: 'constant',
800
- line: member.startPosition.row + 1,
801
+ line: nodeStartLine(member),
801
802
  });
802
803
  }
803
804
  }
@@ -806,7 +807,7 @@ function handleEnumDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
806
807
  ctx.definitions.push({
807
808
  name: nameNode.text,
808
809
  kind: 'enum',
809
- line: node.startPosition.row + 1,
810
+ line: nodeStartLine(node),
810
811
  endLine: nodeEndLine(node),
811
812
  children: enumChildren.length > 0 ? enumChildren : undefined,
812
813
  });
@@ -832,7 +833,7 @@ function handleNewExpr(node: TreeSitterNode, ctx: ExtractorOutput): void {
832
833
  const ctor = node.childForFieldName('constructor') || node.child(1);
833
834
  if (!ctor) return;
834
835
  if (ctor.type === 'identifier') {
835
- ctx.calls.push({ name: ctor.text, line: node.startPosition.row + 1 });
836
+ ctx.calls.push({ name: ctor.text, line: nodeStartLine(node) });
836
837
  } else if (ctor.type === 'member_expression') {
837
838
  const callInfo = extractCallInfo(ctor, node);
838
839
  if (callInfo) ctx.calls.push(callInfo);
@@ -847,10 +848,10 @@ function handleDynamicImportCall(node: TreeSitterNode, imports: Import[]): void
847
848
  if (strArg) {
848
849
  const modPath = strArg.text.replace(/['"]/g, '');
849
850
  const names = extractDynamicImportNames(node);
850
- imports.push({ source: modPath, names, line: node.startPosition.row + 1, dynamicImport: true });
851
+ imports.push({ source: modPath, names, line: nodeStartLine(node), dynamicImport: true });
851
852
  } else {
852
853
  debug(
853
- `Skipping non-static dynamic import() at line ${node.startPosition.row + 1} (template literal or variable)`,
854
+ `Skipping non-static dynamic import() at line ${nodeStartLine(node)} (template literal or variable)`,
854
855
  );
855
856
  }
856
857
  }
@@ -864,14 +865,14 @@ function handleImportStmt(node: TreeSitterNode, ctx: ExtractorOutput): void {
864
865
  ctx.imports.push({
865
866
  source: modPath,
866
867
  names,
867
- line: node.startPosition.row + 1,
868
+ line: nodeStartLine(node),
868
869
  typeOnly: isTypeOnly,
869
870
  });
870
871
  }
871
872
  }
872
873
 
873
874
  function handleExportStmt(node: TreeSitterNode, ctx: ExtractorOutput): void {
874
- const exportLine = node.startPosition.row + 1;
875
+ const exportLine = nodeStartLine(node);
875
876
  const decl = node.childForFieldName('declaration');
876
877
  if (decl) {
877
878
  const declType = decl.type;
@@ -923,7 +924,7 @@ function extractParameters(node: TreeSitterNode): SubDeclaration[] {
923
924
  if (!child) continue;
924
925
  const t = child.type;
925
926
  if (t === 'identifier') {
926
- params.push({ name: child.text, kind: 'parameter', line: child.startPosition.row + 1 });
927
+ params.push({ name: child.text, kind: 'parameter', line: nodeStartLine(child) });
927
928
  } else if (
928
929
  t === 'required_parameter' ||
929
930
  t === 'optional_parameter' ||
@@ -936,12 +937,12 @@ function extractParameters(node: TreeSitterNode): SubDeclaration[] {
936
937
  (nameNode.type === 'identifier' ||
937
938
  nameNode.type === 'shorthand_property_identifier_pattern')
938
939
  ) {
939
- params.push({ name: nameNode.text, kind: 'parameter', line: child.startPosition.row + 1 });
940
+ params.push({ name: nameNode.text, kind: 'parameter', line: nodeStartLine(child) });
940
941
  }
941
942
  } else if (t === 'rest_pattern' || t === 'rest_element') {
942
943
  const nameNode = child.child(1) || child.childForFieldName('name');
943
944
  if (nameNode && nameNode.type === 'identifier') {
944
- params.push({ name: nameNode.text, kind: 'parameter', line: child.startPosition.row + 1 });
945
+ params.push({ name: nameNode.text, kind: 'parameter', line: nodeStartLine(child) });
945
946
  }
946
947
  }
947
948
  }
@@ -975,7 +976,7 @@ function extractClassProperties(classNode: TreeSitterNode): SubDeclaration[] {
975
976
  props.push({
976
977
  name: nameNode.text,
977
978
  kind: 'property',
978
- line: child.startPosition.row + 1,
979
+ line: nodeStartLine(child),
979
980
  visibility: vis,
980
981
  });
981
982
  }
@@ -1044,8 +1045,8 @@ function extractInterfaceMethods(
1044
1045
  definitions.push({
1045
1046
  name: `${interfaceName}.${nameNode.text}`,
1046
1047
  kind: 'method',
1047
- line: child.startPosition.row + 1,
1048
- endLine: child.endPosition.row + 1,
1048
+ line: nodeStartLine(child),
1049
+ endLine: nodeEndLine(child),
1049
1050
  });
1050
1051
  }
1051
1052
  }
@@ -1216,7 +1217,7 @@ function extractReceiverName(objNode: TreeSitterNode | null): string | undefined
1216
1217
  function extractCallInfo(fn: TreeSitterNode, callNode: TreeSitterNode): Call | null {
1217
1218
  const fnType = fn.type;
1218
1219
  if (fnType === 'identifier') {
1219
- return { name: fn.text, line: callNode.startPosition.row + 1 };
1220
+ return { name: fn.text, line: nodeStartLine(callNode) };
1220
1221
  }
1221
1222
  if (fnType === 'member_expression') {
1222
1223
  return extractMemberExprCallInfo(fn, callNode);
@@ -1233,7 +1234,7 @@ function extractMemberExprCallInfo(fn: TreeSitterNode, callNode: TreeSitterNode)
1233
1234
  const prop = fn.childForFieldName('property');
1234
1235
  if (!prop) return null;
1235
1236
 
1236
- const callLine = callNode.startPosition.row + 1;
1237
+ const callLine = nodeStartLine(callNode);
1237
1238
  const propText = prop.text;
1238
1239
 
1239
1240
  // .call()/.apply()/.bind() — dynamic invocation
@@ -1272,7 +1273,7 @@ function extractSubscriptCallInfo(fn: TreeSitterNode, callNode: TreeSitterNode):
1272
1273
  const receiver = extractReceiverName(obj);
1273
1274
  return {
1274
1275
  name: methodName,
1275
- line: callNode.startPosition.row + 1,
1276
+ line: nodeStartLine(callNode),
1276
1277
  dynamic: true,
1277
1278
  receiver,
1278
1279
  };
@@ -1435,7 +1436,7 @@ function extractCallbackReferenceCalls(callNode: TreeSitterNode): Call[] {
1435
1436
  }
1436
1437
 
1437
1438
  const result: Call[] = [];
1438
- const callLine = callNode.startPosition.row + 1;
1439
+ const callLine = nodeStartLine(callNode);
1439
1440
 
1440
1441
  for (let i = 0; i < args.childCount; i++) {
1441
1442
  const child = args.child(i);
@@ -1540,7 +1541,7 @@ function extractCallbackDefinition(
1540
1541
  return {
1541
1542
  name: `command:${firstWord}`,
1542
1543
  kind: 'function',
1543
- line: cb.startPosition.row + 1,
1544
+ line: nodeStartLine(cb),
1544
1545
  endLine: nodeEndLine(cb),
1545
1546
  };
1546
1547
  }
@@ -1554,7 +1555,7 @@ function extractCallbackDefinition(
1554
1555
  return {
1555
1556
  name: `route:${method.toUpperCase()} ${strArg}`,
1556
1557
  kind: 'function',
1557
- line: cb.startPosition.row + 1,
1558
+ line: nodeStartLine(cb),
1558
1559
  endLine: nodeEndLine(cb),
1559
1560
  };
1560
1561
  }
@@ -1568,7 +1569,7 @@ function extractCallbackDefinition(
1568
1569
  return {
1569
1570
  name: `event:${eventName}`,
1570
1571
  kind: 'function',
1571
- line: cb.startPosition.row + 1,
1572
+ line: nodeStartLine(cb),
1572
1573
  endLine: nodeEndLine(cb),
1573
1574
  };
1574
1575
  }