gitnexus 1.6.3 → 1.6.4-rc.10
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/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/core/embeddings/embedder.js +2 -1
- package/dist/core/ingestion/call-processor.js +2 -2
- 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/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 +2 -1
- 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/model/scope-resolution-indexes.d.ts +14 -1
- package/dist/core/ingestion/parsing-processor.js +3 -3
- 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/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.js +3 -3
- package/dist/core/lbug/lbug-adapter.d.ts +3 -4
- package/dist/core/lbug/lbug-adapter.js +6 -9
- package/dist/core/run-analyze.js +4 -6
- 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 +3 -1
- package/package.json +1 -1
- package/skills/gitnexus-cli.md +1 -1
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decompose a TypeScript `import_statement` / re-export `export_statement` /
|
|
3
|
+
* dynamic `call_expression(import)` into one `CaptureMatch` per imported
|
|
4
|
+
* name.
|
|
5
|
+
*
|
|
6
|
+
* Why split here? The `LanguageProvider.interpretImport` contract is
|
|
7
|
+
* one `ParsedImport` per call. Tree-sitter delivers
|
|
8
|
+
*
|
|
9
|
+
* import D, { X as Y, type Z } from './m'
|
|
10
|
+
*
|
|
11
|
+
* as a single `import_statement` match, so without decomposition we'd
|
|
12
|
+
* lose names. The synthesized markers (`@import.kind` / `@import.name`
|
|
13
|
+
* / `@import.alias` / `@import.source`) carry everything
|
|
14
|
+
* `interpretTsImport` needs to recover the `ParsedImport` shape —
|
|
15
|
+
* see `interpret.ts`.
|
|
16
|
+
*
|
|
17
|
+
* Kinds we emit and how `interpret.ts` maps them to `ParsedImport`:
|
|
18
|
+
*
|
|
19
|
+
* - `default` : `import D from './m'` → alias (importedName=default)
|
|
20
|
+
* - `named` : `import { X } from './m'` → named
|
|
21
|
+
* - `named-alias` : `import { X as Y } from './m'` → alias
|
|
22
|
+
* - `namespace` : `import * as N from './m'` → namespace
|
|
23
|
+
* - `reexport` : `export { X } from './m'` → reexport
|
|
24
|
+
* - `reexport-alias` : `export { X as Y } from './m'` → reexport (with alias)
|
|
25
|
+
* - `reexport-wildcard` : `export * from './m'` → wildcard
|
|
26
|
+
* - `reexport-namespace` : `export * as ns from './m'` → namespace (local=ns,imported=source)
|
|
27
|
+
* - `dynamic` : `import('./m')` / `import(x)` → dynamic-resolved or dynamic-unresolved
|
|
28
|
+
*
|
|
29
|
+
* Type-only constructs (`import type { X }`, `import { type X }`,
|
|
30
|
+
* `export type { X }`) emit the same kinds as runtime forms — at the
|
|
31
|
+
* TypeScript scope-resolution layer, types and values share the same
|
|
32
|
+
* lookup; runtime-emission is a downstream concern.
|
|
33
|
+
*
|
|
34
|
+
* Side-effect imports (`import './polyfill'`) produce a single match
|
|
35
|
+
* with `kind: 'side-effect'`. The shared finalize algorithm resolves
|
|
36
|
+
* the target file and emits a file-level IMPORTS edge, but
|
|
37
|
+
* materializes no `BindingRef` (matching the legacy DAG, which counts
|
|
38
|
+
* `import './polyfill'` as a module-reachability dependency only).
|
|
39
|
+
*/
|
|
40
|
+
import { findChild, nodeToCapture, syntheticCapture, } from '../../utils/ast-helpers.js';
|
|
41
|
+
/**
|
|
42
|
+
* Decompose an import anchor. Handles three node types:
|
|
43
|
+
*
|
|
44
|
+
* - `import_statement` : all static import forms (incl. side-effect)
|
|
45
|
+
* - `export_statement` (w/ source) : re-exports
|
|
46
|
+
* - `call_expression` (import fn) : dynamic `import()`
|
|
47
|
+
*/
|
|
48
|
+
export function splitImportStatement(stmtNode) {
|
|
49
|
+
if (stmtNode.type === 'import_statement')
|
|
50
|
+
return splitImport(stmtNode);
|
|
51
|
+
if (stmtNode.type === 'export_statement')
|
|
52
|
+
return splitReexport(stmtNode);
|
|
53
|
+
if (stmtNode.type === 'call_expression')
|
|
54
|
+
return splitDynamicImport(stmtNode);
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
// ─── static imports ─────────────────────────────────────────────────────
|
|
58
|
+
function splitImport(stmtNode) {
|
|
59
|
+
// `import_statement` shape:
|
|
60
|
+
// import_clause? "from" string (static form with bindings)
|
|
61
|
+
// string (side-effect `import './m'`)
|
|
62
|
+
//
|
|
63
|
+
// The `source` field is the string literal — we strip its surrounding
|
|
64
|
+
// quotes. An import without an `import_clause` child is side-effect
|
|
65
|
+
// only and still emits one non-binding match.
|
|
66
|
+
const source = extractSource(stmtNode);
|
|
67
|
+
if (source === null)
|
|
68
|
+
return [];
|
|
69
|
+
const importClause = findChild(stmtNode, 'import_clause');
|
|
70
|
+
if (importClause === null) {
|
|
71
|
+
// `import './polyfill'` — no clause, no local binding. Emit a
|
|
72
|
+
// side-effect match so the finalize layer still produces a
|
|
73
|
+
// file-level IMPORTS edge (parity with the legacy DAG).
|
|
74
|
+
return [
|
|
75
|
+
buildImportMatch(stmtNode, {
|
|
76
|
+
kind: 'side-effect',
|
|
77
|
+
source,
|
|
78
|
+
name: '',
|
|
79
|
+
atNode: stmtNode,
|
|
80
|
+
}),
|
|
81
|
+
];
|
|
82
|
+
}
|
|
83
|
+
const out = [];
|
|
84
|
+
// An import_clause can have any combination of:
|
|
85
|
+
// - leading identifier (default import)
|
|
86
|
+
// - namespace_import (* as N)
|
|
87
|
+
// - named_imports ({ X, Y as Z })
|
|
88
|
+
for (let i = 0; i < importClause.namedChildCount; i++) {
|
|
89
|
+
const child = importClause.namedChild(i);
|
|
90
|
+
if (child === null)
|
|
91
|
+
continue;
|
|
92
|
+
if (child.type === 'identifier') {
|
|
93
|
+
// Default import: `import D from './m'`.
|
|
94
|
+
out.push(buildImportMatch(stmtNode, {
|
|
95
|
+
kind: 'default',
|
|
96
|
+
source,
|
|
97
|
+
name: 'default',
|
|
98
|
+
alias: child.text,
|
|
99
|
+
atNode: child,
|
|
100
|
+
}));
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (child.type === 'namespace_import') {
|
|
104
|
+
// `* as N` — the identifier child is the local binding.
|
|
105
|
+
const aliasId = findChild(child, 'identifier');
|
|
106
|
+
if (aliasId !== null) {
|
|
107
|
+
out.push(buildImportMatch(stmtNode, {
|
|
108
|
+
kind: 'namespace',
|
|
109
|
+
source,
|
|
110
|
+
name: source,
|
|
111
|
+
alias: aliasId.text,
|
|
112
|
+
atNode: child,
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (child.type === 'named_imports') {
|
|
118
|
+
for (let j = 0; j < child.namedChildCount; j++) {
|
|
119
|
+
const spec = child.namedChild(j);
|
|
120
|
+
if (spec === null || spec.type !== 'import_specifier')
|
|
121
|
+
continue;
|
|
122
|
+
const decomposed = decomposeNamedSpecifier(spec, source, stmtNode);
|
|
123
|
+
if (decomposed !== null)
|
|
124
|
+
out.push(decomposed);
|
|
125
|
+
}
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
// Other children (e.g. `type` keyword token for `import type { ... }`)
|
|
129
|
+
// are ignored — they carry no per-specifier info; we fold type-only
|
|
130
|
+
// semantics into the same emitted kinds.
|
|
131
|
+
}
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Decompose a single `import_specifier` into one match. Handles:
|
|
136
|
+
*
|
|
137
|
+
* - `{ X }` → named
|
|
138
|
+
* - `{ X as Y }` → named-alias
|
|
139
|
+
* - `{ type X }` → named (type-only; same shape)
|
|
140
|
+
* - `{ type X as Y }` → named-alias (type-only)
|
|
141
|
+
*/
|
|
142
|
+
function decomposeNamedSpecifier(spec, source, stmtNode) {
|
|
143
|
+
// `import_specifier` layout:
|
|
144
|
+
// name: identifier
|
|
145
|
+
// alias: identifier? (only when `as` is present)
|
|
146
|
+
// plus an optional `type` keyword token in front (per-specifier type-only)
|
|
147
|
+
//
|
|
148
|
+
// tree-sitter-typescript exposes `name` and `alias` as named fields.
|
|
149
|
+
// If `name` is absent, fail closed rather than guessing positionally:
|
|
150
|
+
// binding the alias as the imported name would invert the edge.
|
|
151
|
+
const nameNode = spec.childForFieldName('name');
|
|
152
|
+
const aliasNode = spec.childForFieldName('alias');
|
|
153
|
+
if (nameNode === null)
|
|
154
|
+
return null;
|
|
155
|
+
const name = nameNode.text;
|
|
156
|
+
if (aliasNode !== null && aliasNode.startIndex !== nameNode.startIndex) {
|
|
157
|
+
return buildImportMatch(stmtNode, {
|
|
158
|
+
kind: 'named-alias',
|
|
159
|
+
source,
|
|
160
|
+
name,
|
|
161
|
+
alias: aliasNode.text,
|
|
162
|
+
atNode: spec,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
return buildImportMatch(stmtNode, {
|
|
166
|
+
kind: 'named',
|
|
167
|
+
source,
|
|
168
|
+
name,
|
|
169
|
+
atNode: spec,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
// ─── re-exports ──────────────────────────────────────────────────────────
|
|
173
|
+
function splitReexport(stmtNode) {
|
|
174
|
+
// `export_statement` with a `source:` field is a re-export. Forms:
|
|
175
|
+
//
|
|
176
|
+
// export { X, Y as Z } from './m' → export_clause children
|
|
177
|
+
// export * from './m' → no clause
|
|
178
|
+
// export * as ns from './m' → namespace_export child
|
|
179
|
+
// export type { X } from './m' → same clause path
|
|
180
|
+
//
|
|
181
|
+
// Local `export { X }` (no `from`) is visibility metadata, not an
|
|
182
|
+
// import; the captures-layer query guards with a `source: (string)`
|
|
183
|
+
// predicate so we always have a source here — but we defend
|
|
184
|
+
// structurally anyway.
|
|
185
|
+
const source = extractSource(stmtNode);
|
|
186
|
+
if (source === null)
|
|
187
|
+
return [];
|
|
188
|
+
const exportClause = findChild(stmtNode, 'export_clause');
|
|
189
|
+
if (exportClause !== null) {
|
|
190
|
+
const out = [];
|
|
191
|
+
for (let i = 0; i < exportClause.namedChildCount; i++) {
|
|
192
|
+
const spec = exportClause.namedChild(i);
|
|
193
|
+
if (spec === null || spec.type !== 'export_specifier')
|
|
194
|
+
continue;
|
|
195
|
+
const decomposed = decomposeReexportSpecifier(spec, source, stmtNode);
|
|
196
|
+
if (decomposed !== null)
|
|
197
|
+
out.push(decomposed);
|
|
198
|
+
}
|
|
199
|
+
return out;
|
|
200
|
+
}
|
|
201
|
+
// `export * as ns from './m'` — tree-sitter-typescript emits a
|
|
202
|
+
// `namespace_export` child whose identifier is the local re-export
|
|
203
|
+
// name. Two facts are emitted:
|
|
204
|
+
//
|
|
205
|
+
// 1. An `@import.statement` (kind `reexport-namespace`) so finalize
|
|
206
|
+
// knows the barrel imports `./m` as `ns` (binds `ns` locally
|
|
207
|
+
// inside the barrel for consumers like `barrel.ts` calling
|
|
208
|
+
// `ns.X()`).
|
|
209
|
+
// 2. A synthetic `@declaration.namespace` so the central
|
|
210
|
+
// scope-extractor adds a `Namespace` SymbolDefinition for `ns`
|
|
211
|
+
// to the barrel's `localDefs`. Without this, downstream files
|
|
212
|
+
// doing `import { ns } from './barrel'` cannot resolve `ns`:
|
|
213
|
+
// `findExportByName` and the precomputed re-export closure only
|
|
214
|
+
// consult `localDefs` / `reexport` / `wildcard` drafts, never
|
|
215
|
+
// `namespace`-kind imports. The synthetic declaration fixes that
|
|
216
|
+
// without growing the shared finalizer's surface.
|
|
217
|
+
const namespaceExport = findChild(stmtNode, 'namespace_export');
|
|
218
|
+
if (namespaceExport !== null) {
|
|
219
|
+
const aliasId = findChild(namespaceExport, 'identifier');
|
|
220
|
+
if (aliasId !== null) {
|
|
221
|
+
return [
|
|
222
|
+
buildImportMatch(stmtNode, {
|
|
223
|
+
kind: 'reexport-namespace',
|
|
224
|
+
source,
|
|
225
|
+
name: source,
|
|
226
|
+
alias: aliasId.text,
|
|
227
|
+
atNode: namespaceExport,
|
|
228
|
+
}),
|
|
229
|
+
buildNamespaceDeclarationMatch(namespaceExport, aliasId),
|
|
230
|
+
];
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// `export * from './m'` — no clause, no namespace_export. The bare
|
|
234
|
+
// `*` token is the only remaining marker; we don't need to inspect
|
|
235
|
+
// it since the shape alone says "wildcard".
|
|
236
|
+
return [
|
|
237
|
+
buildImportMatch(stmtNode, {
|
|
238
|
+
kind: 'reexport-wildcard',
|
|
239
|
+
source,
|
|
240
|
+
name: '*',
|
|
241
|
+
atNode: stmtNode,
|
|
242
|
+
}),
|
|
243
|
+
];
|
|
244
|
+
}
|
|
245
|
+
function decomposeReexportSpecifier(spec, source, stmtNode) {
|
|
246
|
+
const nameNode = spec.childForFieldName('name');
|
|
247
|
+
const aliasNode = spec.childForFieldName('alias');
|
|
248
|
+
if (nameNode === null)
|
|
249
|
+
return null;
|
|
250
|
+
const name = nameNode.text;
|
|
251
|
+
if (aliasNode !== null && aliasNode.startIndex !== nameNode.startIndex) {
|
|
252
|
+
return buildImportMatch(stmtNode, {
|
|
253
|
+
kind: 'reexport-alias',
|
|
254
|
+
source,
|
|
255
|
+
name,
|
|
256
|
+
alias: aliasNode.text,
|
|
257
|
+
atNode: spec,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
return buildImportMatch(stmtNode, {
|
|
261
|
+
kind: 'reexport',
|
|
262
|
+
source,
|
|
263
|
+
name,
|
|
264
|
+
atNode: spec,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
// ─── dynamic imports ─────────────────────────────────────────────────────
|
|
268
|
+
function splitDynamicImport(callNode) {
|
|
269
|
+
// `call_expression` shape for dynamic imports:
|
|
270
|
+
// function: (import) — named leaf node in tree-sitter-typescript
|
|
271
|
+
// arguments: (arguments (string) ...) — first arg is the path
|
|
272
|
+
//
|
|
273
|
+
// When the argument is a string literal, preserve its value. When it's
|
|
274
|
+
// anything else (variable, template literal, member access), surface
|
|
275
|
+
// the raw text for diagnostics and let `interpretTsImport` emit
|
|
276
|
+
// `dynamic-unresolved` with a `targetRaw` hint.
|
|
277
|
+
const args = callNode.childForFieldName('arguments');
|
|
278
|
+
if (args === null) {
|
|
279
|
+
return [
|
|
280
|
+
buildImportMatch(callNode, {
|
|
281
|
+
kind: 'dynamic',
|
|
282
|
+
source: null,
|
|
283
|
+
name: '',
|
|
284
|
+
atNode: callNode,
|
|
285
|
+
}),
|
|
286
|
+
];
|
|
287
|
+
}
|
|
288
|
+
const firstArg = args.namedChild(0);
|
|
289
|
+
if (firstArg === null) {
|
|
290
|
+
return [
|
|
291
|
+
buildImportMatch(callNode, {
|
|
292
|
+
kind: 'dynamic',
|
|
293
|
+
source: null,
|
|
294
|
+
name: '',
|
|
295
|
+
atNode: callNode,
|
|
296
|
+
}),
|
|
297
|
+
];
|
|
298
|
+
}
|
|
299
|
+
if (firstArg.type === 'string') {
|
|
300
|
+
const source = stripQuotes(firstArg.text);
|
|
301
|
+
return [
|
|
302
|
+
buildImportMatch(callNode, {
|
|
303
|
+
kind: 'dynamic',
|
|
304
|
+
source,
|
|
305
|
+
name: '',
|
|
306
|
+
atNode: callNode,
|
|
307
|
+
literalSource: true,
|
|
308
|
+
}),
|
|
309
|
+
];
|
|
310
|
+
}
|
|
311
|
+
// Non-literal argument — preserve source text so downstream
|
|
312
|
+
// diagnostics show what the user wrote.
|
|
313
|
+
return [
|
|
314
|
+
buildImportMatch(callNode, {
|
|
315
|
+
kind: 'dynamic',
|
|
316
|
+
source: firstArg.text,
|
|
317
|
+
name: '',
|
|
318
|
+
atNode: callNode,
|
|
319
|
+
}),
|
|
320
|
+
];
|
|
321
|
+
}
|
|
322
|
+
// ─── helpers ─────────────────────────────────────────────────────────────
|
|
323
|
+
function extractSource(stmtNode) {
|
|
324
|
+
// Both `import_statement` and `export_statement` expose the module
|
|
325
|
+
// path through the `source:` field. It's typed as `string` in the
|
|
326
|
+
// grammar; we strip its surrounding quotes.
|
|
327
|
+
const sourceField = stmtNode.childForFieldName('source');
|
|
328
|
+
if (sourceField === null || sourceField.type !== 'string')
|
|
329
|
+
return null;
|
|
330
|
+
return stripQuotes(sourceField.text);
|
|
331
|
+
}
|
|
332
|
+
function stripQuotes(raw) {
|
|
333
|
+
const trimmed = raw.trim();
|
|
334
|
+
if (trimmed.length < 2)
|
|
335
|
+
return trimmed;
|
|
336
|
+
const first = trimmed.charAt(0);
|
|
337
|
+
const last = trimmed.charAt(trimmed.length - 1);
|
|
338
|
+
if ((first === '"' && last === '"') ||
|
|
339
|
+
(first === "'" && last === "'") ||
|
|
340
|
+
(first === '`' && last === '`')) {
|
|
341
|
+
return trimmed.slice(1, -1);
|
|
342
|
+
}
|
|
343
|
+
return trimmed;
|
|
344
|
+
}
|
|
345
|
+
function buildImportMatch(stmtNode, spec) {
|
|
346
|
+
const m = {
|
|
347
|
+
'@import.statement': nodeToCapture('@import.statement', stmtNode),
|
|
348
|
+
'@import.kind': syntheticCapture('@import.kind', spec.atNode, spec.kind),
|
|
349
|
+
'@import.name': syntheticCapture('@import.name', spec.atNode, spec.name),
|
|
350
|
+
};
|
|
351
|
+
if (spec.source !== null) {
|
|
352
|
+
m['@import.source'] = syntheticCapture('@import.source', spec.atNode, spec.source);
|
|
353
|
+
}
|
|
354
|
+
if (spec.alias !== undefined) {
|
|
355
|
+
m['@import.alias'] = syntheticCapture('@import.alias', spec.atNode, spec.alias);
|
|
356
|
+
}
|
|
357
|
+
if (spec.literalSource === true) {
|
|
358
|
+
m['@import.literal'] = syntheticCapture('@import.literal', spec.atNode, '');
|
|
359
|
+
}
|
|
360
|
+
return m;
|
|
361
|
+
}
|
|
362
|
+
/** Synthesize a `@declaration.namespace` match for `export * as ns from './m'`.
|
|
363
|
+
* The central scope-extractor turns this into a `SymbolDefinition` of type
|
|
364
|
+
* `Namespace` in the barrel's `localDefs`, which makes `findExportByName`
|
|
365
|
+
* resolve `ns` for downstream `import { ns } from './barrel'` consumers. */
|
|
366
|
+
function buildNamespaceDeclarationMatch(namespaceExportNode, aliasId) {
|
|
367
|
+
return {
|
|
368
|
+
'@declaration.namespace': nodeToCapture('@declaration.namespace', namespaceExportNode),
|
|
369
|
+
'@declaration.name': nodeToCapture('@declaration.name', aliasId),
|
|
370
|
+
};
|
|
371
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter from `(ParsedImport, WorkspaceIndex)` → concrete file path.
|
|
3
|
+
*
|
|
4
|
+
* Delegates to the existing standard-strategy resolver
|
|
5
|
+
* (`resolveImportPath`) so tsconfig path aliases (`@/`, `~/`, …) and
|
|
6
|
+
* suffix-based resolution follow the same rules as the legacy path.
|
|
7
|
+
*
|
|
8
|
+
* The `WorkspaceIndex` is opaque at the shared contract layer; we
|
|
9
|
+
* narrow it to a TypeScript-shaped context that carries `fromFile` +
|
|
10
|
+
* the full `allFilePaths` set + the optional `tsconfigPaths` the
|
|
11
|
+
* resolver reads.
|
|
12
|
+
*
|
|
13
|
+
* Returning `null` lets the finalize algorithm mark the edge as
|
|
14
|
+
* `linkStatus: 'unresolved'`.
|
|
15
|
+
*/
|
|
16
|
+
import type { ParsedImport, WorkspaceIndex } from '../../../../_shared/index.js';
|
|
17
|
+
import { SupportedLanguages } from '../../../../_shared/index.js';
|
|
18
|
+
import type { TsconfigPaths } from '../../language-config.js';
|
|
19
|
+
export interface TsResolveContext {
|
|
20
|
+
readonly fromFile: string;
|
|
21
|
+
/** Mutable `Set` because the standard resolver consumes `Set<string>`.
|
|
22
|
+
* Callers holding a `ReadonlySet` should copy via `new Set(...)`. */
|
|
23
|
+
readonly allFilePaths: Set<string>;
|
|
24
|
+
/** Repo file list, normalized (lowercased) for suffix matching. May
|
|
25
|
+
* be supplied by the orchestrator; if absent we derive it on the
|
|
26
|
+
* fly from `allFilePaths`. */
|
|
27
|
+
readonly allFileList?: readonly string[];
|
|
28
|
+
readonly normalizedFileList?: readonly string[];
|
|
29
|
+
/** Per-call resolution cache to dedupe repeated lookups. */
|
|
30
|
+
readonly resolveCache?: Map<string, string | null>;
|
|
31
|
+
/** Parsed tsconfig path-aliases. `null` = no aliases configured. */
|
|
32
|
+
readonly tsconfigPaths?: TsconfigPaths | null;
|
|
33
|
+
/** JavaScript vs TypeScript switch — affects the extensions the
|
|
34
|
+
* resolver tries. Defaults to TypeScript. */
|
|
35
|
+
readonly language?: SupportedLanguages.TypeScript | SupportedLanguages.JavaScript;
|
|
36
|
+
}
|
|
37
|
+
export declare function resolveTsImportTarget(parsedImport: ParsedImport, workspaceIndex: WorkspaceIndex): string | null;
|
|
38
|
+
/**
|
|
39
|
+
* Resolve a raw module-path string to a workspace file path using the
|
|
40
|
+
* same standard-strategy resolver as the legacy DAG. Operates directly on
|
|
41
|
+
* the source string without requiring a `ParsedImport`, so the
|
|
42
|
+
* `ScopeResolver.resolveImportTarget` adapter doesn't need to construct
|
|
43
|
+
* a fake `ParsedImport` to reach the resolver.
|
|
44
|
+
*
|
|
45
|
+
* Returns `null` when:
|
|
46
|
+
* - the context is malformed (missing `fromFile` / `allFilePaths`)
|
|
47
|
+
* - `targetRaw` is empty
|
|
48
|
+
* - the resolver finds no matching file
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveTsTarget(targetRaw: string, ctx: TsResolveContext): string | null;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter from `(ParsedImport, WorkspaceIndex)` → concrete file path.
|
|
3
|
+
*
|
|
4
|
+
* Delegates to the existing standard-strategy resolver
|
|
5
|
+
* (`resolveImportPath`) so tsconfig path aliases (`@/`, `~/`, …) and
|
|
6
|
+
* suffix-based resolution follow the same rules as the legacy path.
|
|
7
|
+
*
|
|
8
|
+
* The `WorkspaceIndex` is opaque at the shared contract layer; we
|
|
9
|
+
* narrow it to a TypeScript-shaped context that carries `fromFile` +
|
|
10
|
+
* the full `allFilePaths` set + the optional `tsconfigPaths` the
|
|
11
|
+
* resolver reads.
|
|
12
|
+
*
|
|
13
|
+
* Returning `null` lets the finalize algorithm mark the edge as
|
|
14
|
+
* `linkStatus: 'unresolved'`.
|
|
15
|
+
*/
|
|
16
|
+
import { SupportedLanguages } from '../../../../_shared/index.js';
|
|
17
|
+
import { resolveImportPath } from '../../import-resolvers/standard.js';
|
|
18
|
+
export function resolveTsImportTarget(parsedImport, workspaceIndex) {
|
|
19
|
+
const ctx = narrowTsContext(workspaceIndex);
|
|
20
|
+
if (ctx === null)
|
|
21
|
+
return null;
|
|
22
|
+
// Dynamic imports carry `targetRaw` only for diagnostics; when the
|
|
23
|
+
// expression isn't a string literal we can't resolve a file.
|
|
24
|
+
// A string-literal dynamic import (`import('./m')`) resolves like a
|
|
25
|
+
// static import — fall through to the shared path resolver.
|
|
26
|
+
if (parsedImport.kind === 'dynamic-unresolved' && parsedImport.targetRaw === null)
|
|
27
|
+
return null;
|
|
28
|
+
if (parsedImport.targetRaw === null || parsedImport.targetRaw === '')
|
|
29
|
+
return null;
|
|
30
|
+
return resolveTsTarget(parsedImport.targetRaw, ctx);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolve a raw module-path string to a workspace file path using the
|
|
34
|
+
* same standard-strategy resolver as the legacy DAG. Operates directly on
|
|
35
|
+
* the source string without requiring a `ParsedImport`, so the
|
|
36
|
+
* `ScopeResolver.resolveImportTarget` adapter doesn't need to construct
|
|
37
|
+
* a fake `ParsedImport` to reach the resolver.
|
|
38
|
+
*
|
|
39
|
+
* Returns `null` when:
|
|
40
|
+
* - the context is malformed (missing `fromFile` / `allFilePaths`)
|
|
41
|
+
* - `targetRaw` is empty
|
|
42
|
+
* - the resolver finds no matching file
|
|
43
|
+
*/
|
|
44
|
+
export function resolveTsTarget(targetRaw, ctx) {
|
|
45
|
+
if (targetRaw === '')
|
|
46
|
+
return null;
|
|
47
|
+
const language = ctx.language ?? SupportedLanguages.TypeScript;
|
|
48
|
+
const allFileList = ctx.allFileList ?? Array.from(ctx.allFilePaths);
|
|
49
|
+
const normalizedFileList = ctx.normalizedFileList ?? allFileList.map((f) => f.toLowerCase());
|
|
50
|
+
const resolveCache = ctx.resolveCache ?? new Map();
|
|
51
|
+
return resolveImportPath(ctx.fromFile, targetRaw, ctx.allFilePaths, allFileList, normalizedFileList, resolveCache, language, ctx.tsconfigPaths ?? null);
|
|
52
|
+
}
|
|
53
|
+
function narrowTsContext(workspaceIndex) {
|
|
54
|
+
const ctx = workspaceIndex;
|
|
55
|
+
if (ctx === undefined ||
|
|
56
|
+
typeof ctx.fromFile !== 'string' ||
|
|
57
|
+
!(ctx.allFilePaths instanceof Set)) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return ctx;
|
|
61
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript scope-resolution hooks (RFC #909 Ring 3, RFC §5).
|
|
3
|
+
*
|
|
4
|
+
* Public API barrel. Consumers should import from this file rather
|
|
5
|
+
* than 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` — `emitTsScopeCaptures` orchestrator
|
|
11
|
+
* - `import-decomposer.ts` — each import/re-export/dynamic-import →
|
|
12
|
+
* ParsedImport-shaped captures
|
|
13
|
+
* - `interpret.ts` — capture-match → `ParsedImport` /
|
|
14
|
+
* `ParsedTypeBinding`
|
|
15
|
+
* - `simple-hooks.ts` — `bindingScopeFor` (var hoisting + return-
|
|
16
|
+
* type hoisting), `importOwningScope`
|
|
17
|
+
* (module/namespace default), `receiverBinding`
|
|
18
|
+
* (`this` lookup on Function scope)
|
|
19
|
+
* - `receiver-binding.ts` — synthesize `this` type-bindings on
|
|
20
|
+
* instance-method entry (methods, interface
|
|
21
|
+
* signatures, class-field arrow functions)
|
|
22
|
+
* - `merge-bindings.ts` — TypeScript declaration merging
|
|
23
|
+
* (value / type / namespace spaces) + LEGB
|
|
24
|
+
* tier shadowing
|
|
25
|
+
* - `arity.ts` — TypeScript arity compatibility (rest,
|
|
26
|
+
* optional, default params)
|
|
27
|
+
* - `arity-metadata.ts` — synthesize arity metadata from
|
|
28
|
+
* declarations; includes generics + array-
|
|
29
|
+
* suffix stripping on parameter types
|
|
30
|
+
* - `import-target.ts` — `(ParsedImport, WorkspaceIndex) → file path`
|
|
31
|
+
* adapter delegating to the shared standard
|
|
32
|
+
* resolver (tsconfig paths, node_modules,
|
|
33
|
+
* relative/extension suffix matching)
|
|
34
|
+
* - `cache-stats.ts` — PROF_SCOPE_RESOLUTION cache hit/miss
|
|
35
|
+
* counters
|
|
36
|
+
*
|
|
37
|
+
* ## Known limitations
|
|
38
|
+
*
|
|
39
|
+
* The TypeScript registry-primary path intentionally does NOT resolve
|
|
40
|
+
* the following. Each is a conscious trade-off at migration time.
|
|
41
|
+
*
|
|
42
|
+
* 1. **Type-only import / export separation** — `import type { X }`
|
|
43
|
+
* and `import { X }` produce the same `ParsedImport` shape today;
|
|
44
|
+
* `def.type` on the resolved symbol is the only discriminator.
|
|
45
|
+
* Parity with the legacy path is preserved. Tracking in #927.
|
|
46
|
+
* 2. **Declaration merging for imports** — when `import { Foo }`
|
|
47
|
+
* brings in a symbol that is BOTH a class and a namespace in the
|
|
48
|
+
* source module, we currently surface a single binding per the
|
|
49
|
+
* target `def.type`. Downstream type/value-space lookups still
|
|
50
|
+
* work for the primary space; the other space's members resolve
|
|
51
|
+
* via the same target (class statics reachable via dotted access).
|
|
52
|
+
* 3. **Overload narrowing by argument type** — `@reference.parameter-
|
|
53
|
+
* types` carries static literal types inferred from the callsite
|
|
54
|
+
* (`string`, `number`, `Array`, etc.). Identifier / member-access
|
|
55
|
+
* arguments emit empty strings (unknown type); the registry's
|
|
56
|
+
* narrowing treats them as any-match. Full control-flow type
|
|
57
|
+
* narrowing is out of scope.
|
|
58
|
+
* 4. **Computed member access** — `obj[key]()` / `obj['method']()`
|
|
59
|
+
* is classified as an index-access call; member-call resolution
|
|
60
|
+
* falls back to the identifier-indexed branch and matches only
|
|
61
|
+
* when the key is a string literal.
|
|
62
|
+
* 5. **`this` for nested regular functions inside methods** — our
|
|
63
|
+
* scope-chain lookup returns the enclosing method's `this`, which
|
|
64
|
+
* is technically incorrect at runtime (a non-arrow nested function
|
|
65
|
+
* has its own `this` binding). Accepted false-positive; see
|
|
66
|
+
* `simple-hooks.ts` docstring.
|
|
67
|
+
* 6. **`class_expression` receiver types** — `const C = class { }`
|
|
68
|
+
* skips `this` synthesis when the expression is anonymous (no
|
|
69
|
+
* type name to propagate). `const C = class Named { }` works via
|
|
70
|
+
* the class's own `name` field.
|
|
71
|
+
* 7. **JSX element types** — JSX-specific constructs are ignored by
|
|
72
|
+
* the scope query; component references resolve via regular
|
|
73
|
+
* identifier / member-expression paths.
|
|
74
|
+
* 8. **Ambient module declarations** (`declare module '…'`) — parsed
|
|
75
|
+
* but not indexed at this layer; same as today's legacy path.
|
|
76
|
+
* 9. **Intersection types on parameters** (`(a: A & B)`) — treated
|
|
77
|
+
* as opaque (no strip); overload narrowing on intersections
|
|
78
|
+
* won't match.
|
|
79
|
+
* 10. **`instanceof` member-expression narrowing** — only bare
|
|
80
|
+
* identifiers are narrowed (`user instanceof User`). Member paths
|
|
81
|
+
* such as `user.address instanceof Address` remain unresolved.
|
|
82
|
+
*
|
|
83
|
+
* Shadow-harness corpus parity on `test/integration/resolvers/
|
|
84
|
+
* typescript.test.ts` is the authoritative signal for which of these
|
|
85
|
+
* matter in practice. The CI parity gate blocks any PR that regresses
|
|
86
|
+
* either the legacy or registry-primary run.
|
|
87
|
+
*/
|
|
88
|
+
export { emitTsScopeCaptures } from './captures.js';
|
|
89
|
+
export { getTypescriptCaptureCacheStats, resetTypescriptCaptureCacheStats } from './cache-stats.js';
|
|
90
|
+
export { interpretTsImport, interpretTsTypeBinding } from './interpret.js';
|
|
91
|
+
export { typescriptMergeBindings } from './merge-bindings.js';
|
|
92
|
+
export { typescriptArityCompatibility } from './arity.js';
|
|
93
|
+
export { resolveTsImportTarget, resolveTsTarget, type TsResolveContext } from './import-target.js';
|
|
94
|
+
export { tsBindingScopeFor, tsImportOwningScope, tsReceiverBinding } from './simple-hooks.js';
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript scope-resolution hooks (RFC #909 Ring 3, RFC §5).
|
|
3
|
+
*
|
|
4
|
+
* Public API barrel. Consumers should import from this file rather
|
|
5
|
+
* than 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` — `emitTsScopeCaptures` orchestrator
|
|
11
|
+
* - `import-decomposer.ts` — each import/re-export/dynamic-import →
|
|
12
|
+
* ParsedImport-shaped captures
|
|
13
|
+
* - `interpret.ts` — capture-match → `ParsedImport` /
|
|
14
|
+
* `ParsedTypeBinding`
|
|
15
|
+
* - `simple-hooks.ts` — `bindingScopeFor` (var hoisting + return-
|
|
16
|
+
* type hoisting), `importOwningScope`
|
|
17
|
+
* (module/namespace default), `receiverBinding`
|
|
18
|
+
* (`this` lookup on Function scope)
|
|
19
|
+
* - `receiver-binding.ts` — synthesize `this` type-bindings on
|
|
20
|
+
* instance-method entry (methods, interface
|
|
21
|
+
* signatures, class-field arrow functions)
|
|
22
|
+
* - `merge-bindings.ts` — TypeScript declaration merging
|
|
23
|
+
* (value / type / namespace spaces) + LEGB
|
|
24
|
+
* tier shadowing
|
|
25
|
+
* - `arity.ts` — TypeScript arity compatibility (rest,
|
|
26
|
+
* optional, default params)
|
|
27
|
+
* - `arity-metadata.ts` — synthesize arity metadata from
|
|
28
|
+
* declarations; includes generics + array-
|
|
29
|
+
* suffix stripping on parameter types
|
|
30
|
+
* - `import-target.ts` — `(ParsedImport, WorkspaceIndex) → file path`
|
|
31
|
+
* adapter delegating to the shared standard
|
|
32
|
+
* resolver (tsconfig paths, node_modules,
|
|
33
|
+
* relative/extension suffix matching)
|
|
34
|
+
* - `cache-stats.ts` — PROF_SCOPE_RESOLUTION cache hit/miss
|
|
35
|
+
* counters
|
|
36
|
+
*
|
|
37
|
+
* ## Known limitations
|
|
38
|
+
*
|
|
39
|
+
* The TypeScript registry-primary path intentionally does NOT resolve
|
|
40
|
+
* the following. Each is a conscious trade-off at migration time.
|
|
41
|
+
*
|
|
42
|
+
* 1. **Type-only import / export separation** — `import type { X }`
|
|
43
|
+
* and `import { X }` produce the same `ParsedImport` shape today;
|
|
44
|
+
* `def.type` on the resolved symbol is the only discriminator.
|
|
45
|
+
* Parity with the legacy path is preserved. Tracking in #927.
|
|
46
|
+
* 2. **Declaration merging for imports** — when `import { Foo }`
|
|
47
|
+
* brings in a symbol that is BOTH a class and a namespace in the
|
|
48
|
+
* source module, we currently surface a single binding per the
|
|
49
|
+
* target `def.type`. Downstream type/value-space lookups still
|
|
50
|
+
* work for the primary space; the other space's members resolve
|
|
51
|
+
* via the same target (class statics reachable via dotted access).
|
|
52
|
+
* 3. **Overload narrowing by argument type** — `@reference.parameter-
|
|
53
|
+
* types` carries static literal types inferred from the callsite
|
|
54
|
+
* (`string`, `number`, `Array`, etc.). Identifier / member-access
|
|
55
|
+
* arguments emit empty strings (unknown type); the registry's
|
|
56
|
+
* narrowing treats them as any-match. Full control-flow type
|
|
57
|
+
* narrowing is out of scope.
|
|
58
|
+
* 4. **Computed member access** — `obj[key]()` / `obj['method']()`
|
|
59
|
+
* is classified as an index-access call; member-call resolution
|
|
60
|
+
* falls back to the identifier-indexed branch and matches only
|
|
61
|
+
* when the key is a string literal.
|
|
62
|
+
* 5. **`this` for nested regular functions inside methods** — our
|
|
63
|
+
* scope-chain lookup returns the enclosing method's `this`, which
|
|
64
|
+
* is technically incorrect at runtime (a non-arrow nested function
|
|
65
|
+
* has its own `this` binding). Accepted false-positive; see
|
|
66
|
+
* `simple-hooks.ts` docstring.
|
|
67
|
+
* 6. **`class_expression` receiver types** — `const C = class { }`
|
|
68
|
+
* skips `this` synthesis when the expression is anonymous (no
|
|
69
|
+
* type name to propagate). `const C = class Named { }` works via
|
|
70
|
+
* the class's own `name` field.
|
|
71
|
+
* 7. **JSX element types** — JSX-specific constructs are ignored by
|
|
72
|
+
* the scope query; component references resolve via regular
|
|
73
|
+
* identifier / member-expression paths.
|
|
74
|
+
* 8. **Ambient module declarations** (`declare module '…'`) — parsed
|
|
75
|
+
* but not indexed at this layer; same as today's legacy path.
|
|
76
|
+
* 9. **Intersection types on parameters** (`(a: A & B)`) — treated
|
|
77
|
+
* as opaque (no strip); overload narrowing on intersections
|
|
78
|
+
* won't match.
|
|
79
|
+
* 10. **`instanceof` member-expression narrowing** — only bare
|
|
80
|
+
* identifiers are narrowed (`user instanceof User`). Member paths
|
|
81
|
+
* such as `user.address instanceof Address` remain unresolved.
|
|
82
|
+
*
|
|
83
|
+
* Shadow-harness corpus parity on `test/integration/resolvers/
|
|
84
|
+
* typescript.test.ts` is the authoritative signal for which of these
|
|
85
|
+
* matter in practice. The CI parity gate blocks any PR that regresses
|
|
86
|
+
* either the legacy or registry-primary run.
|
|
87
|
+
*/
|
|
88
|
+
export { emitTsScopeCaptures } from './captures.js';
|
|
89
|
+
export { getTypescriptCaptureCacheStats, resetTypescriptCaptureCacheStats } from './cache-stats.js';
|
|
90
|
+
export { interpretTsImport, interpretTsTypeBinding } from './interpret.js';
|
|
91
|
+
export { typescriptMergeBindings } from './merge-bindings.js';
|
|
92
|
+
export { typescriptArityCompatibility } from './arity.js';
|
|
93
|
+
export { resolveTsImportTarget, resolveTsTarget } from './import-target.js';
|
|
94
|
+
export { tsBindingScopeFor, tsImportOwningScope, tsReceiverBinding } from './simple-hooks.js';
|