@alloy-js/core 0.20.0-dev.4 → 0.20.0-dev.6
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/src/binder.d.ts +62 -38
- package/dist/src/binder.d.ts.map +1 -1
- package/dist/src/binder.js +214 -173
- package/dist/src/components/Declaration.d.ts +2 -2
- package/dist/src/components/Declaration.d.ts.map +1 -1
- package/dist/src/components/Declaration.js +8 -2
- package/dist/src/components/MemberDeclaration.d.ts +2 -2
- package/dist/src/components/MemberDeclaration.d.ts.map +1 -1
- package/dist/src/components/MemberDeclaration.js +9 -5
- package/dist/src/components/MemberScope.d.ts +30 -13
- package/dist/src/components/MemberScope.d.ts.map +1 -1
- package/dist/src/components/MemberScope.js +37 -15
- package/dist/src/components/Output.d.ts.map +1 -1
- package/dist/src/components/Output.js +2 -5
- package/dist/src/components/ReferenceOrContent.d.ts +1 -1
- package/dist/src/components/ReferenceOrContent.d.ts.map +1 -1
- package/dist/src/components/Scope.d.ts +5 -5
- package/dist/src/components/Scope.d.ts.map +1 -1
- package/dist/src/components/Scope.js +9 -5
- package/dist/src/context/member-scope.d.ts +7 -8
- package/dist/src/context/member-scope.d.ts.map +1 -1
- package/dist/src/context/member-scope.js +5 -5
- package/dist/src/context/name-policy.d.ts.map +1 -1
- package/dist/src/context/name-policy.js +3 -0
- package/dist/src/context/scope.d.ts +1 -0
- package/dist/src/context/scope.d.ts.map +1 -1
- package/dist/src/context/scope.js +7 -0
- package/dist/src/inspect.browser.d.ts +5 -0
- package/dist/src/inspect.browser.d.ts.map +1 -0
- package/dist/src/inspect.browser.js +5 -0
- package/dist/src/inspect.d.ts +2 -0
- package/dist/src/inspect.d.ts.map +1 -0
- package/dist/src/inspect.js +1 -0
- package/dist/src/name-policy.d.ts +11 -0
- package/dist/src/name-policy.d.ts.map +1 -1
- package/dist/src/name-policy.js +3 -0
- package/dist/src/reactive-union-set.d.ts.map +1 -1
- package/dist/src/reactive-union-set.js +12 -8
- package/dist/src/refkey.d.ts +39 -3
- package/dist/src/refkey.d.ts.map +1 -1
- package/dist/src/refkey.js +52 -8
- package/dist/src/symbols/basic-scope.d.ts +14 -0
- package/dist/src/symbols/basic-scope.d.ts.map +1 -0
- package/dist/src/symbols/basic-scope.js +20 -0
- package/dist/src/symbols/basic-symbol.d.ts +19 -0
- package/dist/src/symbols/basic-symbol.d.ts.map +1 -0
- package/dist/src/symbols/basic-symbol.js +28 -0
- package/dist/src/symbols/index.d.ts +3 -1
- package/dist/src/symbols/index.d.ts.map +1 -1
- package/dist/src/symbols/index.js +3 -1
- package/dist/src/symbols/output-scope.d.ts +70 -41
- package/dist/src/symbols/output-scope.d.ts.map +1 -1
- package/dist/src/symbols/output-scope.js +98 -130
- package/dist/src/symbols/output-space.d.ts +25 -0
- package/dist/src/symbols/output-space.d.ts.map +1 -0
- package/dist/src/symbols/output-space.js +35 -0
- package/dist/src/symbols/output-symbol.d.ts +213 -37
- package/dist/src/symbols/output-symbol.d.ts.map +1 -1
- package/dist/src/symbols/output-symbol.js +323 -203
- package/dist/src/symbols/symbol-flow.d.ts +1 -1
- package/dist/src/symbols/symbol-flow.d.ts.map +1 -1
- package/dist/src/symbols/symbol-flow.js +22 -7
- package/dist/src/symbols/symbol-slot.d.ts +27 -9
- package/dist/src/symbols/symbol-slot.d.ts.map +1 -1
- package/dist/src/symbols/symbol-slot.js +20 -4
- package/dist/src/symbols/symbol-table.d.ts +19 -8
- package/dist/src/symbols/symbol-table.d.ts.map +1 -1
- package/dist/src/symbols/symbol-table.js +65 -16
- package/dist/src/tracer.d.ts +15 -3
- package/dist/src/tracer.d.ts.map +1 -1
- package/dist/src/tracer.js +39 -63
- package/dist/test/components/declaration.test.js +9 -14
- package/dist/test/components/reference-or-content.test.js +2 -2
- package/dist/test/symbols/output-scope.test.js +33 -198
- package/dist/test/symbols/output-symbol.test.js +139 -385
- package/dist/test/symbols/resolution.test.js +431 -114
- package/dist/test/symbols/symbol-table.test.d.ts +2 -0
- package/dist/test/symbols/symbol-table.test.d.ts.map +1 -0
- package/dist/test/symbols/symbol-table.test.js +14 -0
- package/dist/test/symbols/utils.d.ts +10 -24
- package/dist/test/symbols/utils.d.ts.map +1 -1
- package/dist/test/symbols/utils.js +23 -45
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -2
- package/src/binder.ts +348 -273
- package/src/components/Declaration.tsx +13 -3
- package/src/components/MemberDeclaration.tsx +15 -8
- package/src/components/MemberScope.tsx +61 -20
- package/src/components/Output.tsx +0 -4
- package/src/components/Scope.tsx +16 -9
- package/src/context/member-scope.ts +10 -10
- package/src/context/name-policy.ts +3 -0
- package/src/context/scope.ts +9 -0
- package/src/inspect.browser.ts +6 -0
- package/src/inspect.ts +1 -0
- package/src/name-policy.ts +14 -0
- package/src/reactive-union-set.ts +14 -8
- package/src/refkey.ts +88 -14
- package/src/symbols/basic-scope.ts +23 -0
- package/src/symbols/basic-symbol.ts +32 -0
- package/src/symbols/index.ts +3 -1
- package/src/symbols/output-scope.ts +131 -170
- package/src/symbols/output-space.ts +49 -0
- package/src/symbols/output-symbol.ts +434 -258
- package/src/symbols/symbol-flow.ts +38 -9
- package/src/symbols/symbol-slot.tsx +46 -8
- package/src/symbols/symbol-table.ts +95 -21
- package/src/tracer.ts +53 -83
- package/temp/api.json +5559 -3079
- package/test/components/declaration.test.tsx +6 -19
- package/test/components/reference-or-content.test.tsx +2 -2
- package/test/symbols/output-scope.test.ts +33 -125
- package/test/symbols/output-symbol.test.ts +128 -348
- package/test/symbols/resolution.test.ts +530 -117
- package/test/symbols/symbol-table.test.ts +15 -0
- package/test/symbols/utils.ts +38 -74
- package/tsdoc.json +4 -0
- package/dist/src/slot.d.ts +0 -15
- package/dist/src/slot.d.ts.map +0 -1
- package/dist/src/slot.js +0 -50
- package/dist/src/symbols/flags.d.ts +0 -70
- package/dist/src/symbols/flags.d.ts.map +0 -1
- package/dist/src/symbols/flags.js +0 -72
- package/dist/test/components/slot.test.d.ts +0 -2
- package/dist/test/components/slot.test.d.ts.map +0 -1
- package/dist/test/components/slot.test.js +0 -134
- package/src/slot.ts +0 -89
- package/src/symbols/flags.ts +0 -82
- package/test/components/slot.test.tsx +0 -174
package/src/binder.ts
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import { computed,
|
|
2
|
-
import {
|
|
1
|
+
import { computed, Ref, ShallowRef, shallowRef } from "@vue/reactivity";
|
|
2
|
+
import { useMemberContext } from "./context/member-scope.js";
|
|
3
3
|
import { useScope } from "./context/scope.js";
|
|
4
|
-
import { effect
|
|
5
|
-
import { refkey, Refkey } from "./refkey.js";
|
|
6
|
-
import { OutputSymbolFlags } from "./symbols/flags.js";
|
|
4
|
+
import { effect } from "./reactivity.js";
|
|
5
|
+
import { isMemberRefkey, refkey, Refkey } from "./refkey.js";
|
|
7
6
|
import { OutputScope } from "./symbols/output-scope.js";
|
|
8
7
|
import { type OutputSymbol } from "./symbols/output-symbol.js";
|
|
9
8
|
import {
|
|
10
9
|
formatRefkeys,
|
|
11
|
-
formatSymbol,
|
|
12
10
|
formatSymbolName,
|
|
13
11
|
trace,
|
|
14
12
|
TracePhase,
|
|
@@ -41,52 +39,18 @@ export interface Binder {
|
|
|
41
39
|
TSymbol extends OutputSymbol = OutputSymbol,
|
|
42
40
|
>(
|
|
43
41
|
currentScope: TScope | undefined,
|
|
44
|
-
currentMemberScope: TScope | undefined,
|
|
45
42
|
key: Refkey,
|
|
43
|
+
options?: ResolveDeclarationByKeyOptions<TScope, TSymbol>,
|
|
46
44
|
): Ref<ResolutionResult<TScope, TSymbol> | undefined>;
|
|
47
45
|
|
|
48
|
-
getSymbolForRefkey<TSymbol extends OutputSymbol>(
|
|
49
|
-
refkey: Refkey,
|
|
50
|
-
): Ref<TSymbol | undefined>;
|
|
51
|
-
|
|
52
46
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* will update.
|
|
47
|
+
* Get a ref to the symbol associated with the given refkey. The value of the
|
|
48
|
+
* ref is undefined if the symbol has not been created yet.
|
|
56
49
|
*/
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
TSymbol extends OutputSymbol = OutputSymbol,
|
|
60
|
-
>(
|
|
61
|
-
currentScope: TScope | undefined,
|
|
62
|
-
name: string,
|
|
50
|
+
getSymbolForRefkey<TSymbol extends OutputSymbol>(
|
|
51
|
+
refkey: Refkey,
|
|
63
52
|
): Ref<TSymbol | undefined>;
|
|
64
53
|
|
|
65
|
-
findScopeName<TScope extends OutputScope = OutputScope>(
|
|
66
|
-
currentScope: TScope | undefined,
|
|
67
|
-
name: string,
|
|
68
|
-
): Ref<TScope | undefined>;
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Resolve a fully qualified name to a symbol. Access a nested scope by name
|
|
72
|
-
* with `::`, a nested static member with `.` and a nested instance member
|
|
73
|
-
* with `#`.
|
|
74
|
-
*
|
|
75
|
-
* Per-language packages may provide their own resolveFQN function that uses
|
|
76
|
-
* syntax more natural to that language.
|
|
77
|
-
*/
|
|
78
|
-
resolveFQN<
|
|
79
|
-
TScope extends OutputScope = OutputScope,
|
|
80
|
-
TSymbol extends OutputSymbol = OutputSymbol,
|
|
81
|
-
>(
|
|
82
|
-
fqn: string,
|
|
83
|
-
): Ref<TSymbol | TScope | undefined>;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* The global scope. This is the root scope for all symbols.
|
|
87
|
-
*/
|
|
88
|
-
globalScope: OutputScope;
|
|
89
|
-
|
|
90
54
|
/**
|
|
91
55
|
* The name conflict resolver to use for this binder.
|
|
92
56
|
*/
|
|
@@ -119,7 +83,7 @@ export interface Binder {
|
|
|
119
83
|
* scope: global scope
|
|
120
84
|
* ├── scope: namespace scope 1
|
|
121
85
|
* │ └── symbol: foo
|
|
122
|
-
* │ └── static
|
|
86
|
+
* │ └── static members
|
|
123
87
|
* │ └── symbol: bar
|
|
124
88
|
* └── scope: namespace scope 2
|
|
125
89
|
* └── (resolve bar from here)
|
|
@@ -139,11 +103,21 @@ export interface ResolutionResult<
|
|
|
139
103
|
TSymbol extends OutputSymbol,
|
|
140
104
|
> {
|
|
141
105
|
/**
|
|
142
|
-
* The symbol
|
|
106
|
+
* The resolved symbol. May be declared in a lexical scope or be a member symbol.
|
|
107
|
+
*/
|
|
108
|
+
symbol: TSymbol;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* When the symbol is a member symbol, this is the symbol of the lexical
|
|
112
|
+
* declaration which contains this member symbol, either as one of its own
|
|
113
|
+
* member symbols, or as a member of one of its members.
|
|
114
|
+
*
|
|
115
|
+
* When the symbol is a non-member symbol, this is the same as `symbol`.
|
|
143
116
|
*/
|
|
144
|
-
|
|
117
|
+
lexicalDeclaration: TSymbol;
|
|
118
|
+
|
|
145
119
|
/**
|
|
146
|
-
* The scopes between the common scope and the reference
|
|
120
|
+
* The scopes between the common scope and the reference.
|
|
147
121
|
*/
|
|
148
122
|
pathUp: TScope[];
|
|
149
123
|
|
|
@@ -153,21 +127,78 @@ export interface ResolutionResult<
|
|
|
153
127
|
pathDown: TScope[];
|
|
154
128
|
|
|
155
129
|
/**
|
|
156
|
-
* The
|
|
130
|
+
* The scopes from the root to scope of the lexical declaration.
|
|
131
|
+
*/
|
|
132
|
+
fullSymbolPath: TScope[];
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The scopes from the root to the scope of the reference.
|
|
136
|
+
*/
|
|
137
|
+
fullReferencePath: TScope[];
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The lexical scope which contains both the reference and the lexical
|
|
141
|
+
* declaration. Undefined when they do not share a common scope.
|
|
157
142
|
*/
|
|
158
143
|
commonScope: TScope | undefined;
|
|
159
144
|
|
|
160
145
|
/**
|
|
161
146
|
* When resolving a member symbol, this is the path of symbols that lead from
|
|
162
|
-
* the
|
|
147
|
+
* the lexical declaration to the member symbol.
|
|
163
148
|
*/
|
|
164
|
-
memberPath
|
|
149
|
+
memberPath: TSymbol[];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Describes a member in a member access chain, tracking both the symbol
|
|
154
|
+
* and whether this specific member was accessed via a memberRefkey.
|
|
155
|
+
*/
|
|
156
|
+
export interface MemberDescriptor {
|
|
157
|
+
symbol: OutputSymbol;
|
|
158
|
+
isMemberAccess: boolean;
|
|
165
159
|
}
|
|
166
160
|
|
|
167
161
|
export interface NameConflictResolver {
|
|
168
162
|
(name: string, symbols: OutputSymbol[]): void;
|
|
169
163
|
}
|
|
170
164
|
|
|
165
|
+
/**
|
|
166
|
+
* The context for a member resolution. This is used to properly resolve a
|
|
167
|
+
* member in the MemberResolver.
|
|
168
|
+
*/
|
|
169
|
+
export interface MemberResolutionContext<TScope extends OutputScope> {
|
|
170
|
+
/**
|
|
171
|
+
* The scopes that the member reference occurred in.
|
|
172
|
+
*/
|
|
173
|
+
referencePath: TScope[];
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Whether we are using member access e.g. via `memberRefkey`.
|
|
177
|
+
* This is true when the member was resolved using a memberRefkey,
|
|
178
|
+
* which may carry additional metadata about the member access in the future.
|
|
179
|
+
*/
|
|
180
|
+
isMemberAccess: boolean;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
*
|
|
185
|
+
*/
|
|
186
|
+
export interface MemberResolver<
|
|
187
|
+
TScope extends OutputScope,
|
|
188
|
+
TSymbol extends OutputSymbol,
|
|
189
|
+
> {
|
|
190
|
+
(
|
|
191
|
+
owner: TSymbol,
|
|
192
|
+
member: TSymbol,
|
|
193
|
+
context: MemberResolutionContext<TScope>,
|
|
194
|
+
): void;
|
|
195
|
+
}
|
|
196
|
+
export interface ResolveDeclarationByKeyOptions<
|
|
197
|
+
TScope extends OutputScope,
|
|
198
|
+
TSymbol extends OutputSymbol,
|
|
199
|
+
> {
|
|
200
|
+
memberResolver?: MemberResolver<TScope, TSymbol>;
|
|
201
|
+
}
|
|
171
202
|
export interface BinderOptions {
|
|
172
203
|
nameConflictResolver?: NameConflictResolver;
|
|
173
204
|
}
|
|
@@ -176,21 +207,12 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
176
207
|
const binder: Binder = {
|
|
177
208
|
resolveDeclarationByKey,
|
|
178
209
|
getSymbolForRefkey,
|
|
179
|
-
findSymbolName,
|
|
180
|
-
findScopeName,
|
|
181
|
-
resolveFQN: resolveFQN as any,
|
|
182
|
-
globalScope: undefined as any,
|
|
183
210
|
notifyScopeCreated,
|
|
184
211
|
notifySymbolCreated,
|
|
185
212
|
notifySymbolDeleted,
|
|
186
213
|
nameConflictResolver: options.nameConflictResolver,
|
|
187
214
|
};
|
|
188
215
|
|
|
189
|
-
binder.globalScope = new OutputScope("<global>", {
|
|
190
|
-
binder,
|
|
191
|
-
kind: "global",
|
|
192
|
-
});
|
|
193
|
-
|
|
194
216
|
const knownDeclarations = new Map<Refkey, OutputSymbol>();
|
|
195
217
|
const waitingDeclarations = new Map<Refkey, Ref<OutputSymbol | undefined>>();
|
|
196
218
|
const waitingSymbolNames = new Map<
|
|
@@ -228,75 +250,112 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
228
250
|
}
|
|
229
251
|
}
|
|
230
252
|
|
|
231
|
-
function hasTransientScope(symbol: OutputSymbol) {
|
|
232
|
-
let sym: OutputSymbol | undefined = symbol;
|
|
233
|
-
let transient = false;
|
|
234
|
-
while (sym) {
|
|
235
|
-
if (sym.flags & OutputSymbolFlags.Transient) {
|
|
236
|
-
transient = true;
|
|
237
|
-
break;
|
|
238
|
-
}
|
|
239
|
-
if (sym.flags & ~OutputSymbolFlags.Member) {
|
|
240
|
-
break;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
sym = sym.scope.owner;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return transient;
|
|
247
|
-
}
|
|
248
253
|
function buildResult<
|
|
249
254
|
TScope extends OutputScope = OutputScope,
|
|
250
255
|
TSymbol extends OutputSymbol = OutputSymbol,
|
|
251
256
|
>(
|
|
252
257
|
currentScope: TScope | undefined,
|
|
253
|
-
currentMemberScope: TScope | undefined,
|
|
254
258
|
targetDeclarationBase: TSymbol,
|
|
255
259
|
): ResolutionResult<TScope, TSymbol> {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
260
|
+
const { memberPath: targetMemberPath, scopeChain: targetChain } =
|
|
261
|
+
scopeAndMemberChain<TScope, TSymbol>(targetDeclarationBase);
|
|
262
|
+
|
|
263
|
+
let targetLexicalDeclaration =
|
|
264
|
+
targetMemberPath && targetMemberPath.length > 0 ?
|
|
265
|
+
(targetMemberPath[0].ownerSymbol! as TSymbol)
|
|
266
|
+
: targetDeclarationBase;
|
|
267
|
+
// when we are resolving from a scope which is a member scope and might have
|
|
268
|
+
// member scope parents, and any symbols in the member path are members of
|
|
269
|
+
// the member scope's owner symbol (i.e., those symbols are in scope where
|
|
270
|
+
// the reference is made), we replace the target member path with an entry
|
|
271
|
+
// on the scope chain.
|
|
272
|
+
|
|
273
|
+
// So, first we find all the owner symbols for any member scopes in scope
|
|
274
|
+
// for the reference.
|
|
275
|
+
const referenceChain = scopeChain(currentScope);
|
|
276
|
+
|
|
277
|
+
const inScopeSymbols = new Map<TSymbol, TScope>();
|
|
278
|
+
for (const scope of referenceChain) {
|
|
279
|
+
if (scope.isMemberScope) {
|
|
280
|
+
inScopeSymbols.set(scope.ownerSymbol! as TSymbol, scope);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// then if the lexical declaration symbol's members are in scope, remove the
|
|
285
|
+
// symbol from the member path and add its corresponding member scope to the
|
|
286
|
+
// target chain.
|
|
287
|
+
while (
|
|
288
|
+
targetMemberPath.length > 0 &&
|
|
289
|
+
inScopeSymbols.has(targetLexicalDeclaration)
|
|
290
|
+
) {
|
|
291
|
+
targetChain.push(inScopeSymbols.get(targetLexicalDeclaration)!);
|
|
292
|
+
targetLexicalDeclaration = targetMemberPath.shift()!;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Now we replace any scopes in the target chain with corresponding scopes
|
|
296
|
+
// from the reference chain.
|
|
297
|
+
for (const [index, scope] of targetChain.entries()) {
|
|
298
|
+
if (inScopeSymbols.has(scope.ownerSymbol! as TSymbol)) {
|
|
299
|
+
targetChain[index] = inScopeSymbols.get(scope.ownerSymbol! as TSymbol)!;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Next we look for member scopes in the target chain that correspond to
|
|
304
|
+
// member scopes in the reference chain. We splice the reference chain into
|
|
305
|
+
// the target chain at that point. This ensures that we establish the proper
|
|
306
|
+
// common scope and path up/down even if the reference chain has additional
|
|
307
|
+
// scopes above it (e.g. a scope for the current source file).
|
|
308
|
+
const commonMemberContainer = targetChain.findIndex(
|
|
309
|
+
(scope) =>
|
|
310
|
+
scope.isMemberScope && inScopeSymbols.has(scope.ownerSymbol as TSymbol),
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
if (commonMemberContainer > -1) {
|
|
314
|
+
const sourceLocation = referenceChain.findIndex(
|
|
315
|
+
(scope) =>
|
|
316
|
+
scope.isMemberScope &&
|
|
317
|
+
scope.ownerSymbol === targetChain[commonMemberContainer].ownerSymbol,
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
// source location is guaranteed to exist at this point.
|
|
321
|
+
targetChain.splice(
|
|
322
|
+
0,
|
|
323
|
+
commonMemberContainer + 1,
|
|
324
|
+
...referenceChain.slice(0, sourceLocation + 1),
|
|
325
|
+
);
|
|
268
326
|
}
|
|
269
327
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
TSymbol
|
|
273
|
-
>(targetDeclarationBase);
|
|
274
|
-
const currentChain = scopeChain(currentScope);
|
|
328
|
+
// Now that we have the target chain and scopes, we can determine the common
|
|
329
|
+
// scopes and paths.
|
|
275
330
|
let diffStart = 0;
|
|
276
331
|
while (
|
|
277
332
|
targetChain[diffStart] &&
|
|
278
|
-
|
|
279
|
-
targetChain[diffStart] ===
|
|
333
|
+
referenceChain[diffStart] &&
|
|
334
|
+
targetChain[diffStart] === referenceChain[diffStart]
|
|
280
335
|
) {
|
|
281
336
|
diffStart++;
|
|
282
337
|
}
|
|
283
|
-
|
|
284
|
-
const pathUp = currentChain.slice(diffStart);
|
|
338
|
+
const pathUp = referenceChain.slice(diffStart);
|
|
285
339
|
const pathDown = targetChain.slice(diffStart);
|
|
286
|
-
const commonScope = targetChain[diffStart - 1] ??
|
|
340
|
+
const commonScope = targetChain[diffStart - 1] ?? undefined;
|
|
287
341
|
|
|
288
342
|
return {
|
|
289
343
|
pathUp,
|
|
290
344
|
pathDown,
|
|
291
|
-
memberPath,
|
|
345
|
+
memberPath: targetMemberPath,
|
|
292
346
|
commonScope,
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
347
|
+
symbol: targetDeclarationBase,
|
|
348
|
+
lexicalDeclaration: targetLexicalDeclaration,
|
|
349
|
+
fullSymbolPath: targetChain,
|
|
350
|
+
fullReferencePath: referenceChain,
|
|
297
351
|
};
|
|
298
352
|
}
|
|
299
353
|
|
|
354
|
+
/**
|
|
355
|
+
* Walk from the provided symbol up to the non-member symbol. This constitutes
|
|
356
|
+
* the member path. Then, walk from the first non-member symbol's scope up to
|
|
357
|
+
* the global scope. This constitutes the scope chain.
|
|
358
|
+
*/
|
|
300
359
|
function scopeAndMemberChain<
|
|
301
360
|
TScope extends OutputScope,
|
|
302
361
|
TSymbol extends OutputSymbol,
|
|
@@ -305,15 +364,14 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
305
364
|
memberPath: [] as TSymbol[],
|
|
306
365
|
scopeChain: [] as TScope[],
|
|
307
366
|
};
|
|
308
|
-
|
|
309
367
|
let currentSymbol = symbol;
|
|
310
|
-
while (currentSymbol.flags & OutputSymbolFlags.StaticMember) {
|
|
311
|
-
result.memberPath.unshift(currentSymbol);
|
|
312
|
-
currentSymbol = currentSymbol.scope.owner! as TSymbol;
|
|
313
|
-
}
|
|
314
368
|
|
|
315
|
-
if (
|
|
316
|
-
result.memberPath
|
|
369
|
+
if (currentSymbol.isMemberSymbol) {
|
|
370
|
+
result.memberPath = [];
|
|
371
|
+
while (currentSymbol.isMemberSymbol) {
|
|
372
|
+
result.memberPath.unshift(currentSymbol);
|
|
373
|
+
currentSymbol = currentSymbol.ownerSymbol as TSymbol;
|
|
374
|
+
}
|
|
317
375
|
}
|
|
318
376
|
|
|
319
377
|
const startScope = currentSymbol.scope as TScope;
|
|
@@ -339,7 +397,30 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
339
397
|
return waitingDeclarations.get(refkey)! as ShallowRef<TSymbol>;
|
|
340
398
|
}
|
|
341
399
|
|
|
342
|
-
|
|
400
|
+
let symbolRef: ShallowRef<TSymbol | undefined>;
|
|
401
|
+
|
|
402
|
+
if (isMemberRefkey(refkey)) {
|
|
403
|
+
const baseSymbolRef: ShallowRef<TSymbol | undefined> =
|
|
404
|
+
getSymbolForRefkey<TSymbol>(refkey.base);
|
|
405
|
+
const memberSymbolRef: ShallowRef<TSymbol | undefined> =
|
|
406
|
+
getSymbolForRefkey<TSymbol>(refkey.member);
|
|
407
|
+
|
|
408
|
+
symbolRef = computed(() => {
|
|
409
|
+
// even though we don't necessarily need the base symbol to be available
|
|
410
|
+
// yet (the member symbol might already be declared on a type), we wait
|
|
411
|
+
// to resolve the member refkey until the base symbol is available.
|
|
412
|
+
const baseSymbol = baseSymbolRef.value;
|
|
413
|
+
const memberSymbol = memberSymbolRef.value;
|
|
414
|
+
if (!baseSymbol || !memberSymbol) {
|
|
415
|
+
return undefined;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return memberSymbol;
|
|
419
|
+
}) as ShallowRef<TSymbol | undefined>;
|
|
420
|
+
} else {
|
|
421
|
+
symbolRef = shallowRef<TSymbol | undefined>();
|
|
422
|
+
}
|
|
423
|
+
|
|
343
424
|
waitingDeclarations.set(refkey, symbolRef);
|
|
344
425
|
if (knownDeclarations.has(refkey)) {
|
|
345
426
|
symbolRef.value = knownDeclarations.get(refkey) as TSymbol;
|
|
@@ -347,15 +428,23 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
347
428
|
return symbolRef;
|
|
348
429
|
}
|
|
349
430
|
|
|
431
|
+
/**
|
|
432
|
+
* There are two ways to reference a member symbol - directly via its refkey,
|
|
433
|
+
* and via a member refkey. In the former case, we just find the member
|
|
434
|
+
* symbol, and then compute its path directly from there. In hte latter case,
|
|
435
|
+
* we need to find the base of the member expression, and then add the members
|
|
436
|
+
* from the (possibly nested) member refkey to result.
|
|
437
|
+
*/
|
|
350
438
|
function resolveDeclarationByKey<
|
|
351
439
|
TScope extends OutputScope = OutputScope,
|
|
352
440
|
TSymbol extends OutputSymbol = OutputSymbol,
|
|
353
441
|
>(
|
|
354
442
|
currentScope: TScope | undefined,
|
|
355
|
-
currentMemberScope: TScope | undefined,
|
|
356
443
|
refkey: Refkey,
|
|
444
|
+
options: ResolveDeclarationByKeyOptions<TScope, TSymbol> = {},
|
|
357
445
|
): ShallowRef<ResolutionResult<TScope, TSymbol> | undefined> {
|
|
358
446
|
const resolvedSymbol = getSymbolForRefkey(refkey);
|
|
447
|
+
|
|
359
448
|
return computed(() => {
|
|
360
449
|
trace(
|
|
361
450
|
TracePhase.resolve.pending,
|
|
@@ -374,33 +463,147 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
374
463
|
() =>
|
|
375
464
|
`${formatRefkeys(refkey)} resolved to ${formatSymbolName(symbol)}.`,
|
|
376
465
|
);
|
|
377
|
-
if (
|
|
466
|
+
if (symbol.isTransient) {
|
|
378
467
|
trace(
|
|
379
468
|
TracePhase.resolve.failure,
|
|
380
|
-
() => `Symbol ${formatSymbolName(symbol)}
|
|
469
|
+
() => `Symbol ${formatSymbolName(symbol)} is transient.`,
|
|
381
470
|
);
|
|
382
471
|
return undefined;
|
|
383
472
|
}
|
|
384
473
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
(
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
474
|
+
const chain = scopeChain(symbol.scope);
|
|
475
|
+
if (chain.some((scope) => scope.isTransient)) {
|
|
476
|
+
trace(
|
|
477
|
+
TracePhase.resolve.failure,
|
|
478
|
+
() => `Symbol ${formatSymbolName(symbol)} is in a transient scope.`,
|
|
479
|
+
);
|
|
480
|
+
return undefined;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
let result: ResolutionResult<TScope, TSymbol>;
|
|
484
|
+
let memberDescriptorsFromRefkey: MemberDescriptor[];
|
|
485
|
+
|
|
486
|
+
if (isMemberRefkey(refkey)) {
|
|
487
|
+
memberDescriptorsFromRefkey = getMemberPathFromRefkey(refkey);
|
|
488
|
+
|
|
489
|
+
result = buildResult(
|
|
490
|
+
currentScope,
|
|
491
|
+
memberDescriptorsFromRefkey[0].symbol as TSymbol,
|
|
492
|
+
);
|
|
493
|
+
} else {
|
|
494
|
+
memberDescriptorsFromRefkey = [];
|
|
495
|
+
result = buildResult(currentScope, symbol);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// When we have member descriptors, this first entry is already part of the result due to passing it
|
|
499
|
+
// to buildResult above, so we don't need it here.
|
|
500
|
+
const newMemberPathDescriptors = memberDescriptorsFromRefkey.slice(1);
|
|
501
|
+
const allDescriptors = [
|
|
502
|
+
...result.memberPath.map((s) => ({ symbol: s, isMemberAccess: false })),
|
|
503
|
+
...newMemberPathDescriptors,
|
|
504
|
+
];
|
|
505
|
+
|
|
506
|
+
// update the member path and resolved symbol from our member descriptors
|
|
507
|
+
// (if we have them)
|
|
508
|
+
if (memberDescriptorsFromRefkey.length > 0) {
|
|
509
|
+
for (const descriptor of newMemberPathDescriptors) {
|
|
510
|
+
result.memberPath.push(descriptor.symbol as TSymbol);
|
|
511
|
+
}
|
|
512
|
+
result.symbol = memberDescriptorsFromRefkey.at(-1)!.symbol as TSymbol;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// a subcomputed here ensures we don't lose the progress above When
|
|
516
|
+
// we fail to resolve because a type isn't available yet.
|
|
517
|
+
return computed(() => {
|
|
518
|
+
// resolve each member in the member path
|
|
519
|
+
let currentBase = result.lexicalDeclaration;
|
|
520
|
+
|
|
521
|
+
for (const descriptor of allDescriptors) {
|
|
522
|
+
const member = descriptor.symbol as TSymbol;
|
|
523
|
+
if (currentBase.isTyped && !currentBase.hasTypeSymbol) {
|
|
524
|
+
trace(
|
|
525
|
+
TracePhase.resolve.pending,
|
|
526
|
+
() =>
|
|
527
|
+
`${formatRefkeys(refkey)} needs type information from a parent type.`,
|
|
528
|
+
);
|
|
529
|
+
// waiting for type
|
|
530
|
+
return undefined;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
resolveMember(currentBase, member, options.memberResolver, {
|
|
534
|
+
referencePath: result.fullReferencePath,
|
|
535
|
+
isMemberAccess: descriptor.isMemberAccess,
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
currentBase = member;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
trace(
|
|
542
|
+
TracePhase.resolve.success,
|
|
543
|
+
() =>
|
|
544
|
+
`${formatRefkeys(refkey)} successfully resolved to ${formatSymbolName(symbol)}.`,
|
|
545
|
+
);
|
|
546
|
+
return result;
|
|
547
|
+
}).value;
|
|
391
548
|
});
|
|
392
549
|
}
|
|
393
550
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
551
|
+
/**
|
|
552
|
+
* Extracts member descriptors from a refkey, tracking which members
|
|
553
|
+
* were accessed via memberRefkey for proper member resolution context.
|
|
554
|
+
*/
|
|
555
|
+
function getMemberPathFromRefkey(refkey: Refkey): MemberDescriptor[] {
|
|
556
|
+
if (isMemberRefkey(refkey)) {
|
|
557
|
+
return [
|
|
558
|
+
...getMemberPathFromRefkey(refkey.base),
|
|
559
|
+
{
|
|
560
|
+
symbol: getSymbolForRefkey(refkey.member).value!,
|
|
561
|
+
isMemberAccess: true,
|
|
562
|
+
},
|
|
563
|
+
];
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
return [
|
|
567
|
+
{
|
|
568
|
+
symbol: getSymbolForRefkey(refkey).value!,
|
|
569
|
+
isMemberAccess: false,
|
|
570
|
+
},
|
|
571
|
+
];
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function resolveMember(
|
|
575
|
+
base: OutputSymbol,
|
|
576
|
+
member: OutputSymbol,
|
|
577
|
+
memberResolver: MemberResolver<any, any> | undefined,
|
|
578
|
+
context: MemberResolutionContext<any>,
|
|
579
|
+
) {
|
|
580
|
+
if (memberResolver) {
|
|
581
|
+
memberResolver(base, member, context);
|
|
582
|
+
} else {
|
|
583
|
+
// default member resolution
|
|
584
|
+
if (!member.isMemberSymbol) {
|
|
585
|
+
throw new Error(`${formatSymbolName(member)} is not a member symbol.`);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
const memberOwner = base.hasTypeSymbol ? base.type : base.dealias();
|
|
589
|
+
if (member.ownerSymbol !== memberOwner) {
|
|
590
|
+
throw new Error(
|
|
591
|
+
`${formatSymbolName(
|
|
592
|
+
member,
|
|
593
|
+
)} is not a member of ${formatSymbolName(base)}.`,
|
|
594
|
+
);
|
|
595
|
+
}
|
|
398
596
|
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
function notifySymbolCreated(symbol: OutputSymbol): void {
|
|
399
600
|
effect<Refkey[]>((oldRefkeys) => {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
601
|
+
if (symbol.refkeys) {
|
|
602
|
+
trace(
|
|
603
|
+
TracePhase.resolve.pending,
|
|
604
|
+
() => `Notifying resolutions for ${formatRefkeys(symbol.refkeys)}.`,
|
|
605
|
+
);
|
|
606
|
+
}
|
|
404
607
|
|
|
405
608
|
if (oldRefkeys) {
|
|
406
609
|
for (const refkey of oldRefkeys) {
|
|
@@ -425,8 +628,13 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
425
628
|
signal.value = symbol;
|
|
426
629
|
}
|
|
427
630
|
|
|
631
|
+
const scope = symbol.scope;
|
|
632
|
+
if (!scope) {
|
|
633
|
+
continue;
|
|
634
|
+
}
|
|
635
|
+
|
|
428
636
|
// notify those waiting for this symbol name
|
|
429
|
-
const waitingScope = waitingSymbolNames.get(
|
|
637
|
+
const waitingScope = waitingSymbolNames.get(scope);
|
|
430
638
|
if (waitingScope) {
|
|
431
639
|
const waitingName = waitingScope.get(symbol.name);
|
|
432
640
|
if (waitingName) {
|
|
@@ -438,113 +646,6 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
438
646
|
return [...symbol.refkeys];
|
|
439
647
|
});
|
|
440
648
|
}
|
|
441
|
-
|
|
442
|
-
function findSymbolName<TSymbol extends OutputSymbol = OutputSymbol>(
|
|
443
|
-
scope: OutputScope | undefined,
|
|
444
|
-
name: string,
|
|
445
|
-
): ShallowRef<TSymbol | undefined> {
|
|
446
|
-
return untrack(() => {
|
|
447
|
-
scope ??= binder.globalScope;
|
|
448
|
-
for (const sym of scope.symbols) {
|
|
449
|
-
if (sym.name === name) {
|
|
450
|
-
return shallowRef(sym) as Ref<TSymbol>;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
const symRef = shallowRef<OutputSymbol | undefined>(undefined);
|
|
455
|
-
if (!waitingSymbolNames.has(scope)) {
|
|
456
|
-
waitingSymbolNames.set(scope, new Map());
|
|
457
|
-
}
|
|
458
|
-
const waiting = waitingSymbolNames.get(scope)!;
|
|
459
|
-
waiting.set(name, symRef);
|
|
460
|
-
return symRef as Ref<TSymbol | undefined>;
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
function findScopeName<TScope extends OutputScope = OutputScope>(
|
|
465
|
-
scope: OutputScope | undefined,
|
|
466
|
-
name: string,
|
|
467
|
-
): ShallowRef<TScope | undefined> {
|
|
468
|
-
return untrack(() => {
|
|
469
|
-
scope ??= binder.globalScope;
|
|
470
|
-
for (const child of scope.children) {
|
|
471
|
-
if (child.name === name) {
|
|
472
|
-
return shallowRef(child) as Ref<TScope>;
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
const scopeRef = shallowRef<OutputScope | undefined>(undefined);
|
|
477
|
-
if (!waitingScopeNames.has(scope)) {
|
|
478
|
-
waitingScopeNames.set(scope, new Map());
|
|
479
|
-
}
|
|
480
|
-
const waiting = waitingScopeNames.get(scope)!;
|
|
481
|
-
waiting.set(name, scopeRef);
|
|
482
|
-
|
|
483
|
-
return scopeRef as Ref<TScope | undefined>;
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
function findScopeOrSymbolName(scope: OutputScope, name: string) {
|
|
488
|
-
return untrack(() => {
|
|
489
|
-
return computed(() => {
|
|
490
|
-
return (
|
|
491
|
-
findSymbolName(scope, name).value ?? findScopeName(scope, name).value
|
|
492
|
-
);
|
|
493
|
-
});
|
|
494
|
-
});
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
function resolveFQN(
|
|
498
|
-
fqn: string,
|
|
499
|
-
): Ref<OutputScope | OutputSymbol | undefined> {
|
|
500
|
-
const parts = fqn.match(/[^.#]+|[.#]/g);
|
|
501
|
-
if (!parts) return ref(undefined);
|
|
502
|
-
if (parts.length === 0) return ref(undefined);
|
|
503
|
-
|
|
504
|
-
parts.unshift(".");
|
|
505
|
-
|
|
506
|
-
return computed(() => {
|
|
507
|
-
let base: OutputScope | OutputSymbol | undefined = binder.globalScope;
|
|
508
|
-
|
|
509
|
-
for (let i = 0; i < parts.length; i += 2) {
|
|
510
|
-
if (base === undefined) {
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
const op = parts[i];
|
|
515
|
-
const name = parts[i + 1];
|
|
516
|
-
|
|
517
|
-
if (op === ".") {
|
|
518
|
-
if ("originalName" in base) {
|
|
519
|
-
if (!base.staticMemberScope) {
|
|
520
|
-
return undefined;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
base = findSymbolName(
|
|
524
|
-
(base as OutputSymbol).staticMemberScope,
|
|
525
|
-
name,
|
|
526
|
-
).value;
|
|
527
|
-
} else {
|
|
528
|
-
base = findScopeOrSymbolName(base, name).value;
|
|
529
|
-
}
|
|
530
|
-
} else if (op === "#") {
|
|
531
|
-
if ("originalName" in base) {
|
|
532
|
-
if (!base.instanceMemberScope) {
|
|
533
|
-
return undefined;
|
|
534
|
-
}
|
|
535
|
-
base = findSymbolName(
|
|
536
|
-
(base as OutputSymbol).instanceMemberScope,
|
|
537
|
-
name,
|
|
538
|
-
).value;
|
|
539
|
-
} else {
|
|
540
|
-
return undefined;
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
return base;
|
|
546
|
-
});
|
|
547
|
-
}
|
|
548
649
|
}
|
|
549
650
|
|
|
550
651
|
/**
|
|
@@ -560,22 +661,22 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
560
661
|
export function resolve<
|
|
561
662
|
TScope extends OutputScope,
|
|
562
663
|
TSymbol extends OutputSymbol,
|
|
563
|
-
>(
|
|
664
|
+
>(
|
|
665
|
+
refkey: Refkey,
|
|
666
|
+
options: ResolveDeclarationByKeyOptions<TScope, TSymbol> = {},
|
|
667
|
+
): Ref<ResolutionResult<TScope, TSymbol>> {
|
|
564
668
|
const scope = useScope();
|
|
565
|
-
const memberScope =
|
|
566
|
-
const binder =
|
|
567
|
-
scope?.binder ??
|
|
568
|
-
memberScope?.instanceMembers?.binder ??
|
|
569
|
-
memberScope?.staticMembers?.binder;
|
|
669
|
+
const memberScope = useMemberContext();
|
|
670
|
+
const binder = scope?.binder ?? memberScope?.ownerSymbol.binder;
|
|
570
671
|
|
|
571
672
|
if (!binder) {
|
|
572
673
|
throw new Error("Can't resolve refkey without a binder");
|
|
573
674
|
}
|
|
574
675
|
|
|
575
676
|
return binder.resolveDeclarationByKey(
|
|
576
|
-
scope,
|
|
577
|
-
memberScope?.instanceMembers,
|
|
677
|
+
scope as TScope,
|
|
578
678
|
refkey,
|
|
679
|
+
options,
|
|
579
680
|
) as any;
|
|
580
681
|
}
|
|
581
682
|
|
|
@@ -593,29 +694,3 @@ export function getSymbolCreatorSymbol(): typeof createSymbolsSymbol {
|
|
|
593
694
|
export interface SymbolCreator {
|
|
594
695
|
[createSymbolsSymbol](binder: Binder): void;
|
|
595
696
|
}
|
|
596
|
-
|
|
597
|
-
/**
|
|
598
|
-
* Use symbol flags to determine the scope in which a symbol with those flags
|
|
599
|
-
* should be declared given the current context.
|
|
600
|
-
*
|
|
601
|
-
* @param flags - The symbol flags to use to determine the default scope.
|
|
602
|
-
* @returns an {@link OutputScope} that is the default scope for the given
|
|
603
|
-
* flags.
|
|
604
|
-
*/
|
|
605
|
-
export function useDefaultScope(
|
|
606
|
-
flags: OutputSymbolFlags = OutputSymbolFlags.None,
|
|
607
|
-
) {
|
|
608
|
-
if ((flags & OutputSymbolFlags.Member) === 0) {
|
|
609
|
-
return useScope();
|
|
610
|
-
} else {
|
|
611
|
-
const memberScope = useMemberScope();
|
|
612
|
-
if (!memberScope) {
|
|
613
|
-
throw new Error("Cannot declare member symbols without a member scope");
|
|
614
|
-
}
|
|
615
|
-
if (flags & OutputSymbolFlags.InstanceMember) {
|
|
616
|
-
return memberScope.instanceMembers;
|
|
617
|
-
} else {
|
|
618
|
-
return memberScope.staticMembers;
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
}
|