@optave/codegraph 3.5.0 → 3.6.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 (310) hide show
  1. package/README.md +35 -14
  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 +164 -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/go.d.ts.map +1 -1
  103. package/dist/extractors/go.js +126 -130
  104. package/dist/extractors/go.js.map +1 -1
  105. package/dist/extractors/hcl.js +6 -6
  106. package/dist/extractors/hcl.js.map +1 -1
  107. package/dist/extractors/helpers.d.ts +32 -1
  108. package/dist/extractors/helpers.d.ts.map +1 -1
  109. package/dist/extractors/helpers.js +74 -0
  110. package/dist/extractors/helpers.js.map +1 -1
  111. package/dist/extractors/index.d.ts +6 -0
  112. package/dist/extractors/index.d.ts.map +1 -1
  113. package/dist/extractors/index.js +6 -0
  114. package/dist/extractors/index.js.map +1 -1
  115. package/dist/extractors/java.d.ts.map +1 -1
  116. package/dist/extractors/java.js +32 -47
  117. package/dist/extractors/java.js.map +1 -1
  118. package/dist/extractors/javascript.d.ts.map +1 -1
  119. package/dist/extractors/javascript.js +306 -292
  120. package/dist/extractors/javascript.js.map +1 -1
  121. package/dist/extractors/kotlin.d.ts +6 -0
  122. package/dist/extractors/kotlin.d.ts.map +1 -0
  123. package/dist/extractors/kotlin.js +275 -0
  124. package/dist/extractors/kotlin.js.map +1 -0
  125. package/dist/extractors/php.d.ts.map +1 -1
  126. package/dist/extractors/php.js +39 -44
  127. package/dist/extractors/php.js.map +1 -1
  128. package/dist/extractors/python.d.ts.map +1 -1
  129. package/dist/extractors/python.js +75 -93
  130. package/dist/extractors/python.js.map +1 -1
  131. package/dist/extractors/ruby.js +6 -13
  132. package/dist/extractors/ruby.js.map +1 -1
  133. package/dist/extractors/rust.d.ts.map +1 -1
  134. package/dist/extractors/rust.js +58 -83
  135. package/dist/extractors/rust.js.map +1 -1
  136. package/dist/extractors/scala.d.ts +6 -0
  137. package/dist/extractors/scala.d.ts.map +1 -0
  138. package/dist/extractors/scala.js +269 -0
  139. package/dist/extractors/scala.js.map +1 -0
  140. package/dist/extractors/swift.d.ts +6 -0
  141. package/dist/extractors/swift.d.ts.map +1 -0
  142. package/dist/extractors/swift.js +275 -0
  143. package/dist/extractors/swift.js.map +1 -0
  144. package/dist/features/ast.d.ts +2 -0
  145. package/dist/features/ast.d.ts.map +1 -1
  146. package/dist/features/ast.js +9 -24
  147. package/dist/features/ast.js.map +1 -1
  148. package/dist/features/audit.d.ts.map +1 -1
  149. package/dist/features/audit.js +17 -21
  150. package/dist/features/audit.js.map +1 -1
  151. package/dist/features/branch-compare.d.ts.map +1 -1
  152. package/dist/features/branch-compare.js +47 -3
  153. package/dist/features/branch-compare.js.map +1 -1
  154. package/dist/features/cfg.d.ts +7 -1
  155. package/dist/features/cfg.d.ts.map +1 -1
  156. package/dist/features/cfg.js +118 -62
  157. package/dist/features/cfg.js.map +1 -1
  158. package/dist/features/check.d.ts.map +1 -1
  159. package/dist/features/check.js +79 -62
  160. package/dist/features/check.js.map +1 -1
  161. package/dist/features/complexity-query.d.ts.map +1 -1
  162. package/dist/features/complexity-query.js +142 -137
  163. package/dist/features/complexity-query.js.map +1 -1
  164. package/dist/features/complexity.d.ts +7 -1
  165. package/dist/features/complexity.d.ts.map +1 -1
  166. package/dist/features/complexity.js +62 -1
  167. package/dist/features/complexity.js.map +1 -1
  168. package/dist/features/dataflow.d.ts +7 -1
  169. package/dist/features/dataflow.d.ts.map +1 -1
  170. package/dist/features/dataflow.js +356 -188
  171. package/dist/features/dataflow.js.map +1 -1
  172. package/dist/features/graph-enrichment.d.ts.map +1 -1
  173. package/dist/features/graph-enrichment.js +117 -104
  174. package/dist/features/graph-enrichment.js.map +1 -1
  175. package/dist/features/sequence.d.ts.map +1 -1
  176. package/dist/features/sequence.js +25 -4
  177. package/dist/features/sequence.js.map +1 -1
  178. package/dist/features/structure-query.d.ts.map +1 -1
  179. package/dist/features/structure-query.js +29 -4
  180. package/dist/features/structure-query.js.map +1 -1
  181. package/dist/features/structure.d.ts.map +1 -1
  182. package/dist/features/structure.js +35 -15
  183. package/dist/features/structure.js.map +1 -1
  184. package/dist/graph/algorithms/leiden/adapter.d.ts.map +1 -1
  185. package/dist/graph/algorithms/leiden/adapter.js +88 -73
  186. package/dist/graph/algorithms/leiden/adapter.js.map +1 -1
  187. package/dist/graph/algorithms/leiden/index.js +43 -28
  188. package/dist/graph/algorithms/leiden/index.js.map +1 -1
  189. package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
  190. package/dist/graph/algorithms/leiden/optimiser.js +90 -104
  191. package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
  192. package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -1
  193. package/dist/graph/algorithms/leiden/partition.js +89 -106
  194. package/dist/graph/algorithms/leiden/partition.js.map +1 -1
  195. package/dist/graph/model.d.ts +2 -0
  196. package/dist/graph/model.d.ts.map +1 -1
  197. package/dist/graph/model.js +20 -8
  198. package/dist/graph/model.js.map +1 -1
  199. package/dist/infrastructure/config.d.ts +0 -8
  200. package/dist/infrastructure/config.d.ts.map +1 -1
  201. package/dist/infrastructure/config.js +73 -62
  202. package/dist/infrastructure/config.js.map +1 -1
  203. package/dist/infrastructure/registry.d.ts +0 -8
  204. package/dist/infrastructure/registry.d.ts.map +1 -1
  205. package/dist/infrastructure/registry.js +12 -14
  206. package/dist/infrastructure/registry.js.map +1 -1
  207. package/dist/mcp/server.d.ts.map +1 -1
  208. package/dist/mcp/server.js +45 -36
  209. package/dist/mcp/server.js.map +1 -1
  210. package/dist/presentation/audit.d.ts.map +1 -1
  211. package/dist/presentation/audit.js +61 -57
  212. package/dist/presentation/audit.js.map +1 -1
  213. package/dist/presentation/branch-compare.d.ts.map +1 -1
  214. package/dist/presentation/branch-compare.js +56 -38
  215. package/dist/presentation/branch-compare.js.map +1 -1
  216. package/dist/presentation/check.d.ts.map +1 -1
  217. package/dist/presentation/check.js +30 -32
  218. package/dist/presentation/check.js.map +1 -1
  219. package/dist/presentation/colors.d.ts.map +1 -1
  220. package/dist/presentation/colors.js +2 -0
  221. package/dist/presentation/colors.js.map +1 -1
  222. package/dist/presentation/complexity.d.ts.map +1 -1
  223. package/dist/presentation/complexity.js +25 -19
  224. package/dist/presentation/complexity.js.map +1 -1
  225. package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
  226. package/dist/presentation/queries-cli/exports.js +15 -15
  227. package/dist/presentation/queries-cli/exports.js.map +1 -1
  228. package/dist/presentation/queries-cli/impact.d.ts.map +1 -1
  229. package/dist/presentation/queries-cli/impact.js +29 -19
  230. package/dist/presentation/queries-cli/impact.js.map +1 -1
  231. package/dist/types.d.ts +182 -7
  232. package/dist/types.d.ts.map +1 -1
  233. package/grammars/tree-sitter-bash.wasm +0 -0
  234. package/grammars/tree-sitter-c.wasm +0 -0
  235. package/grammars/tree-sitter-cpp.wasm +0 -0
  236. package/grammars/tree-sitter-kotlin.wasm +0 -0
  237. package/grammars/tree-sitter-scala.wasm +0 -0
  238. package/grammars/tree-sitter-swift.wasm +0 -0
  239. package/package.json +13 -7
  240. package/src/ast-analysis/engine.ts +147 -138
  241. package/src/ast-analysis/visitors/ast-store-visitor.ts +15 -2
  242. package/src/ast-analysis/visitors/complexity-visitor.ts +11 -11
  243. package/src/db/connection.ts +90 -59
  244. package/src/db/index.ts +1 -0
  245. package/src/db/migrations.ts +36 -32
  246. package/src/domain/analysis/context.ts +73 -75
  247. package/src/domain/analysis/dependencies.ts +78 -68
  248. package/src/domain/analysis/exports.ts +45 -34
  249. package/src/domain/analysis/fn-impact.ts +67 -64
  250. package/src/domain/analysis/module-map.ts +103 -8
  251. package/src/domain/analysis/query-helpers.ts +35 -0
  252. package/src/domain/graph/builder/helpers.ts +12 -6
  253. package/src/domain/graph/builder/incremental.ts +3 -2
  254. package/src/domain/graph/builder/pipeline.ts +71 -3
  255. package/src/domain/graph/builder/stages/build-edges.ts +10 -75
  256. package/src/domain/graph/builder/stages/build-structure.ts +9 -7
  257. package/src/domain/graph/builder/stages/collect-files.ts +2 -2
  258. package/src/domain/graph/builder/stages/detect-changes.ts +7 -2
  259. package/src/domain/graph/builder/stages/finalize.ts +159 -125
  260. package/src/domain/graph/builder/stages/insert-nodes.ts +32 -21
  261. package/src/domain/graph/builder/stages/resolve-imports.ts +3 -2
  262. package/src/domain/graph/resolve.ts +34 -46
  263. package/src/domain/graph/watcher.ts +12 -14
  264. package/src/domain/parser.ts +168 -97
  265. package/src/domain/search/search/cli-formatter.ts +121 -94
  266. package/src/extractors/bash.ts +97 -0
  267. package/src/extractors/c.ts +212 -0
  268. package/src/extractors/cpp.ts +298 -0
  269. package/src/extractors/csharp.ts +53 -56
  270. package/src/extractors/go.ts +152 -134
  271. package/src/extractors/hcl.ts +6 -6
  272. package/src/extractors/helpers.ts +93 -1
  273. package/src/extractors/index.ts +6 -0
  274. package/src/extractors/java.ts +43 -48
  275. package/src/extractors/javascript.ts +328 -281
  276. package/src/extractors/kotlin.ts +293 -0
  277. package/src/extractors/php.ts +46 -40
  278. package/src/extractors/python.ts +81 -104
  279. package/src/extractors/ruby.ts +6 -13
  280. package/src/extractors/rust.ts +65 -85
  281. package/src/extractors/scala.ts +285 -0
  282. package/src/extractors/swift.ts +293 -0
  283. package/src/features/ast.ts +10 -25
  284. package/src/features/audit.ts +24 -20
  285. package/src/features/branch-compare.ts +51 -4
  286. package/src/features/cfg.ts +158 -65
  287. package/src/features/check.ts +90 -74
  288. package/src/features/complexity-query.ts +181 -163
  289. package/src/features/complexity.ts +64 -1
  290. package/src/features/dataflow.ts +462 -217
  291. package/src/features/graph-enrichment.ts +161 -117
  292. package/src/features/sequence.ts +27 -4
  293. package/src/features/structure-query.ts +43 -4
  294. package/src/features/structure.ts +50 -22
  295. package/src/graph/algorithms/leiden/adapter.ts +126 -71
  296. package/src/graph/algorithms/leiden/index.ts +67 -28
  297. package/src/graph/algorithms/leiden/optimiser.ts +114 -105
  298. package/src/graph/algorithms/leiden/partition.ts +131 -98
  299. package/src/graph/model.ts +19 -7
  300. package/src/infrastructure/config.ts +60 -58
  301. package/src/infrastructure/registry.ts +17 -14
  302. package/src/mcp/server.ts +46 -37
  303. package/src/presentation/audit.ts +72 -67
  304. package/src/presentation/branch-compare.ts +54 -50
  305. package/src/presentation/check.ts +34 -34
  306. package/src/presentation/colors.ts +2 -0
  307. package/src/presentation/complexity.ts +39 -33
  308. package/src/presentation/queries-cli/exports.ts +17 -17
  309. package/src/presentation/queries-cli/impact.ts +30 -22
  310. package/src/types.ts +189 -7
@@ -0,0 +1,298 @@
1
+ import type {
2
+ Call,
3
+ ExtractorOutput,
4
+ SubDeclaration,
5
+ TreeSitterNode,
6
+ TreeSitterTree,
7
+ } from '../types.js';
8
+ import { extractModifierVisibility, findChild, nodeEndLine } from './helpers.js';
9
+
10
+ /**
11
+ * Extract symbols from C++ files.
12
+ */
13
+ export function extractCppSymbols(tree: TreeSitterTree, _filePath: string): ExtractorOutput {
14
+ const ctx: ExtractorOutput = {
15
+ definitions: [],
16
+ calls: [],
17
+ imports: [],
18
+ classes: [],
19
+ exports: [],
20
+ typeMap: new Map(),
21
+ };
22
+
23
+ walkCppNode(tree.rootNode, ctx);
24
+ return ctx;
25
+ }
26
+
27
+ function walkCppNode(node: TreeSitterNode, ctx: ExtractorOutput): void {
28
+ switch (node.type) {
29
+ case 'function_definition':
30
+ handleCppFunctionDef(node, ctx);
31
+ break;
32
+ case 'class_specifier':
33
+ handleCppClassSpecifier(node, ctx);
34
+ break;
35
+ case 'struct_specifier':
36
+ handleCppStructSpecifier(node, ctx);
37
+ break;
38
+ case 'enum_specifier':
39
+ handleCppEnumSpecifier(node, ctx);
40
+ break;
41
+ case 'namespace_definition':
42
+ handleCppNamespaceDef(node, ctx);
43
+ break;
44
+ case 'type_definition':
45
+ handleCppTypedef(node, ctx);
46
+ break;
47
+ case 'preproc_include':
48
+ handleCppInclude(node, ctx);
49
+ break;
50
+ case 'call_expression':
51
+ handleCppCallExpression(node, ctx);
52
+ break;
53
+ }
54
+
55
+ for (let i = 0; i < node.childCount; i++) {
56
+ const child = node.child(i);
57
+ if (child) walkCppNode(child, ctx);
58
+ }
59
+ }
60
+
61
+ // ── Walk-path per-node-type handlers ────────────────────────────────────────
62
+
63
+ function handleCppFunctionDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
64
+ const declarator = node.childForFieldName('declarator');
65
+ if (!declarator) return;
66
+ const funcDeclarator =
67
+ declarator.type === 'function_declarator'
68
+ ? declarator
69
+ : findChild(declarator, 'function_declarator');
70
+ if (!funcDeclarator) return;
71
+ const nameNode = funcDeclarator.childForFieldName('declarator');
72
+ if (!nameNode) return;
73
+ const name = nameNode.text;
74
+
75
+ // If this function is inside a class/struct field_declaration_list, emit as method
76
+ const parentClass = findCppParentClass(node);
77
+ const fullName = parentClass ? `${parentClass}.${name}` : name;
78
+ const kind = parentClass ? 'method' : 'function';
79
+
80
+ const params = extractCppParameters(funcDeclarator.childForFieldName('parameters'));
81
+ ctx.definitions.push({
82
+ name: fullName,
83
+ kind,
84
+ line: node.startPosition.row + 1,
85
+ endLine: nodeEndLine(node),
86
+ children: params.length > 0 ? params : undefined,
87
+ visibility: parentClass ? extractModifierVisibility(node) : undefined,
88
+ });
89
+ }
90
+
91
+ function handleCppClassSpecifier(node: TreeSitterNode, ctx: ExtractorOutput): void {
92
+ const nameNode = node.childForFieldName('name');
93
+ if (!nameNode) return;
94
+ const children = extractCppClassFields(node);
95
+ ctx.definitions.push({
96
+ name: nameNode.text,
97
+ kind: 'class',
98
+ line: node.startPosition.row + 1,
99
+ endLine: nodeEndLine(node),
100
+ children: children.length > 0 ? children : undefined,
101
+ });
102
+
103
+ // Inheritance via base_class_clause
104
+ const baseClause = findChild(node, 'base_class_clause');
105
+ if (baseClause) {
106
+ for (let i = 0; i < baseClause.childCount; i++) {
107
+ const child = baseClause.child(i);
108
+ if (child && (child.type === 'type_identifier' || child.type === 'qualified_identifier')) {
109
+ ctx.classes.push({
110
+ name: nameNode.text,
111
+ extends: child.text,
112
+ line: node.startPosition.row + 1,
113
+ });
114
+ }
115
+ }
116
+ }
117
+ }
118
+
119
+ function handleCppStructSpecifier(node: TreeSitterNode, ctx: ExtractorOutput): void {
120
+ const nameNode = node.childForFieldName('name');
121
+ if (!nameNode) return;
122
+ const children = extractCppClassFields(node);
123
+ ctx.definitions.push({
124
+ name: nameNode.text,
125
+ kind: 'struct',
126
+ line: node.startPosition.row + 1,
127
+ endLine: nodeEndLine(node),
128
+ children: children.length > 0 ? children : undefined,
129
+ });
130
+
131
+ const baseClause = findChild(node, 'base_class_clause');
132
+ if (baseClause) {
133
+ for (let i = 0; i < baseClause.childCount; i++) {
134
+ const child = baseClause.child(i);
135
+ if (child && (child.type === 'type_identifier' || child.type === 'qualified_identifier')) {
136
+ ctx.classes.push({
137
+ name: nameNode.text,
138
+ extends: child.text,
139
+ line: node.startPosition.row + 1,
140
+ });
141
+ }
142
+ }
143
+ }
144
+ }
145
+
146
+ function handleCppEnumSpecifier(node: TreeSitterNode, ctx: ExtractorOutput): void {
147
+ const nameNode = node.childForFieldName('name');
148
+ if (!nameNode) return;
149
+ const children = extractCppEnumEntries(node);
150
+ ctx.definitions.push({
151
+ name: nameNode.text,
152
+ kind: 'enum',
153
+ line: node.startPosition.row + 1,
154
+ endLine: nodeEndLine(node),
155
+ children: children.length > 0 ? children : undefined,
156
+ });
157
+ }
158
+
159
+ function handleCppNamespaceDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
160
+ const nameNode = node.childForFieldName('name');
161
+ if (!nameNode) return;
162
+ ctx.definitions.push({
163
+ name: nameNode.text,
164
+ kind: 'namespace',
165
+ line: node.startPosition.row + 1,
166
+ endLine: nodeEndLine(node),
167
+ });
168
+ }
169
+
170
+ function handleCppTypedef(node: TreeSitterNode, ctx: ExtractorOutput): void {
171
+ let name: string | undefined;
172
+ for (let i = node.childCount - 1; i >= 0; i--) {
173
+ const child = node.child(i);
174
+ if (
175
+ child &&
176
+ (child.type === 'type_identifier' ||
177
+ child.type === 'identifier' ||
178
+ child.type === 'primitive_type')
179
+ ) {
180
+ name = child.text;
181
+ break;
182
+ }
183
+ }
184
+ if (!name) return;
185
+ ctx.definitions.push({
186
+ name,
187
+ kind: 'type',
188
+ line: node.startPosition.row + 1,
189
+ endLine: nodeEndLine(node),
190
+ });
191
+ }
192
+
193
+ function handleCppInclude(node: TreeSitterNode, ctx: ExtractorOutput): void {
194
+ const pathNode = node.childForFieldName('path');
195
+ if (!pathNode) return;
196
+ const raw = pathNode.text;
197
+ const source = raw.replace(/^["<]|[">]$/g, '');
198
+ const lastName = source.split('/').pop() ?? source;
199
+ ctx.imports.push({
200
+ source,
201
+ names: [lastName],
202
+ line: node.startPosition.row + 1,
203
+ cInclude: true,
204
+ });
205
+ }
206
+
207
+ function handleCppCallExpression(node: TreeSitterNode, ctx: ExtractorOutput): void {
208
+ const funcNode = node.childForFieldName('function');
209
+ if (!funcNode) return;
210
+ const call: Call = { name: '', line: node.startPosition.row + 1 };
211
+ if (funcNode.type === 'field_expression') {
212
+ const field = funcNode.childForFieldName('field');
213
+ const argument = funcNode.childForFieldName('argument');
214
+ if (field) call.name = field.text;
215
+ if (argument) call.receiver = argument.text;
216
+ } else {
217
+ call.name = funcNode.text;
218
+ }
219
+ if (call.name) ctx.calls.push(call);
220
+ }
221
+
222
+ // ── Utility helpers ─────────────────────────────────────────────────────────
223
+
224
+ function findCppParentClass(node: TreeSitterNode): string | null {
225
+ let current = node.parent;
226
+ while (current) {
227
+ if (current.type === 'field_declaration_list') {
228
+ const classNode = current.parent;
229
+ if (
230
+ classNode &&
231
+ (classNode.type === 'class_specifier' || classNode.type === 'struct_specifier')
232
+ ) {
233
+ const nameNode = classNode.childForFieldName('name');
234
+ return nameNode ? nameNode.text : null;
235
+ }
236
+ }
237
+ current = current.parent;
238
+ }
239
+ return null;
240
+ }
241
+
242
+ function extractCppParameters(paramListNode: TreeSitterNode | null): SubDeclaration[] {
243
+ const params: SubDeclaration[] = [];
244
+ if (!paramListNode) return params;
245
+ for (let i = 0; i < paramListNode.childCount; i++) {
246
+ const param = paramListNode.child(i);
247
+ if (!param || param.type !== 'parameter_declaration') continue;
248
+ const nameNode = param.childForFieldName('declarator');
249
+ if (nameNode) {
250
+ const name =
251
+ nameNode.type === 'identifier'
252
+ ? nameNode.text
253
+ : (findChild(nameNode, 'identifier')?.text ?? nameNode.text);
254
+ params.push({ name, kind: 'parameter', line: param.startPosition.row + 1 });
255
+ }
256
+ }
257
+ return params;
258
+ }
259
+
260
+ function extractCppClassFields(classNode: TreeSitterNode): SubDeclaration[] {
261
+ const fields: SubDeclaration[] = [];
262
+ const body =
263
+ classNode.childForFieldName('body') || findChild(classNode, 'field_declaration_list');
264
+ if (!body) return fields;
265
+ for (let i = 0; i < body.childCount; i++) {
266
+ const member = body.child(i);
267
+ if (!member || member.type !== 'field_declaration') continue;
268
+ const nameNode = member.childForFieldName('declarator');
269
+ if (nameNode) {
270
+ const name =
271
+ nameNode.type === 'identifier'
272
+ ? nameNode.text
273
+ : (findChild(nameNode, 'identifier')?.text ?? nameNode.text);
274
+ fields.push({
275
+ name,
276
+ kind: 'property',
277
+ line: member.startPosition.row + 1,
278
+ visibility: extractModifierVisibility(member),
279
+ });
280
+ }
281
+ }
282
+ return fields;
283
+ }
284
+
285
+ function extractCppEnumEntries(enumNode: TreeSitterNode): SubDeclaration[] {
286
+ const entries: SubDeclaration[] = [];
287
+ const body = findChild(enumNode, 'enumerator_list');
288
+ if (!body) return entries;
289
+ for (let i = 0; i < body.childCount; i++) {
290
+ const member = body.child(i);
291
+ if (!member || member.type !== 'enumerator') continue;
292
+ const nameNode = member.childForFieldName('name');
293
+ if (nameNode) {
294
+ entries.push({ name: nameNode.text, kind: 'constant', line: member.startPosition.row + 1 });
295
+ }
296
+ }
297
+ return entries;
298
+ }
@@ -6,7 +6,16 @@ import type {
6
6
  TreeSitterNode,
7
7
  TreeSitterTree,
8
8
  } from '../types.js';
9
- import { extractModifierVisibility, findChild, MAX_WALK_DEPTH, nodeEndLine } from './helpers.js';
9
+ import {
10
+ extractBodyMembers,
11
+ extractModifierVisibility,
12
+ findChild,
13
+ findParentNode,
14
+ lastPathSegment,
15
+ MAX_WALK_DEPTH,
16
+ nodeEndLine,
17
+ setTypeMapEntry,
18
+ } from './helpers.js';
10
19
 
11
20
  /**
12
21
  * Extract symbols from C# files.
@@ -208,7 +217,7 @@ function handleCsUsingDirective(node: TreeSitterNode, ctx: ExtractorOutput): voi
208
217
  findChild(node, 'identifier');
209
218
  if (!nameNode) return;
210
219
  const fullPath = nameNode.text;
211
- const lastName = fullPath.split('.').pop() ?? fullPath;
220
+ const lastName = lastPathSegment(fullPath, '.');
212
221
  ctx.imports.push({
213
222
  source: fullPath,
214
223
  names: [lastName],
@@ -246,22 +255,15 @@ function handleCsObjectCreation(node: TreeSitterNode, ctx: ExtractorOutput): voi
246
255
  if (typeName) ctx.calls.push({ name: typeName, line: node.startPosition.row + 1 });
247
256
  }
248
257
 
258
+ const CS_PARENT_TYPES = [
259
+ 'class_declaration',
260
+ 'struct_declaration',
261
+ 'interface_declaration',
262
+ 'enum_declaration',
263
+ 'record_declaration',
264
+ ] as const;
249
265
  function findCSharpParentType(node: TreeSitterNode): string | null {
250
- let current = node.parent;
251
- while (current) {
252
- if (
253
- current.type === 'class_declaration' ||
254
- current.type === 'struct_declaration' ||
255
- current.type === 'interface_declaration' ||
256
- current.type === 'enum_declaration' ||
257
- current.type === 'record_declaration'
258
- ) {
259
- const nameNode = current.childForFieldName('name');
260
- return nameNode ? nameNode.text : null;
261
- }
262
- current = current.parent;
263
- }
264
- return null;
266
+ return findParentNode(node, CS_PARENT_TYPES);
265
267
  }
266
268
 
267
269
  // ── Child extraction helpers ────────────────────────────────────────────────
@@ -307,19 +309,12 @@ function extractCSharpClassFields(classNode: TreeSitterNode): SubDeclaration[] {
307
309
  }
308
310
 
309
311
  function extractCSharpEnumMembers(enumNode: TreeSitterNode): SubDeclaration[] {
310
- const constants: SubDeclaration[] = [];
311
- const body =
312
- enumNode.childForFieldName('body') || findChild(enumNode, 'enum_member_declaration_list');
313
- if (!body) return constants;
314
- for (let i = 0; i < body.childCount; i++) {
315
- const member = body.child(i);
316
- if (!member || member.type !== 'enum_member_declaration') continue;
317
- const nameNode = member.childForFieldName('name');
318
- if (nameNode) {
319
- constants.push({ name: nameNode.text, kind: 'constant', line: member.startPosition.row + 1 });
320
- }
321
- }
322
- return constants;
312
+ return extractBodyMembers(
313
+ enumNode,
314
+ ['body', 'enum_member_declaration_list'],
315
+ 'enum_member_declaration',
316
+ 'constant',
317
+ );
323
318
  }
324
319
 
325
320
  // ── Type map extraction ──────────────────────────────────────────────────────
@@ -328,6 +323,31 @@ function extractCSharpTypeMap(node: TreeSitterNode, ctx: ExtractorOutput): void
328
323
  extractCSharpTypeMapDepth(node, ctx, 0);
329
324
  }
330
325
 
326
+ /** Extract type info from a variable_declaration node (local vars with explicit types). */
327
+ function handleCSharpVarDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
328
+ const typeNode = node.childForFieldName('type') || node.child(0);
329
+ if (!typeNode || typeNode.type === 'var_keyword') return;
330
+ const typeName = extractCSharpTypeName(typeNode);
331
+ if (!typeName) return;
332
+ for (let i = 0; i < node.childCount; i++) {
333
+ const child = node.child(i);
334
+ if (!child || child.type !== 'variable_declarator') continue;
335
+ const nameNode = child.childForFieldName('name') || child.child(0);
336
+ if (nameNode && nameNode.type === 'identifier' && ctx.typeMap) {
337
+ setTypeMapEntry(ctx.typeMap, nameNode.text, typeName, 0.9);
338
+ }
339
+ }
340
+ }
341
+
342
+ /** Extract type info from a parameter node. */
343
+ function handleCSharpParam(node: TreeSitterNode, ctx: ExtractorOutput): void {
344
+ const typeNode = node.childForFieldName('type');
345
+ const nameNode = node.childForFieldName('name');
346
+ if (!typeNode || !nameNode) return;
347
+ const typeName = extractCSharpTypeName(typeNode);
348
+ if (typeName && ctx.typeMap) setTypeMapEntry(ctx.typeMap, nameNode.text, typeName, 0.9);
349
+ }
350
+
331
351
  function extractCSharpTypeMapDepth(
332
352
  node: TreeSitterNode,
333
353
  ctx: ExtractorOutput,
@@ -335,33 +355,10 @@ function extractCSharpTypeMapDepth(
335
355
  ): void {
336
356
  if (depth >= MAX_WALK_DEPTH) return;
337
357
 
338
- // local_declaration_statement → variable_declaration → type + variable_declarator(s)
339
358
  if (node.type === 'variable_declaration') {
340
- const typeNode = node.childForFieldName('type') || node.child(0);
341
- if (typeNode && typeNode.type !== 'var_keyword') {
342
- const typeName = extractCSharpTypeName(typeNode);
343
- if (typeName) {
344
- for (let i = 0; i < node.childCount; i++) {
345
- const child = node.child(i);
346
- if (child && child.type === 'variable_declarator') {
347
- const nameNode = child.childForFieldName('name') || child.child(0);
348
- if (nameNode && nameNode.type === 'identifier') {
349
- ctx.typeMap?.set(nameNode.text, { type: typeName, confidence: 0.9 });
350
- }
351
- }
352
- }
353
- }
354
- }
355
- }
356
-
357
- // Method/constructor parameter: parameter node has type + name fields
358
- if (node.type === 'parameter') {
359
- const typeNode = node.childForFieldName('type');
360
- const nameNode = node.childForFieldName('name');
361
- if (typeNode && nameNode) {
362
- const typeName = extractCSharpTypeName(typeNode);
363
- if (typeName) ctx.typeMap?.set(nameNode.text, { type: typeName, confidence: 0.9 });
364
- }
359
+ handleCSharpVarDecl(node, ctx);
360
+ } else if (node.type === 'parameter') {
361
+ handleCSharpParam(node, ctx);
365
362
  }
366
363
 
367
364
  for (let i = 0; i < node.childCount; i++) {