gitnexus 1.6.3-rc.8 → 1.6.3

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 (285) hide show
  1. package/README.md +21 -5
  2. package/dist/_shared/graph/types.d.ts +16 -0
  3. package/dist/_shared/graph/types.d.ts.map +1 -1
  4. package/dist/_shared/index.d.ts +20 -2
  5. package/dist/_shared/index.d.ts.map +1 -1
  6. package/dist/_shared/index.js +11 -0
  7. package/dist/_shared/index.js.map +1 -1
  8. package/dist/_shared/scope-resolution/def-index.js +2 -2
  9. package/dist/_shared/scope-resolution/def-index.js.map +1 -1
  10. package/dist/_shared/scope-resolution/method-dispatch-index.d.ts +8 -0
  11. package/dist/_shared/scope-resolution/method-dispatch-index.d.ts.map +1 -1
  12. package/dist/_shared/scope-resolution/method-dispatch-index.js +2 -2
  13. package/dist/_shared/scope-resolution/method-dispatch-index.js.map +1 -1
  14. package/dist/_shared/scope-resolution/module-scope-index.d.ts +8 -0
  15. package/dist/_shared/scope-resolution/module-scope-index.d.ts.map +1 -1
  16. package/dist/_shared/scope-resolution/module-scope-index.js +10 -2
  17. package/dist/_shared/scope-resolution/module-scope-index.js.map +1 -1
  18. package/dist/_shared/scope-resolution/parsed-file.d.ts +76 -0
  19. package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -0
  20. package/dist/_shared/scope-resolution/parsed-file.js +54 -0
  21. package/dist/_shared/scope-resolution/parsed-file.js.map +1 -0
  22. package/dist/_shared/scope-resolution/position-index.d.ts +12 -0
  23. package/dist/_shared/scope-resolution/position-index.d.ts.map +1 -1
  24. package/dist/_shared/scope-resolution/position-index.js +2 -2
  25. package/dist/_shared/scope-resolution/position-index.js.map +1 -1
  26. package/dist/_shared/scope-resolution/qualified-name-index.js +2 -2
  27. package/dist/_shared/scope-resolution/qualified-name-index.js.map +1 -1
  28. package/dist/_shared/scope-resolution/reference-site.d.ts +75 -0
  29. package/dist/_shared/scope-resolution/reference-site.d.ts.map +1 -0
  30. package/dist/_shared/scope-resolution/reference-site.js +24 -0
  31. package/dist/_shared/scope-resolution/reference-site.js.map +1 -0
  32. package/dist/_shared/scope-resolution/registries/class-registry.d.ts +27 -0
  33. package/dist/_shared/scope-resolution/registries/class-registry.d.ts.map +1 -0
  34. package/dist/_shared/scope-resolution/registries/class-registry.js +30 -0
  35. package/dist/_shared/scope-resolution/registries/class-registry.js.map +1 -0
  36. package/dist/_shared/scope-resolution/registries/context.d.ts +69 -0
  37. package/dist/_shared/scope-resolution/registries/context.d.ts.map +1 -0
  38. package/dist/_shared/scope-resolution/registries/context.js +44 -0
  39. package/dist/_shared/scope-resolution/registries/context.js.map +1 -0
  40. package/dist/_shared/scope-resolution/registries/evidence.d.ts +56 -0
  41. package/dist/_shared/scope-resolution/registries/evidence.d.ts.map +1 -0
  42. package/dist/_shared/scope-resolution/registries/evidence.js +150 -0
  43. package/dist/_shared/scope-resolution/registries/evidence.js.map +1 -0
  44. package/dist/_shared/scope-resolution/registries/field-registry.d.ts +26 -0
  45. package/dist/_shared/scope-resolution/registries/field-registry.d.ts.map +1 -0
  46. package/dist/_shared/scope-resolution/registries/field-registry.js +31 -0
  47. package/dist/_shared/scope-resolution/registries/field-registry.js.map +1 -0
  48. package/dist/_shared/scope-resolution/registries/lookup-core.d.ts +81 -0
  49. package/dist/_shared/scope-resolution/registries/lookup-core.d.ts.map +1 -0
  50. package/dist/_shared/scope-resolution/registries/lookup-core.js +332 -0
  51. package/dist/_shared/scope-resolution/registries/lookup-core.js.map +1 -0
  52. package/dist/_shared/scope-resolution/registries/lookup-qualified.d.ts +33 -0
  53. package/dist/_shared/scope-resolution/registries/lookup-qualified.d.ts.map +1 -0
  54. package/dist/_shared/scope-resolution/registries/lookup-qualified.js +56 -0
  55. package/dist/_shared/scope-resolution/registries/lookup-qualified.js.map +1 -0
  56. package/dist/_shared/scope-resolution/registries/method-registry.d.ts +36 -0
  57. package/dist/_shared/scope-resolution/registries/method-registry.d.ts.map +1 -0
  58. package/dist/_shared/scope-resolution/registries/method-registry.js +32 -0
  59. package/dist/_shared/scope-resolution/registries/method-registry.js.map +1 -0
  60. package/dist/_shared/scope-resolution/registries/tie-breaks.d.ts +43 -0
  61. package/dist/_shared/scope-resolution/registries/tie-breaks.d.ts.map +1 -0
  62. package/dist/_shared/scope-resolution/registries/tie-breaks.js +60 -0
  63. package/dist/_shared/scope-resolution/registries/tie-breaks.js.map +1 -0
  64. package/dist/_shared/scope-resolution/resolve-type-ref.d.ts +1 -10
  65. package/dist/_shared/scope-resolution/resolve-type-ref.d.ts.map +1 -1
  66. package/dist/_shared/scope-resolution/resolve-type-ref.js +6 -0
  67. package/dist/_shared/scope-resolution/resolve-type-ref.js.map +1 -1
  68. package/dist/_shared/scope-resolution/scope-tree.d.ts +4 -4
  69. package/dist/_shared/scope-resolution/scope-tree.d.ts.map +1 -1
  70. package/dist/_shared/scope-resolution/scope-tree.js +3 -2
  71. package/dist/_shared/scope-resolution/scope-tree.js.map +1 -1
  72. package/dist/_shared/scope-resolution/shadow/aggregate.d.ts +6 -2
  73. package/dist/_shared/scope-resolution/shadow/aggregate.d.ts.map +1 -1
  74. package/dist/_shared/scope-resolution/shadow/aggregate.js +5 -0
  75. package/dist/_shared/scope-resolution/shadow/aggregate.js.map +1 -1
  76. package/dist/_shared/scope-resolution/types.d.ts +11 -0
  77. package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
  78. package/dist/cli/ai-context.js +35 -4
  79. package/dist/cli/analyze.d.ts +27 -0
  80. package/dist/cli/analyze.js +31 -1
  81. package/dist/cli/clean.js +19 -1
  82. package/dist/cli/group.js +73 -0
  83. package/dist/cli/index-repo.js +8 -1
  84. package/dist/cli/index.js +26 -1
  85. package/dist/cli/list.js +11 -1
  86. package/dist/cli/remove.d.ts +30 -0
  87. package/dist/cli/remove.js +99 -0
  88. package/dist/cli/setup.js +185 -57
  89. package/dist/cli/tool.d.ts +5 -0
  90. package/dist/cli/tool.js +42 -0
  91. package/dist/config/ignore-service.d.ts +9 -0
  92. package/dist/config/ignore-service.js +80 -13
  93. package/dist/core/embedding-mode.d.ts +30 -0
  94. package/dist/core/embedding-mode.js +30 -0
  95. package/dist/core/embeddings/ast-utils.js +22 -22
  96. package/dist/core/embeddings/chunker.js +30 -25
  97. package/dist/core/embeddings/embedding-pipeline.d.ts +6 -0
  98. package/dist/core/embeddings/embedding-pipeline.js +15 -6
  99. package/dist/core/embeddings/text-generator.d.ts +1 -1
  100. package/dist/core/embeddings/text-generator.js +33 -24
  101. package/dist/core/embeddings/types.d.ts +43 -1
  102. package/dist/core/embeddings/types.js +101 -29
  103. package/dist/core/git-staleness.d.ts +18 -0
  104. package/dist/core/git-staleness.js +108 -0
  105. package/dist/core/graph/graph.js +115 -20
  106. package/dist/core/graph/types.d.ts +12 -1
  107. package/dist/core/group/config-parser.d.ts +4 -0
  108. package/dist/core/group/config-parser.js +18 -1
  109. package/dist/core/group/cross-impact.d.ts +41 -0
  110. package/dist/core/group/cross-impact.js +441 -0
  111. package/dist/core/group/extractors/http-patterns/php.js +126 -18
  112. package/dist/core/group/group-path-utils.d.ts +17 -0
  113. package/dist/core/group/group-path-utils.js +40 -0
  114. package/dist/core/group/resolve-at-member.d.ts +10 -0
  115. package/dist/core/group/resolve-at-member.js +31 -0
  116. package/dist/core/group/service.d.ts +9 -0
  117. package/dist/core/group/service.js +259 -25
  118. package/dist/core/group/types.d.ts +30 -0
  119. package/dist/core/ingestion/ast-cache.d.ts +16 -1
  120. package/dist/core/ingestion/ast-cache.js +14 -2
  121. package/dist/core/ingestion/call-processor.js +9 -0
  122. package/dist/core/ingestion/emit-references.d.ts +88 -0
  123. package/dist/core/ingestion/emit-references.js +229 -0
  124. package/dist/core/ingestion/filesystem-walker.js +6 -4
  125. package/dist/core/ingestion/finalize-orchestrator.d.ts +63 -0
  126. package/dist/core/ingestion/finalize-orchestrator.js +139 -0
  127. package/dist/core/ingestion/framework-detection.js +6 -2
  128. package/dist/core/ingestion/import-processor.js +4 -0
  129. package/dist/core/ingestion/import-resolvers/python.js +9 -6
  130. package/dist/core/ingestion/import-target-adapter.d.ts +73 -0
  131. package/dist/core/ingestion/import-target-adapter.js +95 -0
  132. package/dist/core/ingestion/language-provider.d.ts +36 -33
  133. package/dist/core/ingestion/languages/csharp/accessor-unwrap.d.ts +21 -0
  134. package/dist/core/ingestion/languages/csharp/accessor-unwrap.js +56 -0
  135. package/dist/core/ingestion/languages/csharp/arity-metadata.d.ts +26 -0
  136. package/dist/core/ingestion/languages/csharp/arity-metadata.js +46 -0
  137. package/dist/core/ingestion/languages/csharp/arity.d.ts +23 -0
  138. package/dist/core/ingestion/languages/csharp/arity.js +37 -0
  139. package/dist/core/ingestion/languages/csharp/cache-stats.d.ts +15 -0
  140. package/dist/core/ingestion/languages/csharp/cache-stats.js +26 -0
  141. package/dist/core/ingestion/languages/csharp/captures.d.ts +19 -0
  142. package/dist/core/ingestion/languages/csharp/captures.js +249 -0
  143. package/dist/core/ingestion/languages/csharp/import-decomposer.d.ts +19 -0
  144. package/dist/core/ingestion/languages/csharp/import-decomposer.js +93 -0
  145. package/dist/core/ingestion/languages/csharp/import-target.d.ts +25 -0
  146. package/dist/core/ingestion/languages/csharp/import-target.js +123 -0
  147. package/dist/core/ingestion/languages/csharp/index.d.ts +82 -0
  148. package/dist/core/ingestion/languages/csharp/index.js +82 -0
  149. package/dist/core/ingestion/languages/csharp/interpret.d.ts +15 -0
  150. package/dist/core/ingestion/languages/csharp/interpret.js +132 -0
  151. package/dist/core/ingestion/languages/csharp/merge-bindings.d.ts +27 -0
  152. package/dist/core/ingestion/languages/csharp/merge-bindings.js +55 -0
  153. package/dist/core/ingestion/languages/csharp/namespace-siblings.d.ts +50 -0
  154. package/dist/core/ingestion/languages/csharp/namespace-siblings.js +374 -0
  155. package/dist/core/ingestion/languages/csharp/query.d.ts +35 -0
  156. package/dist/core/ingestion/languages/csharp/query.js +515 -0
  157. package/dist/core/ingestion/languages/csharp/receiver-binding.d.ts +31 -0
  158. package/dist/core/ingestion/languages/csharp/receiver-binding.js +135 -0
  159. package/dist/core/ingestion/languages/csharp/scope-resolver.d.ts +10 -0
  160. package/dist/core/ingestion/languages/csharp/scope-resolver.js +63 -0
  161. package/dist/core/ingestion/languages/csharp/simple-hooks.d.ts +53 -0
  162. package/dist/core/ingestion/languages/csharp/simple-hooks.js +76 -0
  163. package/dist/core/ingestion/languages/csharp.js +14 -0
  164. package/dist/core/ingestion/languages/python/arity-metadata.d.ts +24 -0
  165. package/dist/core/ingestion/languages/python/arity-metadata.js +45 -0
  166. package/dist/core/ingestion/languages/python/arity.d.ts +22 -0
  167. package/dist/core/ingestion/languages/python/arity.js +38 -0
  168. package/dist/core/ingestion/languages/python/cache-stats.d.ts +17 -0
  169. package/dist/core/ingestion/languages/python/cache-stats.js +28 -0
  170. package/dist/core/ingestion/languages/python/captures.d.ts +19 -0
  171. package/dist/core/ingestion/languages/python/captures.js +106 -0
  172. package/dist/core/ingestion/languages/python/import-decomposer.d.ts +15 -0
  173. package/dist/core/ingestion/languages/python/import-decomposer.js +112 -0
  174. package/dist/core/ingestion/languages/python/import-target.d.ts +21 -0
  175. package/dist/core/ingestion/languages/python/import-target.js +99 -0
  176. package/dist/core/ingestion/languages/python/index.d.ts +80 -0
  177. package/dist/core/ingestion/languages/python/index.js +80 -0
  178. package/dist/core/ingestion/languages/python/interpret.d.ts +15 -0
  179. package/dist/core/ingestion/languages/python/interpret.js +191 -0
  180. package/dist/core/ingestion/languages/python/merge-bindings.d.ts +16 -0
  181. package/dist/core/ingestion/languages/python/merge-bindings.js +44 -0
  182. package/dist/core/ingestion/languages/python/query.d.ts +9 -0
  183. package/dist/core/ingestion/languages/python/query.js +267 -0
  184. package/dist/core/ingestion/languages/python/receiver-binding.d.ts +21 -0
  185. package/dist/core/ingestion/languages/python/receiver-binding.js +116 -0
  186. package/dist/core/ingestion/languages/python/scope-resolver.d.ts +16 -0
  187. package/dist/core/ingestion/languages/python/scope-resolver.js +53 -0
  188. package/dist/core/ingestion/languages/python/simple-hooks.d.ts +23 -0
  189. package/dist/core/ingestion/languages/python/simple-hooks.js +35 -0
  190. package/dist/core/ingestion/languages/python.js +14 -0
  191. package/dist/core/ingestion/model/method-registry.d.ts +9 -0
  192. package/dist/core/ingestion/model/method-registry.js +4 -0
  193. package/dist/core/ingestion/model/scope-resolution-indexes.d.ts +59 -0
  194. package/dist/core/ingestion/model/scope-resolution-indexes.js +42 -0
  195. package/dist/core/ingestion/model/semantic-model.d.ts +64 -0
  196. package/dist/core/ingestion/model/semantic-model.js +55 -0
  197. package/dist/core/ingestion/mro-processor.js +38 -22
  198. package/dist/core/ingestion/parsing-processor.d.ts +18 -1
  199. package/dist/core/ingestion/parsing-processor.js +45 -11
  200. package/dist/core/ingestion/pipeline-phases/index.d.ts +1 -0
  201. package/dist/core/ingestion/pipeline-phases/index.js +1 -0
  202. package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +10 -0
  203. package/dist/core/ingestion/pipeline-phases/parse-impl.js +17 -2
  204. package/dist/core/ingestion/pipeline-phases/parse.d.ts +18 -0
  205. package/dist/core/ingestion/pipeline.js +2 -1
  206. package/dist/core/ingestion/registry-primary-flag.d.ts +86 -0
  207. package/dist/core/ingestion/registry-primary-flag.js +111 -0
  208. package/dist/core/ingestion/resolve-references.d.ts +63 -0
  209. package/dist/core/ingestion/resolve-references.js +175 -0
  210. package/dist/core/ingestion/scope-extractor-bridge.d.ts +32 -0
  211. package/dist/core/ingestion/scope-extractor-bridge.js +44 -0
  212. package/dist/core/ingestion/scope-extractor.d.ts +86 -0
  213. package/dist/core/ingestion/scope-extractor.js +758 -0
  214. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +372 -0
  215. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.js +212 -0
  216. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +43 -0
  217. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +79 -0
  218. package/dist/core/ingestion/scope-resolution/graph-bridge/ids.d.ts +57 -0
  219. package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +112 -0
  220. package/dist/core/ingestion/scope-resolution/graph-bridge/imports-to-edges.d.ts +17 -0
  221. package/dist/core/ingestion/scope-resolution/graph-bridge/imports-to-edges.js +46 -0
  222. package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.d.ts +19 -0
  223. package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.js +30 -0
  224. package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.d.ts +37 -0
  225. package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +113 -0
  226. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +38 -0
  227. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +73 -0
  228. package/dist/core/ingestion/scope-resolution/passes/compound-receiver.d.ts +42 -0
  229. package/dist/core/ingestion/scope-resolution/passes/compound-receiver.js +198 -0
  230. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +27 -0
  231. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +131 -0
  232. package/dist/core/ingestion/scope-resolution/passes/imported-return-types.d.ts +48 -0
  233. package/dist/core/ingestion/scope-resolution/passes/imported-return-types.js +130 -0
  234. package/dist/core/ingestion/scope-resolution/passes/mro.d.ts +42 -0
  235. package/dist/core/ingestion/scope-resolution/passes/mro.js +99 -0
  236. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +26 -0
  237. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +61 -0
  238. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +46 -0
  239. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +327 -0
  240. package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +47 -0
  241. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +130 -0
  242. package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.d.ts +68 -0
  243. package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +125 -0
  244. package/dist/core/ingestion/scope-resolution/pipeline/registry.d.ts +17 -0
  245. package/dist/core/ingestion/scope-resolution/pipeline/registry.js +21 -0
  246. package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +66 -0
  247. package/dist/core/ingestion/scope-resolution/pipeline/run.js +157 -0
  248. package/dist/core/ingestion/scope-resolution/scope/namespace-targets.d.ts +36 -0
  249. package/dist/core/ingestion/scope-resolution/scope/namespace-targets.js +52 -0
  250. package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +127 -0
  251. package/dist/core/ingestion/scope-resolution/scope/walkers.js +349 -0
  252. package/dist/core/ingestion/scope-resolution/workspace-index.d.ts +52 -0
  253. package/dist/core/ingestion/scope-resolution/workspace-index.js +61 -0
  254. package/dist/core/ingestion/shadow-harness.d.ts +113 -0
  255. package/dist/core/ingestion/shadow-harness.js +148 -0
  256. package/dist/core/ingestion/utils/ast-helpers.d.ts +19 -1
  257. package/dist/core/ingestion/utils/ast-helpers.js +70 -0
  258. package/dist/core/ingestion/utils/max-file-size.d.ts +20 -0
  259. package/dist/core/ingestion/utils/max-file-size.js +52 -0
  260. package/dist/core/ingestion/workers/parse-worker.d.ts +9 -0
  261. package/dist/core/ingestion/workers/parse-worker.js +57 -21
  262. package/dist/core/lbug/lbug-adapter.d.ts +22 -2
  263. package/dist/core/lbug/lbug-adapter.js +58 -14
  264. package/dist/core/lbug/pool-adapter.d.ts +17 -0
  265. package/dist/core/lbug/pool-adapter.js +24 -14
  266. package/dist/core/run-analyze.d.ts +32 -0
  267. package/dist/core/run-analyze.js +74 -19
  268. package/dist/core/search/bm25-index.d.ts +18 -0
  269. package/dist/core/search/bm25-index.js +125 -12
  270. package/dist/core/tree-sitter/parser-loader.js +6 -1
  271. package/dist/mcp/local/local-backend.d.ts +67 -3
  272. package/dist/mcp/local/local-backend.js +296 -34
  273. package/dist/mcp/resources.d.ts +31 -0
  274. package/dist/mcp/resources.js +100 -17
  275. package/dist/mcp/tools.d.ts +4 -1
  276. package/dist/mcp/tools.js +75 -54
  277. package/dist/server/api.js +6 -2
  278. package/dist/storage/git.d.ts +49 -0
  279. package/dist/storage/git.js +111 -0
  280. package/dist/storage/repo-manager.d.ts +246 -1
  281. package/dist/storage/repo-manager.js +391 -9
  282. package/package.json +7 -6
  283. package/scripts/bench-scope-resolution.ts +134 -0
  284. package/scripts/ci-list-migrated-languages.ts +24 -0
  285. package/skills/gitnexus-cli.md +1 -0
@@ -0,0 +1,374 @@
1
+ /**
2
+ * C# same-namespace cross-file visibility.
3
+ *
4
+ * C# makes every type declared in `namespace X` visible to every other
5
+ * file that also declares `namespace X`, without any explicit `using`
6
+ * directive. Python has no equivalent — every cross-file reference
7
+ * needs an explicit import — so this is a C#-specific pass.
8
+ *
9
+ * Without this: `Service.cs` (namespace `FieldTypes`) can't see
10
+ * `User` declared in `Models.cs` (same namespace), so `user.Address`
11
+ * field-chain resolution fails at `findClassBindingInScope('User')`
12
+ * in the Service.cs scope chain.
13
+ *
14
+ * Implementation: after the finalize pass populates `indexes.bindings`
15
+ * (from explicit `using` directives), walk each file's tree-sitter
16
+ * AST for `namespace_declaration` / `file_scoped_namespace_declaration`
17
+ * and `using_directive` nodes. The orchestrator hands us its
18
+ * `treeCache` so files already parsed by `extractParsedFile` are
19
+ * re-used instead of re-parsed — `ParsedFile`'s underlying tree is
20
+ * the single source of truth. Group classes by namespace, and inject
21
+ * cross-file sibling classes into each Namespace scope's finalized
22
+ * bindings with `origin: 'namespace'` — a tier below `local` so a
23
+ * local declaration still shadows a cross-file sibling with the same
24
+ * name.
25
+ *
26
+ * The tree-sitter walk is authoritative: it sees `global using static`,
27
+ * aliased `using static X = Y.Z;`, attributed namespace declarations,
28
+ * and preprocessor-guarded declarations correctly because the
29
+ * tree-sitter grammar parses them as real nodes (not textual
30
+ * coincidences).
31
+ */
32
+ import { getCsharpParser } from './query.js';
33
+ /** Build a structural view of a C# file by walking the tree-sitter
34
+ * AST. Prefers `cachedTree` (handed in via `treeCache`) so we don't
35
+ * re-parse files the orchestrator already parsed for `extractParsedFile`;
36
+ * falls back to a fresh parse on cache miss. Parser singleton is
37
+ * shared across calls. */
38
+ function extractFileStructure(content, cachedTree) {
39
+ const tree = cachedTree ?? getCsharpParser().parse(content);
40
+ const namespaces = [];
41
+ const usingStaticPaths = [];
42
+ const visit = (node) => {
43
+ if (node.type === 'namespace_declaration' ||
44
+ node.type === 'file_scoped_namespace_declaration') {
45
+ const nameNode = node.childForFieldName('name');
46
+ if (nameNode !== null)
47
+ namespaces.push(nameNode.text);
48
+ }
49
+ else if (node.type === 'using_directive') {
50
+ // Inspect the directive's own text for the `static` keyword
51
+ // (tree-sitter-c-sharp does not expose it as a named child).
52
+ // This is a single-node-scoped text inspection, not a whole-file
53
+ // regex, so it stays well within AST semantics.
54
+ if (/^\s*(?:global\s+)?using\s+static\s/.test(node.text)) {
55
+ // Path lives on the `name:` field when the using-directive is
56
+ // aliased (`using static A = X.Y.Z;`); otherwise it's the
57
+ // first named child.
58
+ const aliasField = node.childForFieldName('name');
59
+ let pathNode = null;
60
+ if (aliasField !== null) {
61
+ for (const c of node.namedChildren) {
62
+ if (c !== null && c.startIndex !== aliasField.startIndex) {
63
+ pathNode = c;
64
+ break;
65
+ }
66
+ }
67
+ }
68
+ else {
69
+ pathNode = node.namedChildren[0] ?? null;
70
+ }
71
+ if (pathNode !== null)
72
+ usingStaticPaths.push(pathNode.text);
73
+ }
74
+ }
75
+ for (const child of node.namedChildren) {
76
+ if (child !== null)
77
+ visit(child);
78
+ }
79
+ };
80
+ visit(tree.rootNode);
81
+ return { namespaces, usingStaticPaths };
82
+ }
83
+ /**
84
+ * Mutate `indexes.bindings` in-place, adding cross-file sibling class
85
+ * defs to each Namespace scope. Class-like defs (Class / Interface /
86
+ * Struct / Record / Enum) are visible cross-file; method / field
87
+ * members are not.
88
+ */
89
+ export function populateCsharpNamespaceSiblings(parsedFiles, indexes, inputs) {
90
+ // Build a structural view (namespaces + using-static paths) per
91
+ // file once up-front. Reuses the orchestrator's `treeCache` so
92
+ // files already parsed by `extractParsedFile` don't get re-parsed
93
+ // here — single-source-of-truth for the AST.
94
+ const structureByFile = new Map();
95
+ for (const parsed of parsedFiles) {
96
+ const content = inputs.fileContents.get(parsed.filePath);
97
+ if (content === undefined)
98
+ continue;
99
+ const cachedTree = inputs.treeCache?.get(parsed.filePath);
100
+ structureByFile.set(parsed.filePath, extractFileStructure(content, cachedTree));
101
+ }
102
+ const buckets = new Map();
103
+ const getBucket = (name) => {
104
+ let b = buckets.get(name);
105
+ if (b === undefined) {
106
+ b = { scopes: [], classDefs: [] };
107
+ buckets.set(name, b);
108
+ }
109
+ return b;
110
+ };
111
+ for (const parsed of parsedFiles) {
112
+ const struct = structureByFile.get(parsed.filePath);
113
+ if (struct === undefined)
114
+ continue;
115
+ // Declared namespace names, source order (AST walk visits children
116
+ // left-to-right, matching the scope-extractor's ordering).
117
+ const names = struct.namespaces.length > 0 ? [...struct.namespaces] : [''];
118
+ const namespaceScopes = parsed.scopes.filter((s) => s.kind === 'Namespace');
119
+ // With file-scoped namespaces (`namespace X;`), the Namespace
120
+ // scope's range covers only the declaration line, not the rest of
121
+ // the file — so classes below it land under the Module scope, not
122
+ // the Namespace scope. Group top-level classes by "any class whose
123
+ // parent scope is Module or Namespace" and attribute them to the
124
+ // first declared namespace in the file. Multiple-namespace files
125
+ // are rare enough that first-wins is the right first pass; fix
126
+ // when the parity suite surfaces a case.
127
+ const moduleScope = parsed.scopes.find((s) => s.kind === 'Module');
128
+ const topLevelParentIds = new Set();
129
+ if (moduleScope !== undefined)
130
+ topLevelParentIds.add(moduleScope.id);
131
+ for (const ns of namespaceScopes)
132
+ topLevelParentIds.add(ns.id);
133
+ // Attribute all top-level classes to the first-declared namespace
134
+ // in this file. Multiple-namespace files are rare and can be
135
+ // addressed if the parity suite surfaces a case. Inject into BOTH
136
+ // the Module and the Namespace scopes — the Module scope is on
137
+ // the ancestor chain of every function body (the Namespace scope
138
+ // is not, because file-scoped `namespace X;` has a 1-line range).
139
+ const firstName = names[0];
140
+ const bucket = getBucket(firstName);
141
+ if (moduleScope !== undefined) {
142
+ bucket.scopes.push({
143
+ filePath: parsed.filePath,
144
+ scopeId: moduleScope.id,
145
+ scope: moduleScope,
146
+ });
147
+ }
148
+ for (const ns of namespaceScopes) {
149
+ bucket.scopes.push({ filePath: parsed.filePath, scopeId: ns.id, scope: ns });
150
+ }
151
+ for (const s of parsed.scopes) {
152
+ if (s.kind !== 'Class')
153
+ continue;
154
+ if (s.parent === null || !topLevelParentIds.has(s.parent))
155
+ continue;
156
+ for (const def of s.ownedDefs) {
157
+ if (isTypeDef(def)) {
158
+ bucket.classDefs.push(def);
159
+ break;
160
+ }
161
+ }
162
+ }
163
+ }
164
+ // Inject cross-file siblings into each namespace scope's finalized
165
+ // bindings. `indexes.bindings` is typed `ReadonlyMap<ScopeId, ...>`
166
+ // but is a plain Map at runtime; mutating here is the established
167
+ // pattern (see `propagateImportedReturnTypes` which does the same
168
+ // for module-scope typeBindings).
169
+ const finalized = indexes.bindings;
170
+ // Cross-namespace type-binding propagation: for each file, mirror
171
+ // method return-type bindings from same-namespace sibling files and
172
+ // from files in namespaces the importer `using`s, into the
173
+ // importer's Module scope typeBindings. This enables
174
+ // chain-follow from `var u = svc.GetUser()` → `GetUser → User`
175
+ // even across files — without it the chain stalls at `GetUser`
176
+ // because the return binding lives in the defining file's Module
177
+ // scope, which isn't an ancestor of the importer's scope chain.
178
+ for (const parsed of parsedFiles) {
179
+ const moduleScope = parsed.scopes.find((s) => s.kind === 'Module');
180
+ if (moduleScope === undefined)
181
+ continue;
182
+ const moduleTypeBindings = moduleScope.typeBindings;
183
+ // Accessible namespaces = this file's own namespaces + every
184
+ // `using namespace X;` target. Source of truth is the cached AST
185
+ // structure captured above.
186
+ const accessibleNamespaces = new Set();
187
+ const struct = structureByFile.get(parsed.filePath);
188
+ if (struct !== undefined) {
189
+ for (const n of struct.namespaces)
190
+ accessibleNamespaces.add(n);
191
+ }
192
+ if (accessibleNamespaces.size === 0)
193
+ accessibleNamespaces.add('');
194
+ for (const imp of parsed.parsedImports) {
195
+ if (imp.kind === 'namespace' && imp.targetRaw !== null) {
196
+ accessibleNamespaces.add(imp.targetRaw);
197
+ }
198
+ }
199
+ // For each accessible namespace, also walk up the dotted path —
200
+ // `using static X.Y.Z;` targets a type, so the real namespace is
201
+ // `X.Y`. Both parse into `accessibleNamespaces` as-is; we probe
202
+ // the bucket map with every prefix.
203
+ const expandedNamespaces = new Set(accessibleNamespaces);
204
+ for (const ns of accessibleNamespaces) {
205
+ const segments = ns.split('.');
206
+ for (let i = segments.length - 1; i > 0; i--) {
207
+ expandedNamespaces.add(segments.slice(0, i).join('.'));
208
+ }
209
+ }
210
+ for (const nsName of expandedNamespaces) {
211
+ const bucket = buckets.get(nsName);
212
+ if (bucket === undefined)
213
+ continue;
214
+ for (const scopeInfo of bucket.scopes) {
215
+ if (scopeInfo.filePath === parsed.filePath)
216
+ continue;
217
+ if (scopeInfo.scope.kind !== 'Module')
218
+ continue;
219
+ for (const [boundName, typeRef] of scopeInfo.scope.typeBindings) {
220
+ if (moduleTypeBindings.has(boundName))
221
+ continue;
222
+ moduleTypeBindings.set(boundName, typeRef);
223
+ }
224
+ }
225
+ }
226
+ }
227
+ // `using static X.Y.Z;` — expose every public static method of
228
+ // class Z as a free-callable binding in the importer's module
229
+ // scope, so `Record(...)` (without `Logger.` qualifier) resolves
230
+ // to `Logger.Record`. AST walk above captured these (including
231
+ // `global using static` and aliased forms).
232
+ for (const parsed of parsedFiles) {
233
+ const struct = structureByFile.get(parsed.filePath);
234
+ if (struct === undefined)
235
+ continue;
236
+ const moduleScope = parsed.scopes.find((s) => s.kind === 'Module');
237
+ if (moduleScope === undefined)
238
+ continue;
239
+ for (const fullPath of struct.usingStaticPaths) {
240
+ const lastDot = fullPath.lastIndexOf('.');
241
+ if (lastDot === -1)
242
+ continue;
243
+ const className = fullPath.slice(lastDot + 1);
244
+ const enclosingNs = fullPath.slice(0, lastDot);
245
+ // Find the target class in the named namespace bucket.
246
+ const bucket = buckets.get(enclosingNs);
247
+ if (bucket === undefined)
248
+ continue;
249
+ const targetDef = bucket.classDefs.find((d) => {
250
+ const q = d.qualifiedName ?? '';
251
+ const simple = q.includes('.') ? q.slice(q.lastIndexOf('.') + 1) : q;
252
+ return simple === className;
253
+ });
254
+ if (targetDef === undefined)
255
+ continue;
256
+ // Inject the class's member methods into the importer's module
257
+ // scope. `memberByOwner` wasn't built yet here, so we walk the
258
+ // file's localDefs to find members with `ownerId === targetDef.nodeId`.
259
+ const targetFile = parsedFiles.find((p) => p.filePath === targetDef.filePath);
260
+ if (targetFile === undefined)
261
+ continue;
262
+ for (const memberDef of targetFile.localDefs) {
263
+ if (memberDef.ownerId !== targetDef.nodeId)
264
+ continue;
265
+ if (memberDef.type !== 'Method' && memberDef.type !== 'Function')
266
+ continue;
267
+ const mq = memberDef.qualifiedName ?? '';
268
+ const simpleName = mq.includes('.') ? mq.slice(mq.lastIndexOf('.') + 1) : mq;
269
+ if (simpleName === '')
270
+ continue;
271
+ // Add to `indexes.bindings[moduleScope]` so
272
+ // `findCallableBindingInScope` picks it up.
273
+ let scopeBindings = finalized.get(moduleScope.id);
274
+ if (scopeBindings === undefined) {
275
+ scopeBindings = new Map();
276
+ finalized.set(moduleScope.id, scopeBindings);
277
+ }
278
+ const existing = scopeBindings.get(simpleName) ?? [];
279
+ if (existing.some((b) => b.def.nodeId === memberDef.nodeId))
280
+ continue;
281
+ existing.push({ def: memberDef, origin: 'import' });
282
+ scopeBindings.set(simpleName, existing);
283
+ }
284
+ }
285
+ }
286
+ // Cross-namespace imports: for each file's `using X;` directive,
287
+ // if `X` matches a known namespace bucket, inject that bucket's
288
+ // classes into the importer's module scope. This is what makes
289
+ // `new User()` in `namespace App;` resolve to `User` declared in
290
+ // a sibling file with `namespace Models;` when the importer says
291
+ // `using Models;`. Legacy uses csproj directory↔namespace mapping;
292
+ // the scope-resolver layer uses the declared namespace directly.
293
+ for (const parsed of parsedFiles) {
294
+ const moduleScope = parsed.scopes.find((s) => s.kind === 'Module');
295
+ if (moduleScope === undefined)
296
+ continue;
297
+ for (const imp of parsed.parsedImports) {
298
+ if (imp.kind !== 'namespace')
299
+ continue;
300
+ const targetNs = imp.targetRaw;
301
+ if (targetNs === null || targetNs === '')
302
+ continue;
303
+ const bucket = buckets.get(targetNs);
304
+ if (bucket === undefined)
305
+ continue;
306
+ for (const def of bucket.classDefs) {
307
+ if (def.filePath === parsed.filePath)
308
+ continue;
309
+ const q = def.qualifiedName ?? '';
310
+ const simpleName = q.includes('.') ? q.slice(q.lastIndexOf('.') + 1) : q;
311
+ if (simpleName === '')
312
+ continue;
313
+ let scopeBindings = finalized.get(moduleScope.id);
314
+ if (scopeBindings === undefined) {
315
+ scopeBindings = new Map();
316
+ finalized.set(moduleScope.id, scopeBindings);
317
+ }
318
+ const existing = scopeBindings.get(simpleName) ?? [];
319
+ if (existing.some((b) => b.def.nodeId === def.nodeId))
320
+ continue;
321
+ existing.push({ def, origin: 'namespace' });
322
+ scopeBindings.set(simpleName, existing);
323
+ }
324
+ }
325
+ }
326
+ for (const [, bucket] of buckets) {
327
+ // De-dup by (nodeId, filePath) across multiple declarations (e.g.
328
+ // partial classes declaring the same name in two files — we take
329
+ // both and leave de-dup to downstream consumers of bindings).
330
+ const defsByName = new Map();
331
+ for (const def of bucket.classDefs) {
332
+ // Simple name = last segment of qualifiedName (e.g. `App.User` → `User`).
333
+ const q = def.qualifiedName ?? '';
334
+ const key = q.includes('.') ? q.slice(q.lastIndexOf('.') + 1) : q;
335
+ if (key === '')
336
+ continue;
337
+ const arr = defsByName.get(key) ?? [];
338
+ arr.push(def);
339
+ defsByName.set(key, arr);
340
+ }
341
+ for (const { scopeId, filePath } of bucket.scopes) {
342
+ let scopeBindings = finalized.get(scopeId);
343
+ if (scopeBindings === undefined) {
344
+ scopeBindings = new Map();
345
+ finalized.set(scopeId, scopeBindings);
346
+ }
347
+ for (const [name, defs] of defsByName) {
348
+ // Skip names already present locally — `origin: 'local'` in
349
+ // scope.bindings would naturally shadow the cross-file
350
+ // namespace entry, but we also keep this index lean.
351
+ const local = bucket.scopes.find((s) => s.filePath === filePath)?.scope.bindings.get(name);
352
+ if (local !== undefined && local.some((b) => b.origin === 'local'))
353
+ continue;
354
+ const existing = scopeBindings.get(name) ?? [];
355
+ for (const def of defs) {
356
+ if (def.filePath === filePath)
357
+ continue; // don't self-reference
358
+ if (existing.some((b) => b.def.nodeId === def.nodeId))
359
+ continue;
360
+ existing.push({ def, origin: 'namespace' });
361
+ }
362
+ if (existing.length > 0)
363
+ scopeBindings.set(name, existing);
364
+ }
365
+ }
366
+ }
367
+ }
368
+ function isTypeDef(def) {
369
+ return (def.type === 'Class' ||
370
+ def.type === 'Interface' ||
371
+ def.type === 'Struct' ||
372
+ def.type === 'Record' ||
373
+ def.type === 'Enum');
374
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Tree-sitter query for C# scope captures (RFC §5.1).
3
+ *
4
+ * Captures the structural skeleton the generic scope-resolution
5
+ * pipeline consumes: scopes (module/namespace/class/function),
6
+ * declarations (class-likes, method-likes, properties, variables,
7
+ * local functions), imports (using directives), type bindings
8
+ * (parameter annotations, variable annotations, constructor
9
+ * inference), and references (call sites, member writes).
10
+ *
11
+ * C# specifics that shape this query:
12
+ *
13
+ * - Both block-scoped (`namespace X { }`) and file-scoped
14
+ * (`namespace X;`) namespaces. tree-sitter-c-sharp emits them
15
+ * under distinct node types (`namespace_declaration` vs
16
+ * `file_scoped_namespace_declaration`); both map to
17
+ * `@scope.namespace` since the scope semantics are identical.
18
+ * - `partial class X` splits a Class def across files. Each file
19
+ * emits its own `@declaration.class`; cross-file resolution is
20
+ * handled at the graph-bridge layer via the qualified-name key.
21
+ * - `using X = Y;` aliases and `using static X;` are interpreted in
22
+ * `interpret.ts` via the `@import.*` captures. All three using
23
+ * flavors share the same anchor (`@import.statement`).
24
+ * - Explicit interface implementations (`void IFoo.Bar() { }`)
25
+ * expose the qualified name via the existing `@declaration.name`
26
+ * — the extractor's `csharpMethodConfig.extractQualifiedName`
27
+ * picks up the explicit qualifier from the method declaration
28
+ * node.
29
+ *
30
+ * Exposes lazy `Parser` and `Query` singletons so callers don't pay
31
+ * tree-sitter init cost per file.
32
+ */
33
+ import Parser from 'tree-sitter';
34
+ export declare function getCsharpParser(): Parser;
35
+ export declare function getCsharpScopeQuery(): Parser.Query;