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