@optave/codegraph 3.5.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (346) hide show
  1. package/README.md +47 -21
  2. package/dist/ast-analysis/engine.d.ts.map +1 -1
  3. package/dist/ast-analysis/engine.js +119 -127
  4. package/dist/ast-analysis/engine.js.map +1 -1
  5. package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
  6. package/dist/ast-analysis/visitors/ast-store-visitor.js +14 -1
  7. package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
  8. package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
  9. package/dist/ast-analysis/visitors/complexity-visitor.js +11 -13
  10. package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
  11. package/dist/db/connection.d.ts +12 -2
  12. package/dist/db/connection.d.ts.map +1 -1
  13. package/dist/db/connection.js +81 -53
  14. package/dist/db/connection.js.map +1 -1
  15. package/dist/db/index.d.ts +1 -1
  16. package/dist/db/index.d.ts.map +1 -1
  17. package/dist/db/index.js +1 -1
  18. package/dist/db/index.js.map +1 -1
  19. package/dist/db/migrations.d.ts.map +1 -1
  20. package/dist/db/migrations.js +38 -32
  21. package/dist/db/migrations.js.map +1 -1
  22. package/dist/domain/analysis/context.d.ts.map +1 -1
  23. package/dist/domain/analysis/context.js +51 -66
  24. package/dist/domain/analysis/context.js.map +1 -1
  25. package/dist/domain/analysis/dependencies.d.ts.map +1 -1
  26. package/dist/domain/analysis/dependencies.js +62 -70
  27. package/dist/domain/analysis/dependencies.js.map +1 -1
  28. package/dist/domain/analysis/diff-impact.d.ts +9 -7
  29. package/dist/domain/analysis/diff-impact.d.ts.map +1 -1
  30. package/dist/domain/analysis/exports.d.ts.map +1 -1
  31. package/dist/domain/analysis/exports.js +29 -33
  32. package/dist/domain/analysis/exports.js.map +1 -1
  33. package/dist/domain/analysis/fn-impact.d.ts +15 -17
  34. package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
  35. package/dist/domain/analysis/fn-impact.js +35 -65
  36. package/dist/domain/analysis/fn-impact.js.map +1 -1
  37. package/dist/domain/analysis/module-map.d.ts.map +1 -1
  38. package/dist/domain/analysis/module-map.js +91 -6
  39. package/dist/domain/analysis/module-map.js.map +1 -1
  40. package/dist/domain/analysis/query-helpers.d.ts +20 -0
  41. package/dist/domain/analysis/query-helpers.d.ts.map +1 -0
  42. package/dist/domain/analysis/query-helpers.js +27 -0
  43. package/dist/domain/analysis/query-helpers.js.map +1 -0
  44. package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
  45. package/dist/domain/graph/builder/helpers.js +15 -9
  46. package/dist/domain/graph/builder/helpers.js.map +1 -1
  47. package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
  48. package/dist/domain/graph/builder/incremental.js +3 -2
  49. package/dist/domain/graph/builder/incremental.js.map +1 -1
  50. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
  51. package/dist/domain/graph/builder/pipeline.js +69 -3
  52. package/dist/domain/graph/builder/pipeline.js.map +1 -1
  53. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
  54. package/dist/domain/graph/builder/stages/build-edges.js +7 -51
  55. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
  56. package/dist/domain/graph/builder/stages/build-structure.d.ts.map +1 -1
  57. package/dist/domain/graph/builder/stages/build-structure.js +7 -5
  58. package/dist/domain/graph/builder/stages/build-structure.js.map +1 -1
  59. package/dist/domain/graph/builder/stages/collect-files.js +2 -2
  60. package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
  61. package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
  62. package/dist/domain/graph/builder/stages/detect-changes.js +2 -2
  63. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
  64. package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
  65. package/dist/domain/graph/builder/stages/finalize.js +124 -105
  66. package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
  67. package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
  68. package/dist/domain/graph/builder/stages/insert-nodes.js +28 -15
  69. package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
  70. package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
  71. package/dist/domain/graph/builder/stages/resolve-imports.js +3 -2
  72. package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
  73. package/dist/domain/graph/resolve.d.ts +0 -4
  74. package/dist/domain/graph/resolve.d.ts.map +1 -1
  75. package/dist/domain/graph/resolve.js +32 -48
  76. package/dist/domain/graph/resolve.js.map +1 -1
  77. package/dist/domain/graph/watcher.d.ts.map +1 -1
  78. package/dist/domain/graph/watcher.js +12 -12
  79. package/dist/domain/graph/watcher.js.map +1 -1
  80. package/dist/domain/parser.d.ts +1 -1
  81. package/dist/domain/parser.d.ts.map +1 -1
  82. package/dist/domain/parser.js +206 -101
  83. package/dist/domain/parser.js.map +1 -1
  84. package/dist/domain/search/search/cli-formatter.d.ts.map +1 -1
  85. package/dist/domain/search/search/cli-formatter.js +88 -83
  86. package/dist/domain/search/search/cli-formatter.js.map +1 -1
  87. package/dist/extractors/bash.d.ts +6 -0
  88. package/dist/extractors/bash.d.ts.map +1 -0
  89. package/dist/extractors/bash.js +91 -0
  90. package/dist/extractors/bash.js.map +1 -0
  91. package/dist/extractors/c.d.ts +6 -0
  92. package/dist/extractors/c.d.ts.map +1 -0
  93. package/dist/extractors/c.js +204 -0
  94. package/dist/extractors/c.js.map +1 -0
  95. package/dist/extractors/cpp.d.ts +6 -0
  96. package/dist/extractors/cpp.d.ts.map +1 -0
  97. package/dist/extractors/cpp.js +283 -0
  98. package/dist/extractors/cpp.js.map +1 -0
  99. package/dist/extractors/csharp.d.ts.map +1 -1
  100. package/dist/extractors/csharp.js +42 -54
  101. package/dist/extractors/csharp.js.map +1 -1
  102. package/dist/extractors/dart.d.ts +6 -0
  103. package/dist/extractors/dart.d.ts.map +1 -0
  104. package/dist/extractors/dart.js +277 -0
  105. package/dist/extractors/dart.js.map +1 -0
  106. package/dist/extractors/elixir.d.ts +9 -0
  107. package/dist/extractors/elixir.d.ts.map +1 -0
  108. package/dist/extractors/elixir.js +223 -0
  109. package/dist/extractors/elixir.js.map +1 -0
  110. package/dist/extractors/go.d.ts.map +1 -1
  111. package/dist/extractors/go.js +126 -130
  112. package/dist/extractors/go.js.map +1 -1
  113. package/dist/extractors/haskell.d.ts +8 -0
  114. package/dist/extractors/haskell.d.ts.map +1 -0
  115. package/dist/extractors/haskell.js +217 -0
  116. package/dist/extractors/haskell.js.map +1 -0
  117. package/dist/extractors/hcl.js +6 -6
  118. package/dist/extractors/hcl.js.map +1 -1
  119. package/dist/extractors/helpers.d.ts +32 -1
  120. package/dist/extractors/helpers.d.ts.map +1 -1
  121. package/dist/extractors/helpers.js +74 -0
  122. package/dist/extractors/helpers.js.map +1 -1
  123. package/dist/extractors/index.d.ts +12 -0
  124. package/dist/extractors/index.d.ts.map +1 -1
  125. package/dist/extractors/index.js +12 -0
  126. package/dist/extractors/index.js.map +1 -1
  127. package/dist/extractors/java.d.ts.map +1 -1
  128. package/dist/extractors/java.js +32 -47
  129. package/dist/extractors/java.js.map +1 -1
  130. package/dist/extractors/javascript.d.ts.map +1 -1
  131. package/dist/extractors/javascript.js +306 -292
  132. package/dist/extractors/javascript.js.map +1 -1
  133. package/dist/extractors/kotlin.d.ts +6 -0
  134. package/dist/extractors/kotlin.d.ts.map +1 -0
  135. package/dist/extractors/kotlin.js +275 -0
  136. package/dist/extractors/kotlin.js.map +1 -0
  137. package/dist/extractors/lua.d.ts +6 -0
  138. package/dist/extractors/lua.d.ts.map +1 -0
  139. package/dist/extractors/lua.js +162 -0
  140. package/dist/extractors/lua.js.map +1 -0
  141. package/dist/extractors/ocaml.d.ts +6 -0
  142. package/dist/extractors/ocaml.d.ts.map +1 -0
  143. package/dist/extractors/ocaml.js +236 -0
  144. package/dist/extractors/ocaml.js.map +1 -0
  145. package/dist/extractors/php.d.ts.map +1 -1
  146. package/dist/extractors/php.js +39 -44
  147. package/dist/extractors/php.js.map +1 -1
  148. package/dist/extractors/python.d.ts.map +1 -1
  149. package/dist/extractors/python.js +75 -93
  150. package/dist/extractors/python.js.map +1 -1
  151. package/dist/extractors/ruby.js +6 -13
  152. package/dist/extractors/ruby.js.map +1 -1
  153. package/dist/extractors/rust.d.ts.map +1 -1
  154. package/dist/extractors/rust.js +58 -83
  155. package/dist/extractors/rust.js.map +1 -1
  156. package/dist/extractors/scala.d.ts +6 -0
  157. package/dist/extractors/scala.d.ts.map +1 -0
  158. package/dist/extractors/scala.js +269 -0
  159. package/dist/extractors/scala.js.map +1 -0
  160. package/dist/extractors/swift.d.ts +6 -0
  161. package/dist/extractors/swift.d.ts.map +1 -0
  162. package/dist/extractors/swift.js +275 -0
  163. package/dist/extractors/swift.js.map +1 -0
  164. package/dist/extractors/zig.d.ts +9 -0
  165. package/dist/extractors/zig.d.ts.map +1 -0
  166. package/dist/extractors/zig.js +276 -0
  167. package/dist/extractors/zig.js.map +1 -0
  168. package/dist/features/ast.d.ts +2 -0
  169. package/dist/features/ast.d.ts.map +1 -1
  170. package/dist/features/ast.js +9 -24
  171. package/dist/features/ast.js.map +1 -1
  172. package/dist/features/audit.d.ts.map +1 -1
  173. package/dist/features/audit.js +17 -21
  174. package/dist/features/audit.js.map +1 -1
  175. package/dist/features/branch-compare.d.ts.map +1 -1
  176. package/dist/features/branch-compare.js +47 -3
  177. package/dist/features/branch-compare.js.map +1 -1
  178. package/dist/features/cfg.d.ts +7 -1
  179. package/dist/features/cfg.d.ts.map +1 -1
  180. package/dist/features/cfg.js +72 -61
  181. package/dist/features/cfg.js.map +1 -1
  182. package/dist/features/check.d.ts.map +1 -1
  183. package/dist/features/check.js +79 -62
  184. package/dist/features/check.js.map +1 -1
  185. package/dist/features/complexity-query.d.ts.map +1 -1
  186. package/dist/features/complexity-query.js +142 -137
  187. package/dist/features/complexity-query.js.map +1 -1
  188. package/dist/features/complexity.d.ts +7 -1
  189. package/dist/features/complexity.d.ts.map +1 -1
  190. package/dist/features/complexity.js +62 -1
  191. package/dist/features/complexity.js.map +1 -1
  192. package/dist/features/dataflow.d.ts +7 -1
  193. package/dist/features/dataflow.d.ts.map +1 -1
  194. package/dist/features/dataflow.js +356 -188
  195. package/dist/features/dataflow.js.map +1 -1
  196. package/dist/features/graph-enrichment.d.ts.map +1 -1
  197. package/dist/features/graph-enrichment.js +117 -104
  198. package/dist/features/graph-enrichment.js.map +1 -1
  199. package/dist/features/sequence.d.ts.map +1 -1
  200. package/dist/features/sequence.js +25 -4
  201. package/dist/features/sequence.js.map +1 -1
  202. package/dist/features/structure-query.d.ts.map +1 -1
  203. package/dist/features/structure-query.js +29 -4
  204. package/dist/features/structure-query.js.map +1 -1
  205. package/dist/features/structure.d.ts.map +1 -1
  206. package/dist/features/structure.js +35 -15
  207. package/dist/features/structure.js.map +1 -1
  208. package/dist/graph/algorithms/leiden/adapter.d.ts.map +1 -1
  209. package/dist/graph/algorithms/leiden/adapter.js +88 -73
  210. package/dist/graph/algorithms/leiden/adapter.js.map +1 -1
  211. package/dist/graph/algorithms/leiden/index.js +43 -28
  212. package/dist/graph/algorithms/leiden/index.js.map +1 -1
  213. package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
  214. package/dist/graph/algorithms/leiden/optimiser.js +90 -104
  215. package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
  216. package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -1
  217. package/dist/graph/algorithms/leiden/partition.js +89 -106
  218. package/dist/graph/algorithms/leiden/partition.js.map +1 -1
  219. package/dist/graph/model.d.ts +2 -0
  220. package/dist/graph/model.d.ts.map +1 -1
  221. package/dist/graph/model.js +20 -8
  222. package/dist/graph/model.js.map +1 -1
  223. package/dist/infrastructure/config.d.ts +0 -8
  224. package/dist/infrastructure/config.d.ts.map +1 -1
  225. package/dist/infrastructure/config.js +73 -62
  226. package/dist/infrastructure/config.js.map +1 -1
  227. package/dist/infrastructure/registry.d.ts +0 -8
  228. package/dist/infrastructure/registry.d.ts.map +1 -1
  229. package/dist/infrastructure/registry.js +12 -14
  230. package/dist/infrastructure/registry.js.map +1 -1
  231. package/dist/mcp/server.d.ts.map +1 -1
  232. package/dist/mcp/server.js +45 -36
  233. package/dist/mcp/server.js.map +1 -1
  234. package/dist/presentation/audit.d.ts.map +1 -1
  235. package/dist/presentation/audit.js +61 -57
  236. package/dist/presentation/audit.js.map +1 -1
  237. package/dist/presentation/branch-compare.d.ts.map +1 -1
  238. package/dist/presentation/branch-compare.js +56 -38
  239. package/dist/presentation/branch-compare.js.map +1 -1
  240. package/dist/presentation/check.d.ts.map +1 -1
  241. package/dist/presentation/check.js +30 -32
  242. package/dist/presentation/check.js.map +1 -1
  243. package/dist/presentation/colors.d.ts.map +1 -1
  244. package/dist/presentation/colors.js +2 -0
  245. package/dist/presentation/colors.js.map +1 -1
  246. package/dist/presentation/complexity.d.ts.map +1 -1
  247. package/dist/presentation/complexity.js +25 -19
  248. package/dist/presentation/complexity.js.map +1 -1
  249. package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
  250. package/dist/presentation/queries-cli/exports.js +15 -15
  251. package/dist/presentation/queries-cli/exports.js.map +1 -1
  252. package/dist/presentation/queries-cli/impact.d.ts.map +1 -1
  253. package/dist/presentation/queries-cli/impact.js +29 -19
  254. package/dist/presentation/queries-cli/impact.js.map +1 -1
  255. package/dist/types.d.ts +182 -7
  256. package/dist/types.d.ts.map +1 -1
  257. package/grammars/tree-sitter-bash.wasm +0 -0
  258. package/grammars/tree-sitter-c.wasm +0 -0
  259. package/grammars/tree-sitter-cpp.wasm +0 -0
  260. package/grammars/tree-sitter-dart.wasm +0 -0
  261. package/grammars/tree-sitter-elixir.wasm +0 -0
  262. package/grammars/tree-sitter-haskell.wasm +0 -0
  263. package/grammars/tree-sitter-kotlin.wasm +0 -0
  264. package/grammars/tree-sitter-lua.wasm +0 -0
  265. package/grammars/tree-sitter-ocaml.wasm +0 -0
  266. package/grammars/tree-sitter-scala.wasm +0 -0
  267. package/grammars/tree-sitter-swift.wasm +0 -0
  268. package/grammars/tree-sitter-zig.wasm +0 -0
  269. package/package.json +19 -7
  270. package/src/ast-analysis/engine.ts +147 -138
  271. package/src/ast-analysis/visitors/ast-store-visitor.ts +15 -2
  272. package/src/ast-analysis/visitors/complexity-visitor.ts +11 -11
  273. package/src/db/connection.ts +90 -59
  274. package/src/db/index.ts +1 -0
  275. package/src/db/migrations.ts +36 -32
  276. package/src/domain/analysis/context.ts +73 -75
  277. package/src/domain/analysis/dependencies.ts +78 -68
  278. package/src/domain/analysis/exports.ts +45 -34
  279. package/src/domain/analysis/fn-impact.ts +67 -64
  280. package/src/domain/analysis/module-map.ts +103 -8
  281. package/src/domain/analysis/query-helpers.ts +35 -0
  282. package/src/domain/graph/builder/helpers.ts +12 -6
  283. package/src/domain/graph/builder/incremental.ts +3 -2
  284. package/src/domain/graph/builder/pipeline.ts +71 -3
  285. package/src/domain/graph/builder/stages/build-edges.ts +10 -75
  286. package/src/domain/graph/builder/stages/build-structure.ts +9 -7
  287. package/src/domain/graph/builder/stages/collect-files.ts +2 -2
  288. package/src/domain/graph/builder/stages/detect-changes.ts +7 -2
  289. package/src/domain/graph/builder/stages/finalize.ts +159 -125
  290. package/src/domain/graph/builder/stages/insert-nodes.ts +32 -21
  291. package/src/domain/graph/builder/stages/resolve-imports.ts +3 -2
  292. package/src/domain/graph/resolve.ts +34 -46
  293. package/src/domain/graph/watcher.ts +12 -14
  294. package/src/domain/parser.ts +222 -97
  295. package/src/domain/search/search/cli-formatter.ts +121 -94
  296. package/src/extractors/bash.ts +97 -0
  297. package/src/extractors/c.ts +212 -0
  298. package/src/extractors/cpp.ts +298 -0
  299. package/src/extractors/csharp.ts +53 -56
  300. package/src/extractors/dart.ts +304 -0
  301. package/src/extractors/elixir.ts +251 -0
  302. package/src/extractors/go.ts +152 -134
  303. package/src/extractors/haskell.ts +235 -0
  304. package/src/extractors/hcl.ts +6 -6
  305. package/src/extractors/helpers.ts +93 -1
  306. package/src/extractors/index.ts +12 -0
  307. package/src/extractors/java.ts +43 -48
  308. package/src/extractors/javascript.ts +328 -281
  309. package/src/extractors/kotlin.ts +293 -0
  310. package/src/extractors/lua.ts +169 -0
  311. package/src/extractors/ocaml.ts +259 -0
  312. package/src/extractors/php.ts +46 -40
  313. package/src/extractors/python.ts +81 -104
  314. package/src/extractors/ruby.ts +6 -13
  315. package/src/extractors/rust.ts +65 -85
  316. package/src/extractors/scala.ts +285 -0
  317. package/src/extractors/swift.ts +293 -0
  318. package/src/extractors/zig.ts +294 -0
  319. package/src/features/ast.ts +10 -25
  320. package/src/features/audit.ts +24 -20
  321. package/src/features/branch-compare.ts +51 -4
  322. package/src/features/cfg.ts +113 -65
  323. package/src/features/check.ts +90 -74
  324. package/src/features/complexity-query.ts +181 -163
  325. package/src/features/complexity.ts +64 -1
  326. package/src/features/dataflow.ts +462 -217
  327. package/src/features/graph-enrichment.ts +161 -117
  328. package/src/features/sequence.ts +27 -4
  329. package/src/features/structure-query.ts +43 -4
  330. package/src/features/structure.ts +50 -22
  331. package/src/graph/algorithms/leiden/adapter.ts +126 -71
  332. package/src/graph/algorithms/leiden/index.ts +67 -28
  333. package/src/graph/algorithms/leiden/optimiser.ts +114 -105
  334. package/src/graph/algorithms/leiden/partition.ts +131 -98
  335. package/src/graph/model.ts +19 -7
  336. package/src/infrastructure/config.ts +60 -58
  337. package/src/infrastructure/registry.ts +17 -14
  338. package/src/mcp/server.ts +46 -37
  339. package/src/presentation/audit.ts +72 -67
  340. package/src/presentation/branch-compare.ts +54 -50
  341. package/src/presentation/check.ts +34 -34
  342. package/src/presentation/colors.ts +2 -0
  343. package/src/presentation/complexity.ts +39 -33
  344. package/src/presentation/queries-cli/exports.ts +17 -17
  345. package/src/presentation/queries-cli/impact.ts +30 -22
  346. package/src/types.ts +195 -7
@@ -16,27 +16,51 @@ import type {
16
16
 
17
17
  // Re-export all extractors for backward compatibility
18
18
  export {
19
+ extractBashSymbols,
20
+ extractCppSymbols,
19
21
  extractCSharpSymbols,
22
+ extractCSymbols,
23
+ extractDartSymbols,
24
+ extractElixirSymbols,
20
25
  extractGoSymbols,
26
+ extractHaskellSymbols,
21
27
  extractHCLSymbols,
22
28
  extractJavaSymbols,
29
+ extractKotlinSymbols,
30
+ extractLuaSymbols,
31
+ extractOCamlSymbols,
23
32
  extractPHPSymbols,
24
33
  extractPythonSymbols,
25
34
  extractRubySymbols,
26
35
  extractRustSymbols,
36
+ extractScalaSymbols,
37
+ extractSwiftSymbols,
27
38
  extractSymbols,
39
+ extractZigSymbols,
28
40
  } from '../extractors/index.js';
29
41
 
30
42
  import {
43
+ extractBashSymbols,
44
+ extractCppSymbols,
31
45
  extractCSharpSymbols,
46
+ extractCSymbols,
47
+ extractDartSymbols,
48
+ extractElixirSymbols,
32
49
  extractGoSymbols,
50
+ extractHaskellSymbols,
33
51
  extractHCLSymbols,
34
52
  extractJavaSymbols,
53
+ extractKotlinSymbols,
54
+ extractLuaSymbols,
55
+ extractOCamlSymbols,
35
56
  extractPHPSymbols,
36
57
  extractPythonSymbols,
37
58
  extractRubySymbols,
38
59
  extractRustSymbols,
60
+ extractScalaSymbols,
61
+ extractSwiftSymbols,
39
62
  extractSymbols,
63
+ extractZigSymbols,
40
64
  } from '../extractors/index.js';
41
65
 
42
66
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -273,37 +297,38 @@ function resolveEngine(opts: ParseEngineOpts = {}): ResolvedEngine {
273
297
  * - Backward compat for older native binaries missing js_name annotations
274
298
  * - dataflow argFlows/mutations bindingType -> binding wrapper
275
299
  */
276
- function patchNativeResult(r: any): ExtractorOutput {
277
- // lineCount: napi(js_name) emits "lineCount"; older binaries may emit "line_count"
278
- r.lineCount = r.lineCount ?? r.line_count ?? null;
279
- r._lineCount = r.lineCount;
280
-
281
- // Backward compat for older binaries missing js_name annotations
282
- if (r.definitions) {
283
- for (const d of r.definitions) {
284
- if (d.endLine === undefined && d.end_line !== undefined) {
285
- d.endLine = d.end_line;
286
- }
300
+ /** Patch definition fields for backward compat with older native binaries. */
301
+ function patchDefinitions(definitions: any[]): void {
302
+ for (const d of definitions) {
303
+ if (d.endLine === undefined && d.end_line !== undefined) {
304
+ d.endLine = d.end_line;
287
305
  }
288
306
  }
289
- if (r.imports) {
290
- for (const i of r.imports) {
291
- if (i.typeOnly === undefined) i.typeOnly = i.type_only;
292
- if (i.wildcardReexport === undefined) i.wildcardReexport = i.wildcard_reexport;
293
- if (i.pythonImport === undefined) i.pythonImport = i.python_import;
294
- if (i.goImport === undefined) i.goImport = i.go_import;
295
- if (i.rustUse === undefined) i.rustUse = i.rust_use;
296
- if (i.javaImport === undefined) i.javaImport = i.java_import;
297
- if (i.csharpUsing === undefined) i.csharpUsing = i.csharp_using;
298
- if (i.rubyRequire === undefined) i.rubyRequire = i.ruby_require;
299
- if (i.phpUse === undefined) i.phpUse = i.php_use;
300
- if (i.dynamicImport === undefined) i.dynamicImport = i.dynamic_import;
301
- }
307
+ }
308
+
309
+ /** Patch import fields for backward compat with older native binaries. */
310
+ function patchImports(imports: any[]): void {
311
+ for (const i of imports) {
312
+ if (i.typeOnly === undefined) i.typeOnly = i.type_only;
313
+ if (i.wildcardReexport === undefined) i.wildcardReexport = i.wildcard_reexport;
314
+ if (i.pythonImport === undefined) i.pythonImport = i.python_import;
315
+ if (i.goImport === undefined) i.goImport = i.go_import;
316
+ if (i.rustUse === undefined) i.rustUse = i.rust_use;
317
+ if (i.javaImport === undefined) i.javaImport = i.java_import;
318
+ if (i.csharpUsing === undefined) i.csharpUsing = i.csharp_using;
319
+ if (i.rubyRequire === undefined) i.rubyRequire = i.ruby_require;
320
+ if (i.phpUse === undefined) i.phpUse = i.php_use;
321
+ if (i.cInclude === undefined) i.cInclude = i.c_include;
322
+ if (i.kotlinImport === undefined) i.kotlinImport = i.kotlin_import;
323
+ if (i.swiftImport === undefined) i.swiftImport = i.swift_import;
324
+ if (i.scalaImport === undefined) i.scalaImport = i.scala_import;
325
+ if (i.bashSource === undefined) i.bashSource = i.bash_source;
326
+ if (i.dynamicImport === undefined) i.dynamicImport = i.dynamic_import;
302
327
  }
328
+ }
303
329
 
304
- // typeMap: native returns an array of {name, typeName}; normalize to Map.
305
- // Non-TS languages may omit typeMap entirely — default to empty Map so
306
- // callers can safely access .entries()/.size without null checks.
330
+ /** Normalize native typeMap array to a Map instance. */
331
+ function patchTypeMap(r: any): void {
307
332
  if (!r.typeMap) {
308
333
  r.typeMap = new Map();
309
334
  } else if (!(r.typeMap instanceof Map)) {
@@ -314,20 +339,31 @@ function patchNativeResult(r: any): ExtractorOutput {
314
339
  ]),
315
340
  );
316
341
  }
342
+ }
317
343
 
318
- // dataflow: wrap bindingType into binding object for argFlows and mutations
319
- if (r.dataflow) {
320
- if (r.dataflow.argFlows) {
321
- for (const f of r.dataflow.argFlows) {
322
- f.binding = f.bindingType ? { type: f.bindingType } : null;
323
- }
344
+ /** Wrap bindingType into binding object for dataflow argFlows and mutations. */
345
+ function patchDataflow(dataflow: any): void {
346
+ if (dataflow.argFlows) {
347
+ for (const f of dataflow.argFlows) {
348
+ f.binding = f.bindingType ? { type: f.bindingType } : null;
324
349
  }
325
- if (r.dataflow.mutations) {
326
- for (const m of r.dataflow.mutations) {
327
- m.binding = m.bindingType ? { type: m.bindingType } : null;
328
- }
350
+ }
351
+ if (dataflow.mutations) {
352
+ for (const m of dataflow.mutations) {
353
+ m.binding = m.bindingType ? { type: m.bindingType } : null;
329
354
  }
330
355
  }
356
+ }
357
+
358
+ function patchNativeResult(r: any): ExtractorOutput {
359
+ // lineCount: napi(js_name) emits "lineCount"; older binaries may emit "line_count"
360
+ r.lineCount = r.lineCount ?? r.line_count ?? null;
361
+ r._lineCount = r.lineCount;
362
+
363
+ if (r.definitions) patchDefinitions(r.definitions);
364
+ if (r.imports) patchImports(r.imports);
365
+ patchTypeMap(r);
366
+ if (r.dataflow) patchDataflow(r.dataflow);
331
367
 
332
368
  return r;
333
369
  }
@@ -414,6 +450,90 @@ export const LANGUAGE_REGISTRY: LanguageRegistryEntry[] = [
414
450
  extractor: extractPHPSymbols,
415
451
  required: false,
416
452
  },
453
+ {
454
+ id: 'c',
455
+ extensions: ['.c', '.h'],
456
+ grammarFile: 'tree-sitter-c.wasm',
457
+ extractor: extractCSymbols,
458
+ required: false,
459
+ },
460
+ {
461
+ id: 'cpp',
462
+ extensions: ['.cpp', '.cc', '.cxx', '.hpp'],
463
+ grammarFile: 'tree-sitter-cpp.wasm',
464
+ extractor: extractCppSymbols,
465
+ required: false,
466
+ },
467
+ {
468
+ id: 'kotlin',
469
+ extensions: ['.kt', '.kts'],
470
+ grammarFile: 'tree-sitter-kotlin.wasm',
471
+ extractor: extractKotlinSymbols,
472
+ required: false,
473
+ },
474
+ {
475
+ id: 'swift',
476
+ extensions: ['.swift'],
477
+ grammarFile: 'tree-sitter-swift.wasm',
478
+ extractor: extractSwiftSymbols,
479
+ required: false,
480
+ },
481
+ {
482
+ id: 'scala',
483
+ extensions: ['.scala'],
484
+ grammarFile: 'tree-sitter-scala.wasm',
485
+ extractor: extractScalaSymbols,
486
+ required: false,
487
+ },
488
+ {
489
+ id: 'bash',
490
+ extensions: ['.sh', '.bash'],
491
+ grammarFile: 'tree-sitter-bash.wasm',
492
+ extractor: extractBashSymbols,
493
+ required: false,
494
+ },
495
+ {
496
+ id: 'elixir',
497
+ extensions: ['.ex', '.exs'],
498
+ grammarFile: 'tree-sitter-elixir.wasm',
499
+ extractor: extractElixirSymbols,
500
+ required: false,
501
+ },
502
+ {
503
+ id: 'lua',
504
+ extensions: ['.lua'],
505
+ grammarFile: 'tree-sitter-lua.wasm',
506
+ extractor: extractLuaSymbols,
507
+ required: false,
508
+ },
509
+ {
510
+ id: 'dart',
511
+ extensions: ['.dart'],
512
+ grammarFile: 'tree-sitter-dart.wasm',
513
+ extractor: extractDartSymbols,
514
+ required: false,
515
+ },
516
+ {
517
+ id: 'zig',
518
+ extensions: ['.zig'],
519
+ grammarFile: 'tree-sitter-zig.wasm',
520
+ extractor: extractZigSymbols,
521
+ required: false,
522
+ },
523
+ {
524
+ id: 'haskell',
525
+ extensions: ['.hs'],
526
+ grammarFile: 'tree-sitter-haskell.wasm',
527
+ extractor: extractHaskellSymbols,
528
+ required: false,
529
+ },
530
+ {
531
+ id: 'ocaml',
532
+ extensions: ['.ml', '.mli'],
533
+ grammarFile: 'tree-sitter-ocaml.wasm',
534
+ extractor: extractOCamlSymbols,
535
+ required: false,
536
+ },
417
537
  ];
418
538
 
419
539
  const _extToLang: Map<string, LanguageRegistryEntry> = new Map();
@@ -522,73 +642,48 @@ export async function parseFileAuto(
522
642
  return extracted ? extracted.symbols : null;
523
643
  }
524
644
 
525
- /**
526
- * Parse multiple files in bulk and return a Map<relPath, symbols>.
527
- */
528
- export async function parseFilesAuto(
529
- filePaths: string[],
530
- rootDir: string,
531
- opts: ParseEngineOpts = {},
532
- ): Promise<Map<string, ExtractorOutput>> {
533
- const { native } = resolveEngine(opts);
534
- const result = new Map<string, ExtractorOutput>();
645
+ /** Backfill typeMap via WASM for files missing type-map data from native engine. */
646
+ async function backfillTypeMapBatch(
647
+ needsTypeMap: { filePath: string; relPath: string }[],
648
+ result: Map<string, ExtractorOutput>,
649
+ ): Promise<void> {
650
+ const tsFiles = needsTypeMap.filter(({ filePath }) =>
651
+ TS_BACKFILL_EXTS.has(path.extname(filePath)),
652
+ );
653
+ if (tsFiles.length === 0) return;
535
654
 
536
- if (native) {
537
- const nativeResults = native.parseFiles(
538
- filePaths,
539
- rootDir,
540
- !!opts.dataflow,
541
- opts.ast !== false,
542
- );
543
- const needsTypeMap: { filePath: string; relPath: string }[] = [];
544
- for (const r of nativeResults) {
545
- if (!r) continue;
546
- const patched = patchNativeResult(r);
547
- const relPath = path.relative(rootDir, r.file).split(path.sep).join('/');
548
- result.set(relPath, patched);
549
- if (patched.typeMap.size === 0) {
550
- needsTypeMap.push({ filePath: r.file, relPath });
655
+ const parsers = await createParsers();
656
+ for (const { filePath, relPath } of tsFiles) {
657
+ let extracted: WasmExtractResult | null | undefined;
658
+ try {
659
+ const code = fs.readFileSync(filePath, 'utf-8');
660
+ extracted = wasmExtractSymbols(parsers, filePath, code);
661
+ if (extracted?.symbols && extracted.symbols.typeMap.size > 0) {
662
+ const symbols = result.get(relPath);
663
+ if (!symbols) continue;
664
+ symbols.typeMap = extracted.symbols.typeMap;
665
+ symbols._typeMapBackfilled = true;
551
666
  }
552
- }
553
- // Backfill typeMap via WASM for native binaries that predate the type-map feature
554
- if (needsTypeMap.length > 0) {
555
- // Only backfill for languages where WASM extraction can produce typeMap
556
- // (TS/TSX have type annotations; JS only has `new Expr()` which native already handles)
557
- const tsFiles = needsTypeMap.filter(({ filePath }) =>
558
- TS_BACKFILL_EXTS.has(path.extname(filePath)),
559
- );
560
- if (tsFiles.length > 0) {
561
- const parsers = await createParsers();
562
- for (const { filePath, relPath } of tsFiles) {
563
- let extracted: WasmExtractResult | null | undefined;
564
- try {
565
- const code = fs.readFileSync(filePath, 'utf-8');
566
- extracted = wasmExtractSymbols(parsers, filePath, code);
567
- if (extracted?.symbols && extracted.symbols.typeMap.size > 0) {
568
- const symbols = result.get(relPath);
569
- if (!symbols) continue;
570
- symbols.typeMap = extracted.symbols.typeMap;
571
- symbols._typeMapBackfilled = true;
572
- }
573
- } catch (e) {
574
- debug(`batchExtract: typeMap backfill failed: ${toErrorMessage(e)}`);
575
- } finally {
576
- // Free the WASM tree to prevent memory accumulation across repeated builds
577
- if (extracted?.tree && typeof extracted.tree.delete === 'function') {
578
- try {
579
- extracted.tree.delete();
580
- } catch (e) {
581
- debug(`batchExtract: WASM tree cleanup failed: ${toErrorMessage(e)}`);
582
- }
583
- }
584
- }
667
+ } catch (e) {
668
+ debug(`batchExtract: typeMap backfill failed: ${toErrorMessage(e)}`);
669
+ } finally {
670
+ if (extracted?.tree && typeof extracted.tree.delete === 'function') {
671
+ try {
672
+ extracted.tree.delete();
673
+ } catch (e) {
674
+ debug(`batchExtract: WASM tree cleanup failed: ${toErrorMessage(e)}`);
585
675
  }
586
676
  }
587
677
  }
588
- return result;
589
678
  }
679
+ }
590
680
 
591
- // WASM path
681
+ /** Parse files via WASM engine, returning a Map<relPath, symbols>. */
682
+ async function parseFilesWasm(
683
+ filePaths: string[],
684
+ rootDir: string,
685
+ ): Promise<Map<string, ExtractorOutput>> {
686
+ const result = new Map<string, ExtractorOutput>();
592
687
  const parsers = await createParsers();
593
688
  for (const filePath of filePaths) {
594
689
  let code: string;
@@ -610,6 +705,36 @@ export async function parseFilesAuto(
610
705
  return result;
611
706
  }
612
707
 
708
+ /**
709
+ * Parse multiple files in bulk and return a Map<relPath, symbols>.
710
+ */
711
+ export async function parseFilesAuto(
712
+ filePaths: string[],
713
+ rootDir: string,
714
+ opts: ParseEngineOpts = {},
715
+ ): Promise<Map<string, ExtractorOutput>> {
716
+ const { native } = resolveEngine(opts);
717
+
718
+ if (!native) return parseFilesWasm(filePaths, rootDir);
719
+
720
+ const result = new Map<string, ExtractorOutput>();
721
+ const nativeResults = native.parseFiles(filePaths, rootDir, !!opts.dataflow, opts.ast !== false);
722
+ const needsTypeMap: { filePath: string; relPath: string }[] = [];
723
+ for (const r of nativeResults) {
724
+ if (!r) continue;
725
+ const patched = patchNativeResult(r);
726
+ const relPath = path.relative(rootDir, r.file).split(path.sep).join('/');
727
+ result.set(relPath, patched);
728
+ if (patched.typeMap.size === 0) {
729
+ needsTypeMap.push({ filePath: r.file, relPath });
730
+ }
731
+ }
732
+ if (needsTypeMap.length > 0) {
733
+ await backfillTypeMapBatch(needsTypeMap, result);
734
+ }
735
+ return result;
736
+ }
737
+
613
738
  /**
614
739
  * Report which engine is active.
615
740
  */
@@ -11,113 +11,98 @@ interface SearchOpts extends SemanticSearchOpts {
11
11
  offset?: number;
12
12
  }
13
13
 
14
- export async function search(
15
- query: string,
16
- customDbPath: string | undefined,
17
- opts: SearchOpts = {},
18
- ): Promise<void> {
19
- const mode = opts.mode || 'hybrid';
14
+ const kindIcon = (kind: string): string =>
15
+ kind === 'function' ? 'f' : kind === 'class' ? '*' : 'o';
20
16
 
21
- const queries = query
22
- .split(';')
23
- .map((q) => q.trim())
24
- .filter((q) => q.length > 0);
25
-
26
- const kindIcon = (kind: string): string =>
27
- kind === 'function' ? 'f' : kind === 'class' ? '*' : 'o';
28
-
29
- // Keyword-only mode
30
- if (mode === 'keyword') {
31
- const singleQuery = queries.length === 1 ? queries[0]! : query;
32
- const data = ftsSearchData(singleQuery, customDbPath, opts);
33
- if (!data) {
34
- console.log('No FTS5 index found. Run `codegraph embed` to build the keyword index.');
35
- return;
36
- }
37
- if (opts.json) {
38
- console.log(JSON.stringify(data, null, 2));
39
- return;
40
- }
41
- console.log(`\nKeyword search: "${singleQuery}" (BM25)\n`);
42
- if (data.results.length === 0) {
43
- console.log(' No results found.');
44
- } else {
45
- for (const r of data.results) {
46
- console.log(
47
- ` BM25 ${r.bm25Score.toFixed(2)} ${kindIcon(r.kind)} ${r.name} -- ${r.file}:${r.line}`,
48
- );
49
- }
50
- }
51
- console.log(`\n ${data.results.length} results shown\n`);
17
+ function formatKeywordResults(
18
+ singleQuery: string,
19
+ customDbPath: string | undefined,
20
+ opts: SearchOpts,
21
+ ): void {
22
+ const data = ftsSearchData(singleQuery, customDbPath, opts);
23
+ if (!data) {
24
+ console.log('No FTS5 index found. Run `codegraph embed` to build the keyword index.');
52
25
  return;
53
26
  }
54
-
55
- // Semantic-only mode
56
- if (mode === 'semantic') {
57
- if (queries.length <= 1) {
58
- const singleQuery = queries[0] || query;
59
- const data = await searchData(singleQuery, customDbPath, opts);
60
- if (!data) return;
61
- if (opts.json) {
62
- console.log(JSON.stringify(data, null, 2));
63
- return;
64
- }
65
- console.log(`\nSemantic search: "${singleQuery}"\n`);
66
- if (data.results.length === 0) {
67
- console.log(' No results above threshold.');
68
- } else {
69
- for (const r of data.results) {
70
- const bar = '#'.repeat(Math.round(r.similarity * 20));
71
- console.log(` ${(r.similarity * 100).toFixed(1)}% ${bar}`);
72
- console.log(` ${kindIcon(r.kind)} ${r.name} -- ${r.file}:${r.line}`);
73
- }
74
- }
75
- console.log(`\n ${data.results.length} results shown\n`);
76
- } else {
77
- const data = await multiSearchData(queries, customDbPath, opts);
78
- if (!data) return;
79
- if (opts.json) {
80
- console.log(JSON.stringify(data, null, 2));
81
- return;
82
- }
83
- console.log(`\nMulti-query semantic search (RRF, k=${opts.rrfK || 60}):`);
84
- for (let i = 0; i < queries.length; i++) console.log(` [${i + 1}] "${queries[i]}"`);
85
- console.log();
86
- if (data.results.length === 0) {
87
- console.log(' No results above threshold.');
88
- } else {
89
- for (const r of data.results) {
90
- console.log(
91
- ` RRF ${r.rrf.toFixed(4)} ${kindIcon(r.kind)} ${r.name} -- ${r.file}:${r.line}`,
92
- );
93
- for (const qs of r.queryScores) {
94
- const bar = '#'.repeat(Math.round(qs.similarity * 20));
95
- console.log(
96
- ` [${queries.indexOf(qs.query) + 1}] ${(qs.similarity * 100).toFixed(1)}% ${bar} (rank ${qs.rank})`,
97
- );
98
- }
99
- }
100
- }
101
- console.log(`\n ${data.results.length} results shown\n`);
102
- }
27
+ if (opts.json) {
28
+ console.log(JSON.stringify(data, null, 2));
103
29
  return;
104
30
  }
31
+ console.log(`\nKeyword search: "${singleQuery}" (BM25)\n`);
32
+ if (data.results.length === 0) {
33
+ console.log(' No results found.');
34
+ } else {
35
+ for (const r of data.results) {
36
+ console.log(
37
+ ` BM25 ${r.bm25Score.toFixed(2)} ${kindIcon(r.kind)} ${r.name} -- ${r.file}:${r.line}`,
38
+ );
39
+ }
40
+ }
41
+ console.log(`\n ${data.results.length} results shown\n`);
42
+ }
105
43
 
106
- // Hybrid mode (default)
107
- const data = await hybridSearchData(query, customDbPath, opts);
108
-
109
- if (!data) {
110
- warn(
111
- 'FTS5 index not found using semantic search only. Re-run `codegraph embed` to enable hybrid mode.',
112
- );
113
- return search(query, customDbPath, { ...opts, mode: 'semantic' });
44
+ async function formatSemanticSingle(
45
+ singleQuery: string,
46
+ customDbPath: string | undefined,
47
+ opts: SearchOpts,
48
+ ): Promise<void> {
49
+ const data = await searchData(singleQuery, customDbPath, opts);
50
+ if (!data) return;
51
+ if (opts.json) {
52
+ console.log(JSON.stringify(data, null, 2));
53
+ return;
54
+ }
55
+ console.log(`\nSemantic search: "${singleQuery}"\n`);
56
+ if (data.results.length === 0) {
57
+ console.log(' No results above threshold.');
58
+ } else {
59
+ for (const r of data.results) {
60
+ const bar = '#'.repeat(Math.round(r.similarity * 20));
61
+ console.log(` ${(r.similarity * 100).toFixed(1)}% ${bar}`);
62
+ console.log(` ${kindIcon(r.kind)} ${r.name} -- ${r.file}:${r.line}`);
63
+ }
114
64
  }
65
+ console.log(`\n ${data.results.length} results shown\n`);
66
+ }
115
67
 
68
+ async function formatSemanticMulti(
69
+ queries: string[],
70
+ customDbPath: string | undefined,
71
+ opts: SearchOpts,
72
+ ): Promise<void> {
73
+ const data = await multiSearchData(queries, customDbPath, opts);
74
+ if (!data) return;
116
75
  if (opts.json) {
117
76
  console.log(JSON.stringify(data, null, 2));
118
77
  return;
119
78
  }
79
+ console.log(`\nMulti-query semantic search (RRF, k=${opts.rrfK || 60}):`);
80
+ for (let i = 0; i < queries.length; i++) console.log(` [${i + 1}] "${queries[i]}"`);
81
+ console.log();
82
+ if (data.results.length === 0) {
83
+ console.log(' No results above threshold.');
84
+ } else {
85
+ for (const r of data.results) {
86
+ console.log(
87
+ ` RRF ${r.rrf.toFixed(4)} ${kindIcon(r.kind)} ${r.name} -- ${r.file}:${r.line}`,
88
+ );
89
+ for (const qs of r.queryScores) {
90
+ const bar = '#'.repeat(Math.round(qs.similarity * 20));
91
+ console.log(
92
+ ` [${queries.indexOf(qs.query) + 1}] ${(qs.similarity * 100).toFixed(1)}% ${bar} (rank ${qs.rank})`,
93
+ );
94
+ }
95
+ }
96
+ }
97
+ console.log(`\n ${data.results.length} results shown\n`);
98
+ }
120
99
 
100
+ function formatHybridResults(
101
+ queries: string[],
102
+ query: string,
103
+ data: { results: any[] },
104
+ opts: SearchOpts,
105
+ ): void {
121
106
  const rrfK = opts.rrfK || 60;
122
107
  if (queries.length <= 1) {
123
108
  const singleQuery = queries[0] || query;
@@ -150,3 +135,45 @@ export async function search(
150
135
 
151
136
  console.log(`\n ${data.results.length} results shown\n`);
152
137
  }
138
+
139
+ export async function search(
140
+ query: string,
141
+ customDbPath: string | undefined,
142
+ opts: SearchOpts = {},
143
+ ): Promise<void> {
144
+ const mode = opts.mode || 'hybrid';
145
+
146
+ const queries = query
147
+ .split(';')
148
+ .map((q) => q.trim())
149
+ .filter((q) => q.length > 0);
150
+
151
+ if (mode === 'keyword') {
152
+ const singleQuery = queries.length === 1 ? queries[0]! : query;
153
+ return formatKeywordResults(singleQuery, customDbPath, opts);
154
+ }
155
+
156
+ if (mode === 'semantic') {
157
+ if (queries.length <= 1) {
158
+ return formatSemanticSingle(queries[0] || query, customDbPath, opts);
159
+ }
160
+ return formatSemanticMulti(queries, customDbPath, opts);
161
+ }
162
+
163
+ // Hybrid mode (default)
164
+ const data = await hybridSearchData(query, customDbPath, opts);
165
+
166
+ if (!data) {
167
+ warn(
168
+ 'FTS5 index not found — using semantic search only. Re-run `codegraph embed` to enable hybrid mode.',
169
+ );
170
+ return search(query, customDbPath, { ...opts, mode: 'semantic' });
171
+ }
172
+
173
+ if (opts.json) {
174
+ console.log(JSON.stringify(data, null, 2));
175
+ return;
176
+ }
177
+
178
+ formatHybridResults(queries, query, data, opts);
179
+ }