gitnexus 1.6.3-rc.2 → 1.6.3-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/dist/_shared/graph/types.d.ts +16 -0
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/index.d.ts +41 -1
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/index.js +28 -0
- package/dist/_shared/index.js.map +1 -1
- package/dist/_shared/scope-resolution/def-index.d.ts +36 -0
- package/dist/_shared/scope-resolution/def-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/def-index.js +51 -0
- package/dist/_shared/scope-resolution/def-index.js.map +1 -0
- package/dist/_shared/scope-resolution/finalize-algorithm.d.ts +139 -0
- package/dist/_shared/scope-resolution/finalize-algorithm.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/finalize-algorithm.js +479 -0
- package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts +80 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.js +79 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.js.map +1 -0
- package/dist/_shared/scope-resolution/module-scope-index.d.ts +46 -0
- package/dist/_shared/scope-resolution/module-scope-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/module-scope-index.js +58 -0
- package/dist/_shared/scope-resolution/module-scope-index.js.map +1 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts +64 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/parsed-file.js +42 -0
- package/dist/_shared/scope-resolution/parsed-file.js.map +1 -0
- package/dist/_shared/scope-resolution/position-index.d.ts +62 -0
- package/dist/_shared/scope-resolution/position-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/position-index.js +134 -0
- package/dist/_shared/scope-resolution/position-index.js.map +1 -0
- package/dist/_shared/scope-resolution/qualified-name-index.d.ts +44 -0
- package/dist/_shared/scope-resolution/qualified-name-index.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/qualified-name-index.js +75 -0
- package/dist/_shared/scope-resolution/qualified-name-index.js.map +1 -0
- package/dist/_shared/scope-resolution/reference-site.d.ts +67 -0
- package/dist/_shared/scope-resolution/reference-site.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/reference-site.js +24 -0
- package/dist/_shared/scope-resolution/reference-site.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/class-registry.d.ts +27 -0
- package/dist/_shared/scope-resolution/registries/class-registry.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/class-registry.js +30 -0
- package/dist/_shared/scope-resolution/registries/class-registry.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/context.d.ts +69 -0
- package/dist/_shared/scope-resolution/registries/context.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/context.js +44 -0
- package/dist/_shared/scope-resolution/registries/context.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/evidence.d.ts +56 -0
- package/dist/_shared/scope-resolution/registries/evidence.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/evidence.js +150 -0
- package/dist/_shared/scope-resolution/registries/evidence.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/field-registry.d.ts +26 -0
- package/dist/_shared/scope-resolution/registries/field-registry.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/field-registry.js +31 -0
- package/dist/_shared/scope-resolution/registries/field-registry.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/lookup-core.d.ts +81 -0
- package/dist/_shared/scope-resolution/registries/lookup-core.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/lookup-core.js +332 -0
- package/dist/_shared/scope-resolution/registries/lookup-core.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/lookup-qualified.d.ts +33 -0
- package/dist/_shared/scope-resolution/registries/lookup-qualified.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/lookup-qualified.js +56 -0
- package/dist/_shared/scope-resolution/registries/lookup-qualified.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/method-registry.d.ts +36 -0
- package/dist/_shared/scope-resolution/registries/method-registry.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/method-registry.js +32 -0
- package/dist/_shared/scope-resolution/registries/method-registry.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/tie-breaks.d.ts +43 -0
- package/dist/_shared/scope-resolution/registries/tie-breaks.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/tie-breaks.js +60 -0
- package/dist/_shared/scope-resolution/registries/tie-breaks.js.map +1 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.d.ts +53 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.js +126 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.js.map +1 -0
- package/dist/_shared/scope-resolution/scope-id.d.ts +43 -0
- package/dist/_shared/scope-resolution/scope-id.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/scope-id.js +46 -0
- package/dist/_shared/scope-resolution/scope-id.js.map +1 -0
- package/dist/_shared/scope-resolution/scope-tree.d.ts +61 -0
- package/dist/_shared/scope-resolution/scope-tree.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/scope-tree.js +186 -0
- package/dist/_shared/scope-resolution/scope-tree.js.map +1 -0
- package/dist/_shared/scope-resolution/shadow/aggregate.d.ts +63 -0
- package/dist/_shared/scope-resolution/shadow/aggregate.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/shadow/aggregate.js +122 -0
- package/dist/_shared/scope-resolution/shadow/aggregate.js.map +1 -0
- package/dist/_shared/scope-resolution/shadow/diff.d.ts +59 -0
- package/dist/_shared/scope-resolution/shadow/diff.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/shadow/diff.js +79 -0
- package/dist/_shared/scope-resolution/shadow/diff.js.map +1 -0
- package/dist/_shared/scope-resolution/types.d.ts +156 -0
- package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
- package/dist/cli/analyze.d.ts +15 -0
- package/dist/cli/analyze.js +22 -1
- package/dist/cli/index.js +4 -0
- package/dist/cli/list.js +11 -1
- package/dist/core/ingestion/emit-references.d.ts +88 -0
- package/dist/core/ingestion/emit-references.js +229 -0
- package/dist/core/ingestion/finalize-orchestrator.d.ts +63 -0
- package/dist/core/ingestion/finalize-orchestrator.js +139 -0
- package/dist/core/ingestion/framework-detection.js +6 -2
- package/dist/core/ingestion/import-target-adapter.d.ts +73 -0
- package/dist/core/ingestion/import-target-adapter.js +95 -0
- package/dist/core/ingestion/language-provider.d.ts +187 -1
- package/dist/core/ingestion/model/scope-resolution-indexes.d.ts +59 -0
- package/dist/core/ingestion/model/scope-resolution-indexes.js +42 -0
- package/dist/core/ingestion/model/semantic-model.d.ts +25 -0
- package/dist/core/ingestion/model/semantic-model.js +16 -0
- package/dist/core/ingestion/parsing-processor.d.ts +9 -0
- package/dist/core/ingestion/parsing-processor.js +10 -0
- package/dist/core/ingestion/registry-primary-flag.d.ts +59 -0
- package/dist/core/ingestion/registry-primary-flag.js +78 -0
- package/dist/core/ingestion/scope-extractor-bridge.d.ts +32 -0
- package/dist/core/ingestion/scope-extractor-bridge.js +44 -0
- package/dist/core/ingestion/scope-extractor.d.ts +87 -0
- package/dist/core/ingestion/scope-extractor.js +603 -0
- package/dist/core/ingestion/shadow-harness.d.ts +113 -0
- package/dist/core/ingestion/shadow-harness.js +148 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +9 -0
- package/dist/core/ingestion/workers/parse-worker.js +20 -1
- package/dist/core/run-analyze.d.ts +21 -0
- package/dist/core/run-analyze.js +15 -4
- package/dist/core/search/phase-timer.d.ts +72 -0
- package/dist/core/search/phase-timer.js +106 -0
- package/dist/mcp/local/local-backend.js +70 -8
- package/dist/storage/git.d.ts +25 -0
- package/dist/storage/git.js +52 -0
- package/dist/storage/repo-manager.d.ts +70 -1
- package/dist/storage/repo-manager.js +107 -5
- package/package.json +1 -1
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `finalize` — cross-file finalize algorithm for the SemanticModel
|
|
3
|
+
* (RFC §3.2 Phase 2; Ring 2 SHARED #915).
|
|
4
|
+
*
|
|
5
|
+
* Pure logic that takes per-file parse output (`ParsedImport[]` +
|
|
6
|
+
* `SymbolDefinition[]`) and returns:
|
|
7
|
+
*
|
|
8
|
+
* - Linked `ImportEdge[]` per module scope, with `targetModuleScope` and
|
|
9
|
+
* `targetDefId` filled where resolvable; edges that could not be
|
|
10
|
+
* resolved within the hard fixpoint cap are marked
|
|
11
|
+
* `linkStatus: 'unresolved'`.
|
|
12
|
+
* - Materialized `bindings` per module scope — local defs merged with
|
|
13
|
+
* imported / wildcard-expanded / re-exported names via the provider's
|
|
14
|
+
* `mergeBindings` precedence.
|
|
15
|
+
* - The SCC condensation of the import graph, exposed so disjoint SCCs
|
|
16
|
+
* can be processed in parallel by callers that want that.
|
|
17
|
+
*
|
|
18
|
+
* The algorithm is **SCC-aware**: it runs Tarjan SCC over the file-level
|
|
19
|
+
* import graph, processes SCCs in reverse-topological order (leaves
|
|
20
|
+
* first), and within each SCC runs a bounded fixpoint link pass capped at
|
|
21
|
+
* `N = |edges in SCC|`. Cyclic imports finalize without hanging; malformed
|
|
22
|
+
* inputs are bounded by the cap.
|
|
23
|
+
*
|
|
24
|
+
* **No language-specific logic.** Target resolution, wildcard expansion,
|
|
25
|
+
* and binding precedence all go through caller-supplied hooks
|
|
26
|
+
* (`resolveImportTarget`, `expandsWildcardTo`, `mergeBindings`) that
|
|
27
|
+
* match the LanguageProvider surface from #911.
|
|
28
|
+
*
|
|
29
|
+
* **Dynamic imports rule.** `kind === 'dynamic-unresolved'` passes through
|
|
30
|
+
* as an `ImportEdge { kind: 'dynamic-unresolved', targetFile: null }`
|
|
31
|
+
* with no `BindingRef`. They are parse-time signals, not linkable targets.
|
|
32
|
+
*/
|
|
33
|
+
// ─── Entry point ───────────────────────────────────────────────────────────
|
|
34
|
+
export function finalize(input, hooks) {
|
|
35
|
+
const byFilePath = new Map();
|
|
36
|
+
for (const f of input.files)
|
|
37
|
+
byFilePath.set(f.filePath, f);
|
|
38
|
+
// ── Phase 0: pre-resolve raw import targets (one syscall-equivalent per
|
|
39
|
+
// (file, parsedImport)). Edges with no resolvable target become
|
|
40
|
+
// `linkStatus: 'unresolved'` or, for dynamic-unresolved, pass through
|
|
41
|
+
// with `targetFile: null`.
|
|
42
|
+
const edgeIndex = new Map(); // filePath → drafts
|
|
43
|
+
let totalEdges = 0;
|
|
44
|
+
for (const file of input.files) {
|
|
45
|
+
const drafts = [];
|
|
46
|
+
for (const parsed of file.parsedImports) {
|
|
47
|
+
const draft = makeEdgeDraft(parsed, file, hooks, input.workspaceIndex);
|
|
48
|
+
drafts.push(draft);
|
|
49
|
+
totalEdges++;
|
|
50
|
+
}
|
|
51
|
+
edgeIndex.set(file.filePath, drafts);
|
|
52
|
+
}
|
|
53
|
+
// ── Phase 1: build file-level import graph (only resolvable edges form
|
|
54
|
+
// graph edges; unresolvable ones are terminal and contribute no
|
|
55
|
+
// fixpoint obligation).
|
|
56
|
+
const graph = new Map();
|
|
57
|
+
for (const file of input.files) {
|
|
58
|
+
graph.set(file.filePath, new Set());
|
|
59
|
+
}
|
|
60
|
+
for (const [fromFile, drafts] of edgeIndex) {
|
|
61
|
+
const edges = graph.get(fromFile);
|
|
62
|
+
for (const d of drafts) {
|
|
63
|
+
if (d.targetFile !== null && byFilePath.has(d.targetFile)) {
|
|
64
|
+
edges.add(d.targetFile);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// ── Phase 2: Tarjan SCC → reverse-topological list of SCCs.
|
|
69
|
+
const sccs = tarjanSccs(graph);
|
|
70
|
+
// ── Phase 3: process SCCs in reverse-topological order (leaves first).
|
|
71
|
+
// Within each SCC, run a bounded fixpoint that resolves intra-SCC edges.
|
|
72
|
+
// Edges leaving the SCC are already resolved (their target SCC is
|
|
73
|
+
// already finalized); edges inside the SCC may need multiple passes.
|
|
74
|
+
const linkedByScope = new Map();
|
|
75
|
+
let linkedEdges = 0;
|
|
76
|
+
for (const scc of sccs) {
|
|
77
|
+
const sccFiles = new Set(scc.files);
|
|
78
|
+
const capacity = countEdgesWithin(edgeIndex, sccFiles);
|
|
79
|
+
// Run the fixpoint up to `capacity` iterations. Each iteration tries to
|
|
80
|
+
// resolve every still-unlinked edge in the SCC; stops early if a pass
|
|
81
|
+
// makes no progress.
|
|
82
|
+
let progressed = true;
|
|
83
|
+
let iterations = 0;
|
|
84
|
+
while (progressed && iterations < capacity) {
|
|
85
|
+
progressed = false;
|
|
86
|
+
iterations++;
|
|
87
|
+
for (const filePath of scc.files) {
|
|
88
|
+
const drafts = edgeIndex.get(filePath);
|
|
89
|
+
for (const draft of drafts) {
|
|
90
|
+
if (draft.finalized !== null)
|
|
91
|
+
continue;
|
|
92
|
+
const finalized = tryFinalize(draft, byFilePath);
|
|
93
|
+
if (finalized !== null) {
|
|
94
|
+
draft.finalized = finalized;
|
|
95
|
+
progressed = true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Any drafts still not finalized within this SCC hit the cap → unresolved.
|
|
101
|
+
for (const filePath of scc.files) {
|
|
102
|
+
const drafts = edgeIndex.get(filePath);
|
|
103
|
+
for (const draft of drafts) {
|
|
104
|
+
if (draft.finalized !== null)
|
|
105
|
+
continue;
|
|
106
|
+
draft.finalized = {
|
|
107
|
+
...draft.base,
|
|
108
|
+
linkStatus: 'unresolved',
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// ── Phase 4: collect finalized `ImportEdge[]` per module scope, preserving
|
|
114
|
+
// input order within each file, and wildcard-expand where applicable.
|
|
115
|
+
for (const file of input.files) {
|
|
116
|
+
const drafts = edgeIndex.get(file.filePath);
|
|
117
|
+
const finalized = [];
|
|
118
|
+
for (const d of drafts) {
|
|
119
|
+
const edge = d.finalized;
|
|
120
|
+
if (d.source.kind === 'wildcard' && edge.linkStatus !== 'unresolved') {
|
|
121
|
+
// Produce one `wildcard-expanded` ImportEdge per exported name.
|
|
122
|
+
const expanded = expandWildcard(edge, byFilePath, hooks, input.workspaceIndex);
|
|
123
|
+
for (const e of expanded)
|
|
124
|
+
finalized.push(e);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
finalized.push(edge);
|
|
128
|
+
}
|
|
129
|
+
if (edge.linkStatus !== 'unresolved')
|
|
130
|
+
linkedEdges++;
|
|
131
|
+
}
|
|
132
|
+
linkedByScope.set(file.moduleScope, Object.freeze(finalized));
|
|
133
|
+
}
|
|
134
|
+
// ── Phase 5: materialize module-scope bindings (local + imports + wildcards),
|
|
135
|
+
// delegating precedence to `provider.mergeBindings`.
|
|
136
|
+
const bindingsByScope = materializeBindings(input.files, linkedByScope, hooks);
|
|
137
|
+
// ── Stats.
|
|
138
|
+
const sccCount = sccs.length;
|
|
139
|
+
let largestSccSize = 0;
|
|
140
|
+
for (const scc of sccs) {
|
|
141
|
+
if (scc.files.length > largestSccSize)
|
|
142
|
+
largestSccSize = scc.files.length;
|
|
143
|
+
}
|
|
144
|
+
const stats = {
|
|
145
|
+
totalFiles: input.files.length,
|
|
146
|
+
totalEdges,
|
|
147
|
+
linkedEdges,
|
|
148
|
+
unresolvedEdges: totalEdges - linkedEdges,
|
|
149
|
+
sccCount,
|
|
150
|
+
largestSccSize,
|
|
151
|
+
};
|
|
152
|
+
return Object.freeze({
|
|
153
|
+
imports: linkedByScope,
|
|
154
|
+
bindings: bindingsByScope,
|
|
155
|
+
sccs,
|
|
156
|
+
stats,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
function makeEdgeDraft(parsed, file, hooks, workspace) {
|
|
160
|
+
// Dynamic-unresolved passes through — no `BindingRef`, no target file.
|
|
161
|
+
if (parsed.kind === 'dynamic-unresolved') {
|
|
162
|
+
const base = {
|
|
163
|
+
localName: parsed.localName,
|
|
164
|
+
targetFile: null,
|
|
165
|
+
targetExportedName: '',
|
|
166
|
+
kind: 'dynamic-unresolved',
|
|
167
|
+
};
|
|
168
|
+
return {
|
|
169
|
+
source: parsed,
|
|
170
|
+
fromFile: file.filePath,
|
|
171
|
+
fromScope: file.moduleScope,
|
|
172
|
+
targetFile: null,
|
|
173
|
+
base,
|
|
174
|
+
finalized: base, // already fully finalized
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
const targetFile = hooks.resolveImportTarget(parsed.targetRaw ?? '', file.filePath, workspace);
|
|
178
|
+
// Edge is unresolvable at the file level — mark unresolved now.
|
|
179
|
+
if (targetFile === null) {
|
|
180
|
+
const edgeKind = parsed.kind === 'wildcard' ? 'wildcard-expanded' : parsed.kind;
|
|
181
|
+
const localName = parsed.kind === 'wildcard' ? '' : parsed.localName;
|
|
182
|
+
const targetExportedName = extractExportedName(parsed);
|
|
183
|
+
const base = {
|
|
184
|
+
localName,
|
|
185
|
+
targetFile: null,
|
|
186
|
+
targetExportedName,
|
|
187
|
+
kind: edgeKind,
|
|
188
|
+
linkStatus: 'unresolved',
|
|
189
|
+
};
|
|
190
|
+
return {
|
|
191
|
+
source: parsed,
|
|
192
|
+
fromFile: file.filePath,
|
|
193
|
+
fromScope: file.moduleScope,
|
|
194
|
+
targetFile: null,
|
|
195
|
+
base,
|
|
196
|
+
finalized: base,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
// Resolvable at the file level; intra-SCC fixpoint may still fail to fill
|
|
200
|
+
// in `targetDefId` (e.g., symbol not exported from target).
|
|
201
|
+
const edgeKind = parsed.kind === 'wildcard' ? 'wildcard-expanded' : parsed.kind;
|
|
202
|
+
const localName = parsed.kind === 'wildcard' ? '' : parsed.localName;
|
|
203
|
+
const targetExportedName = extractExportedName(parsed);
|
|
204
|
+
const base = {
|
|
205
|
+
localName,
|
|
206
|
+
targetFile,
|
|
207
|
+
targetExportedName,
|
|
208
|
+
kind: edgeKind,
|
|
209
|
+
};
|
|
210
|
+
return {
|
|
211
|
+
source: parsed,
|
|
212
|
+
fromFile: file.filePath,
|
|
213
|
+
fromScope: file.moduleScope,
|
|
214
|
+
targetFile,
|
|
215
|
+
base,
|
|
216
|
+
finalized: null,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function extractExportedName(parsed) {
|
|
220
|
+
switch (parsed.kind) {
|
|
221
|
+
case 'named':
|
|
222
|
+
case 'alias':
|
|
223
|
+
case 'namespace':
|
|
224
|
+
case 'reexport':
|
|
225
|
+
return parsed.importedName;
|
|
226
|
+
case 'wildcard':
|
|
227
|
+
case 'dynamic-unresolved':
|
|
228
|
+
return '';
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// ─── Internal: per-edge finalization (phase 3) ─────────────────────────────
|
|
232
|
+
function tryFinalize(draft, byFilePath) {
|
|
233
|
+
const targetFile = draft.targetFile;
|
|
234
|
+
if (targetFile === null)
|
|
235
|
+
return draft.base; // already terminal
|
|
236
|
+
const targetModule = byFilePath.get(targetFile);
|
|
237
|
+
if (targetModule === undefined)
|
|
238
|
+
return draft.base; // external target — leave as-is
|
|
239
|
+
// Wildcards finalize at the file level; their per-name expansion happens
|
|
240
|
+
// in phase 4. At this stage we just record the target module scope.
|
|
241
|
+
if (draft.source.kind === 'wildcard') {
|
|
242
|
+
return {
|
|
243
|
+
...draft.base,
|
|
244
|
+
targetModuleScope: targetModule.moduleScope,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
// Namespace imports alias the target *module*; they don't name a
|
|
248
|
+
// specific export. Link the module scope unconditionally. If the target
|
|
249
|
+
// also exposes a def whose simple name matches `importedName` (some
|
|
250
|
+
// languages emit a synthetic module-def), pick it up as the `targetDefId`
|
|
251
|
+
// so consumers can reach the module as a symbol — but its absence is not
|
|
252
|
+
// a failure.
|
|
253
|
+
if (draft.source.kind === 'namespace') {
|
|
254
|
+
const moduleDef = findExportByName(targetModule.localDefs, extractExportedName(draft.source));
|
|
255
|
+
return {
|
|
256
|
+
...draft.base,
|
|
257
|
+
targetModuleScope: targetModule.moduleScope,
|
|
258
|
+
...(moduleDef !== undefined ? { targetDefId: moduleDef.nodeId } : {}),
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
// named / alias / reexport: look up the imported name in the target's
|
|
262
|
+
// local defs. Multi-hop re-export chains settle iteratively — each hop
|
|
263
|
+
// resolves once its prior hop is finalized.
|
|
264
|
+
const importedName = extractExportedName(draft.source);
|
|
265
|
+
const exported = findExportByName(targetModule.localDefs, importedName);
|
|
266
|
+
if (exported === undefined) {
|
|
267
|
+
// Target resolvable but the name isn't exported — keep trying in case a
|
|
268
|
+
// re-export inside the target's SCC surfaces it in a later iteration.
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
const transitiveVia = draft.source.kind === 'reexport' ? Object.freeze([targetFile]) : undefined;
|
|
272
|
+
return {
|
|
273
|
+
...draft.base,
|
|
274
|
+
targetModuleScope: targetModule.moduleScope,
|
|
275
|
+
targetDefId: exported.nodeId,
|
|
276
|
+
...(transitiveVia !== undefined ? { transitiveVia } : {}),
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* The "simple" (unqualified) name of a def, for import-name matching.
|
|
281
|
+
*
|
|
282
|
+
* Canonical source: `def.qualifiedName` — the tail after the last `.` (or
|
|
283
|
+
* the whole string if no dot). Defs without a qualifiedName can't be
|
|
284
|
+
* resolved by name here and return `null`; callers treat that as "name
|
|
285
|
+
* not exported" and either retry in a later fixpoint iteration or mark
|
|
286
|
+
* the edge unresolved.
|
|
287
|
+
*/
|
|
288
|
+
function deriveSimpleName(def) {
|
|
289
|
+
const q = def.qualifiedName;
|
|
290
|
+
if (q === undefined || q.length === 0)
|
|
291
|
+
return null;
|
|
292
|
+
const dot = q.lastIndexOf('.');
|
|
293
|
+
return dot === -1 ? q : q.slice(dot + 1);
|
|
294
|
+
}
|
|
295
|
+
function findExportByName(defs, name) {
|
|
296
|
+
for (const d of defs) {
|
|
297
|
+
if (deriveSimpleName(d) === name)
|
|
298
|
+
return d;
|
|
299
|
+
}
|
|
300
|
+
return undefined;
|
|
301
|
+
}
|
|
302
|
+
function countEdgesWithin(edgeIndex, files) {
|
|
303
|
+
let n = 0;
|
|
304
|
+
for (const filePath of files) {
|
|
305
|
+
const drafts = edgeIndex.get(filePath);
|
|
306
|
+
if (drafts === undefined)
|
|
307
|
+
continue;
|
|
308
|
+
for (const d of drafts) {
|
|
309
|
+
if (d.targetFile !== null && files.has(d.targetFile))
|
|
310
|
+
n++;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
// Guarantee at least one pass even for a trivial SCC (ensures deterministic
|
|
314
|
+
// fixpoint termination even when a single-file SCC has zero intra-SCC edges
|
|
315
|
+
// but still needs one settle pass).
|
|
316
|
+
return Math.max(n, 1);
|
|
317
|
+
}
|
|
318
|
+
// ─── Internal: wildcard expansion (phase 4) ────────────────────────────────
|
|
319
|
+
function expandWildcard(edge, byFilePath, hooks, workspace) {
|
|
320
|
+
if (edge.targetModuleScope === undefined || edge.targetFile === null) {
|
|
321
|
+
return [edge]; // unresolvable wildcard survives as a single unlinked edge
|
|
322
|
+
}
|
|
323
|
+
const target = byFilePath.get(edge.targetFile);
|
|
324
|
+
if (target === undefined)
|
|
325
|
+
return [edge];
|
|
326
|
+
const names = hooks.expandsWildcardTo(edge.targetModuleScope, workspace);
|
|
327
|
+
if (names.length === 0)
|
|
328
|
+
return [];
|
|
329
|
+
const expanded = [];
|
|
330
|
+
for (const name of names) {
|
|
331
|
+
const def = findExportByName(target.localDefs, name);
|
|
332
|
+
if (def === undefined)
|
|
333
|
+
continue;
|
|
334
|
+
expanded.push({
|
|
335
|
+
localName: name,
|
|
336
|
+
targetFile: edge.targetFile,
|
|
337
|
+
targetExportedName: name,
|
|
338
|
+
kind: 'wildcard-expanded',
|
|
339
|
+
targetModuleScope: edge.targetModuleScope,
|
|
340
|
+
targetDefId: def.nodeId,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
return expanded;
|
|
344
|
+
}
|
|
345
|
+
// ─── Internal: bindings materialization (phase 5) ───────────────────────────
|
|
346
|
+
function materializeBindings(files, linkedByScope, hooks) {
|
|
347
|
+
const out = new Map();
|
|
348
|
+
for (const file of files) {
|
|
349
|
+
const scopeBindings = new Map();
|
|
350
|
+
// Start with local defs as `origin: 'local'` bindings.
|
|
351
|
+
for (const def of file.localDefs) {
|
|
352
|
+
const name = deriveSimpleName(def);
|
|
353
|
+
if (name === null)
|
|
354
|
+
continue;
|
|
355
|
+
const incoming = [{ def, origin: 'local' }];
|
|
356
|
+
const existing = scopeBindings.get(name) ?? [];
|
|
357
|
+
scopeBindings.set(name, hooks.mergeBindings(existing, incoming, file.moduleScope));
|
|
358
|
+
}
|
|
359
|
+
// Layer in finalized imports.
|
|
360
|
+
const imports = linkedByScope.get(file.moduleScope) ?? [];
|
|
361
|
+
for (const edge of imports) {
|
|
362
|
+
if (edge.targetDefId === undefined || edge.linkStatus === 'unresolved')
|
|
363
|
+
continue;
|
|
364
|
+
// Every def the importing file needs to reach is in some other file's
|
|
365
|
+
// `localDefs`; walk all files to find it. In practice we could index
|
|
366
|
+
// this, but at finalize-time N(files) is small per workspace pass.
|
|
367
|
+
const def = findDefById(files, edge.targetDefId);
|
|
368
|
+
if (def === undefined)
|
|
369
|
+
continue;
|
|
370
|
+
const origin = edge.kind === 'namespace'
|
|
371
|
+
? 'namespace'
|
|
372
|
+
: edge.kind === 'wildcard-expanded'
|
|
373
|
+
? 'wildcard'
|
|
374
|
+
: edge.kind === 'reexport'
|
|
375
|
+
? 'reexport'
|
|
376
|
+
: 'import';
|
|
377
|
+
const fallback = deriveSimpleName(def);
|
|
378
|
+
const name = edge.localName.length > 0 ? edge.localName : fallback;
|
|
379
|
+
if (name === null)
|
|
380
|
+
continue;
|
|
381
|
+
const incoming = [{ def, origin, via: edge }];
|
|
382
|
+
const existing = scopeBindings.get(name) ?? [];
|
|
383
|
+
scopeBindings.set(name, hooks.mergeBindings(existing, incoming, file.moduleScope));
|
|
384
|
+
}
|
|
385
|
+
// Freeze nested buckets for immutability.
|
|
386
|
+
const frozen = new Map();
|
|
387
|
+
for (const [name, refs] of scopeBindings) {
|
|
388
|
+
frozen.set(name, Object.freeze(refs.slice()));
|
|
389
|
+
}
|
|
390
|
+
out.set(file.moduleScope, frozen);
|
|
391
|
+
}
|
|
392
|
+
return out;
|
|
393
|
+
}
|
|
394
|
+
function findDefById(files, defId) {
|
|
395
|
+
for (const f of files) {
|
|
396
|
+
for (const d of f.localDefs) {
|
|
397
|
+
if (d.nodeId === defId)
|
|
398
|
+
return d;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return undefined;
|
|
402
|
+
}
|
|
403
|
+
// ─── Internal: Tarjan SCC ──────────────────────────────────────────────────
|
|
404
|
+
/**
|
|
405
|
+
* Iterative Tarjan SCC. Returns SCCs in **reverse-topological** order
|
|
406
|
+
* (leaves first — a property Tarjan gives for free, and the order
|
|
407
|
+
* `finalize` wants so leaves are fully resolved before their dependents).
|
|
408
|
+
*/
|
|
409
|
+
function tarjanSccs(graph) {
|
|
410
|
+
const index = new Map();
|
|
411
|
+
const lowlink = new Map();
|
|
412
|
+
const onStack = new Set();
|
|
413
|
+
const stack = [];
|
|
414
|
+
const sccs = [];
|
|
415
|
+
let idx = 0;
|
|
416
|
+
// Iterative DFS to avoid stack overflow on deep import chains.
|
|
417
|
+
const allNodes = Array.from(graph.keys()).sort(); // deterministic order
|
|
418
|
+
const iterStack = [];
|
|
419
|
+
for (const root of allNodes) {
|
|
420
|
+
if (index.has(root))
|
|
421
|
+
continue;
|
|
422
|
+
iterStack.push({
|
|
423
|
+
node: root,
|
|
424
|
+
children: (graph.get(root) ?? new Set()).values(),
|
|
425
|
+
entered: false,
|
|
426
|
+
});
|
|
427
|
+
while (iterStack.length > 0) {
|
|
428
|
+
const frame = iterStack[iterStack.length - 1];
|
|
429
|
+
if (!frame.entered) {
|
|
430
|
+
frame.entered = true;
|
|
431
|
+
index.set(frame.node, idx);
|
|
432
|
+
lowlink.set(frame.node, idx);
|
|
433
|
+
idx++;
|
|
434
|
+
stack.push(frame.node);
|
|
435
|
+
onStack.add(frame.node);
|
|
436
|
+
}
|
|
437
|
+
const nextChild = frame.children.next();
|
|
438
|
+
if (nextChild.done) {
|
|
439
|
+
// Post-visit: compute SCC membership if frame.node is a root.
|
|
440
|
+
if (lowlink.get(frame.node) === index.get(frame.node)) {
|
|
441
|
+
const scc = [];
|
|
442
|
+
let selfInCycle = false;
|
|
443
|
+
while (true) {
|
|
444
|
+
const w = stack.pop();
|
|
445
|
+
onStack.delete(w);
|
|
446
|
+
scc.push(w);
|
|
447
|
+
// A single-file self-loop counts as a cycle.
|
|
448
|
+
if (w === frame.node) {
|
|
449
|
+
selfInCycle = (graph.get(w) ?? new Set()).has(w);
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
const isCycle = scc.length > 1 || selfInCycle;
|
|
454
|
+
sccs.push({ files: Object.freeze(scc), isCycle });
|
|
455
|
+
}
|
|
456
|
+
iterStack.pop();
|
|
457
|
+
// Propagate lowlink to parent.
|
|
458
|
+
if (iterStack.length > 0) {
|
|
459
|
+
const parent = iterStack[iterStack.length - 1];
|
|
460
|
+
lowlink.set(parent.node, Math.min(lowlink.get(parent.node), lowlink.get(frame.node)));
|
|
461
|
+
}
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
const child = nextChild.value;
|
|
465
|
+
if (!index.has(child)) {
|
|
466
|
+
iterStack.push({
|
|
467
|
+
node: child,
|
|
468
|
+
children: (graph.get(child) ?? new Set()).values(),
|
|
469
|
+
entered: false,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
else if (onStack.has(child)) {
|
|
473
|
+
lowlink.set(frame.node, Math.min(lowlink.get(frame.node), index.get(child)));
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
return sccs;
|
|
478
|
+
}
|
|
479
|
+
//# sourceMappingURL=finalize-algorithm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finalize-algorithm.js","sourceRoot":"","sources":["../../src/scope-resolution/finalize-algorithm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `MethodDispatchIndex` — materialized view of class hierarchies keyed by
|
|
3
|
+
* `DefId` (RFC §3.1; Ring 2 SHARED #914).
|
|
4
|
+
*
|
|
5
|
+
* Two O(1)-access maps used by `Registry.lookupMethod` and interface-
|
|
6
|
+
* dispatch callers:
|
|
7
|
+
*
|
|
8
|
+
* - `mroByOwnerDefId` : owner class → full MRO ancestor chain
|
|
9
|
+
* (excludes the owner itself, in per-language
|
|
10
|
+
* strategy order).
|
|
11
|
+
* - `implsByInterfaceDefId` : interface/trait → classes that implement it.
|
|
12
|
+
*
|
|
13
|
+
* **Not an MRO implementation.** The build function is a pure aggregator: it
|
|
14
|
+
* asks the caller (via `computeMro` and `implementsOf` callbacks) for the
|
|
15
|
+
* per-language answers and materializes the two-way index. MRO strategies
|
|
16
|
+
* live where they already do today (`model/resolve.ts § c3Linearize`,
|
|
17
|
+
* `languages/ruby.ts § selectDispatch`, etc.) — this index does not
|
|
18
|
+
* reimplement them.
|
|
19
|
+
*
|
|
20
|
+
* Why callbacks and not a shared strategy registry: the five strategies
|
|
21
|
+
* (Python C3, Ruby kind-aware, Java/Kotlin linear, Rust qualified-syntax,
|
|
22
|
+
* COBOL none) already exist in the CLI package and depend on the CLI's
|
|
23
|
+
* `HeritageMap` + `SemanticModel`. Pulling them into `gitnexus-shared` would
|
|
24
|
+
* require migrating both — out of scope for #914. Callbacks let the shared
|
|
25
|
+
* build stay pure while honoring existing strategies verbatim.
|
|
26
|
+
*
|
|
27
|
+
* Consumed by: #917 (`Registry.lookupMethod` MRO fast path, interface
|
|
28
|
+
* dispatch resolver).
|
|
29
|
+
*/
|
|
30
|
+
import type { DefId } from './types.js';
|
|
31
|
+
export interface MethodDispatchIndex {
|
|
32
|
+
/**
|
|
33
|
+
* Full MRO ancestor chain per owner class (excludes the owner itself).
|
|
34
|
+
* Order reflects the per-language strategy used by `computeMro`.
|
|
35
|
+
*/
|
|
36
|
+
readonly mroByOwnerDefId: ReadonlyMap<DefId, readonly DefId[]>;
|
|
37
|
+
/** Interfaces / traits → classes that implement them. */
|
|
38
|
+
readonly implsByInterfaceDefId: ReadonlyMap<DefId, readonly DefId[]>;
|
|
39
|
+
/** `mroByOwnerDefId.get`, with an empty frozen array on miss. */
|
|
40
|
+
mroFor(ownerDefId: DefId): readonly DefId[];
|
|
41
|
+
/** `implsByInterfaceDefId.get`, with an empty frozen array on miss. */
|
|
42
|
+
implementorsOf(interfaceDefId: DefId): readonly DefId[];
|
|
43
|
+
}
|
|
44
|
+
export interface MethodDispatchInput {
|
|
45
|
+
/**
|
|
46
|
+
* Owner defs to index (classes, structs, traits, interfaces — any kind
|
|
47
|
+
* that can appear on the owner side of a method-dispatch graph).
|
|
48
|
+
*/
|
|
49
|
+
readonly owners: readonly DefId[];
|
|
50
|
+
/**
|
|
51
|
+
* Return the full MRO ancestor chain for `ownerDefId`, **excluding the
|
|
52
|
+
* owner itself**, in the order dictated by the owner's language-specific
|
|
53
|
+
* MRO strategy.
|
|
54
|
+
*
|
|
55
|
+
* Contract:
|
|
56
|
+
* - Pure (no side effects).
|
|
57
|
+
* - Deterministic per input.
|
|
58
|
+
* - `undefined` not allowed — return `[]` when the owner has no parents.
|
|
59
|
+
*/
|
|
60
|
+
readonly computeMro: (ownerDefId: DefId) => readonly DefId[];
|
|
61
|
+
/**
|
|
62
|
+
* Return the set of interface/trait defs that `ownerDefId` implements.
|
|
63
|
+
* Transitive inclusion (e.g., `implements` on a parent class) is the
|
|
64
|
+
* caller's choice — the build function simply inverts whatever is
|
|
65
|
+
* returned.
|
|
66
|
+
*
|
|
67
|
+
* Repeated IDs in the output are deduplicated automatically.
|
|
68
|
+
*
|
|
69
|
+
* **Call-count contract.** `implementsOf` is invoked **once per
|
|
70
|
+
* occurrence** of an owner in `input.owners`, not once per unique
|
|
71
|
+
* owner. Duplicate owners therefore re-invoke it; dedup happens at
|
|
72
|
+
* the bucket layer (after the callback returns). Callers with
|
|
73
|
+
* expensive `implementsOf` implementations should pass a deduplicated
|
|
74
|
+
* `owners` list. `computeMro`, by contrast, is memoized by the first-
|
|
75
|
+
* write-wins policy and fires at most once per unique owner.
|
|
76
|
+
*/
|
|
77
|
+
readonly implementsOf: (ownerDefId: DefId) => readonly DefId[];
|
|
78
|
+
}
|
|
79
|
+
export declare function buildMethodDispatchIndex(input: MethodDispatchInput): MethodDispatchIndex;
|
|
80
|
+
//# sourceMappingURL=method-dispatch-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"method-dispatch-index.d.ts","sourceRoot":"","sources":["../../src/scope-resolution/method-dispatch-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAIxC,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,KAAK,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC;IAC/D,yDAAyD;IACzD,QAAQ,CAAC,qBAAqB,EAAE,WAAW,CAAC,KAAK,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC;IAErE,iEAAiE;IACjE,MAAM,CAAC,UAAU,EAAE,KAAK,GAAG,SAAS,KAAK,EAAE,CAAC;IAC5C,uEAAuE;IACvE,cAAc,CAAC,cAAc,EAAE,KAAK,GAAG,SAAS,KAAK,EAAE,CAAC;CACzD;AAED,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC;;;;;;;;;OASG;IACH,QAAQ,CAAC,UAAU,EAAE,CAAC,UAAU,EAAE,KAAK,KAAK,SAAS,KAAK,EAAE,CAAC;IAC7D;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,KAAK,KAAK,SAAS,KAAK,EAAE,CAAC;CAChE;AAID,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,mBAAmB,GAAG,mBAAmB,CAqCxF"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `MethodDispatchIndex` — materialized view of class hierarchies keyed by
|
|
3
|
+
* `DefId` (RFC §3.1; Ring 2 SHARED #914).
|
|
4
|
+
*
|
|
5
|
+
* Two O(1)-access maps used by `Registry.lookupMethod` and interface-
|
|
6
|
+
* dispatch callers:
|
|
7
|
+
*
|
|
8
|
+
* - `mroByOwnerDefId` : owner class → full MRO ancestor chain
|
|
9
|
+
* (excludes the owner itself, in per-language
|
|
10
|
+
* strategy order).
|
|
11
|
+
* - `implsByInterfaceDefId` : interface/trait → classes that implement it.
|
|
12
|
+
*
|
|
13
|
+
* **Not an MRO implementation.** The build function is a pure aggregator: it
|
|
14
|
+
* asks the caller (via `computeMro` and `implementsOf` callbacks) for the
|
|
15
|
+
* per-language answers and materializes the two-way index. MRO strategies
|
|
16
|
+
* live where they already do today (`model/resolve.ts § c3Linearize`,
|
|
17
|
+
* `languages/ruby.ts § selectDispatch`, etc.) — this index does not
|
|
18
|
+
* reimplement them.
|
|
19
|
+
*
|
|
20
|
+
* Why callbacks and not a shared strategy registry: the five strategies
|
|
21
|
+
* (Python C3, Ruby kind-aware, Java/Kotlin linear, Rust qualified-syntax,
|
|
22
|
+
* COBOL none) already exist in the CLI package and depend on the CLI's
|
|
23
|
+
* `HeritageMap` + `SemanticModel`. Pulling them into `gitnexus-shared` would
|
|
24
|
+
* require migrating both — out of scope for #914. Callbacks let the shared
|
|
25
|
+
* build stay pure while honoring existing strategies verbatim.
|
|
26
|
+
*
|
|
27
|
+
* Consumed by: #917 (`Registry.lookupMethod` MRO fast path, interface
|
|
28
|
+
* dispatch resolver).
|
|
29
|
+
*/
|
|
30
|
+
// ─── Builder ────────────────────────────────────────────────────────────────
|
|
31
|
+
export function buildMethodDispatchIndex(input) {
|
|
32
|
+
const mroByOwnerDefId = new Map();
|
|
33
|
+
const implsBuilding = new Map();
|
|
34
|
+
const implsSeen = new Map();
|
|
35
|
+
for (const ownerId of input.owners) {
|
|
36
|
+
// First-write-wins on duplicate owner ids: a stable policy consistent
|
|
37
|
+
// with sibling indexes (#913 DefIndex / ModuleScopeIndex).
|
|
38
|
+
if (!mroByOwnerDefId.has(ownerId)) {
|
|
39
|
+
const chain = input.computeMro(ownerId);
|
|
40
|
+
mroByOwnerDefId.set(ownerId, Object.freeze(chain.slice()));
|
|
41
|
+
}
|
|
42
|
+
for (const ifaceId of input.implementsOf(ownerId)) {
|
|
43
|
+
let seen = implsSeen.get(ifaceId);
|
|
44
|
+
if (seen === undefined) {
|
|
45
|
+
seen = new Set();
|
|
46
|
+
implsSeen.set(ifaceId, seen);
|
|
47
|
+
}
|
|
48
|
+
if (seen.has(ownerId))
|
|
49
|
+
continue;
|
|
50
|
+
seen.add(ownerId);
|
|
51
|
+
let bucket = implsBuilding.get(ifaceId);
|
|
52
|
+
if (bucket === undefined) {
|
|
53
|
+
bucket = [];
|
|
54
|
+
implsBuilding.set(ifaceId, bucket);
|
|
55
|
+
}
|
|
56
|
+
bucket.push(ownerId);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const implsByInterfaceDefId = new Map();
|
|
60
|
+
for (const [ifaceId, owners] of implsBuilding) {
|
|
61
|
+
implsByInterfaceDefId.set(ifaceId, Object.freeze(owners.slice()));
|
|
62
|
+
}
|
|
63
|
+
return wrapIndex(mroByOwnerDefId, implsByInterfaceDefId);
|
|
64
|
+
}
|
|
65
|
+
// ─── Internal ───────────────────────────────────────────────────────────────
|
|
66
|
+
const EMPTY = Object.freeze([]);
|
|
67
|
+
function wrapIndex(mroByOwnerDefId, implsByInterfaceDefId) {
|
|
68
|
+
return {
|
|
69
|
+
mroByOwnerDefId,
|
|
70
|
+
implsByInterfaceDefId,
|
|
71
|
+
mroFor(ownerDefId) {
|
|
72
|
+
return mroByOwnerDefId.get(ownerDefId) ?? EMPTY;
|
|
73
|
+
},
|
|
74
|
+
implementorsOf(interfaceDefId) {
|
|
75
|
+
return implsByInterfaceDefId.get(interfaceDefId) ?? EMPTY;
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=method-dispatch-index.js.map
|