@optave/codegraph 3.11.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 (223) hide show
  1. package/README.md +38 -31
  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/visitor-utils.d.ts +3 -0
  6. package/dist/ast-analysis/visitor-utils.d.ts.map +1 -1
  7. package/dist/ast-analysis/visitor-utils.js +83 -49
  8. package/dist/ast-analysis/visitor-utils.js.map +1 -1
  9. package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
  10. package/dist/ast-analysis/visitors/ast-store-visitor.js +78 -62
  11. package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
  12. package/dist/ast-analysis/visitors/dataflow-visitor.d.ts.map +1 -1
  13. package/dist/ast-analysis/visitors/dataflow-visitor.js +61 -42
  14. package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
  15. package/dist/cli/commands/embed.d.ts.map +1 -1
  16. package/dist/cli/commands/embed.js +49 -4
  17. package/dist/cli/commands/embed.js.map +1 -1
  18. package/dist/domain/analysis/dependencies.d.ts.map +1 -1
  19. package/dist/domain/analysis/dependencies.js +106 -80
  20. package/dist/domain/analysis/dependencies.js.map +1 -1
  21. package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
  22. package/dist/domain/analysis/fn-impact.js +77 -52
  23. package/dist/domain/analysis/fn-impact.js.map +1 -1
  24. package/dist/domain/analysis/module-map.d.ts.map +1 -1
  25. package/dist/domain/analysis/module-map.js +132 -121
  26. package/dist/domain/analysis/module-map.js.map +1 -1
  27. package/dist/domain/graph/builder/helpers.d.ts +4 -4
  28. package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
  29. package/dist/domain/graph/builder/helpers.js +47 -33
  30. package/dist/domain/graph/builder/helpers.js.map +1 -1
  31. package/dist/domain/graph/builder/incremental.d.ts +6 -0
  32. package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
  33. package/dist/domain/graph/builder/incremental.js +142 -76
  34. package/dist/domain/graph/builder/incremental.js.map +1 -1
  35. package/dist/domain/graph/builder/pipeline.d.ts +1 -44
  36. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
  37. package/dist/domain/graph/builder/pipeline.js +10 -766
  38. package/dist/domain/graph/builder/pipeline.js.map +1 -1
  39. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
  40. package/dist/domain/graph/builder/stages/build-edges.js +133 -96
  41. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
  42. package/dist/domain/graph/builder/stages/build-structure.d.ts.map +1 -1
  43. package/dist/domain/graph/builder/stages/build-structure.js +82 -65
  44. package/dist/domain/graph/builder/stages/build-structure.js.map +1 -1
  45. package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
  46. package/dist/domain/graph/builder/stages/detect-changes.js +84 -56
  47. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
  48. package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
  49. package/dist/domain/graph/builder/stages/finalize.js +60 -51
  50. package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
  51. package/dist/domain/graph/builder/stages/insert-nodes.d.ts +8 -6
  52. package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
  53. package/dist/domain/graph/builder/stages/insert-nodes.js +107 -122
  54. package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
  55. package/dist/domain/graph/builder/stages/native-db-lifecycle.d.ts +14 -0
  56. package/dist/domain/graph/builder/stages/native-db-lifecycle.d.ts.map +1 -0
  57. package/dist/domain/graph/builder/stages/native-db-lifecycle.js +77 -0
  58. package/dist/domain/graph/builder/stages/native-db-lifecycle.js.map +1 -0
  59. package/dist/domain/graph/builder/stages/native-orchestrator.d.ts +62 -0
  60. package/dist/domain/graph/builder/stages/native-orchestrator.d.ts.map +1 -0
  61. package/dist/domain/graph/builder/stages/native-orchestrator.js +747 -0
  62. package/dist/domain/graph/builder/stages/native-orchestrator.js.map +1 -0
  63. package/dist/domain/graph/cycles.d.ts +6 -4
  64. package/dist/domain/graph/cycles.d.ts.map +1 -1
  65. package/dist/domain/graph/cycles.js +50 -55
  66. package/dist/domain/graph/cycles.js.map +1 -1
  67. package/dist/domain/graph/journal.d.ts.map +1 -1
  68. package/dist/domain/graph/journal.js +89 -70
  69. package/dist/domain/graph/journal.js.map +1 -1
  70. package/dist/domain/graph/watcher.d.ts.map +1 -1
  71. package/dist/domain/graph/watcher.js +5 -2
  72. package/dist/domain/graph/watcher.js.map +1 -1
  73. package/dist/domain/parser.d.ts +12 -23
  74. package/dist/domain/parser.d.ts.map +1 -1
  75. package/dist/domain/parser.js +126 -79
  76. package/dist/domain/parser.js.map +1 -1
  77. package/dist/domain/search/generator.d.ts +3 -1
  78. package/dist/domain/search/generator.d.ts.map +1 -1
  79. package/dist/domain/search/generator.js +68 -45
  80. package/dist/domain/search/generator.js.map +1 -1
  81. package/dist/domain/search/models.d.ts +2 -0
  82. package/dist/domain/search/models.d.ts.map +1 -1
  83. package/dist/domain/search/models.js +37 -3
  84. package/dist/domain/search/models.js.map +1 -1
  85. package/dist/domain/search/search/hybrid.d.ts.map +1 -1
  86. package/dist/domain/search/search/hybrid.js +49 -40
  87. package/dist/domain/search/search/hybrid.js.map +1 -1
  88. package/dist/domain/search/search/semantic.d.ts.map +1 -1
  89. package/dist/domain/search/search/semantic.js +69 -49
  90. package/dist/domain/search/search/semantic.js.map +1 -1
  91. package/dist/domain/wasm-worker-entry.js +201 -136
  92. package/dist/domain/wasm-worker-entry.js.map +1 -1
  93. package/dist/extractors/elixir.js +95 -71
  94. package/dist/extractors/elixir.js.map +1 -1
  95. package/dist/extractors/gleam.d.ts.map +1 -1
  96. package/dist/extractors/gleam.js +23 -31
  97. package/dist/extractors/gleam.js.map +1 -1
  98. package/dist/extractors/helpers.d.ts +79 -1
  99. package/dist/extractors/helpers.d.ts.map +1 -1
  100. package/dist/extractors/helpers.js +137 -0
  101. package/dist/extractors/helpers.js.map +1 -1
  102. package/dist/extractors/java.d.ts.map +1 -1
  103. package/dist/extractors/java.js +37 -49
  104. package/dist/extractors/java.js.map +1 -1
  105. package/dist/extractors/javascript.d.ts.map +1 -1
  106. package/dist/extractors/javascript.js +44 -44
  107. package/dist/extractors/javascript.js.map +1 -1
  108. package/dist/extractors/julia.js +27 -34
  109. package/dist/extractors/julia.js.map +1 -1
  110. package/dist/extractors/r.d.ts.map +1 -1
  111. package/dist/extractors/r.js +33 -58
  112. package/dist/extractors/r.js.map +1 -1
  113. package/dist/extractors/solidity.d.ts.map +1 -1
  114. package/dist/extractors/solidity.js +38 -61
  115. package/dist/extractors/solidity.js.map +1 -1
  116. package/dist/features/boundaries.d.ts.map +1 -1
  117. package/dist/features/boundaries.js +49 -39
  118. package/dist/features/boundaries.js.map +1 -1
  119. package/dist/features/cfg.d.ts.map +1 -1
  120. package/dist/features/cfg.js +90 -63
  121. package/dist/features/cfg.js.map +1 -1
  122. package/dist/features/check.d.ts.map +1 -1
  123. package/dist/features/check.js +43 -34
  124. package/dist/features/check.js.map +1 -1
  125. package/dist/features/cochange.d.ts.map +1 -1
  126. package/dist/features/cochange.js +68 -56
  127. package/dist/features/cochange.js.map +1 -1
  128. package/dist/features/complexity.d.ts.map +1 -1
  129. package/dist/features/complexity.js +105 -75
  130. package/dist/features/complexity.js.map +1 -1
  131. package/dist/features/dataflow.d.ts.map +1 -1
  132. package/dist/features/dataflow.js +37 -29
  133. package/dist/features/dataflow.js.map +1 -1
  134. package/dist/features/flow.d.ts.map +1 -1
  135. package/dist/features/flow.js +31 -22
  136. package/dist/features/flow.js.map +1 -1
  137. package/dist/features/graph-enrichment.d.ts.map +1 -1
  138. package/dist/features/graph-enrichment.js +77 -70
  139. package/dist/features/graph-enrichment.js.map +1 -1
  140. package/dist/features/owners.d.ts +17 -26
  141. package/dist/features/owners.d.ts.map +1 -1
  142. package/dist/features/owners.js +120 -109
  143. package/dist/features/owners.js.map +1 -1
  144. package/dist/features/sequence.d.ts.map +1 -1
  145. package/dist/features/sequence.js +59 -54
  146. package/dist/features/sequence.js.map +1 -1
  147. package/dist/features/structure-query.d.ts.map +1 -1
  148. package/dist/features/structure-query.js +60 -60
  149. package/dist/features/structure-query.js.map +1 -1
  150. package/dist/features/structure.js +28 -36
  151. package/dist/features/structure.js.map +1 -1
  152. package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
  153. package/dist/graph/algorithms/leiden/optimiser.js +100 -69
  154. package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
  155. package/dist/graph/classifiers/roles.d.ts.map +1 -1
  156. package/dist/graph/classifiers/roles.js +63 -59
  157. package/dist/graph/classifiers/roles.js.map +1 -1
  158. package/dist/infrastructure/config.d.ts +1 -1
  159. package/dist/infrastructure/config.d.ts.map +1 -1
  160. package/dist/infrastructure/config.js +1 -1
  161. package/dist/infrastructure/config.js.map +1 -1
  162. package/dist/presentation/cfg.d.ts.map +1 -1
  163. package/dist/presentation/cfg.js +44 -29
  164. package/dist/presentation/cfg.js.map +1 -1
  165. package/dist/presentation/flow.d.ts.map +1 -1
  166. package/dist/presentation/flow.js +58 -38
  167. package/dist/presentation/flow.js.map +1 -1
  168. package/dist/types.d.ts +1 -1
  169. package/dist/types.d.ts.map +1 -1
  170. package/package.json +7 -7
  171. package/src/ast-analysis/engine.ts +145 -61
  172. package/src/ast-analysis/visitor-utils.ts +86 -46
  173. package/src/ast-analysis/visitors/ast-store-visitor.ts +104 -69
  174. package/src/ast-analysis/visitors/dataflow-visitor.ts +86 -47
  175. package/src/cli/commands/embed.ts +54 -4
  176. package/src/domain/analysis/dependencies.ts +166 -85
  177. package/src/domain/analysis/fn-impact.ts +120 -50
  178. package/src/domain/analysis/module-map.ts +175 -140
  179. package/src/domain/graph/builder/helpers.ts +85 -76
  180. package/src/domain/graph/builder/incremental.ts +217 -90
  181. package/src/domain/graph/builder/pipeline.ts +19 -957
  182. package/src/domain/graph/builder/stages/build-edges.ts +198 -140
  183. package/src/domain/graph/builder/stages/build-structure.ts +115 -82
  184. package/src/domain/graph/builder/stages/detect-changes.ts +107 -64
  185. package/src/domain/graph/builder/stages/finalize.ts +72 -70
  186. package/src/domain/graph/builder/stages/insert-nodes.ts +154 -120
  187. package/src/domain/graph/builder/stages/native-db-lifecycle.ts +74 -0
  188. package/src/domain/graph/builder/stages/native-orchestrator.ts +942 -0
  189. package/src/domain/graph/cycles.ts +51 -49
  190. package/src/domain/graph/journal.ts +84 -69
  191. package/src/domain/graph/watcher.ts +8 -2
  192. package/src/domain/parser.ts +143 -66
  193. package/src/domain/search/generator.ts +132 -74
  194. package/src/domain/search/models.ts +39 -3
  195. package/src/domain/search/search/hybrid.ts +53 -42
  196. package/src/domain/search/search/semantic.ts +105 -65
  197. package/src/domain/wasm-worker-entry.ts +235 -152
  198. package/src/extractors/elixir.ts +91 -64
  199. package/src/extractors/gleam.ts +33 -37
  200. package/src/extractors/helpers.ts +205 -1
  201. package/src/extractors/java.ts +42 -45
  202. package/src/extractors/javascript.ts +44 -43
  203. package/src/extractors/julia.ts +28 -35
  204. package/src/extractors/r.ts +38 -56
  205. package/src/extractors/solidity.ts +43 -71
  206. package/src/features/boundaries.ts +64 -46
  207. package/src/features/cfg.ts +145 -74
  208. package/src/features/check.ts +60 -43
  209. package/src/features/cochange.ts +95 -72
  210. package/src/features/complexity.ts +134 -79
  211. package/src/features/dataflow.ts +57 -34
  212. package/src/features/flow.ts +48 -24
  213. package/src/features/graph-enrichment.ts +105 -70
  214. package/src/features/owners.ts +186 -146
  215. package/src/features/sequence.ts +99 -69
  216. package/src/features/structure-query.ts +94 -79
  217. package/src/features/structure.ts +56 -56
  218. package/src/graph/algorithms/leiden/optimiser.ts +142 -87
  219. package/src/graph/classifiers/roles.ts +64 -54
  220. package/src/infrastructure/config.ts +1 -1
  221. package/src/presentation/cfg.ts +48 -32
  222. package/src/presentation/flow.ts +100 -52
  223. package/src/types.ts +1 -1
@@ -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
  }
@@ -1,5 +1,5 @@
1
1
  import type { ExtractorOutput, SubDeclaration, TreeSitterNode, TreeSitterTree } from '../types.js';
2
- import { findChild, nodeEndLine } from './helpers.js';
2
+ import { findChild, nodeEndLine, nodeStartLine, pushCall, pushImport } from './helpers.js';
3
3
 
4
4
  /**
5
5
  * Extract symbols from Julia files.
@@ -76,7 +76,7 @@ function handleModuleDef(node: TreeSitterNode, ctx: ExtractorOutput): string | n
76
76
  ctx.definitions.push({
77
77
  name: nameNode.text,
78
78
  kind: 'module',
79
- line: node.startPosition.row + 1,
79
+ line: nodeStartLine(node),
80
80
  endLine: nodeEndLine(node),
81
81
  });
82
82
 
@@ -130,7 +130,7 @@ function handleFunctionDef(
130
130
  ctx.definitions.push({
131
131
  name,
132
132
  kind: 'function',
133
- line: node.startPosition.row + 1,
133
+ line: nodeStartLine(node),
134
134
  endLine: nodeEndLine(node),
135
135
  children: params.length > 0 ? params : undefined,
136
136
  });
@@ -145,7 +145,7 @@ function handleFunctionDef(
145
145
  ctx.definitions.push({
146
146
  name: qualifyName(nameNode.text, currentModule),
147
147
  kind: 'function',
148
- line: node.startPosition.row + 1,
148
+ line: nodeStartLine(node),
149
149
  endLine: nodeEndLine(node),
150
150
  });
151
151
  }
@@ -169,7 +169,7 @@ function handleAssignment(
169
169
  ctx.definitions.push({
170
170
  name: qualifyName(funcNameNode.text, currentModule),
171
171
  kind: 'function',
172
- line: node.startPosition.row + 1,
172
+ line: nodeStartLine(node),
173
173
  endLine: nodeEndLine(node),
174
174
  children: params.length > 0 ? params : undefined,
175
175
  });
@@ -253,14 +253,14 @@ function handleStructDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
253
253
  children.push({
254
254
  name: fieldName.text,
255
255
  kind: 'property',
256
- line: child.startPosition.row + 1,
256
+ line: nodeStartLine(child),
257
257
  });
258
258
  }
259
259
  } else if (child.type === 'identifier') {
260
260
  // Plain identifier fields (no type annotation) appear as direct
261
261
  // identifier children of struct_definition. The type_head is a
262
262
  // separate node so there is nothing to filter out here.
263
- children.push({ name: child.text, kind: 'property', line: child.startPosition.row + 1 });
263
+ children.push({ name: child.text, kind: 'property', line: nodeStartLine(child) });
264
264
  }
265
265
  }
266
266
 
@@ -268,14 +268,14 @@ function handleStructDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
268
268
  ctx.classes.push({
269
269
  name: structName,
270
270
  extends: supertypeNode.text,
271
- line: node.startPosition.row + 1,
271
+ line: nodeStartLine(node),
272
272
  });
273
273
  }
274
274
 
275
275
  ctx.definitions.push({
276
276
  name: structName,
277
277
  kind: 'struct',
278
- line: node.startPosition.row + 1,
278
+ line: nodeStartLine(node),
279
279
  endLine: nodeEndLine(node),
280
280
  children: children.length > 0 ? children : undefined,
281
281
  });
@@ -295,7 +295,7 @@ function handleAbstractDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
295
295
  ctx.definitions.push({
296
296
  name: nameNode.text,
297
297
  kind: 'type',
298
- line: node.startPosition.row + 1,
298
+ line: nodeStartLine(node),
299
299
  endLine: nodeEndLine(node),
300
300
  });
301
301
  }
@@ -319,7 +319,7 @@ function handleMacroDef(
319
319
  ctx.definitions.push({
320
320
  name,
321
321
  kind: 'function',
322
- line: node.startPosition.row + 1,
322
+ line: nodeStartLine(node),
323
323
  endLine: nodeEndLine(node),
324
324
  });
325
325
  }
@@ -363,11 +363,10 @@ function handleImport(node: TreeSitterNode, ctx: ExtractorOutput): void {
363
363
  }
364
364
 
365
365
  if (source) {
366
- ctx.imports.push({
367
- source,
368
- names: names.length > 0 ? names : [source],
369
- line: node.startPosition.row + 1,
370
- });
366
+ // pushImport falls back to source basename for empty `names`. Julia module
367
+ // sources have no `/` separator, so the basename equals `source` — matching
368
+ // the previous explicit `[source]` fallback.
369
+ pushImport(ctx, node, source, names);
371
370
  }
372
371
  }
373
372
 
@@ -388,21 +387,26 @@ function handleCall(node: TreeSitterNode, ctx: ExtractorOutput): void {
388
387
  if (!funcNode) return;
389
388
 
390
389
  if (funcNode.type === 'identifier') {
391
- ctx.calls.push({ name: funcNode.text, line: node.startPosition.row + 1 });
390
+ pushCall(ctx, node, funcNode.text);
392
391
  } else if (funcNode.type === 'field_expression' || funcNode.type === 'scoped_identifier') {
393
392
  const parts = funcNode.text.split('.');
394
393
  if (parts.length >= 2) {
395
- ctx.calls.push({
396
- name: parts[parts.length - 1]!,
394
+ pushCall(ctx, node, parts[parts.length - 1]!, {
397
395
  receiver: parts.slice(0, -1).join('.'),
398
- line: node.startPosition.row + 1,
399
396
  });
400
397
  } else {
401
- ctx.calls.push({ name: funcNode.text, line: node.startPosition.row + 1 });
398
+ pushCall(ctx, node, funcNode.text);
402
399
  }
403
400
  }
404
401
  }
405
402
 
403
+ const JULIA_PARAM_WRAPPER_TYPES = new Set([
404
+ 'typed_parameter',
405
+ 'typed_expression',
406
+ 'optional_parameter',
407
+ 'default_parameter',
408
+ ]);
409
+
406
410
  function extractJuliaParams(callExpr: TreeSitterNode): SubDeclaration[] {
407
411
  const params: SubDeclaration[] = [];
408
412
  const argList = findChild(callExpr, 'argument_list') || findChild(callExpr, 'tuple_expression');
@@ -412,25 +416,14 @@ function extractJuliaParams(callExpr: TreeSitterNode): SubDeclaration[] {
412
416
  const child = argList.child(i);
413
417
  if (!child) continue;
414
418
  if (child.type === 'identifier') {
415
- params.push({ name: child.text, kind: 'parameter', line: child.startPosition.row + 1 });
416
- }
417
- if (child.type === 'typed_parameter' || child.type === 'typed_expression') {
418
- const nameNode = findChild(child, 'identifier');
419
- if (nameNode) {
420
- params.push({
421
- name: nameNode.text,
422
- kind: 'parameter',
423
- line: child.startPosition.row + 1,
424
- });
425
- }
426
- }
427
- if (child.type === 'optional_parameter' || child.type === 'default_parameter') {
419
+ params.push({ name: child.text, kind: 'parameter', line: nodeStartLine(child) });
420
+ } else if (JULIA_PARAM_WRAPPER_TYPES.has(child.type)) {
428
421
  const nameNode = findChild(child, 'identifier');
429
422
  if (nameNode) {
430
423
  params.push({
431
424
  name: nameNode.text,
432
425
  kind: 'parameter',
433
- line: child.startPosition.row + 1,
426
+ line: nodeStartLine(child),
434
427
  });
435
428
  }
436
429
  }