gitnexus 1.6.4-rc.2 → 1.6.4-rc.21
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.
- package/README.md +35 -0
- package/dist/_shared/index.d.ts +1 -1
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/index.js +1 -1
- package/dist/_shared/index.js.map +1 -1
- package/dist/_shared/scope-resolution/finalize-algorithm.d.ts +22 -14
- package/dist/_shared/scope-resolution/finalize-algorithm.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/finalize-algorithm.js +298 -37
- package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -1
- package/dist/_shared/scope-resolution/scope-tree.d.ts +23 -1
- package/dist/_shared/scope-resolution/scope-tree.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/scope-tree.js +36 -2
- package/dist/_shared/scope-resolution/scope-tree.js.map +1 -1
- package/dist/_shared/scope-resolution/types.d.ts +47 -3
- package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/types.js +10 -2
- package/dist/_shared/scope-resolution/types.js.map +1 -1
- package/dist/cli/analyze.d.ts +6 -0
- package/dist/cli/analyze.js +35 -0
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.js +31 -0
- package/dist/cli/index.js +13 -0
- package/dist/cli/setup.js +2 -2
- package/dist/core/embeddings/config.d.ts +2 -0
- package/dist/core/embeddings/config.js +36 -0
- package/dist/core/embeddings/embedder.js +11 -6
- package/dist/core/embeddings/embedding-pipeline.d.ts +7 -1
- package/dist/core/embeddings/embedding-pipeline.js +93 -29
- package/dist/core/embeddings/exact-search.d.ts +15 -0
- package/dist/core/embeddings/exact-search.js +27 -0
- package/dist/core/embeddings/types.d.ts +4 -0
- package/dist/core/embeddings/types.js +2 -0
- package/dist/core/group/config-parser.js +2 -0
- package/dist/core/group/matching.d.ts +3 -3
- package/dist/core/group/matching.js +46 -6
- package/dist/core/group/storage.js +2 -0
- package/dist/core/group/sync.js +1 -1
- package/dist/core/group/types.d.ts +18 -0
- package/dist/core/ingestion/call-processor.d.ts +3 -3
- package/dist/core/ingestion/call-processor.js +58 -65
- package/dist/core/ingestion/constants.d.ts +4 -3
- package/dist/core/ingestion/constants.js +8 -3
- package/dist/core/ingestion/finalize-orchestrator.js +6 -3
- package/dist/core/ingestion/heritage-processor.js +2 -2
- package/dist/core/ingestion/import-processor.js +1 -1
- package/dist/core/ingestion/language-provider.d.ts +8 -0
- package/dist/core/ingestion/languages/csharp/captures.js +4 -1
- package/dist/core/ingestion/languages/csharp/namespace-siblings.d.ts +14 -13
- package/dist/core/ingestion/languages/csharp/namespace-siblings.js +62 -50
- package/dist/core/ingestion/languages/python/captures.js +9 -1
- package/dist/core/ingestion/languages/python/index.d.ts +1 -1
- package/dist/core/ingestion/languages/python/index.js +1 -1
- package/dist/core/ingestion/languages/python/simple-hooks.d.ts +3 -1
- package/dist/core/ingestion/languages/python/simple-hooks.js +8 -0
- package/dist/core/ingestion/languages/python.js +28 -1
- package/dist/core/ingestion/languages/swift.js +14 -0
- package/dist/core/ingestion/languages/typescript/arity-metadata.d.ts +59 -0
- package/dist/core/ingestion/languages/typescript/arity-metadata.js +103 -0
- package/dist/core/ingestion/languages/typescript/arity.d.ts +37 -0
- package/dist/core/ingestion/languages/typescript/arity.js +54 -0
- package/dist/core/ingestion/languages/typescript/cache-stats.d.ts +17 -0
- package/dist/core/ingestion/languages/typescript/cache-stats.js +28 -0
- package/dist/core/ingestion/languages/typescript/captures.d.ts +28 -0
- package/dist/core/ingestion/languages/typescript/captures.js +451 -0
- package/dist/core/ingestion/languages/typescript/import-decomposer.d.ts +49 -0
- package/dist/core/ingestion/languages/typescript/import-decomposer.js +371 -0
- package/dist/core/ingestion/languages/typescript/import-target.d.ts +50 -0
- package/dist/core/ingestion/languages/typescript/import-target.js +61 -0
- package/dist/core/ingestion/languages/typescript/index.d.ts +94 -0
- package/dist/core/ingestion/languages/typescript/index.js +94 -0
- package/dist/core/ingestion/languages/typescript/interpret.d.ts +35 -0
- package/dist/core/ingestion/languages/typescript/interpret.js +317 -0
- package/dist/core/ingestion/languages/typescript/merge-bindings.d.ts +62 -0
- package/dist/core/ingestion/languages/typescript/merge-bindings.js +158 -0
- package/dist/core/ingestion/languages/typescript/query.d.ts +77 -0
- package/dist/core/ingestion/languages/typescript/query.js +778 -0
- package/dist/core/ingestion/languages/typescript/receiver-binding.d.ts +59 -0
- package/dist/core/ingestion/languages/typescript/receiver-binding.js +171 -0
- package/dist/core/ingestion/languages/typescript/scope-resolver.d.ts +16 -0
- package/dist/core/ingestion/languages/typescript/scope-resolver.js +113 -0
- package/dist/core/ingestion/languages/typescript/simple-hooks.d.ts +71 -0
- package/dist/core/ingestion/languages/typescript/simple-hooks.js +131 -0
- package/dist/core/ingestion/languages/typescript.js +19 -0
- package/dist/core/ingestion/method-extractors/configs/swift.js +3 -4
- package/dist/core/ingestion/model/scope-resolution-indexes.d.ts +14 -1
- package/dist/core/ingestion/parsing-processor.js +20 -9
- package/dist/core/ingestion/pipeline-phases/processes.js +9 -4
- package/dist/core/ingestion/pipeline-phases/tools.d.ts +1 -0
- package/dist/core/ingestion/pipeline-phases/tools.js +10 -4
- package/dist/core/ingestion/registry-primary-flag.d.ts +3 -1
- package/dist/core/ingestion/registry-primary-flag.js +4 -1
- package/dist/core/ingestion/scope-extractor-bridge.d.ts +5 -2
- package/dist/core/ingestion/scope-extractor-bridge.js +7 -2
- package/dist/core/ingestion/scope-extractor.js +19 -18
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +73 -11
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.js +48 -10
- package/dist/core/ingestion/scope-resolution/passes/compound-receiver.js +283 -14
- package/dist/core/ingestion/scope-resolution/passes/imported-return-types.d.ts +23 -2
- package/dist/core/ingestion/scope-resolution/passes/imported-return-types.js +109 -37
- package/dist/core/ingestion/scope-resolution/passes/mro.js +3 -1
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +13 -5
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +11 -2
- package/dist/core/ingestion/scope-resolution/pipeline/registry.js +2 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +8 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +21 -5
- package/dist/core/ingestion/scope-resolution/pipeline/validate-bindings-immutability.d.ts +39 -0
- package/dist/core/ingestion/scope-resolution/pipeline/validate-bindings-immutability.js +65 -0
- package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +54 -11
- package/dist/core/ingestion/scope-resolution/scope/walkers.js +105 -30
- package/dist/core/ingestion/type-extractors/swift.js +7 -4
- package/dist/core/ingestion/utils/ast-helpers.d.ts +2 -0
- package/dist/core/ingestion/utils/ast-helpers.js +12 -0
- package/dist/core/ingestion/utils/env.d.ts +10 -0
- package/dist/core/ingestion/utils/env.js +14 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +1 -0
- package/dist/core/ingestion/workers/parse-worker.js +15 -9
- package/dist/core/ingestion/workers/worker-pool.d.ts +11 -4
- package/dist/core/ingestion/workers/worker-pool.js +244 -48
- package/dist/core/lbug/extension-loader.d.ts +86 -0
- package/dist/core/lbug/extension-loader.js +184 -0
- package/dist/core/lbug/lbug-adapter.d.ts +18 -17
- package/dist/core/lbug/lbug-adapter.js +45 -73
- package/dist/core/lbug/pool-adapter.js +10 -28
- package/dist/core/platform/capabilities.d.ts +24 -0
- package/dist/core/platform/capabilities.js +54 -0
- package/dist/core/run-analyze.js +36 -9
- package/dist/core/search/bm25-index.d.ts +0 -17
- package/dist/core/search/bm25-index.js +10 -118
- package/dist/core/search/fts-indexes.d.ts +1 -0
- package/dist/core/search/fts-indexes.js +7 -0
- package/dist/core/search/fts-schema.d.ts +6 -0
- package/dist/core/search/fts-schema.js +7 -0
- package/dist/mcp/core/embedder.js +11 -4
- package/dist/mcp/local/local-backend.js +50 -15
- package/dist/server/api.d.ts +5 -0
- package/dist/server/api.js +113 -0
- package/hooks/claude/gitnexus-hook.cjs +11 -1
- package/package.json +6 -5
- package/scripts/build-tree-sitter-dart.cjs +42 -0
- package/scripts/build-tree-sitter-proto.cjs +1 -1
- package/scripts/build.js +22 -2
- package/scripts/install-duckdb-extension.mjs +37 -0
- package/vendor/tree-sitter-dart/README.md +18 -0
- package/vendor/tree-sitter-dart/binding.gyp +31 -0
- package/vendor/tree-sitter-dart/bindings/node/binding.cc +20 -0
- package/vendor/tree-sitter-dart/bindings/node/index.d.ts +28 -0
- package/vendor/tree-sitter-dart/bindings/node/index.js +7 -0
- package/vendor/tree-sitter-dart/grammar.js +2895 -0
- package/vendor/tree-sitter-dart/package.json +18 -0
- package/vendor/tree-sitter-dart/queries/highlights.scm +246 -0
- package/vendor/tree-sitter-dart/queries/tags.scm +92 -0
- package/vendor/tree-sitter-dart/queries/test.scm +1 -0
- package/vendor/tree-sitter-dart/src/grammar.json +12459 -0
- package/vendor/tree-sitter-dart/src/node-types.json +15055 -0
- package/vendor/tree-sitter-dart/src/parser.c +196127 -0
- package/vendor/tree-sitter-dart/src/scanner.c +130 -0
- package/vendor/tree-sitter-dart/src/tree_sitter/alloc.h +54 -0
- package/vendor/tree-sitter-dart/src/tree_sitter/array.h +290 -0
- package/vendor/tree-sitter-dart/src/tree_sitter/parser.h +265 -0
- package/vendor/tree-sitter-swift/LICENSE +21 -0
- package/vendor/tree-sitter-swift/README.md +139 -0
- package/vendor/tree-sitter-swift/bindings/node/index.d.ts +28 -0
- package/vendor/tree-sitter-swift/bindings/node/index.js +7 -0
- package/vendor/tree-sitter-swift/package.json +28 -0
- package/vendor/tree-sitter-swift/prebuilds/darwin-arm64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/darwin-x64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/linux-arm64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/linux-x64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/win32-arm64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/win32-x64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/src/node-types.json +30694 -0
- package/web/assets/agent-DaprsFSX.js +597 -0
- package/web/assets/architecture-YZFGNWBL-S5CXDPWN-DEdGaPg2.js +1 -0
- package/web/assets/architectureDiagram-EMZXCZ2Q-Domyk_gO.js +36 -0
- package/web/assets/blockDiagram-IGV67L2C-B_2kD7tM.js +132 -0
- package/web/assets/c4Diagram-DFAF54RM-BhJJW8Gg.js +10 -0
- package/web/assets/chunk-3GS5O3IE-jlWIjPsl.js +231 -0
- package/web/assets/chunk-3YCYZ6SJ-Blq_IzZs.js +1 -0
- package/web/assets/chunk-6NTNNK5N-DyPc58pp.js +1 -0
- package/web/assets/chunk-7RZVMHOQ-BdIU-RGO.js +321 -0
- package/web/assets/chunk-A34GCYZU-BI2i_LdU.js +1 -0
- package/web/assets/chunk-AEOMTBSW-D7qjBMHW.js +1 -0
- package/web/assets/chunk-CilyBKbf.js +1 -0
- package/web/assets/chunk-DJ7UZH7F-i11ywiBl.js +1 -0
- package/web/assets/chunk-DKKBVRCY-1SffGI1N.js +4 -0
- package/web/assets/chunk-DU5LTGQ6-DaPeiwD5.js +1 -0
- package/web/assets/chunk-FXACKDTF-uhhi2PC2.js +159 -0
- package/web/assets/chunk-H3VCZNTA-IchcISDt.js +1 -0
- package/web/assets/chunk-HN6EAY2L-D7ZFMNrB.js +1 -0
- package/web/assets/chunk-KSICW3F5-C2tZmXwv.js +15 -0
- package/web/assets/chunk-O5ABG6QK-Bt-Km84H.js +1 -0
- package/web/assets/chunk-PK6DOVAG-ChlWY0BQ.js +206 -0
- package/web/assets/chunk-RNJOYNJ4-B724K7cW.js +1 -0
- package/web/assets/chunk-RWUO3TPN-DYn1XriD.js +1 -0
- package/web/assets/chunk-TBF5ZNIQ-DKtDz6ae.js +1 -0
- package/web/assets/chunk-TU3PZOEN-DE5Qhc0N.js +1 -0
- package/web/assets/chunk-TYMNRAUI-g1h33cq-.js +1 -0
- package/web/assets/chunk-VELTKBKT-C9dVN39o.js +1 -0
- package/web/assets/chunk-W7ZLLLMY-Du-Hb9yb.js +1 -0
- package/web/assets/chunk-WSB5WSVC-B123clsZ.js +1 -0
- package/web/assets/chunk-XGPFEOL4-BR7Eue38.js +1 -0
- package/web/assets/classDiagram-PPOCWD7C-BglfKSs_.js +1 -0
- package/web/assets/classDiagram-v2-23LJLIIU-BSzTM28O.js +1 -0
- package/web/assets/context-builder-CqQNhRj1.js +15 -0
- package/web/assets/cose-bilkent-PNC4W37J-DCfErU-A.js +1 -0
- package/web/assets/dagre-E77IOHMT-tDRRhDoN.js +4 -0
- package/web/assets/diagram-H7BISOXX-CUVHlmAh.js +43 -0
- package/web/assets/diagram-JC5VWROH-BoyOxulB.js +24 -0
- package/web/assets/diagram-LXUTUG65-osr9hb7N.js +10 -0
- package/web/assets/diagram-WEHSV5V5-d8nUqS39.js +24 -0
- package/web/assets/erDiagram-GCSMX5X6-b-IwOhPS.js +85 -0
- package/web/assets/flowDiagram-OTCZ4VVT-Ott2Q0AP.js +162 -0
- package/web/assets/ganttDiagram-MUNLMDZQ-BYtgN_5s.js +292 -0
- package/web/assets/gitGraph-7Q5UKJZL-54BCDZD5-CFyBIGZq.js +1 -0
- package/web/assets/gitGraphDiagram-3HKGZ4G3-CsVD2gn4.js +106 -0
- package/web/assets/index-BleGLU8S.css +2 -0
- package/web/assets/index-C_xK08EW.js +885 -0
- package/web/assets/info-OMHHGYJF-BF2H5H6G-yjAxKEzh.js +1 -0
- package/web/assets/infoDiagram-MN7RKWGX-DXK0Unn5.js +2 -0
- package/web/assets/ishikawaDiagram-YMYX4NHK-CXsnC2FA.js +70 -0
- package/web/assets/journeyDiagram-SO5T7YLQ-BzZ07B-X.js +139 -0
- package/web/assets/kanban-definition-LJHFXRCJ-C6_EpAd9.js +89 -0
- package/web/assets/katex-GD7MH7QM-CJiOjBBJ.js +261 -0
- package/web/assets/mindmap-definition-2EUWGEK5-CCYGWZ1m.js +96 -0
- package/web/assets/packet-4T2RLAQJ-EV4IVRXR-B8k4E3IT.js +1 -0
- package/web/assets/pie-ZZUOXDRM-N23DN5KN-DdvfY118.js +1 -0
- package/web/assets/pieDiagram-3IATQBI2-RyvRlQb4.js +30 -0
- package/web/assets/quadrantDiagram-E256RVCF-Bfb6sxCx.js +7 -0
- package/web/assets/radar-PYXPWWZC-P6TP7ZYP-1EEDC_yU.js +1 -0
- package/web/assets/requirementDiagram-M5DCFWZL-DjvHDyvN.js +84 -0
- package/web/assets/sankeyDiagram-L3NBLAOT-CBCbbl8s.js +10 -0
- package/web/assets/sequenceDiagram-ZOUHS735-BscU8TUR.js +157 -0
- package/web/assets/stateDiagram-MLPALWAM-CJusEK2D.js +1 -0
- package/web/assets/stateDiagram-v2-B5LQ5ZB2-DImJ3PXD.js +1 -0
- package/web/assets/timeline-definition-5SPVSISX-DigPA1X8.js +120 -0
- package/web/assets/treeView-SZITEDCU-5DXDK3XO-CzPDt3aG.js +1 -0
- package/web/assets/treemap-W4RFUUIX-WYLRDWKO-B9Iqiorr.js +1 -0
- package/web/assets/vennDiagram-IE5QUKF5-C91UkZIf.js +34 -0
- package/web/assets/wardley-RL74JXVD-BCRCBASE-x42Qw7hp.js +1 -0
- package/web/assets/wardleyDiagram-XU3VSMPF-DloBhI0U.js +20 -0
- package/web/assets/xychartDiagram-ZHJ5623Y-BGWJvgwI.js +7 -0
- package/web/index.html +21 -0
- package/scripts/patch-tree-sitter-swift.cjs +0 -78
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture-match → semantic-shape interpreters for TypeScript.
|
|
3
|
+
*
|
|
4
|
+
* Two pure functions, both consumed by the central scope extractor:
|
|
5
|
+
*
|
|
6
|
+
* - `interpretTsImport` → `ParsedImport`
|
|
7
|
+
* - `interpretTsTypeBinding` → `ParsedTypeBinding` (wired in Unit 6)
|
|
8
|
+
*
|
|
9
|
+
* The import matches arrive pre-decomposed by `emitTsScopeCaptures`
|
|
10
|
+
* (one imported name per match, with synthesized
|
|
11
|
+
* `@import.kind/source/name/alias` markers — see `import-decomposer.ts`).
|
|
12
|
+
* The type-binding matches arrive straight from the raw query captures —
|
|
13
|
+
* each `@type-binding.*` anchor carries `@type-binding.name` +
|
|
14
|
+
* `@type-binding.type`.
|
|
15
|
+
*/
|
|
16
|
+
import type { CaptureMatch, ParsedImport, ParsedTypeBinding } from '../../../../_shared/index.js';
|
|
17
|
+
export declare function interpretTsImport(captures: CaptureMatch): ParsedImport | null;
|
|
18
|
+
/**
|
|
19
|
+
* Interpret a `@type-binding.*` capture-match into a `ParsedTypeBinding`.
|
|
20
|
+
*
|
|
21
|
+
* TypeScript-specific strips:
|
|
22
|
+
*
|
|
23
|
+
* - Trailing `?` on optional parameters: `(u?: User)` → `User`
|
|
24
|
+
* - `Promise<User>` / `Array<User>` / `ReadonlyArray<User>` / `Readonly<User>`
|
|
25
|
+
* → `User` (wrappers that are transparent to chain propagation)
|
|
26
|
+
* - Single-arg `List<User>` / `Iterable<User>` / `Iterator<User>` —
|
|
27
|
+
* mirrors Python/C#'s generic-collection strip for for-of loops
|
|
28
|
+
* - Trailing `[]` on array types: `User[]` → `User`
|
|
29
|
+
* - Nullable unions: `User | null` / `User | undefined` / `null | User`
|
|
30
|
+
* → `User`
|
|
31
|
+
* - Dotted qualifiers: `models.User` → `User` (unless the suffix is
|
|
32
|
+
* a known collection accessor we'd want to preserve — none apply
|
|
33
|
+
* to TS today, since TS uses `.values()` / `.keys()` call syntax)
|
|
34
|
+
*/
|
|
35
|
+
export declare function interpretTsTypeBinding(captures: CaptureMatch): ParsedTypeBinding | null;
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture-match → semantic-shape interpreters for TypeScript.
|
|
3
|
+
*
|
|
4
|
+
* Two pure functions, both consumed by the central scope extractor:
|
|
5
|
+
*
|
|
6
|
+
* - `interpretTsImport` → `ParsedImport`
|
|
7
|
+
* - `interpretTsTypeBinding` → `ParsedTypeBinding` (wired in Unit 6)
|
|
8
|
+
*
|
|
9
|
+
* The import matches arrive pre-decomposed by `emitTsScopeCaptures`
|
|
10
|
+
* (one imported name per match, with synthesized
|
|
11
|
+
* `@import.kind/source/name/alias` markers — see `import-decomposer.ts`).
|
|
12
|
+
* The type-binding matches arrive straight from the raw query captures —
|
|
13
|
+
* each `@type-binding.*` anchor carries `@type-binding.name` +
|
|
14
|
+
* `@type-binding.type`.
|
|
15
|
+
*/
|
|
16
|
+
// ─── interpretImport ──────────────────────────────────────────────────────
|
|
17
|
+
export function interpretTsImport(captures) {
|
|
18
|
+
// Markers attached by `splitImportStatement` (import-decomposer.ts):
|
|
19
|
+
// @import.kind : one of the kinds documented there
|
|
20
|
+
// @import.name : imported name from the source module
|
|
21
|
+
// @import.alias : local alias name (for default / aliased / namespace forms)
|
|
22
|
+
// @import.source : module path (always present except dynamic-unresolved)
|
|
23
|
+
const kindCap = captures['@import.kind'];
|
|
24
|
+
const nameCap = captures['@import.name'];
|
|
25
|
+
const aliasCap = captures['@import.alias'];
|
|
26
|
+
const sourceCap = captures['@import.source'];
|
|
27
|
+
const kind = kindCap?.text;
|
|
28
|
+
if (kind === undefined)
|
|
29
|
+
return null;
|
|
30
|
+
switch (kind) {
|
|
31
|
+
case 'default': {
|
|
32
|
+
// `import D from './m'` — semantically "alias for the module's
|
|
33
|
+
// default export". We map to ParsedImport `alias` with
|
|
34
|
+
// importedName='default' so the finalize algorithm looks up the
|
|
35
|
+
// target module's `default` export for cross-file resolution.
|
|
36
|
+
if (sourceCap === undefined || aliasCap === undefined)
|
|
37
|
+
return null;
|
|
38
|
+
return {
|
|
39
|
+
kind: 'alias',
|
|
40
|
+
localName: aliasCap.text,
|
|
41
|
+
importedName: 'default',
|
|
42
|
+
alias: aliasCap.text,
|
|
43
|
+
targetRaw: sourceCap.text,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
case 'named': {
|
|
47
|
+
// `import { X } from './m'` (plus type-only forms).
|
|
48
|
+
if (sourceCap === undefined || nameCap === undefined)
|
|
49
|
+
return null;
|
|
50
|
+
return {
|
|
51
|
+
kind: 'named',
|
|
52
|
+
localName: nameCap.text,
|
|
53
|
+
importedName: nameCap.text,
|
|
54
|
+
targetRaw: sourceCap.text,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
case 'named-alias': {
|
|
58
|
+
// `import { X as Y } from './m'`.
|
|
59
|
+
if (sourceCap === undefined || nameCap === undefined || aliasCap === undefined) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
kind: 'alias',
|
|
64
|
+
localName: aliasCap.text,
|
|
65
|
+
importedName: nameCap.text,
|
|
66
|
+
alias: aliasCap.text,
|
|
67
|
+
targetRaw: sourceCap.text,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
case 'namespace': {
|
|
71
|
+
// `import * as N from './m'` — `N` binds the whole module.
|
|
72
|
+
if (sourceCap === undefined || aliasCap === undefined)
|
|
73
|
+
return null;
|
|
74
|
+
return {
|
|
75
|
+
kind: 'namespace',
|
|
76
|
+
localName: aliasCap.text,
|
|
77
|
+
importedName: sourceCap.text,
|
|
78
|
+
targetRaw: sourceCap.text,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
case 'reexport': {
|
|
82
|
+
// `export { X } from './m'`.
|
|
83
|
+
if (sourceCap === undefined || nameCap === undefined)
|
|
84
|
+
return null;
|
|
85
|
+
return {
|
|
86
|
+
kind: 'reexport',
|
|
87
|
+
localName: nameCap.text,
|
|
88
|
+
importedName: nameCap.text,
|
|
89
|
+
targetRaw: sourceCap.text,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
case 'reexport-alias': {
|
|
93
|
+
// `export { X as Y } from './m'`.
|
|
94
|
+
if (sourceCap === undefined || nameCap === undefined || aliasCap === undefined) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
kind: 'reexport',
|
|
99
|
+
localName: aliasCap.text,
|
|
100
|
+
importedName: nameCap.text,
|
|
101
|
+
alias: aliasCap.text,
|
|
102
|
+
targetRaw: sourceCap.text,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
case 'reexport-wildcard': {
|
|
106
|
+
// `export * from './m'` — no local name, just a blanket passthrough.
|
|
107
|
+
if (sourceCap === undefined)
|
|
108
|
+
return null;
|
|
109
|
+
return { kind: 'wildcard', targetRaw: sourceCap.text };
|
|
110
|
+
}
|
|
111
|
+
case 'reexport-namespace': {
|
|
112
|
+
// `export * as ns from './m'` — creates a local binding `ns`
|
|
113
|
+
// that exposes the whole module, while also re-exporting it.
|
|
114
|
+
// Closest ParsedImport fit is `namespace`; the re-export side
|
|
115
|
+
// of this edge is tracked by the export detector downstream.
|
|
116
|
+
if (sourceCap === undefined || aliasCap === undefined)
|
|
117
|
+
return null;
|
|
118
|
+
return {
|
|
119
|
+
kind: 'namespace',
|
|
120
|
+
localName: aliasCap.text,
|
|
121
|
+
importedName: sourceCap.text,
|
|
122
|
+
targetRaw: sourceCap.text,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
case 'dynamic': {
|
|
126
|
+
// `import('./m')` / `import(x)`. The decomposer marks literal-
|
|
127
|
+
// string arguments with `@import.literal` so we can promote them
|
|
128
|
+
// to `dynamic-resolved` here — that lets the shared finalizer
|
|
129
|
+
// produce a file-level IMPORTS edge for lazy-loaded modules.
|
|
130
|
+
// Non-literal arguments stay `dynamic-unresolved` (target is
|
|
131
|
+
// runtime-computed and unreachable to the static finalizer).
|
|
132
|
+
const isLiteral = captures['@import.literal'] !== undefined;
|
|
133
|
+
if (isLiteral && sourceCap !== undefined) {
|
|
134
|
+
return { kind: 'dynamic-resolved', targetRaw: sourceCap.text };
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
kind: 'dynamic-unresolved',
|
|
138
|
+
localName: '',
|
|
139
|
+
targetRaw: sourceCap?.text ?? null,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
case 'side-effect': {
|
|
143
|
+
// `import './polyfill'` — bare-source, no local binding. The
|
|
144
|
+
// finalize layer resolves to a target file and emits a
|
|
145
|
+
// file-level IMPORTS edge; no `BindingRef` is materialized.
|
|
146
|
+
if (sourceCap === undefined)
|
|
147
|
+
return null;
|
|
148
|
+
return { kind: 'side-effect', targetRaw: sourceCap.text };
|
|
149
|
+
}
|
|
150
|
+
default:
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// ─── interpretTypeBinding ─────────────────────────────────────────────────
|
|
155
|
+
/**
|
|
156
|
+
* Interpret a `@type-binding.*` capture-match into a `ParsedTypeBinding`.
|
|
157
|
+
*
|
|
158
|
+
* TypeScript-specific strips:
|
|
159
|
+
*
|
|
160
|
+
* - Trailing `?` on optional parameters: `(u?: User)` → `User`
|
|
161
|
+
* - `Promise<User>` / `Array<User>` / `ReadonlyArray<User>` / `Readonly<User>`
|
|
162
|
+
* → `User` (wrappers that are transparent to chain propagation)
|
|
163
|
+
* - Single-arg `List<User>` / `Iterable<User>` / `Iterator<User>` —
|
|
164
|
+
* mirrors Python/C#'s generic-collection strip for for-of loops
|
|
165
|
+
* - Trailing `[]` on array types: `User[]` → `User`
|
|
166
|
+
* - Nullable unions: `User | null` / `User | undefined` / `null | User`
|
|
167
|
+
* → `User`
|
|
168
|
+
* - Dotted qualifiers: `models.User` → `User` (unless the suffix is
|
|
169
|
+
* a known collection accessor we'd want to preserve — none apply
|
|
170
|
+
* to TS today, since TS uses `.values()` / `.keys()` call syntax)
|
|
171
|
+
*/
|
|
172
|
+
export function interpretTsTypeBinding(captures) {
|
|
173
|
+
const nameCap = captures['@type-binding.name'];
|
|
174
|
+
const typeCap = captures['@type-binding.type'];
|
|
175
|
+
if (nameCap === undefined || typeCap === undefined)
|
|
176
|
+
return null;
|
|
177
|
+
// Readonly/array/nullable wrappers can stack; apply passes until a
|
|
178
|
+
// fixed point (bounded by the text length since every strip monotonically
|
|
179
|
+
// shrinks the string).
|
|
180
|
+
let prev = '';
|
|
181
|
+
let rawType = typeCap.text.trim();
|
|
182
|
+
while (prev !== rawType) {
|
|
183
|
+
prev = rawType;
|
|
184
|
+
rawType = stripReadonly(rawType);
|
|
185
|
+
rawType = stripNullableUnion(rawType);
|
|
186
|
+
rawType = stripGeneric(rawType);
|
|
187
|
+
rawType = stripArraySuffix(rawType);
|
|
188
|
+
}
|
|
189
|
+
// Destructuring / member-alias / map-tuple / dotted-call-alias bindings
|
|
190
|
+
// carry receiver paths or sentinel strings that must survive verbatim.
|
|
191
|
+
// Also preserve dotted member-call callee text (`svc.getUser`) for
|
|
192
|
+
// `@type-binding.alias` — stripQualifier would reduce it to `getUser`,
|
|
193
|
+
// breaking compound-receiver's `obj.method()` split.
|
|
194
|
+
const isDestructured = captures['@type-binding.destructured'] !== undefined;
|
|
195
|
+
const isMemberAlias = captures['@type-binding.member-alias'] !== undefined;
|
|
196
|
+
const isMapTupleEntry = captures['@type-binding.map-tuple-entry'] !== undefined;
|
|
197
|
+
const isInstanceofNarrow = captures['@type-binding.instanceof-narrow'] !== undefined;
|
|
198
|
+
const isAlias = captures['@type-binding.alias'] !== undefined;
|
|
199
|
+
const preserveRawTypeName = isDestructured ||
|
|
200
|
+
isMemberAlias ||
|
|
201
|
+
isMapTupleEntry ||
|
|
202
|
+
isInstanceofNarrow ||
|
|
203
|
+
(isAlias && rawType.includes('.'));
|
|
204
|
+
if (!preserveRawTypeName) {
|
|
205
|
+
rawType = stripQualifier(rawType);
|
|
206
|
+
}
|
|
207
|
+
// Drop non-discriminating / wildcard types — `as any` / `as unknown`
|
|
208
|
+
// should not block a more-informative sibling binding (typically the
|
|
209
|
+
// constructor-inferred capture from the inner `new_expression`). By
|
|
210
|
+
// returning null here we let the scope-extractor's tie-break select
|
|
211
|
+
// the next-best binding for the same name.
|
|
212
|
+
if (UNINFORMATIVE_TYPES.has(rawType))
|
|
213
|
+
return null;
|
|
214
|
+
// Anchor captures distinguish the source of the binding. Order
|
|
215
|
+
// matters: more-specific anchors take precedence. `this` is a
|
|
216
|
+
// TypeScript-specific receiver synthesized in `receiver-binding.ts`
|
|
217
|
+
// (Unit 3); treat it as `self` for Registry.lookup parity with
|
|
218
|
+
// Python/C#.
|
|
219
|
+
let source = 'parameter-annotation';
|
|
220
|
+
if (captures['@type-binding.this'] !== undefined)
|
|
221
|
+
source = 'self';
|
|
222
|
+
else if (captures['@type-binding.constructor'] !== undefined)
|
|
223
|
+
source = 'constructor-inferred';
|
|
224
|
+
else if (captures['@type-binding.assertion'] !== undefined)
|
|
225
|
+
source = 'annotation';
|
|
226
|
+
else if (captures['@type-binding.annotation'] !== undefined)
|
|
227
|
+
source = 'annotation';
|
|
228
|
+
else if (captures['@type-binding.member-alias'] !== undefined)
|
|
229
|
+
source = 'assignment-inferred';
|
|
230
|
+
else if (captures['@type-binding.alias'] !== undefined)
|
|
231
|
+
source = 'assignment-inferred';
|
|
232
|
+
else if (captures['@type-binding.return'] !== undefined)
|
|
233
|
+
source = 'return-annotation';
|
|
234
|
+
else if (captures['@type-binding.parameter-property'] !== undefined)
|
|
235
|
+
source = 'annotation';
|
|
236
|
+
else if (captures['@type-binding.destructured'] !== undefined)
|
|
237
|
+
source = 'assignment-inferred';
|
|
238
|
+
else if (captures['@type-binding.map-tuple-entry'] !== undefined)
|
|
239
|
+
source = 'assignment-inferred';
|
|
240
|
+
else if (captures['@type-binding.instanceof-narrow'] !== undefined)
|
|
241
|
+
source = 'annotation';
|
|
242
|
+
return { boundName: nameCap.text, rawTypeName: rawType, source };
|
|
243
|
+
}
|
|
244
|
+
/** Types that carry no discriminating information for chain resolution.
|
|
245
|
+
* `any` / `unknown` / `object` / `never` / `void` match anything, so a
|
|
246
|
+
* sibling capture (e.g. a constructor-inferred type from `new X() as any`)
|
|
247
|
+
* is strictly preferable. Empty string emerges from malformed captures
|
|
248
|
+
* and is also useless. `null` / `undefined` shouldn't survive
|
|
249
|
+
* stripNullableUnion but are listed here for defense-in-depth. */
|
|
250
|
+
const UNINFORMATIVE_TYPES = new Set([
|
|
251
|
+
'',
|
|
252
|
+
'any',
|
|
253
|
+
'unknown',
|
|
254
|
+
'object',
|
|
255
|
+
'never',
|
|
256
|
+
'void',
|
|
257
|
+
'null',
|
|
258
|
+
'undefined',
|
|
259
|
+
]);
|
|
260
|
+
/** `readonly User[]` → `User[]`. Applied before stripArraySuffix so
|
|
261
|
+
* `readonly User[]` reduces through the same pipeline. */
|
|
262
|
+
function stripReadonly(text) {
|
|
263
|
+
if (text.startsWith('readonly '))
|
|
264
|
+
return text.slice('readonly '.length).trim();
|
|
265
|
+
return text;
|
|
266
|
+
}
|
|
267
|
+
/** `User | null` / `User | undefined` / `null | User | undefined` → `User`.
|
|
268
|
+
* Any number of `null` / `undefined` arms may appear; collapse to the
|
|
269
|
+
* single remaining discriminating arm. Preserves multi-arm unions
|
|
270
|
+
* of real types (`User | Admin`) since the concrete receiver type is
|
|
271
|
+
* ambiguous. */
|
|
272
|
+
function stripNullableUnion(text) {
|
|
273
|
+
const parts = text.split('|').map((p) => p.trim());
|
|
274
|
+
if (parts.length < 2)
|
|
275
|
+
return text;
|
|
276
|
+
const NULLS = new Set(['null', 'undefined']);
|
|
277
|
+
const nonNull = parts.filter((p) => !NULLS.has(p));
|
|
278
|
+
if (nonNull.length === 1)
|
|
279
|
+
return nonNull[0];
|
|
280
|
+
return text;
|
|
281
|
+
}
|
|
282
|
+
/** Single-arg generic wrappers transparent to receiver-type chain
|
|
283
|
+
* propagation: `Promise<X>`, `Array<X>`, `ReadonlyArray<X>`,
|
|
284
|
+
* `Readonly<X>`, `Iterable<X>`, `Iterator<X>`, `Set<X>`, `List<X>`,
|
|
285
|
+
* `Map<X>` (single-arg form rare but kept for completeness), etc.
|
|
286
|
+
* Multi-arg generics (`Map<K, V>`, `Record<K, V>`) are left alone —
|
|
287
|
+
* element semantics aren't unambiguous. */
|
|
288
|
+
function stripGeneric(text) {
|
|
289
|
+
const single = text.match(/^(?:[A-Za-z_][A-Za-z0-9_]*\.)?(?:Promise|Array|ReadonlyArray|Readonly|Iterable|Iterator|AsyncIterable|AsyncIterator|AsyncGenerator|Generator|Set|ReadonlySet|List|Awaited)<([^,<>]+)>$/);
|
|
290
|
+
if (single !== null)
|
|
291
|
+
return single[1].trim();
|
|
292
|
+
return text;
|
|
293
|
+
}
|
|
294
|
+
/** `User[]` / `(User)[]` → `User`. Chained `User[][]` unwraps one
|
|
295
|
+
* level at a time per resolve pass. */
|
|
296
|
+
function stripArraySuffix(text) {
|
|
297
|
+
if (text.endsWith('[]')) {
|
|
298
|
+
const inner = text.slice(0, -2).trim();
|
|
299
|
+
// Unwrap a single pair of parentheses introduced for precedence
|
|
300
|
+
// disambiguation: `(User | Admin)[]` — we leave the union intact
|
|
301
|
+
// but drop the parens.
|
|
302
|
+
if (inner.startsWith('(') && inner.endsWith(')')) {
|
|
303
|
+
return inner.slice(1, -1).trim();
|
|
304
|
+
}
|
|
305
|
+
return inner;
|
|
306
|
+
}
|
|
307
|
+
return text;
|
|
308
|
+
}
|
|
309
|
+
/** `models.User` → `User`. TS doesn't carry a qualified-suffix exception
|
|
310
|
+
* list today — `.values()` / `.keys()` use method-call syntax and are
|
|
311
|
+
* resolved via the member-call chain, not via a dotted type. */
|
|
312
|
+
function stripQualifier(text) {
|
|
313
|
+
const lastDot = text.lastIndexOf('.');
|
|
314
|
+
if (lastDot === -1)
|
|
315
|
+
return text;
|
|
316
|
+
return text.slice(lastDot + 1);
|
|
317
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript declaration-merging + LEGB precedence for the `mergeBindings`
|
|
3
|
+
* hook.
|
|
4
|
+
*
|
|
5
|
+
* TypeScript has a unique wrinkle that Python / C# don't: **declaration
|
|
6
|
+
* merging**. The same name can legally coexist in several "declaration
|
|
7
|
+
* spaces" simultaneously:
|
|
8
|
+
*
|
|
9
|
+
* - **value** space — `class X`, `function X`, `const X`, `var X`,
|
|
10
|
+
* `let X`, `enum X`, `namespace X` (adds runtime object)
|
|
11
|
+
* - **type** space — `interface X`, `type X`, `class X`, `enum X`
|
|
12
|
+
* - **namespace** space — `namespace X`, `class X` (static-accessed
|
|
13
|
+
* members are reachable via dotted name)
|
|
14
|
+
*
|
|
15
|
+
* Classes and enums are unique in that each declaration occupies both
|
|
16
|
+
* the value AND type spaces. This lets:
|
|
17
|
+
*
|
|
18
|
+
* class Foo {}
|
|
19
|
+
* interface Foo { bar: number; } // merges additional type members
|
|
20
|
+
* namespace Foo { export const X = 1; } // adds static-like value
|
|
21
|
+
*
|
|
22
|
+
* all coexist for the same name.
|
|
23
|
+
*
|
|
24
|
+
* ## Algorithm
|
|
25
|
+
*
|
|
26
|
+
* For each declaration space independently:
|
|
27
|
+
* 1. Tier bindings by origin (lower wins):
|
|
28
|
+
* 0 — `local`
|
|
29
|
+
* 1 — `import` / `namespace` / `reexport`
|
|
30
|
+
* 2 — `wildcard` (`export * from …`)
|
|
31
|
+
* 2. Keep only bindings at the best (lowest) tier in that space.
|
|
32
|
+
*
|
|
33
|
+
* Then union survivors across spaces and dedupe by `DefId`.
|
|
34
|
+
*
|
|
35
|
+
* ## Shadowing examples
|
|
36
|
+
*
|
|
37
|
+
* - `class Foo {}` + `function Foo() {}` in same scope → COMPILE ERROR
|
|
38
|
+
* in TS source, but if both reach us with distinct DefIds we keep
|
|
39
|
+
* both (value space has two locals at tier 0 — de-dup by nodeId
|
|
40
|
+
* preserves both). No worse than C#-style merge.
|
|
41
|
+
* - `class Foo {}` (local, value+type) + `import type { Foo } from './a'`
|
|
42
|
+
* (tier-1, type-only) → local wins in both type AND value spaces;
|
|
43
|
+
* the import is not kept.
|
|
44
|
+
* - `interface Foo {}` (local, type-only) + `import { Foo } from './a'`
|
|
45
|
+
* (tier-1, value+type) → local wins in type space; import wins in
|
|
46
|
+
* value space (local doesn't occupy it). Both kept.
|
|
47
|
+
* - `namespace Foo {}` (local, namespace+value) + `class Foo {}` (local,
|
|
48
|
+
* value+type) → both at tier 0 in their respective spaces, kept.
|
|
49
|
+
*
|
|
50
|
+
* ## Limitations
|
|
51
|
+
*
|
|
52
|
+
* - We classify imports by their `def.type` just like locals. Without
|
|
53
|
+
* a space-annotation on `ParsedImport`, `import type { Foo }` looks
|
|
54
|
+
* the same as `import { Foo }` at this layer — the parse phase
|
|
55
|
+
* decomposer marks type-only imports so the extractor CAN annotate
|
|
56
|
+
* `def.type = 'Type'` downstream if desired. Today it doesn't, so
|
|
57
|
+
* `import type` imports and value imports fall in the same bucket
|
|
58
|
+
* per their target def's NodeLabel. Parity with legacy behavior
|
|
59
|
+
* (which also doesn't track type-only separately) is preserved.
|
|
60
|
+
*/
|
|
61
|
+
import type { BindingRef } from '../../../../_shared/index.js';
|
|
62
|
+
export declare function typescriptMergeBindings(bindings: readonly BindingRef[]): readonly BindingRef[];
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript declaration-merging + LEGB precedence for the `mergeBindings`
|
|
3
|
+
* hook.
|
|
4
|
+
*
|
|
5
|
+
* TypeScript has a unique wrinkle that Python / C# don't: **declaration
|
|
6
|
+
* merging**. The same name can legally coexist in several "declaration
|
|
7
|
+
* spaces" simultaneously:
|
|
8
|
+
*
|
|
9
|
+
* - **value** space — `class X`, `function X`, `const X`, `var X`,
|
|
10
|
+
* `let X`, `enum X`, `namespace X` (adds runtime object)
|
|
11
|
+
* - **type** space — `interface X`, `type X`, `class X`, `enum X`
|
|
12
|
+
* - **namespace** space — `namespace X`, `class X` (static-accessed
|
|
13
|
+
* members are reachable via dotted name)
|
|
14
|
+
*
|
|
15
|
+
* Classes and enums are unique in that each declaration occupies both
|
|
16
|
+
* the value AND type spaces. This lets:
|
|
17
|
+
*
|
|
18
|
+
* class Foo {}
|
|
19
|
+
* interface Foo { bar: number; } // merges additional type members
|
|
20
|
+
* namespace Foo { export const X = 1; } // adds static-like value
|
|
21
|
+
*
|
|
22
|
+
* all coexist for the same name.
|
|
23
|
+
*
|
|
24
|
+
* ## Algorithm
|
|
25
|
+
*
|
|
26
|
+
* For each declaration space independently:
|
|
27
|
+
* 1. Tier bindings by origin (lower wins):
|
|
28
|
+
* 0 — `local`
|
|
29
|
+
* 1 — `import` / `namespace` / `reexport`
|
|
30
|
+
* 2 — `wildcard` (`export * from …`)
|
|
31
|
+
* 2. Keep only bindings at the best (lowest) tier in that space.
|
|
32
|
+
*
|
|
33
|
+
* Then union survivors across spaces and dedupe by `DefId`.
|
|
34
|
+
*
|
|
35
|
+
* ## Shadowing examples
|
|
36
|
+
*
|
|
37
|
+
* - `class Foo {}` + `function Foo() {}` in same scope → COMPILE ERROR
|
|
38
|
+
* in TS source, but if both reach us with distinct DefIds we keep
|
|
39
|
+
* both (value space has two locals at tier 0 — de-dup by nodeId
|
|
40
|
+
* preserves both). No worse than C#-style merge.
|
|
41
|
+
* - `class Foo {}` (local, value+type) + `import type { Foo } from './a'`
|
|
42
|
+
* (tier-1, type-only) → local wins in both type AND value spaces;
|
|
43
|
+
* the import is not kept.
|
|
44
|
+
* - `interface Foo {}` (local, type-only) + `import { Foo } from './a'`
|
|
45
|
+
* (tier-1, value+type) → local wins in type space; import wins in
|
|
46
|
+
* value space (local doesn't occupy it). Both kept.
|
|
47
|
+
* - `namespace Foo {}` (local, namespace+value) + `class Foo {}` (local,
|
|
48
|
+
* value+type) → both at tier 0 in their respective spaces, kept.
|
|
49
|
+
*
|
|
50
|
+
* ## Limitations
|
|
51
|
+
*
|
|
52
|
+
* - We classify imports by their `def.type` just like locals. Without
|
|
53
|
+
* a space-annotation on `ParsedImport`, `import type { Foo }` looks
|
|
54
|
+
* the same as `import { Foo }` at this layer — the parse phase
|
|
55
|
+
* decomposer marks type-only imports so the extractor CAN annotate
|
|
56
|
+
* `def.type = 'Type'` downstream if desired. Today it doesn't, so
|
|
57
|
+
* `import type` imports and value imports fall in the same bucket
|
|
58
|
+
* per their target def's NodeLabel. Parity with legacy behavior
|
|
59
|
+
* (which also doesn't track type-only separately) is preserved.
|
|
60
|
+
*/
|
|
61
|
+
const TIER_LOCAL = 0;
|
|
62
|
+
const TIER_IMPORT = 1;
|
|
63
|
+
const TIER_WILDCARD = 2;
|
|
64
|
+
const TIER_UNKNOWN = 3;
|
|
65
|
+
function tierOf(b) {
|
|
66
|
+
switch (b.origin) {
|
|
67
|
+
case 'local':
|
|
68
|
+
return TIER_LOCAL;
|
|
69
|
+
case 'reexport':
|
|
70
|
+
case 'import':
|
|
71
|
+
case 'namespace':
|
|
72
|
+
return TIER_IMPORT;
|
|
73
|
+
case 'wildcard':
|
|
74
|
+
return TIER_WILDCARD;
|
|
75
|
+
default:
|
|
76
|
+
return TIER_UNKNOWN;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Map a `SymbolDefinition.type` (`NodeLabel`) to the set of TypeScript
|
|
81
|
+
* declaration spaces the binding occupies.
|
|
82
|
+
*
|
|
83
|
+
* Unknown / unused labels default to `['value']` — the permissive choice,
|
|
84
|
+
* matching legacy behavior where everything lives in a single flat bucket.
|
|
85
|
+
*/
|
|
86
|
+
function spacesOf(type) {
|
|
87
|
+
switch (type) {
|
|
88
|
+
// value-only
|
|
89
|
+
case 'Function':
|
|
90
|
+
case 'Method':
|
|
91
|
+
case 'Variable':
|
|
92
|
+
case 'Const':
|
|
93
|
+
case 'Static':
|
|
94
|
+
case 'Property':
|
|
95
|
+
case 'Constructor':
|
|
96
|
+
case 'Macro':
|
|
97
|
+
return ['value'];
|
|
98
|
+
// type-only
|
|
99
|
+
case 'Interface':
|
|
100
|
+
case 'Type':
|
|
101
|
+
case 'TypeAlias':
|
|
102
|
+
case 'Typedef':
|
|
103
|
+
case 'Trait':
|
|
104
|
+
case 'Annotation':
|
|
105
|
+
case 'Decorator':
|
|
106
|
+
return ['type'];
|
|
107
|
+
// dual: value AND type
|
|
108
|
+
case 'Class':
|
|
109
|
+
case 'Enum':
|
|
110
|
+
case 'Struct':
|
|
111
|
+
case 'Record':
|
|
112
|
+
case 'Union':
|
|
113
|
+
return ['value', 'type'];
|
|
114
|
+
// namespace AND value (namespaces introduce a runtime object AND a
|
|
115
|
+
// named scope for static-style access)
|
|
116
|
+
case 'Namespace':
|
|
117
|
+
case 'Module':
|
|
118
|
+
return ['namespace', 'value'];
|
|
119
|
+
// catch-all — treat as value to match legacy permissive behavior
|
|
120
|
+
default:
|
|
121
|
+
return ['value'];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
export function typescriptMergeBindings(bindings) {
|
|
125
|
+
if (bindings.length === 0)
|
|
126
|
+
return bindings;
|
|
127
|
+
// Partition bindings by space. A single binding occupying two spaces
|
|
128
|
+
// (e.g. a class) is duplicated into both partitions; the final dedupe
|
|
129
|
+
// by nodeId collapses it back.
|
|
130
|
+
const perSpace = new Map();
|
|
131
|
+
for (const b of bindings) {
|
|
132
|
+
const spaces = spacesOf(b.def.type);
|
|
133
|
+
for (const s of spaces) {
|
|
134
|
+
const list = perSpace.get(s);
|
|
135
|
+
if (list === undefined)
|
|
136
|
+
perSpace.set(s, [b]);
|
|
137
|
+
else
|
|
138
|
+
list.push(b);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Within each space, keep only the best-tier bindings.
|
|
142
|
+
const survivorsSet = new Set();
|
|
143
|
+
for (const list of perSpace.values()) {
|
|
144
|
+
let bestTier = Number.POSITIVE_INFINITY;
|
|
145
|
+
for (const b of list)
|
|
146
|
+
bestTier = Math.min(bestTier, tierOf(b));
|
|
147
|
+
for (const b of list) {
|
|
148
|
+
if (tierOf(b) === bestTier)
|
|
149
|
+
survivorsSet.add(b);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Dedupe by def.nodeId. If the same binding survived in multiple
|
|
153
|
+
// spaces (e.g. a class in both value + type) we keep a single entry.
|
|
154
|
+
const seen = new Map();
|
|
155
|
+
for (const b of survivorsSet)
|
|
156
|
+
seen.set(b.def.nodeId, b);
|
|
157
|
+
return [...seen.values()];
|
|
158
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tree-sitter query for TypeScript scope captures (RFC §5.1).
|
|
3
|
+
*
|
|
4
|
+
* Captures the structural skeleton the generic scope-resolution pipeline
|
|
5
|
+
* consumes: scopes (module/namespace/class/function), declarations (class-
|
|
6
|
+
* likes, method-likes, properties, variables), imports (one anchor per
|
|
7
|
+
* statement — decomposed in `import-decomposer.ts`), type bindings
|
|
8
|
+
* (parameter annotations, variable annotations, constructor inference,
|
|
9
|
+
* return types), and references (call sites, member writes).
|
|
10
|
+
*
|
|
11
|
+
* TypeScript specifics that shape this query:
|
|
12
|
+
*
|
|
13
|
+
* - **Namespaces** (`namespace Foo { }`) use `internal_module` with a
|
|
14
|
+
* `namespace` anon keyword + `identifier` or `nested_identifier` name +
|
|
15
|
+
* `statement_block` body. Verified via Unit 1 probe.
|
|
16
|
+
* - **`this` / `super`** are NAMED nodes `(this)` / `(super)` — unlike
|
|
17
|
+
* C#'s `this`/`base` which are anonymous tokens. `(_)` wildcard matches
|
|
18
|
+
* them as the receiver child of `member_expression`, so we don't need
|
|
19
|
+
* explicit string patterns.
|
|
20
|
+
* - **Optional chaining** (`obj?.m()`) still matches the regular
|
|
21
|
+
* `member_expression > object: (_) / property: (property_identifier)`
|
|
22
|
+
* pattern; the `(optional_chain)` child sits between them but doesn't
|
|
23
|
+
* occupy a named field. Same query handles both.
|
|
24
|
+
* - **Dynamic imports** (`import('./mod')`) are `call_expression` whose
|
|
25
|
+
* `function` field is a named `import` node (not a regular identifier).
|
|
26
|
+
* Captured via a dedicated pattern.
|
|
27
|
+
* - **Function overloads** — `function f(x:string); function f(x:number);
|
|
28
|
+
* function f(x) { … }` emits two `function_signature` nodes plus one
|
|
29
|
+
* `function_declaration`. All three emit `@declaration.function`;
|
|
30
|
+
* arity metadata synthesis merges parameterTypes.
|
|
31
|
+
* - **Parameter properties** (`constructor(public name: string)`) — each
|
|
32
|
+
* parameter emits `@declaration.property` on the enclosing class; the
|
|
33
|
+
* same identifier also binds as a parameter in the constructor scope
|
|
34
|
+
* via the normal `required_parameter` → `@type-binding.parameter` path.
|
|
35
|
+
* - **Enum** — dual type+value. Emits `@scope.class` (enum body contains
|
|
36
|
+
* member declarations) + `@declaration.enum`. Members are captured as
|
|
37
|
+
* `@declaration.property` via the generic property_identifier pattern
|
|
38
|
+
* inside enum_body.
|
|
39
|
+
*
|
|
40
|
+
* Node types pinned via `scripts/_probe_typescript_grammar.ts`:
|
|
41
|
+
* internal_module, namespace_export, namespace_import, import_specifier,
|
|
42
|
+
* export_specifier, enum_declaration, type_alias_declaration,
|
|
43
|
+
* abstract_class_declaration, abstract_method_signature, method_signature,
|
|
44
|
+
* generator_function_declaration, optional_parameter, rest_parameter,
|
|
45
|
+
* required_parameter, public_field_definition, private_property_identifier,
|
|
46
|
+
* new_expression (constructor field), call_expression with (import) fn.
|
|
47
|
+
*
|
|
48
|
+
* Grammar version: tree-sitter-typescript pinned in gitnexus/package.json.
|
|
49
|
+
*
|
|
50
|
+
* Exposes lazy `Parser` and `Query` singletons so callers don't pay tree-
|
|
51
|
+
* sitter init cost per file.
|
|
52
|
+
*/
|
|
53
|
+
import Parser from 'tree-sitter';
|
|
54
|
+
/**
|
|
55
|
+
* Return the right tree-sitter parser for `filePath` (or the TS parser
|
|
56
|
+
* when no path is given — the legacy callsite shape).
|
|
57
|
+
*/
|
|
58
|
+
export declare function getTsParser(filePath?: string): Parser;
|
|
59
|
+
/**
|
|
60
|
+
* Return the right tree-sitter Query (compiled against the same grammar
|
|
61
|
+
* as the parser). A Query bound to the `typescript` grammar can NOT be
|
|
62
|
+
* executed against a Tree produced by the `tsx` grammar — tree-sitter
|
|
63
|
+
* matches by node-type id, and the two grammars have separate id
|
|
64
|
+
* spaces.
|
|
65
|
+
*/
|
|
66
|
+
export declare function getTsScopeQuery(filePath?: string): Parser.Query;
|
|
67
|
+
/**
|
|
68
|
+
* Validate that a cached `Tree` was produced by the grammar matching
|
|
69
|
+
* `filePath` (TSX vs TypeScript). The runtime tree-sitter `Tree` exposes
|
|
70
|
+
* `getLanguage()` (returning the grammar object the parser was bound
|
|
71
|
+
* to); the .d.ts is incomplete, so we reach via a cast. Identity
|
|
72
|
+
* comparison against `TSX_GRAMMAR` / `TS_GRAMMAR` is exact: the same
|
|
73
|
+
* module instance produces both. If `getLanguage` is unavailable for
|
|
74
|
+
* any reason, return true to keep behavior backwards-compatible (the
|
|
75
|
+
* original code never validated grammar at all).
|
|
76
|
+
*/
|
|
77
|
+
export declare function tsCachedTreeMatchesGrammar(tree: unknown, filePath: string): boolean;
|