@alloy-js/core 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/src/binder.d.ts +18 -235
  3. package/dist/src/binder.d.ts.map +1 -1
  4. package/dist/src/binder.js +85 -386
  5. package/dist/src/components/Block.d.ts +1 -1
  6. package/dist/src/components/Block.d.ts.map +1 -1
  7. package/dist/src/components/Block.js +3 -1
  8. package/dist/src/components/Declaration.d.ts +1 -1
  9. package/dist/src/components/Declaration.d.ts.map +1 -1
  10. package/dist/src/components/Declaration.js +5 -4
  11. package/dist/src/components/For.d.ts +1 -1
  12. package/dist/src/components/For.d.ts.map +1 -1
  13. package/dist/src/components/For.js +1 -1
  14. package/dist/src/components/Indent.d.ts +1 -1
  15. package/dist/src/components/Indent.d.ts.map +1 -1
  16. package/dist/src/components/List.d.ts +1 -1
  17. package/dist/src/components/List.d.ts.map +1 -1
  18. package/dist/src/components/List.js +2 -1
  19. package/dist/src/components/MemberDeclaration.d.ts +1 -1
  20. package/dist/src/components/MemberDeclaration.d.ts.map +1 -1
  21. package/dist/src/components/MemberDeclaration.js +3 -4
  22. package/dist/src/components/MemberScope.d.ts +1 -1
  23. package/dist/src/components/MemberScope.d.ts.map +1 -1
  24. package/dist/src/components/MemberScope.js +0 -2
  25. package/dist/src/components/Prose.d.ts +1 -1
  26. package/dist/src/components/Prose.d.ts.map +1 -1
  27. package/dist/src/components/ReferenceOrContent.d.ts +1 -1
  28. package/dist/src/components/ReferenceOrContent.d.ts.map +1 -1
  29. package/dist/src/components/Scope.d.ts +1 -1
  30. package/dist/src/components/Scope.d.ts.map +1 -1
  31. package/dist/src/components/Scope.js +3 -6
  32. package/dist/src/components/Show.d.ts +1 -1
  33. package/dist/src/components/Show.d.ts.map +1 -1
  34. package/dist/src/components/StatementList.d.ts +1 -1
  35. package/dist/src/components/StatementList.d.ts.map +1 -1
  36. package/dist/src/components/StatementList.js +1 -1
  37. package/dist/src/components/Switch.d.ts +1 -1
  38. package/dist/src/components/Switch.d.ts.map +1 -1
  39. package/dist/src/components/Switch.js +1 -1
  40. package/dist/src/components/Wrap.d.ts +1 -1
  41. package/dist/src/components/Wrap.d.ts.map +1 -1
  42. package/dist/src/context/assignment.d.ts +1 -1
  43. package/dist/src/context/assignment.d.ts.map +1 -1
  44. package/dist/src/context/binder.d.ts +2 -2
  45. package/dist/src/context/binder.d.ts.map +1 -1
  46. package/dist/src/context/declaration.d.ts +1 -1
  47. package/dist/src/context/declaration.d.ts.map +1 -1
  48. package/dist/src/context/member-declaration.d.ts +1 -1
  49. package/dist/src/context/member-declaration.d.ts.map +1 -1
  50. package/dist/src/context/member-declaration.js +0 -1
  51. package/dist/src/context/member-scope.d.ts +1 -1
  52. package/dist/src/context/member-scope.d.ts.map +1 -1
  53. package/dist/src/context/name-policy.d.ts +1 -1
  54. package/dist/src/context/name-policy.d.ts.map +1 -1
  55. package/dist/src/context/scope.d.ts +1 -1
  56. package/dist/src/context/scope.d.ts.map +1 -1
  57. package/dist/src/context/source-directory.d.ts +1 -1
  58. package/dist/src/context/source-directory.d.ts.map +1 -1
  59. package/dist/src/context/source-file.d.ts +2 -2
  60. package/dist/src/context/source-file.d.ts.map +1 -1
  61. package/dist/src/index.d.ts +4 -1
  62. package/dist/src/index.d.ts.map +1 -1
  63. package/dist/src/index.js +4 -1
  64. package/dist/src/jsx-runtime.d.ts +12 -3
  65. package/dist/src/jsx-runtime.d.ts.map +1 -1
  66. package/dist/src/jsx-runtime.js +6 -2
  67. package/dist/src/reactive-union-set.d.ts +29 -0
  68. package/dist/src/reactive-union-set.d.ts.map +1 -0
  69. package/dist/src/reactive-union-set.js +183 -0
  70. package/dist/src/refkey.d.ts +36 -0
  71. package/dist/src/refkey.d.ts.map +1 -1
  72. package/dist/src/refkey.js +40 -0
  73. package/dist/src/scheduler.d.ts +2 -2
  74. package/dist/src/scheduler.d.ts.map +1 -1
  75. package/dist/src/scheduler.js +27 -6
  76. package/dist/src/slot.d.ts +1 -1
  77. package/dist/src/slot.d.ts.map +1 -1
  78. package/dist/src/stc.d.ts +1 -1
  79. package/dist/src/stc.d.ts.map +1 -1
  80. package/dist/src/sti.d.ts +1 -1
  81. package/dist/src/sti.d.ts.map +1 -1
  82. package/dist/src/sti.js +1 -1
  83. package/dist/src/symbols/index.d.ts +6 -0
  84. package/dist/src/symbols/index.d.ts.map +1 -0
  85. package/dist/src/symbols/index.js +5 -0
  86. package/dist/src/symbols/output-scope.d.ts +116 -0
  87. package/dist/src/symbols/output-scope.d.ts.map +1 -0
  88. package/dist/src/symbols/output-scope.js +246 -0
  89. package/dist/src/symbols/output-symbol.d.ts +134 -0
  90. package/dist/src/symbols/output-symbol.d.ts.map +1 -0
  91. package/dist/src/symbols/output-symbol.js +379 -0
  92. package/dist/src/symbols/symbol-flow.d.ts +13 -0
  93. package/dist/src/symbols/symbol-flow.d.ts.map +1 -0
  94. package/dist/src/symbols/symbol-flow.js +74 -0
  95. package/dist/src/symbols/symbol-slot.d.ts +12 -0
  96. package/dist/src/symbols/symbol-slot.d.ts.map +1 -0
  97. package/dist/src/symbols/symbol-slot.js +36 -0
  98. package/dist/src/symbols/symbol-table.d.ts +14 -0
  99. package/dist/src/symbols/symbol-table.d.ts.map +1 -0
  100. package/dist/src/symbols/symbol-table.js +42 -0
  101. package/dist/src/tap.d.ts +2 -1
  102. package/dist/src/tap.d.ts.map +1 -1
  103. package/dist/src/tracer.d.ts +181 -0
  104. package/dist/src/tracer.d.ts.map +1 -0
  105. package/dist/src/tracer.js +441 -0
  106. package/dist/src/tsdoc-metadata.json +1 -1
  107. package/dist/test/components/slot.test.js +5 -7
  108. package/dist/test/reactive-union-set.test.d.ts +2 -0
  109. package/dist/test/reactive-union-set.test.d.ts.map +1 -0
  110. package/dist/test/reactive-union-set.test.js +170 -0
  111. package/dist/test/symbols/output-scope.test.d.ts +2 -0
  112. package/dist/test/symbols/output-scope.test.d.ts.map +1 -0
  113. package/dist/test/symbols/output-scope.test.js +342 -0
  114. package/dist/test/symbols/output-symbol.test.d.ts +2 -0
  115. package/dist/test/symbols/output-symbol.test.d.ts.map +1 -0
  116. package/dist/test/symbols/output-symbol.test.js +446 -0
  117. package/dist/test/symbols/resolution.test.d.ts +2 -0
  118. package/dist/test/symbols/resolution.test.d.ts.map +1 -0
  119. package/dist/test/symbols/resolution.test.js +140 -0
  120. package/dist/test/symbols/utils.d.ts +24 -0
  121. package/dist/test/symbols/utils.d.ts.map +1 -0
  122. package/dist/test/symbols/utils.js +46 -0
  123. package/dist/tsconfig.tsbuildinfo +1 -1
  124. package/package.json +3 -3
  125. package/src/binder.ts +148 -672
  126. package/src/components/Block.tsx +4 -1
  127. package/src/components/Declaration.tsx +6 -6
  128. package/src/components/For.tsx +1 -1
  129. package/src/components/Indent.tsx +1 -1
  130. package/src/components/List.tsx +1 -1
  131. package/src/components/MemberDeclaration.tsx +4 -4
  132. package/src/components/MemberScope.tsx +2 -5
  133. package/src/components/Prose.tsx +1 -1
  134. package/src/components/ReferenceOrContent.tsx +1 -1
  135. package/src/components/Scope.tsx +2 -6
  136. package/src/components/Show.tsx +1 -1
  137. package/src/components/StatementList.tsx +2 -1
  138. package/src/components/Switch.tsx +1 -1
  139. package/src/components/Wrap.tsx +1 -1
  140. package/src/context/assignment.ts +1 -1
  141. package/src/context/binder.ts +2 -2
  142. package/src/context/declaration.ts +1 -1
  143. package/src/context/member-declaration.ts +1 -1
  144. package/src/context/member-scope.ts +1 -1
  145. package/src/context/name-policy.ts +1 -1
  146. package/src/context/scope.ts +1 -1
  147. package/src/context/source-directory.ts +1 -1
  148. package/src/context/source-file.ts +2 -2
  149. package/src/index.ts +11 -0
  150. package/src/jsx-runtime.ts +18 -2
  151. package/src/reactive-union-set.ts +238 -0
  152. package/src/refkey.ts +40 -0
  153. package/src/scheduler.ts +31 -6
  154. package/src/slot.ts +1 -1
  155. package/src/stc.ts +3 -3
  156. package/src/sti.ts +5 -5
  157. package/src/symbols/index.ts +5 -0
  158. package/src/symbols/output-scope.ts +323 -0
  159. package/src/symbols/output-symbol.ts +512 -0
  160. package/src/symbols/symbol-flow.ts +104 -0
  161. package/src/symbols/symbol-slot.tsx +47 -0
  162. package/src/symbols/symbol-table.ts +72 -0
  163. package/src/tap.ts +2 -1
  164. package/src/tracer.ts +440 -0
  165. package/temp/api.json +4172 -1582
  166. package/test/components/slot.test.tsx +8 -11
  167. package/test/reactive-union-set.test.tsx +191 -0
  168. package/test/symbols/output-scope.test.ts +302 -0
  169. package/test/symbols/output-symbol.test.ts +459 -0
  170. package/test/symbols/resolution.test.ts +172 -0
  171. package/test/symbols/utils.ts +95 -0
  172. package/dist/test/symbols.test.d.ts +0 -2
  173. package/dist/test/symbols.test.d.ts.map +0 -1
  174. package/dist/test/symbols.test.js +0 -884
  175. package/test/symbols.test.ts +0 -1006
package/src/binder.ts CHANGED
@@ -1,251 +1,22 @@
1
- import {
2
- computed,
3
- reactive,
4
- ref,
5
- Ref,
6
- ShallowRef,
7
- shallowRef,
8
- } from "@vue/reactivity";
9
- import { useBinder } from "./context/binder.js";
1
+ import { computed, ref, Ref, ShallowRef, shallowRef } from "@vue/reactivity";
10
2
  import { useMemberScope } from "./context/member-scope.js";
11
3
  import { useScope } from "./context/scope.js";
12
- import { effect, memo, onCleanup, untrack } from "./jsx-runtime.js";
4
+ import { effect, untrack } from "./jsx-runtime.js";
13
5
  import { refkey, Refkey } from "./refkey.js";
14
- import { queueJob, QueueJob } from "./scheduler.js";
6
+ import { OutputScope } from "./symbols/output-scope.js";
7
+ import {
8
+ OutputSymbolFlags,
9
+ type OutputSymbol,
10
+ } from "./symbols/output-symbol.js";
11
+ import {
12
+ formatRefkeys,
13
+ formatSymbol,
14
+ formatSymbolName,
15
+ trace,
16
+ TracePhase,
17
+ } from "./tracer.js";
15
18
  export type Metadata = object;
16
19
 
17
- /**
18
- * Flags that describe an output symbol.
19
- */
20
- export enum OutputSymbolFlags {
21
- None = 0,
22
-
23
- /**
24
- * The symbol is an instance member container. Symbols with this flag will have a
25
- * instanceMemberScope property that contains symbols for instance members.
26
- */
27
- InstanceMemberContainer = 1 << 0,
28
-
29
- /**
30
- * The symbol is a static member container. Symbols with this flag will have a
31
- * staticMemberScope property that contains symbols for static members.
32
- */
33
- StaticMemberContainer = 1 << 1,
34
-
35
- /**
36
- * Whether this symbol contains members of any kind.
37
- */
38
- MemberContainer = InstanceMemberContainer | StaticMemberContainer,
39
-
40
- /**
41
- * Whether this symbol is an instance member of another symbol (i.e that it is
42
- * stored in an instance member scope).
43
- */
44
- InstanceMember = 1 << 2,
45
-
46
- /**
47
- * Whether this symbol is a static member of another symbol (i.e that it is
48
- * stored in a static member scope).
49
- */
50
- StaticMember = 1 << 3,
51
-
52
- /**
53
- * Whether this is an instance member or static member of another symbol.
54
- */
55
- Member = InstanceMember | StaticMember,
56
- }
57
-
58
- /**
59
- * An output symbol is a named entity that can be referenced in your output
60
- * code. Referencing symbols is generally accomplished by using a
61
- * {@link Refkey}.
62
- *
63
- * @remarks
64
- *
65
- * This interface is the base implementation of symbol. Generally, most
66
- * languages will have subtypes of this interface that provide additional,
67
- * language-specific metadata about declared symbols. For example, symbols in
68
- * TypeScript need to track whether they are exported or what kind of symbol
69
- * they are (e.g. type, value, parameter, etc.)
70
- *
71
- * Symbols are reactive values, which allows you to observe changes to the symbol
72
- * information. For example, a symbol's name may change if it becomes conflicted
73
- * with a symbol that is added later.
74
- */
75
- export interface OutputSymbol {
76
- /**
77
- * The original name of the symbol, before any conflicts were resolved.
78
- */
79
- originalName: string;
80
-
81
- /**
82
- * The name of the symbol.
83
- */
84
- name: string;
85
-
86
- /**
87
- * The symbol's flags.
88
- */
89
- flags: OutputSymbolFlags;
90
-
91
- /**
92
- * The scope in which the symbol is defined.
93
- */
94
- scope: OutputScope;
95
-
96
- /**
97
- * The binder instance that created this symbol.
98
- */
99
- binder: Binder;
100
-
101
- /**
102
- * The unique values that reference this symbol.
103
- */
104
- refkeys: Refkey[];
105
-
106
- /**
107
- * The instance members available on this symbol.
108
- *
109
- * @remarks
110
- *
111
- * Instance members are members that are available when this symbol is
112
- * instantiated. Instantiation is language-specific. For example, in
113
- * TypeScript, instance members of symbols for classes are available when the
114
- * class is instantiated with a new expression.
115
- *
116
- * When a symbol cannot have instance members, this is undefined.
117
- */
118
- instanceMemberScope?: OutputScope;
119
-
120
- /**
121
- * The static members available on this symbol.
122
- *
123
- * @remarks
124
- *
125
- * Static members are members that are available on the symbol itself. These symbols
126
- * can be accessed off the parent symbol directly with a refkey. There is only ever
127
- * one static member symbol in the output (i.e., the symbol is unique).
128
- */
129
- staticMemberScope?: OutputScope;
130
-
131
- /**
132
- * Additional custom metadata about this symbol.
133
- */
134
- metadata: Record<string, unknown>;
135
- }
136
-
137
- /**
138
- * Flags that describe an output scope.
139
- */
140
- export enum OutputScopeFlags {
141
- None = 0,
142
-
143
- /**
144
- * This scope is a static member scope.
145
- */
146
- StaticMemberScope = 1 << 0,
147
-
148
- /**
149
- * This scope is an instance member scope.
150
- */
151
- InstanceMemberScope = 1 << 1,
152
-
153
- /**
154
- * This scope is a member scope. Scopes with this flag will have an `owner`
155
- * property that points to the symbol whose member this scope holds.
156
- */
157
- MemberScope = StaticMemberScope | InstanceMemberScope,
158
- }
159
-
160
- /**
161
- * A container of symbols accessible within some scope in your output code.
162
- *
163
- * @remarks
164
- *
165
- * Scopes form a tree. All scopes except the global scope have a parent scope
166
- * identified by `parent`. Scopes can have nested scopes which can be accessed
167
- * using the `children` property. Whether a child scope can be accessed from
168
- * the parent scope is determined by each language's scoping rules.
169
- *
170
- * This interface is the base implementation of scope. Generally, most languages
171
- * will have subtypes of this interface that provide additional metadata about
172
- * the scope. For example, TypeScript scopes need to track whether the scope
173
- * represents a package, module, class, function, etc.
174
- *
175
- * Scopes are reactive values, which allows you to observe changes to the scope
176
- * within a reactive context.
177
- */
178
- export interface OutputScope {
179
- /**
180
- * The kind of scope. Subtypes will likely provide a set of known scope kinds.
181
- * The kind is not used by the binder itself.
182
- */
183
- kind?: string;
184
-
185
- /**
186
- * The name of the scope.
187
- */
188
- name: string;
189
-
190
- /**
191
- * The flags that describe this scope.
192
- */
193
- flags: OutputScopeFlags;
194
-
195
- /**
196
- * The symbols defined within this scope.
197
- */
198
- symbols: Set<OutputSymbol>;
199
-
200
- /**
201
- * The symbols defined within this scope, indexed by refkey.
202
- */
203
- symbolsByRefkey: Map<Refkey, OutputSymbol>;
204
-
205
- /**
206
- * The scopes nested within this scope.
207
- */
208
- children: Set<OutputScope>;
209
-
210
- /**
211
- * The container of this scope.
212
- */
213
- parent: OutputScope | undefined;
214
-
215
- /**
216
- * The symbol that owns this scope. This is only defined for scopes that have
217
- * the {@link OutputScopeFlags.StaticMemberScope} flag.
218
- */
219
- owner?: OutputSymbol;
220
-
221
- /**
222
- * The binder that created this scope.
223
- */
224
- binder: Binder;
225
-
226
- /**
227
- * Get the names of all symbols in this scope.
228
- */
229
- getSymbolNames(): Set<string>;
230
- }
231
-
232
- export type CreateSymbolOptions<T extends OutputSymbol = OutputSymbol> = {
233
- name: string;
234
- scope?: OutputScope;
235
- refkey?: Refkey | Refkey[];
236
- flags?: OutputSymbolFlags;
237
- metadata?: Record<string, unknown>;
238
- } & Omit<T, keyof OutputSymbol>;
239
-
240
- export type CreateScopeOptions<T extends OutputScope = OutputScope> = {
241
- kind: T["kind"];
242
- name: string;
243
- parent?: OutputScope | undefined;
244
- flags?: OutputScopeFlags;
245
- owner?: OutputSymbol;
246
- metadata?: Record<string, unknown>;
247
- } & Omit<T, keyof OutputScope>;
248
-
249
20
  /**
250
21
  * The binder tracks all output scopes and symbols. Scopes are nested containers
251
22
  * for symbols.
@@ -260,47 +31,6 @@ export type CreateScopeOptions<T extends OutputScope = OutputScope> = {
260
31
  *
261
32
  */
262
33
  export interface Binder {
263
- /**
264
- * Create a new scope. The scope will be added to the parent scope's children.
265
- * The returned scope object is reactive.
266
- */
267
- createScope<T extends OutputScope>(args: CreateScopeOptions<T>): T;
268
-
269
- /**
270
- * Create a new symbol. The symbol will be added to the parent scope's symbols.
271
- * The returned symbol object is reactive.
272
- */
273
- createSymbol<T extends OutputSymbol>(args: CreateSymbolOptions<T>): T;
274
-
275
- /**
276
- * Delete the given symbol. The symbol will be removed from its parent's
277
- * scope. Any resolutions to this symbol will become undefined.
278
- */
279
- deleteSymbol(symbol: OutputSymbol): void;
280
-
281
- /**
282
- * Instantiate the static members of a symbol into the instance members of
283
- * another symbol.
284
- *
285
- * @param sourceSym - The symbol to add instance members to.
286
- * @param targetSym - The symbol with the static members to instantiate.
287
- */
288
- instantiateSymbolInto(sourceSym: OutputSymbol, targetSym: OutputSymbol): void;
289
-
290
- /**
291
- * Add static members to an existing symbol.
292
- *
293
- * @param symbol - The symbol to add static members to.
294
- */
295
- addStaticMembersToSymbol(symbol: OutputSymbol): void;
296
-
297
- /**
298
- * Add instance members to an existing symbol.
299
- *
300
- * @param symbol - The symbol to add instance members to.
301
- */
302
- addInstanceMembersToSymbol(symbol: OutputSymbol): void;
303
-
304
34
  /**
305
35
  * Resolve the given refkey in the current scope.
306
36
  *
@@ -358,6 +88,26 @@ export interface Binder {
358
88
  * The global scope. This is the root scope for all symbols.
359
89
  */
360
90
  globalScope: OutputScope;
91
+
92
+ /**
93
+ * The name conflict resolver to use for this binder.
94
+ */
95
+ nameConflictResolver?: NameConflictResolver;
96
+
97
+ /**
98
+ * Notifies the binder that a scope has been created.
99
+ */
100
+ notifyScopeCreated(scope: OutputScope): void;
101
+
102
+ /**
103
+ * Notifies the binder that a symbol has been created.
104
+ */
105
+ notifySymbolCreated(symbol: OutputSymbol): void;
106
+
107
+ /**
108
+ * Notifies the binder that a symbol has been deleted.
109
+ */
110
+ notifySymbolDeleted(symbol: OutputSymbol): void;
361
111
  }
362
112
 
363
113
  /**
@@ -426,32 +176,21 @@ export interface BinderOptions {
426
176
 
427
177
  export function createOutputBinder(options: BinderOptions = {}): Binder {
428
178
  const binder: Binder = {
429
- createScope,
430
- createSymbol,
431
- deleteSymbol,
432
179
  resolveDeclarationByKey,
433
180
  getSymbolForRefkey,
434
- addStaticMembersToSymbol,
435
- addInstanceMembersToSymbol,
436
- instantiateSymbolInto,
437
181
  findSymbolName,
438
182
  findScopeName,
439
183
  resolveFQN: resolveFQN as any,
440
184
  globalScope: undefined as any,
185
+ notifyScopeCreated,
186
+ notifySymbolCreated,
187
+ notifySymbolDeleted,
188
+ nameConflictResolver: options.nameConflictResolver,
441
189
  };
442
190
 
443
- const globalSymbols = reactive(new Set<OutputSymbol>());
444
-
445
- binder.globalScope = reactive({
446
- kind: "global",
447
- name: "<global>",
448
- symbols: new Set(),
449
- symbolsByRefkey: new Map(),
450
- children: new Set(),
451
- parent: undefined,
191
+ binder.globalScope = new OutputScope("<global>", {
452
192
  binder,
453
- flags: OutputScopeFlags.None,
454
- getSymbolNames: symbolNames(globalSymbols),
193
+ kind: "global",
455
194
  });
456
195
 
457
196
  const knownDeclarations = new Map<Refkey, OutputSymbol>();
@@ -464,153 +203,22 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
464
203
  OutputScope,
465
204
  Map<string, Ref<OutputScope | undefined>>
466
205
  >();
467
- const deconflictJobs = new Map<OutputScope, Map<string, QueueJob>>();
468
206
 
469
207
  return binder;
470
208
 
471
- function createScope<T extends OutputScope>(args: CreateScopeOptions<T>): T {
472
- const {
473
- kind,
474
- name,
475
- parent,
476
- owner,
477
- flags = OutputScopeFlags.None,
478
- metadata = {},
479
- ...rest
480
- } = args;
481
-
482
- if (flags & OutputScopeFlags.MemberScope) {
483
- if (!owner) {
484
- throw new Error("Member scopes must have an owner");
485
- }
486
- }
487
-
488
- // member scopes don't have a parent regular scope. Perhaps in the future
489
- // their parent would be something like a prototype object.
490
- let parentScope: OutputScope | undefined;
491
- if (parent) {
492
- parentScope = parent;
493
- } else if (flags & OutputScopeFlags.MemberScope) {
494
- parentScope = undefined;
495
- } else {
496
- parentScope = useScope() ?? binder.globalScope;
497
- }
498
-
499
- const symbols = reactive(new Set<OutputSymbol>());
500
- const symbolsByRefkey = reactive(new Map<Refkey, OutputSymbol>());
501
- const scope: T = reactive({
502
- kind: kind,
503
- name: name,
504
- symbols,
505
- symbolsByRefkey,
506
- children: new Set(),
507
- parent: parentScope,
508
- flags,
509
- owner,
510
- binder,
511
- metadata,
512
- ...rest,
513
- getSymbolNames: symbolNames(symbols),
514
- }) as T;
515
-
516
- if (parentScope) {
517
- parentScope.children.add(scope);
518
- }
519
-
520
- if (waitingScopeNames.has(parentScope!)) {
521
- const waiting = waitingScopeNames.get(parentScope!);
522
- if (waiting?.has(name)) {
523
- const ref = waiting.get(name)!;
524
- ref.value = scope;
525
- }
526
- }
527
-
528
- return scope as T;
529
- }
530
-
531
- function createSymbol<T extends OutputSymbol>(
532
- args: CreateSymbolOptions<T>,
533
- ): T {
534
- const {
535
- name,
536
- scope = useDefaultScope(args.flags),
537
- refkey,
538
- flags = OutputSymbolFlags.None,
539
- metadata = {},
540
- ...rest
541
- } = args;
542
-
543
- const allRefkeys = [refkey ?? []].flat();
544
-
545
- if (!scope) {
546
- throw new Error(
547
- "No scope was provided and no scope could be found in context",
548
- );
549
- }
550
-
551
- if (
552
- flags & OutputSymbolFlags.Member &&
553
- (scope.flags & OutputScopeFlags.MemberScope) === 0
554
- ) {
555
- throw new Error("Member symbols must be stored in a member scope.");
556
- }
557
-
558
- if (scope.flags & OutputScopeFlags.StaticMemberScope) {
559
- if (
560
- ~flags & OutputSymbolFlags.InstanceMember &&
561
- ~flags & OutputSymbolFlags.StaticMember
562
- ) {
563
- throw new Error(
564
- "Symbols stored in a member scope must have either OutputSymbolFlags.InstanceMember or OutputSymbolFlags.StaticMember flags",
565
- );
566
- }
567
- }
568
-
569
- const symbol = reactive({
570
- originalName: name,
571
- name: name,
572
- scope,
573
- refkeys: allRefkeys,
574
- binder,
575
- flags,
576
- metadata,
577
- ...rest,
578
- }) as T;
579
-
580
- if (args.flags && args.flags & OutputSymbolFlags.InstanceMemberContainer) {
581
- symbol.instanceMemberScope = createScope({
582
- kind: "member",
583
- name: "instance members",
584
- parent: undefined,
585
- owner: symbol,
586
- flags: OutputScopeFlags.InstanceMemberScope,
587
- });
588
- }
589
-
590
- if (args.flags && args.flags & OutputSymbolFlags.StaticMemberContainer) {
591
- symbol.staticMemberScope = createScope({
592
- kind: "member",
593
- name: "static members",
594
- parent: undefined,
595
- owner: symbol,
596
- flags: OutputScopeFlags.StaticMemberScope,
597
- });
209
+ function notifyScopeCreated(scope: OutputScope) {
210
+ if (!scope.parent || !waitingScopeNames.has(scope.parent)) {
211
+ return;
598
212
  }
599
213
 
600
- scope.symbols.add(symbol);
601
- for (const refkey of allRefkeys) {
602
- scope.symbolsByRefkey.set(refkey, symbol);
214
+ const waiting = waitingScopeNames.get(scope.parent)!;
215
+ if (waiting?.has(scope.name)) {
216
+ const ref = waiting.get(scope.name)!;
217
+ ref.value = scope;
603
218
  }
604
-
605
- deconflict(symbol);
606
- notifyRefkey(symbol);
607
-
608
- return symbol;
609
219
  }
610
220
 
611
- function deleteSymbol(symbol: OutputSymbol) {
612
- symbol.scope.symbols.delete(symbol);
613
-
221
+ function notifySymbolDeleted(symbol: OutputSymbol) {
614
222
  if (!refkey) {
615
223
  return;
616
224
  }
@@ -622,138 +230,23 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
622
230
  }
623
231
  }
624
232
 
625
- function instantiateSymbolInto(source: OutputSymbol, target: OutputSymbol) {
626
- if (target.staticMemberScope) {
627
- return;
628
- }
629
-
630
- // Ensure static member scope exists
631
- addStaticMembersToSymbol(target);
632
-
633
- effect(() => {
634
- // copy instance members if it's an instance‐container
635
- if (source.flags & OutputSymbolFlags.InstanceMemberContainer) {
636
- copyMembers(
637
- source.instanceMemberScope!.symbols,
638
- target,
639
- target.staticMemberScope!,
640
- );
233
+ function hasTransientScope(symbol: OutputSymbol) {
234
+ let sym: OutputSymbol | undefined = symbol;
235
+ let transient = false;
236
+ while (sym) {
237
+ if (sym.flags & OutputSymbolFlags.Transient) {
238
+ transient = true;
239
+ break;
641
240
  }
642
-
643
- // copy static members if it's a static‐container
644
- if (source.flags & OutputSymbolFlags.StaticMemberContainer) {
645
- copyMembers(
646
- source.staticMemberScope!.symbols,
647
- target,
648
- target.staticMemberScope!,
649
- );
241
+ if (sym.flags & ~OutputSymbolFlags.Member) {
242
+ break;
650
243
  }
651
- });
652
244
 
653
- /**
654
- * Recursively copy `symbols` from `sourceSym` into `intoScope` of `targetSym`.
655
- * Always marks each instantiation as StaticMember so lookups use dot notation (e.g. Parent.child)
656
- * and preserves any StaticMemberContainer flag to auto create newSym.staticMemberScope.
657
- */
658
- function copyMembers(
659
- symbols: Set<OutputSymbol>,
660
- targetSym: OutputSymbol,
661
- intoScope: OutputScope,
662
- ) {
663
- for (const srcSym of symbols) {
664
- untrack(() => {
665
- const wantKey = refkey(targetSym.refkeys[0], srcSym.refkeys[0]);
666
-
667
- // create the new symbol. Preserve StaticMemberContainer if present
668
- const newSym = createSymbol({
669
- name: srcSym.name,
670
- scope: intoScope,
671
- refkey: wantKey,
672
- flags: srcSym.flags | OutputSymbolFlags.StaticMember,
673
- });
674
-
675
- onCleanup(() => {
676
- binder.deleteSymbol(newSym);
677
- });
678
-
679
- // if the source symbol itself was a container of static members,
680
- // recurse into the newSym.staticMemberScope that createSymbol just gave us
681
- if (
682
- srcSym.staticMemberScope &&
683
- srcSym.staticMemberScope.symbols.size > 0
684
- ) {
685
- // ensure we have that scope
686
- addStaticMembersToSymbol(newSym);
687
-
688
- copyMembers(
689
- srcSym.staticMemberScope.symbols,
690
- newSym,
691
- newSym.staticMemberScope!,
692
- );
693
- }
694
- });
695
- }
696
- }
697
- }
698
-
699
- function addStaticMembersToSymbol(symbol: OutputSymbol) {
700
- if (symbol.flags & OutputSymbolFlags.StaticMemberContainer) {
701
- // nothing to do.
702
- return;
245
+ sym = sym.scope.owner;
703
246
  }
704
247
 
705
- symbol.flags |= OutputSymbolFlags.StaticMemberContainer;
706
- symbol.staticMemberScope = createScope({
707
- kind: "member",
708
- name: "static members",
709
- parent: undefined,
710
- owner: symbol,
711
- flags: OutputScopeFlags.StaticMemberScope,
712
- });
713
- }
714
-
715
- function addInstanceMembersToSymbol(symbol: OutputSymbol) {
716
- if (symbol.flags & OutputSymbolFlags.InstanceMemberContainer) {
717
- // nothing to do.
718
- return;
719
- }
720
-
721
- symbol.flags |= OutputSymbolFlags.InstanceMemberContainer;
722
- symbol.instanceMemberScope = createScope({
723
- kind: "member",
724
- name: "instance members",
725
- parent: undefined,
726
- owner: symbol,
727
- flags: OutputScopeFlags.InstanceMemberScope,
728
- });
729
- }
730
-
731
- function resolveDeclarationByKey<
732
- TScope extends OutputScope = OutputScope,
733
- TSymbol extends OutputSymbol = OutputSymbol,
734
- >(
735
- currentScope: TScope | undefined,
736
- currentMemberScope: TScope | undefined,
737
- key: Refkey,
738
- ): Ref<ResolutionResult<TScope, TSymbol> | undefined> {
739
- const targetDeclaration = knownDeclarations.get(key);
740
-
741
- if (targetDeclaration) {
742
- // this any cast hides a ridiculous error, fix it probably
743
- return shallowRef(
744
- buildResult(currentScope, currentMemberScope, targetDeclaration),
745
- ) as any;
746
- } else {
747
- return waitForRefkey(key, (symbol) => {
748
- if (symbol) {
749
- return buildResult(currentScope, currentMemberScope, symbol);
750
- } else {
751
- return undefined;
752
- }
753
- });
754
- }
248
+ return transient;
755
249
  }
756
-
757
250
  function buildResult<
758
251
  TScope extends OutputScope = OutputScope,
759
252
  TSymbol extends OutputSymbol = OutputSymbol,
@@ -762,6 +255,9 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
762
255
  currentMemberScope: TScope | undefined,
763
256
  targetDeclarationBase: TSymbol,
764
257
  ): ResolutionResult<TScope, TSymbol> {
258
+ trace(TracePhase.resolve.success, () => {
259
+ return `Resolved ${formatRefkeys(targetDeclarationBase.refkeys)} to ${formatSymbol(targetDeclarationBase)}`;
260
+ });
765
261
  if (targetDeclarationBase.flags & OutputSymbolFlags.InstanceMember) {
766
262
  // todo: handle referencing nested objects by refkey
767
263
  return {
@@ -838,109 +334,91 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
838
334
  return chain;
839
335
  }
840
336
 
841
- function deconflict(symbol: OutputSymbol) {
842
- const scope = symbol.scope;
843
- const existingNames = [...scope.symbols].filter(
844
- (sym) => sym.name === symbol.name,
845
- );
846
-
847
- if (existingNames.length < 2) {
848
- return;
849
- }
850
-
851
- queueJob(
852
- deconflictJobForScopeAndName(
853
- scope,
854
- symbol.name,
855
- options.nameConflictResolver,
856
- ),
857
- );
858
- }
859
-
860
- function deconflictJobForScopeAndName(
861
- scope: OutputScope,
862
- name: string,
863
- handler: NameConflictResolver | undefined,
337
+ function getSymbolForRefkey<TSymbol extends OutputSymbol = OutputSymbol>(
338
+ refkey: Refkey,
864
339
  ) {
865
- if (!deconflictJobs.has(scope)) {
866
- deconflictJobs.set(scope, new Map());
340
+ if (waitingDeclarations.has(refkey)) {
341
+ return waitingDeclarations.get(refkey)! as ShallowRef<TSymbol>;
867
342
  }
868
343
 
869
- const jobs = deconflictJobs.get(scope)!;
870
- if (jobs.has(name)) {
871
- return jobs.get(name)!;
344
+ const symbolRef = shallowRef<TSymbol | undefined>();
345
+ waitingDeclarations.set(refkey, symbolRef);
346
+ if (knownDeclarations.has(refkey)) {
347
+ symbolRef.value = knownDeclarations.get(refkey) as TSymbol;
872
348
  }
873
- const job = () => {
874
- const conflictedSymbols = [...scope.symbols].filter(
875
- (sym) => sym.name === name,
876
- );
877
- if (handler) {
878
- handler(name, conflictedSymbols);
879
- } else {
880
- defaultConflictHandler(name, conflictedSymbols);
881
- }
882
- jobs.delete(name);
883
- };
884
-
885
- jobs.set(name, job);
886
- return job;
349
+ return symbolRef;
887
350
  }
888
351
 
889
- /**
890
- * Default conflict handler. This will rename all but the first symbol
891
- * to have a suffix of _2, _3, etc.
892
- */
893
- function defaultConflictHandler(
894
- _: string,
895
- conflictedSymbols: OutputSymbol[],
896
- ) {
897
- for (let i = 1; i < conflictedSymbols.length; i++) {
898
- conflictedSymbols[i].name =
899
- conflictedSymbols[i].originalName + "_" + (i + 1);
900
- }
901
- }
902
-
903
- function getSymbolForRefkey<TSymbol extends OutputSymbol>(
352
+ function resolveDeclarationByKey<
353
+ TScope extends OutputScope = OutputScope,
354
+ TSymbol extends OutputSymbol = OutputSymbol,
355
+ >(
356
+ currentScope: TScope | undefined,
357
+ currentMemberScope: TScope | undefined,
904
358
  refkey: Refkey,
905
- ): Ref<TSymbol | undefined> {
906
- const symbol = knownDeclarations.get(refkey);
907
- if (symbol) {
908
- return shallowRef(symbol as TSymbol);
909
- } else {
910
- if (waitingDeclarations.has(refkey)) {
911
- return waitingDeclarations.get(refkey)! as ShallowRef<
912
- TSymbol | undefined
913
- >;
914
- } else {
915
- const declSignal = shallowRef();
916
- waitingDeclarations.set(refkey, declSignal);
917
- return declSignal;
359
+ ): ShallowRef<ResolutionResult<TScope, TSymbol> | undefined> {
360
+ const resolvedSymbol = getSymbolForRefkey(refkey);
361
+ return computed(() => {
362
+ trace(
363
+ TracePhase.resolve.pending,
364
+ () => `Resolving ${formatRefkeys(refkey)}.`,
365
+ );
366
+ const symbol = resolvedSymbol.value as TSymbol;
367
+ if (!symbol) {
368
+ trace(
369
+ TracePhase.resolve.failure,
370
+ () => `No symbol for ${formatRefkeys(refkey)}.`,
371
+ );
372
+ return undefined;
918
373
  }
919
- }
374
+ trace(
375
+ TracePhase.resolve.pending,
376
+ () =>
377
+ `${formatRefkeys(refkey)} resolved to ${formatSymbolName(symbol)}.`,
378
+ );
379
+ if (hasTransientScope(symbol)) {
380
+ trace(
381
+ TracePhase.resolve.failure,
382
+ () => `Symbol ${formatSymbolName(symbol)} in transient scope.`,
383
+ );
384
+ return undefined;
385
+ }
386
+
387
+ trace(
388
+ TracePhase.resolve.success,
389
+ () =>
390
+ `${formatRefkeys(refkey)} successfully resolved to ${formatSymbolName(symbol)}.`,
391
+ );
392
+ return buildResult(currentScope, currentMemberScope, symbol);
393
+ });
920
394
  }
921
395
 
922
- function waitForRefkey<
923
- TScope extends OutputScope,
924
- TSymbol extends OutputSymbol,
925
- >(
926
- refkey: Refkey,
927
- cb: (
928
- symbol: TSymbol | undefined,
929
- ) => ResolutionResult<TScope, TSymbol> | undefined,
930
- ): ShallowRef<ResolutionResult<TScope, TSymbol> | undefined> {
931
- let declSignal;
932
- if (waitingDeclarations.has(refkey)) {
933
- declSignal = waitingDeclarations.get(refkey)! as ShallowRef<TSymbol>;
934
- } else {
935
- declSignal = shallowRef();
936
- waitingDeclarations.set(refkey, declSignal);
396
+ function notifySymbolCreated(symbol: OutputSymbol): void {
397
+ if (symbol.flags & OutputSymbolFlags.Transient) {
398
+ // just ignore transient symbols.
399
+ return;
937
400
  }
401
+ effect<Refkey[]>((oldRefkeys) => {
402
+ trace(
403
+ TracePhase.resolve.pending,
404
+ () => `Notifying resolutions for ${formatRefkeys(symbol.refkeys)}.`,
405
+ );
938
406
 
939
- return computed(() => cb(declSignal.value));
940
- }
407
+ if (oldRefkeys) {
408
+ for (const refkey of oldRefkeys) {
409
+ if (!symbol.refkeys.includes(refkey)) {
410
+ // remove the old refkey from the known declarations
411
+ knownDeclarations.delete(refkey);
412
+
413
+ // reset any waiting declarations
414
+ if (waitingDeclarations.has(refkey)) {
415
+ const signal = waitingDeclarations.get(refkey)!;
416
+ signal.value = undefined;
417
+ }
418
+ }
419
+ }
420
+ }
941
421
 
942
- function notifyRefkey(symbol: OutputSymbol): void {
943
- effect(() => {
944
422
  for (const refkey of symbol.refkeys) {
945
423
  // notify those waiting for this refkey
946
424
  knownDeclarations.set(refkey, symbol);
@@ -958,13 +436,15 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
958
436
  }
959
437
  }
960
438
  }
439
+
440
+ return [...symbol.refkeys];
961
441
  });
962
442
  }
963
443
 
964
444
  function findSymbolName<TSymbol extends OutputSymbol = OutputSymbol>(
965
445
  scope: OutputScope | undefined,
966
446
  name: string,
967
- ): Ref<TSymbol | undefined> {
447
+ ): ShallowRef<TSymbol | undefined> {
968
448
  return untrack(() => {
969
449
  scope ??= binder.globalScope;
970
450
  for (const sym of scope.symbols) {
@@ -986,12 +466,12 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
986
466
  function findScopeName<TScope extends OutputScope = OutputScope>(
987
467
  scope: OutputScope | undefined,
988
468
  name: string,
989
- ): Ref<TScope | undefined> {
469
+ ): ShallowRef<TScope | undefined> {
990
470
  return untrack(() => {
991
471
  scope ??= binder.globalScope;
992
472
  for (const child of scope.children) {
993
473
  if (child.name === name) {
994
- return ref(child) as Ref<TScope>;
474
+ return shallowRef(child) as Ref<TScope>;
995
475
  }
996
476
  }
997
477
 
@@ -1083,9 +563,16 @@ export function resolve<
1083
563
  TScope extends OutputScope,
1084
564
  TSymbol extends OutputSymbol,
1085
565
  >(refkey: Refkey): Ref<ResolutionResult<TScope, TSymbol>> {
1086
- const scope = useScope() ?? useBinder().globalScope;
566
+ const scope = useScope();
1087
567
  const memberScope = useMemberScope();
1088
- const binder = scope.binder;
568
+ const binder =
569
+ scope?.binder ??
570
+ memberScope?.instanceMembers?.binder ??
571
+ memberScope?.staticMembers?.binder;
572
+
573
+ if (!binder) {
574
+ throw new Error("Can't resolve refkey without a binder");
575
+ }
1089
576
 
1090
577
  return binder.resolveDeclarationByKey(
1091
578
  scope,
@@ -1109,17 +596,6 @@ export interface SymbolCreator {
1109
596
  [createSymbolsSymbol](binder: Binder): void;
1110
597
  }
1111
598
 
1112
- function symbolNames(symbols: Set<OutputSymbol>): () => Set<string> {
1113
- return memo(() => {
1114
- const names = new Set<string>();
1115
- for (const sym of symbols.values()) {
1116
- names.add(sym.name);
1117
- }
1118
-
1119
- return names;
1120
- });
1121
- }
1122
-
1123
599
  /**
1124
600
  * Use symbol flags to determine the scope in which a symbol with those flags
1125
601
  * should be declared given the current context.