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,249 @@
1
+ /**
2
+ * `emitScopeCaptures` for C#.
3
+ *
4
+ * Drives the C# scope query against tree-sitter-c-sharp and groups raw
5
+ * matches into `CaptureMatch[]` for the central extractor. Layers one
6
+ * synthesized stream on top today:
7
+ *
8
+ * 1. **Decomposed using directives** — each `using_directive` is
9
+ * re-emitted with `@import.kind/source/name/alias` markers so
10
+ * `interpretCsharpImport` can recover the ParsedImport shape
11
+ * without re-parsing raw text (see `import-decomposer.ts`).
12
+ *
13
+ * Receiver-binding synthesis (`this` / `base` type anchors) and arity
14
+ * metadata synthesis (Unit 5) layer on top later.
15
+ *
16
+ * Pure given the input source text. No I/O, no globals consulted.
17
+ */
18
+ import { findNodeAtRange, nodeToCapture, syntheticCapture } from '../../utils/ast-helpers.js';
19
+ import { splitUsingDirective } from './import-decomposer.js';
20
+ import { computeCsharpArityMetadata } from './arity-metadata.js';
21
+ import { synthesizeCsharpReceiverBinding } from './receiver-binding.js';
22
+ import { getCsharpParser, getCsharpScopeQuery } from './query.js';
23
+ import { recordCacheHit, recordCacheMiss } from './cache-stats.js';
24
+ /** Declaration anchors that carry function-like arity metadata. */
25
+ const FUNCTION_DECL_TAGS = [
26
+ '@declaration.method',
27
+ '@declaration.constructor',
28
+ '@declaration.function',
29
+ ];
30
+ /** tree-sitter-c-sharp node types that the method extractor accepts. */
31
+ const FUNCTION_NODE_TYPES = [
32
+ 'method_declaration',
33
+ 'constructor_declaration',
34
+ 'destructor_declaration',
35
+ 'operator_declaration',
36
+ 'conversion_operator_declaration',
37
+ 'local_function_statement',
38
+ ];
39
+ export function emitCsharpScopeCaptures(sourceText, _filePath, cachedTree) {
40
+ // Skip the parse when the caller (parse phase's scopeTreeCache)
41
+ // already produced a Tree for this source. Cache miss = re-parse,
42
+ // same as before. The cachedTree parameter is typed as `unknown` at
43
+ // the LanguageProvider contract layer; cast here at the use site.
44
+ let tree = cachedTree;
45
+ if (tree === undefined) {
46
+ tree = getCsharpParser().parse(sourceText);
47
+ recordCacheMiss();
48
+ }
49
+ else {
50
+ recordCacheHit();
51
+ }
52
+ const rawMatches = getCsharpScopeQuery().matches(tree.rootNode);
53
+ const out = [];
54
+ for (const m of rawMatches) {
55
+ // Group captures by their tag name. Tree-sitter strips the leading
56
+ // `@`; we put it back so the central extractor's prefix lookups
57
+ // (`@scope.`, `@declaration.`, …) work.
58
+ const grouped = {};
59
+ for (const c of m.captures) {
60
+ const tag = '@' + c.name;
61
+ grouped[tag] = nodeToCapture(tag, c.node);
62
+ }
63
+ if (Object.keys(grouped).length === 0)
64
+ continue;
65
+ // Decompose each `using_directive` so `interpretCsharpImport` sees
66
+ // the kind/source/name/alias markers it consumes. Raw query match
67
+ // only carries the @import.statement anchor.
68
+ if (grouped['@import.statement'] !== undefined) {
69
+ const stmtCapture = grouped['@import.statement'];
70
+ const stmtNode = findNodeAtRange(tree.rootNode, stmtCapture.range, 'using_directive');
71
+ if (stmtNode !== null) {
72
+ const decomposed = splitUsingDirective(stmtNode);
73
+ if (decomposed !== null) {
74
+ out.push(decomposed);
75
+ continue;
76
+ }
77
+ }
78
+ // Defensive fallback: emit the raw match so the extractor at
79
+ // least sees an anchor, even without markers.
80
+ out.push(grouped);
81
+ continue;
82
+ }
83
+ // Synthesize `this` / `base` receiver type-bindings on every
84
+ // instance method-like. Tree-sitter can't cleanly express "the
85
+ // implicit receiver of a non-static member of a class/struct/
86
+ // record/interface" via a static `.scm` pattern, so we walk up
87
+ // the AST in code. Mirrors Python's `self`/`cls` synthesis on
88
+ // `@scope.function` matches.
89
+ if (grouped['@scope.function'] !== undefined) {
90
+ out.push(grouped);
91
+ const anchor = grouped['@scope.function'];
92
+ const fnNode = findFunctionNode(tree.rootNode, anchor.range);
93
+ if (fnNode !== null) {
94
+ for (const synth of synthesizeCsharpReceiverBinding(fnNode)) {
95
+ out.push(synth);
96
+ }
97
+ }
98
+ continue;
99
+ }
100
+ // Synthesize arity metadata on function-like declarations so the
101
+ // registry can narrow overloads (C# relies heavily on this). Mirrors
102
+ // Python's captures.ts pattern — one anchor per match, so we find
103
+ // the first tag that matches.
104
+ const declTag = FUNCTION_DECL_TAGS.find((t) => grouped[t] !== undefined);
105
+ if (declTag !== undefined) {
106
+ const anchor = grouped[declTag];
107
+ const fnNode = findFunctionNode(tree.rootNode, anchor.range);
108
+ if (fnNode !== null) {
109
+ const arity = computeCsharpArityMetadata(fnNode);
110
+ if (arity.parameterCount !== undefined) {
111
+ grouped['@declaration.parameter-count'] = syntheticCapture('@declaration.parameter-count', fnNode, String(arity.parameterCount));
112
+ }
113
+ if (arity.requiredParameterCount !== undefined) {
114
+ grouped['@declaration.required-parameter-count'] = syntheticCapture('@declaration.required-parameter-count', fnNode, String(arity.requiredParameterCount));
115
+ }
116
+ if (arity.parameterTypes !== undefined) {
117
+ grouped['@declaration.parameter-types'] = syntheticCapture('@declaration.parameter-types', fnNode, JSON.stringify(arity.parameterTypes));
118
+ }
119
+ }
120
+ }
121
+ // Synthesize `@reference.arity` on every callsite so the
122
+ // registry's arity filter can narrow overloads. Count the
123
+ // `argument` named children of the backing `argument_list`.
124
+ // Python doesn't synthesize this today; C# needs it because the
125
+ // language has method overloading and the suite asserts overload
126
+ // resolution.
127
+ const callTag = ['@reference.call.free', '@reference.call.member', '@reference.call.constructor'].find((t) => grouped[t] !== undefined);
128
+ if (callTag !== undefined && grouped['@reference.arity'] === undefined) {
129
+ const anchor = grouped[callTag];
130
+ const callNode = findNodeAtRange(tree.rootNode, anchor.range, 'invocation_expression') ??
131
+ findNodeAtRange(tree.rootNode, anchor.range, 'object_creation_expression');
132
+ if (callNode !== null) {
133
+ const argList = callNode.childForFieldName('arguments');
134
+ const args = argList === null
135
+ ? []
136
+ : argList.namedChildren.filter((c) => c !== null && c.type === 'argument');
137
+ grouped['@reference.arity'] = syntheticCapture('@reference.arity', callNode, String(args.length));
138
+ // Infer argument types from literal nodes so overload
139
+ // disambiguation can narrow same-arity candidates by param
140
+ // type. Non-literal arguments emit empty string to indicate
141
+ // "unknown" — consumers treat unknown as any-match.
142
+ const argTypes = args.map((arg) => inferArgType(arg));
143
+ grouped['@reference.parameter-types'] = syntheticCapture('@reference.parameter-types', callNode, JSON.stringify(argTypes));
144
+ }
145
+ }
146
+ out.push(grouped);
147
+ // Synthesize primary-constructor declarations on class/record
148
+ // declarations that carry a `parameter_list` child (C# 12 syntax
149
+ // `public class User(string name, int age) { ... }` or
150
+ // `public record Person(string FirstName, string LastName)`).
151
+ // Legacy `csharpMethodConfig.extractPrimaryConstructor` runs via
152
+ // the parse phase; the scope-resolution path needs its own emit so
153
+ // `new User(...)` resolves to a Constructor def in memberByOwner.
154
+ if (grouped['@declaration.class'] !== undefined ||
155
+ grouped['@declaration.record'] !== undefined) {
156
+ const anchor = grouped['@declaration.class'] ?? grouped['@declaration.record'];
157
+ const typeNode = findNodeAtRange(tree.rootNode, anchor.range, 'class_declaration') ??
158
+ findNodeAtRange(tree.rootNode, anchor.range, 'record_declaration');
159
+ if (typeNode !== null) {
160
+ const synth = synthesizePrimaryConstructor(typeNode);
161
+ if (synth !== null)
162
+ out.push(synth);
163
+ }
164
+ }
165
+ }
166
+ return out;
167
+ }
168
+ /** C# 12 primary constructor: `class X(a, b) { }` / `record X(a, b)`.
169
+ * The parameters are a bare `parameter_list` named child of the type
170
+ * declaration (no `constructor_declaration` node). Emit a synthetic
171
+ * @declaration.constructor match so the extractor creates a
172
+ * Constructor def in memberByOwner — free-call-fallback's
173
+ * `pickConstructorOrClass` then targets it for `new X(...)` calls. */
174
+ function synthesizePrimaryConstructor(typeNode) {
175
+ // Skip types with an explicit constructor_declaration — that would
176
+ // create duplicate defs.
177
+ const body = typeNode.childForFieldName('body');
178
+ if (body !== null) {
179
+ for (let i = 0; i < body.namedChildCount; i++) {
180
+ const child = body.namedChild(i);
181
+ if (child !== null && child.type === 'constructor_declaration')
182
+ return null;
183
+ }
184
+ }
185
+ let paramList = null;
186
+ for (let i = 0; i < typeNode.namedChildCount; i++) {
187
+ const child = typeNode.namedChild(i);
188
+ if (child !== null && child.type === 'parameter_list') {
189
+ paramList = child;
190
+ break;
191
+ }
192
+ }
193
+ if (paramList === null)
194
+ return null;
195
+ const nameNode = typeNode.childForFieldName('name');
196
+ if (nameNode === null)
197
+ return null;
198
+ const paramCount = paramList.namedChildren.filter((c) => c !== null && c.type === 'parameter').length;
199
+ const m = {
200
+ '@declaration.constructor': nodeToCapture('@declaration.constructor', paramList),
201
+ '@declaration.name': syntheticCapture('@declaration.name', nameNode, nameNode.text),
202
+ '@declaration.parameter-count': syntheticCapture('@declaration.parameter-count', paramList, String(paramCount)),
203
+ '@declaration.required-parameter-count': syntheticCapture('@declaration.required-parameter-count', paramList, String(paramCount)),
204
+ };
205
+ return m;
206
+ }
207
+ /** Infer a C# argument's static type from literal / constructor
208
+ * patterns. Returns `''` when the arg has no statically-derivable
209
+ * type (e.g. identifier — would require full type inference). */
210
+ function inferArgType(argNode) {
211
+ // `argument > expression` — tree-sitter-c-sharp wraps the value.
212
+ const expr = argNode.namedChild(0);
213
+ if (expr === null)
214
+ return '';
215
+ switch (expr.type) {
216
+ case 'integer_literal':
217
+ return 'int';
218
+ case 'real_literal':
219
+ return 'double';
220
+ case 'string_literal':
221
+ case 'verbatim_string_literal':
222
+ case 'interpolated_string_expression':
223
+ case 'raw_string_literal':
224
+ return 'string';
225
+ case 'character_literal':
226
+ return 'char';
227
+ case 'boolean_literal':
228
+ return 'bool';
229
+ case 'null_literal':
230
+ return 'null';
231
+ case 'object_creation_expression': {
232
+ const typeNode = expr.childForFieldName('type');
233
+ return typeNode?.text ?? '';
234
+ }
235
+ default:
236
+ return '';
237
+ }
238
+ }
239
+ /** Find the first C# function-like node at the given range. The
240
+ * declaration anchor range covers the whole method/constructor/etc.
241
+ * node, but the tag alone doesn't tell us which node type. */
242
+ function findFunctionNode(rootNode, range) {
243
+ for (const nodeType of FUNCTION_NODE_TYPES) {
244
+ const n = findNodeAtRange(rootNode, range, nodeType);
245
+ if (n !== null)
246
+ return n;
247
+ }
248
+ return null;
249
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Decompose a C# `using_directive` into a `CaptureMatch` carrying the
3
+ * synthesized markers `@import.kind` / `@import.source` / `@import.name`
4
+ * / `@import.alias` that `interpretCsharpImport` consumes.
5
+ *
6
+ * Unlike Python's decomposer this is 1:1 — each `using` produces exactly
7
+ * one import. The split layer exists to expose the kind (namespace vs
8
+ * alias vs static) without pushing raw-text parsing into `interpret.ts`.
9
+ *
10
+ * using System; → namespace
11
+ * using System.Collections.Generic; → namespace
12
+ * using Foo = System.Bar; → alias
13
+ * using static System.Math; → static
14
+ * global using System.IO; → namespace (treated as file-scoped)
15
+ * using global::System.IO; → namespace (global:: alias stripped)
16
+ */
17
+ import type { CaptureMatch } from '../../../../_shared/index.js';
18
+ import { type SyntaxNode } from '../../utils/ast-helpers.js';
19
+ export declare function splitUsingDirective(stmtNode: SyntaxNode): CaptureMatch | null;
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Decompose a C# `using_directive` into a `CaptureMatch` carrying the
3
+ * synthesized markers `@import.kind` / `@import.source` / `@import.name`
4
+ * / `@import.alias` that `interpretCsharpImport` consumes.
5
+ *
6
+ * Unlike Python's decomposer this is 1:1 — each `using` produces exactly
7
+ * one import. The split layer exists to expose the kind (namespace vs
8
+ * alias vs static) without pushing raw-text parsing into `interpret.ts`.
9
+ *
10
+ * using System; → namespace
11
+ * using System.Collections.Generic; → namespace
12
+ * using Foo = System.Bar; → alias
13
+ * using static System.Math; → static
14
+ * global using System.IO; → namespace (treated as file-scoped)
15
+ * using global::System.IO; → namespace (global:: alias stripped)
16
+ */
17
+ import { nodeToCapture, syntheticCapture } from '../../utils/ast-helpers.js';
18
+ export function splitUsingDirective(stmtNode) {
19
+ if (stmtNode.type !== 'using_directive')
20
+ return null;
21
+ const spec = parseUsingDirective(stmtNode);
22
+ if (spec === null)
23
+ return null;
24
+ return buildImportMatch(stmtNode, spec);
25
+ }
26
+ function parseUsingDirective(node) {
27
+ // tree-sitter-c-sharp's using_directive exposes named children
28
+ // corresponding to the parts of the directive but omits keyword tokens
29
+ // (`using`, `static`, `global`) from the named-child list. We inspect
30
+ // the raw source text to detect the flavor — the grammar doesn't give
31
+ // us a cleaner signal.
32
+ const raw = node.text;
33
+ // Named child layout:
34
+ // namespace form: [pathNode]
35
+ // alias form: [aliasIdNode, pathNode] (name field = aliasId)
36
+ // static form: [pathNode] (same as namespace)
37
+ // global using: [pathNode] (same as namespace)
38
+ const aliasField = node.childForFieldName('name');
39
+ const children = node.namedChildren;
40
+ if (children.length === 0)
41
+ return null;
42
+ // Alias form — the `name:` field is the alias identifier; the
43
+ // remaining named child is the type/namespace path.
44
+ if (aliasField !== null) {
45
+ const pathNode = children.find((c) => c !== null && c.startIndex !== aliasField.startIndex);
46
+ if (pathNode === undefined)
47
+ return null;
48
+ return {
49
+ kind: 'alias',
50
+ source: stripGenericArgs(unwrapGlobalAlias(pathNode.text)),
51
+ name: aliasField.text,
52
+ alias: aliasField.text,
53
+ atNode: node,
54
+ };
55
+ }
56
+ const pathNode = children[0];
57
+ if (pathNode === null)
58
+ return null;
59
+ const source = stripGenericArgs(unwrapGlobalAlias(pathNode.text));
60
+ if (source === '')
61
+ return null;
62
+ const lastSegment = source.split('.').pop() ?? source;
63
+ // `using static X.Y;` — detect by scanning the raw text before the path.
64
+ // `global using` behaves semantically as a file-scoped using for our
65
+ // purposes, so it isn't a separate kind here.
66
+ if (/^\s*(?:global\s+)?using\s+static\s/.test(raw)) {
67
+ return { kind: 'static', source, name: '*', atNode: node };
68
+ }
69
+ return { kind: 'namespace', source, name: lastSegment, atNode: node };
70
+ }
71
+ /** Strip `global::` prefix — `global::System.IO` → `System.IO`. */
72
+ function unwrapGlobalAlias(text) {
73
+ return text.replace(/^global::/, '');
74
+ }
75
+ /** Strip generic type arguments — `Dictionary<string, int>` → `Dictionary`. */
76
+ function stripGenericArgs(text) {
77
+ const lt = text.indexOf('<');
78
+ if (lt === -1)
79
+ return text;
80
+ return text.slice(0, lt);
81
+ }
82
+ function buildImportMatch(stmtNode, spec) {
83
+ const m = {
84
+ '@import.statement': nodeToCapture('@import.statement', stmtNode),
85
+ '@import.kind': syntheticCapture('@import.kind', spec.atNode, spec.kind),
86
+ '@import.source': syntheticCapture('@import.source', spec.atNode, spec.source),
87
+ '@import.name': syntheticCapture('@import.name', spec.atNode, spec.name),
88
+ };
89
+ if (spec.alias !== undefined) {
90
+ m['@import.alias'] = syntheticCapture('@import.alias', spec.atNode, spec.alias);
91
+ }
92
+ return m;
93
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Adapter from `(ParsedImport, WorkspaceIndex)` → concrete file path.
3
+ *
4
+ * Unit 2 shape: suffix-match against the repo's `.cs` files. Each
5
+ * `using System.Collections.Generic;` could legally expand to multiple
6
+ * files (every `.cs` that declares `namespace System.Collections.Generic`
7
+ * — partial classes, assembly-wide namespaces). The scope-resolver
8
+ * contract returns a single primary target, so we pick the first
9
+ * match. Cross-file partial-class aggregation runs at graph-bridge
10
+ * time (Unit 6) via `populateOwners`.
11
+ *
12
+ * The legacy csproj-based `resolveCSharpImportInternal` needs config
13
+ * objects the scope-resolver doesn't carry; the Unit 7 parity gate
14
+ * will surface cases where the suffix-match diverges from the
15
+ * namespace-based resolver and we'll adjust the contract if needed.
16
+ *
17
+ * Returning `null` lets the finalize algorithm mark the edge as
18
+ * `linkStatus: 'unresolved'`.
19
+ */
20
+ import type { ParsedImport, WorkspaceIndex } from '../../../../_shared/index.js';
21
+ export interface CsharpResolveContext {
22
+ readonly fromFile: string;
23
+ readonly allFilePaths: ReadonlySet<string>;
24
+ }
25
+ export declare function resolveCsharpImportTarget(parsedImport: ParsedImport, workspaceIndex: WorkspaceIndex): string | null;
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Adapter from `(ParsedImport, WorkspaceIndex)` → concrete file path.
3
+ *
4
+ * Unit 2 shape: suffix-match against the repo's `.cs` files. Each
5
+ * `using System.Collections.Generic;` could legally expand to multiple
6
+ * files (every `.cs` that declares `namespace System.Collections.Generic`
7
+ * — partial classes, assembly-wide namespaces). The scope-resolver
8
+ * contract returns a single primary target, so we pick the first
9
+ * match. Cross-file partial-class aggregation runs at graph-bridge
10
+ * time (Unit 6) via `populateOwners`.
11
+ *
12
+ * The legacy csproj-based `resolveCSharpImportInternal` needs config
13
+ * objects the scope-resolver doesn't carry; the Unit 7 parity gate
14
+ * will surface cases where the suffix-match diverges from the
15
+ * namespace-based resolver and we'll adjust the contract if needed.
16
+ *
17
+ * Returning `null` lets the finalize algorithm mark the edge as
18
+ * `linkStatus: 'unresolved'`.
19
+ */
20
+ export function resolveCsharpImportTarget(parsedImport, workspaceIndex) {
21
+ // WorkspaceIndex is `unknown` in the shared contract (Ring 1
22
+ // placeholder). The scope-resolution orchestrator hands us a
23
+ // CsharpResolveContext-shaped object; narrow structurally rather
24
+ // than via a cast chain so unexpected shapes return null cleanly.
25
+ const ctx = workspaceIndex;
26
+ if (ctx === undefined ||
27
+ typeof ctx.fromFile !== 'string' ||
28
+ !(ctx.allFilePaths instanceof Set)) {
29
+ return null;
30
+ }
31
+ if (parsedImport.kind === 'dynamic-unresolved')
32
+ return null;
33
+ if (parsedImport.targetRaw === null || parsedImport.targetRaw === '')
34
+ return null;
35
+ // Namespace path: `System.Collections.Generic` → `System/Collections/Generic`.
36
+ const pathLike = parsedImport.targetRaw.replace(/\./g, '/');
37
+ const suffix = `/${pathLike}`;
38
+ // Exact file match: `System/Collections/Generic.cs` (rare but legal).
39
+ // Suffix match for nested layouts: `src/lib/System/Collections/Generic.cs`.
40
+ // Directory match: first `.cs` file directly inside the namespace dir
41
+ // (e.g. `System/Collections/Generic/List.cs` matches namespace Generic).
42
+ let exactFile = null;
43
+ let suffixFile = null;
44
+ let directoryChild = null;
45
+ const dirPrefix = `${pathLike}/`;
46
+ const suffixDirPrefix = `/${dirPrefix}`;
47
+ for (const raw of ctx.allFilePaths) {
48
+ const f = raw.replace(/\\/g, '/');
49
+ if (!f.endsWith('.cs'))
50
+ continue;
51
+ if (f === `${pathLike}.cs`) {
52
+ exactFile = raw;
53
+ break;
54
+ }
55
+ if (suffixFile === null && f.endsWith(`${suffix}.cs`)) {
56
+ suffixFile = raw;
57
+ }
58
+ if (directoryChild === null) {
59
+ // Namespace-to-directory match: pick the first `.cs` directly in
60
+ // the namespace dir (not nested deeper). Legacy resolver emits
61
+ // all of them; we take one so the scope-resolver contract stays
62
+ // single-target.
63
+ const atRoot = f.startsWith(dirPrefix);
64
+ const atNested = f.includes(suffixDirPrefix);
65
+ if (atRoot || atNested) {
66
+ const idx = atRoot ? 0 : f.indexOf(suffixDirPrefix) + 1;
67
+ const after = f.slice(idx + dirPrefix.length);
68
+ if (after.length > 0 && !after.includes('/')) {
69
+ directoryChild = raw;
70
+ }
71
+ }
72
+ }
73
+ }
74
+ if (exactFile !== null)
75
+ return exactFile;
76
+ if (suffixFile !== null)
77
+ return suffixFile;
78
+ if (directoryChild !== null)
79
+ return directoryChild;
80
+ // Progressive prefix stripping — mirrors csproj's root-namespace
81
+ // mapping without the csproj. `using CrossFile.Models;` in a repo
82
+ // laid out `Models/User.cs` (no `CrossFile/` prefix) works because
83
+ // the legacy resolver consults csproj; the scope-resolver layer
84
+ // doesn't have csproj, so we try each suffix of the namespace path
85
+ // against `.cs` files and directories.
86
+ //
87
+ // Also handles `using static CrossFile.Models.UserFactory;` —
88
+ // strip the leading segment, try `Models/UserFactory.cs`; strip
89
+ // two, try `UserFactory.cs`.
90
+ const segments = pathLike.split('/').filter(Boolean);
91
+ for (let skip = 1; skip < segments.length; skip++) {
92
+ const tail = segments.slice(skip).join('/');
93
+ if (tail === '')
94
+ continue;
95
+ const tailFile = `${tail}.cs`;
96
+ const tailSuffix = `/${tailFile}`;
97
+ const tailDir = `${tail}/`;
98
+ const tailSuffixDir = `/${tailDir}`;
99
+ let tailDirectChild = null;
100
+ for (const raw of ctx.allFilePaths) {
101
+ const f = raw.replace(/\\/g, '/');
102
+ if (!f.endsWith('.cs'))
103
+ continue;
104
+ if (f === tailFile)
105
+ return raw;
106
+ if (f.endsWith(tailSuffix))
107
+ return raw;
108
+ if (tailDirectChild === null) {
109
+ const atRoot = f.startsWith(tailDir);
110
+ const atNested = f.includes(tailSuffixDir);
111
+ if (atRoot || atNested) {
112
+ const idx = atRoot ? 0 : f.indexOf(tailSuffixDir) + 1;
113
+ const after = f.slice(idx + tailDir.length);
114
+ if (after.length > 0 && !after.includes('/'))
115
+ tailDirectChild = raw;
116
+ }
117
+ }
118
+ }
119
+ if (tailDirectChild !== null)
120
+ return tailDirectChild;
121
+ }
122
+ return null;
123
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * C# scope-resolution hooks (RFC #909 Ring 3, RFC §5).
3
+ *
4
+ * Public API barrel. Consumers should import from this file rather than
5
+ * the individual modules.
6
+ *
7
+ * Module layout (each file is a single concern):
8
+ *
9
+ * - `query.ts` — tree-sitter query + lazy parser/query singletons
10
+ * - `captures.ts` — `emitCsharpScopeCaptures` orchestrator
11
+ * - `import-decomposer.ts` — each `using` → ParsedImport-shaped captures
12
+ * - `interpret.ts` — capture-match → `ParsedImport` / `ParsedTypeBinding`
13
+ * - `simple-hooks.ts` — small/no-op hooks made explicit
14
+ * - `receiver-binding.ts` — synthesize `this`/`base` type-bindings on
15
+ * instance-method entry
16
+ * - `merge-bindings.ts` — C# `using` precedence
17
+ * - `arity.ts` — C# arity compatibility (`params`, default values)
18
+ * - `arity-metadata.ts` — synthesize arity metadata from declarations
19
+ * - `accessor-unwrap.ts` — `.Values` / `.Keys` receiver-type unwrap for
20
+ * `Dictionary<K,V>` chains
21
+ * - `namespace-siblings.ts` — AST-driven cross-file implicit-namespace
22
+ * visibility (file/namespace attribution, no
23
+ * regex; reuses orchestrator's treeCache)
24
+ * - `import-target.ts` — `(ParsedImport, WorkspaceIndex) → file path` adapter
25
+ * - `scope-resolver.ts` — `ScopeResolver` registered in `SCOPE_RESOLVERS`
26
+ * - `cache-stats.ts` — PROF_SCOPE_RESOLUTION cache hit/miss counters
27
+ *
28
+ * ## Known limitations
29
+ *
30
+ * The C# registry-primary path intentionally does NOT resolve the
31
+ * following. Each is a conscious trade-off at migration time.
32
+ *
33
+ * 1. **csproj-driven namespace resolution** — the legacy path
34
+ * consults `csharpConfigs` (the parsed .csproj workspace) to map
35
+ * `using X.Y;` back to the exact files declaring `namespace X.Y`.
36
+ * The scope-resolver contract passes only `allFilePaths`, so we
37
+ * fall back to suffix matching on `.cs` files. Unit 7's parity
38
+ * gate flags any divergence.
39
+ * 2. **Multi-file namespace expansion** — a single `using X.Y;` in
40
+ * the legacy path can emit multiple IMPORTS edges (every file
41
+ * declaring that namespace). The scope-resolver contract returns
42
+ * a single target, so we pick the first match; partial-class
43
+ * aggregation runs at graph-bridge time.
44
+ * 3. **Overload resolution by parameter type** — arity narrowing is
45
+ * wired (`arity.ts` + `arity-metadata.ts`), but type-based
46
+ * disambiguation (`F(int)` vs `F(string)` at a call with a typed
47
+ * argument) is left to the registry's type-binding layer.
48
+ * 4. **Generic type parameter resolution** — `List<User>` binds the
49
+ * bound name to `User` via the single-arg-generic stripper;
50
+ * nested generics (`Dictionary<K, List<V>>`) fall through the
51
+ * receiver-type heuristic.
52
+ * 5. **`dynamic` typed expressions** — runtime dispatch through
53
+ * `dynamic` is not followed.
54
+ * 6. **Preprocessor-conditional code** — `#if DEBUG` blocks parse
55
+ * as usual; branch selection is ignored, so both arms contribute
56
+ * bindings.
57
+ * 7. **Global using propagation across files** — treated as a
58
+ * file-scoped using for the declaring file. Unit 7 parity gate
59
+ * will flag cases where this matters.
60
+ * 8. **Expression-bodied `=>` members** — handled by the method
61
+ * extractor, but receiver synthesis for `=> this.Field` shortcuts
62
+ * follows the same path as block-bodied methods.
63
+ * 9. **Multi-namespace file attribution** — when a single file
64
+ * declares two namespaces (rare), all top-level classes are
65
+ * attributed to the first declared namespace via a `first-wins`
66
+ * rule in `namespace-siblings.ts`. Namespace detection itself is
67
+ * AST-driven (tree-sitter), so `global using static`, aliased
68
+ * `using static X = Y.Z;`, attributes, and preprocessor-gated
69
+ * declarations are all recognized correctly.
70
+ *
71
+ * Shadow-harness corpus parity is the authoritative signal for which
72
+ * of these matter in practice. The CI parity gate blocks any PR that
73
+ * regresses either the legacy or registry-primary run of
74
+ * `test/integration/resolvers/csharp.test.ts`.
75
+ */
76
+ export { emitCsharpScopeCaptures } from './captures.js';
77
+ export { getCsharpCaptureCacheStats, resetCsharpCaptureCacheStats } from './cache-stats.js';
78
+ export { interpretCsharpImport, interpretCsharpTypeBinding } from './interpret.js';
79
+ export { csharpMergeBindings } from './merge-bindings.js';
80
+ export { csharpArityCompatibility } from './arity.js';
81
+ export { resolveCsharpImportTarget, type CsharpResolveContext } from './import-target.js';
82
+ export { csharpBindingScopeFor, csharpImportOwningScope, csharpReceiverBinding, } from './simple-hooks.js';