@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
@@ -0,0 +1,512 @@
1
+ import {
2
+ reactive,
3
+ ReactiveFlags,
4
+ shallowReactive,
5
+ track,
6
+ TrackOpTypes,
7
+ trigger,
8
+ TriggerOpTypes,
9
+ watch,
10
+ } from "@vue/reactivity";
11
+ import type { Binder } from "../binder.js";
12
+ import { useBinder } from "../context/binder.js";
13
+ import { useMemberScope } from "../context/member-scope.js";
14
+ import { useScope } from "../context/scope.js";
15
+ import { isRefkey, refkey, type Refkey } from "../refkey.js";
16
+ import {
17
+ formatScopeName,
18
+ formatSymbol,
19
+ formatSymbolName,
20
+ trace,
21
+ traceEffect,
22
+ TracePhase,
23
+ } from "../tracer.js";
24
+ import { OutputScope, OutputScopeFlags } from "./output-scope.js";
25
+ /**
26
+ * Flags that describe an output symbol.
27
+ */
28
+ export enum OutputSymbolFlags {
29
+ None = 0,
30
+
31
+ /**
32
+ * The symbol is an instance member container. Symbols with this flag will have a
33
+ * instanceMemberScope property that contains symbols for instance members.
34
+ */
35
+ InstanceMemberContainer = 1 << 0,
36
+
37
+ /**
38
+ * The symbol is a static member container. Symbols with this flag will have a
39
+ * staticMemberScope property that contains symbols for static members.
40
+ */
41
+ StaticMemberContainer = 1 << 1,
42
+
43
+ /**
44
+ * Whether this symbol contains members of any kind.
45
+ */
46
+ MemberContainer = InstanceMemberContainer | StaticMemberContainer,
47
+
48
+ /**
49
+ * Whether this symbol is an instance member of another symbol (i.e that it is
50
+ * stored in an instance member scope).
51
+ */
52
+ InstanceMember = 1 << 2,
53
+
54
+ /**
55
+ * Whether this symbol is a static member of another symbol (i.e that it is
56
+ * stored in a static member scope).
57
+ */
58
+ StaticMember = 1 << 3,
59
+
60
+ /**
61
+ * Transient symbols are not added to symbol tables and do not create
62
+ * referencable refkeys. They are used for temporary symbols that are intended
63
+ * to be used to calculate other symbols.
64
+ */
65
+ Transient = 1 << 4,
66
+
67
+ /**
68
+ * This symbol aliases another symbol. Only its name, flags, and scope are
69
+ * stored in this symbol. Otherwise, everything else is located on the alias
70
+ * target.
71
+ */
72
+ Alias = 1 << 5,
73
+
74
+ /**
75
+ * Whether this is an instance member or static member of another symbol.
76
+ */
77
+ Member = InstanceMember | StaticMember,
78
+ }
79
+
80
+ export interface OutputSymbolOptions {
81
+ binder?: Binder;
82
+ scope?: OutputScope;
83
+ flags?: OutputSymbolFlags;
84
+ refkeys?: Refkey | Refkey[];
85
+ metadata?: Record<string, unknown>;
86
+ aliasTarget?: OutputSymbol;
87
+ }
88
+
89
+ let symbolCount = 0;
90
+
91
+ /**
92
+ * An output symbol is a named entity that can be referenced in your output
93
+ * code.
94
+ *
95
+ * @remarks
96
+ *
97
+ * This class is the base implementation of symbol. Most languages will have
98
+ * subtypes that provide additional metadata. Symbols are reactive values, so
99
+ * you can observe changes to their properties in a reactive context.
100
+ */
101
+ export class OutputSymbol {
102
+ #originalName: string;
103
+ get originalName() {
104
+ return this.#originalName;
105
+ }
106
+
107
+ #name: string;
108
+ get name() {
109
+ track(this, TrackOpTypes.GET, "name");
110
+ return this.#name;
111
+ }
112
+ set name(name: string) {
113
+ const old = this.#name;
114
+
115
+ if (old === name) {
116
+ return;
117
+ }
118
+
119
+ this.#name = name;
120
+ trigger(this, TriggerOpTypes.SET, "name", name, old);
121
+ }
122
+
123
+ #id: number;
124
+ get id() {
125
+ return this.#id;
126
+ }
127
+
128
+ #flags: OutputSymbolFlags;
129
+ get flags() {
130
+ track(this, TrackOpTypes.GET, "flags");
131
+ return this.#flags;
132
+ }
133
+ set flags(flags: OutputSymbolFlags) {
134
+ const old = this.#flags;
135
+
136
+ if (old === flags) {
137
+ return;
138
+ }
139
+
140
+ this.#flags = flags;
141
+ trigger(this, TriggerOpTypes.SET, "flags", flags, old);
142
+
143
+ this.#createInstanceMemberScope();
144
+ this.#createStaticMemberScope();
145
+ }
146
+
147
+ #scope: OutputScope;
148
+ get scope() {
149
+ track(this, TrackOpTypes.GET, "scope");
150
+ return this.#scope;
151
+ }
152
+
153
+ set scope(scope: OutputScope) {
154
+ const old = this.#scope;
155
+
156
+ if (old === scope) {
157
+ return;
158
+ }
159
+
160
+ this.#handleNewScope(scope, old);
161
+
162
+ this.#scope = scope;
163
+
164
+ trigger(this, TriggerOpTypes.SET, "scope", scope, old);
165
+ }
166
+
167
+ #handleNewScope(newScope: OutputScope, oldScope?: OutputScope) {
168
+ if (oldScope) {
169
+ // ensure when changing scope that this symbol only belongs to one of them
170
+ oldScope.symbols.delete(this);
171
+ }
172
+
173
+ if (!newScope) {
174
+ return;
175
+ }
176
+
177
+ newScope.symbols.add(this);
178
+
179
+ if (newScope.flags & OutputScopeFlags.InstanceMemberScope) {
180
+ this.flags |= OutputSymbolFlags.InstanceMember;
181
+ }
182
+
183
+ if (newScope.flags & OutputScopeFlags.StaticMemberScope) {
184
+ this.flags |= OutputSymbolFlags.StaticMember;
185
+ }
186
+ }
187
+
188
+ #binder: Binder | undefined;
189
+ get binder() {
190
+ return this.#binder;
191
+ }
192
+
193
+ #refkeys: Refkey[];
194
+ get refkeys() {
195
+ track(this, TrackOpTypes.GET, "refkeys");
196
+ return this.#refkeys;
197
+ }
198
+
199
+ set refkeys(refkeys: Refkey[]) {
200
+ const old = this.#refkeys;
201
+
202
+ if (old === refkeys) {
203
+ return;
204
+ }
205
+
206
+ this.#refkeys = shallowReactive(
207
+ Array.isArray(refkeys) ? refkeys : [refkeys],
208
+ );
209
+ trigger(this, TriggerOpTypes.SET, "refkeys", this.#refkeys, old);
210
+ }
211
+
212
+ #instanceMemberScope?: OutputScope;
213
+ get instanceMemberScope() {
214
+ track(this, TrackOpTypes.GET, "instanceMemberScope");
215
+ return this.#instanceMemberScope;
216
+ }
217
+
218
+ #aliasTarget?: OutputSymbol;
219
+ get aliasTarget() {
220
+ return this.#aliasTarget;
221
+ }
222
+
223
+ #createInstanceMemberScope() {
224
+ if (
225
+ this.#instanceMemberScope ||
226
+ !(this.#flags & OutputSymbolFlags.InstanceMemberContainer)
227
+ ) {
228
+ return;
229
+ }
230
+
231
+ this.#instanceMemberScope = new OutputScope(
232
+ `${this.name} instance members`,
233
+ {
234
+ binder: this.#binder,
235
+ owner: this,
236
+ flags: OutputScopeFlags.InstanceMemberScope,
237
+ },
238
+ );
239
+ trigger(
240
+ this,
241
+ TriggerOpTypes.SET,
242
+ "instanceMemberScope",
243
+ this.#instanceMemberScope,
244
+ undefined,
245
+ );
246
+ }
247
+
248
+ /**
249
+ * Create an output scope to hold member symbols. By default this just creates
250
+ * an OutputScope, but can be subclassed to build scope subtypes when needed.
251
+ */
252
+ protected createMemberScope(
253
+ name: string,
254
+ options: {
255
+ owner?: OutputSymbol;
256
+ flags?: OutputScopeFlags;
257
+ },
258
+ ) {
259
+ return new OutputScope(name, {
260
+ binder: this.#binder,
261
+ owner: options.owner,
262
+ flags: options.flags,
263
+ });
264
+ }
265
+
266
+ #staticMemberScope?: OutputScope;
267
+ get staticMemberScope() {
268
+ track(this, TrackOpTypes.GET, "staticMemberScope");
269
+ return this.#staticMemberScope;
270
+ }
271
+
272
+ #createStaticMemberScope() {
273
+ if (
274
+ this.#staticMemberScope ||
275
+ !(this.#flags & OutputSymbolFlags.StaticMemberContainer)
276
+ ) {
277
+ return;
278
+ }
279
+
280
+ this.#staticMemberScope = new OutputScope(`${this.name} static members`, {
281
+ binder: this.#binder,
282
+ owner: this,
283
+ flags: OutputScopeFlags.StaticMemberScope,
284
+ });
285
+ trigger(
286
+ this,
287
+ TriggerOpTypes.SET,
288
+ "staticMemberScope",
289
+ this.#staticMemberScope,
290
+ undefined,
291
+ );
292
+ }
293
+
294
+ #metadata: Record<string, unknown>;
295
+ get metadata() {
296
+ return this.#metadata;
297
+ }
298
+
299
+ /**
300
+ * Tell \@vue/reactivity that this symbol should never be wrapped in a reactive
301
+ * proxy.
302
+ */
303
+ [ReactiveFlags.SKIP] = true;
304
+
305
+ constructor(name: string, options: OutputSymbolOptions = {}) {
306
+ this.#binder = options.binder ?? useBinder();
307
+ this.#name = name;
308
+ this.#originalName = name;
309
+ this.#id = symbolCount++;
310
+ this.#flags = options.flags ?? OutputSymbolFlags.None;
311
+ this.#scope = options.scope ?? (this.#defaultScope() as OutputScope);
312
+ this.#aliasTarget = options.aliasTarget;
313
+ if (this.#aliasTarget) {
314
+ this.#flags |= OutputSymbolFlags.Alias;
315
+ this.#flags &= ~(
316
+ OutputSymbolFlags.MemberContainer | OutputSymbolFlags.Member
317
+ );
318
+ }
319
+ this.#refkeys = shallowReactive(
320
+ Array.isArray(options.refkeys) ? options.refkeys
321
+ : isRefkey(options.refkeys) ? [options.refkeys]
322
+ : [],
323
+ );
324
+ this.#metadata = reactive(options.metadata ?? {});
325
+ this.#createInstanceMemberScope();
326
+ this.#createStaticMemberScope();
327
+ this.#handleNewScope(this.#scope);
328
+
329
+ trace(TracePhase.symbol.create, () => `${formatSymbol(this)}`);
330
+ traceEffect(TracePhase.symbol.update, () => {
331
+ return `${formatSymbol(this)}`;
332
+ });
333
+ this.#binder?.notifySymbolCreated(this);
334
+ }
335
+
336
+ delete() {
337
+ trace(TracePhase.symbol.delete, () => `${formatSymbolName(this)}`);
338
+ if (this.#scope) {
339
+ this.#scope.symbols.delete(this);
340
+ }
341
+
342
+ this.#binder?.notifySymbolDeleted(this);
343
+ }
344
+
345
+ /**
346
+ * Takes the instance members or static members on this symbol and creates
347
+ * corresponding static members on the target symbol. Instance or static
348
+ * members of instantiated symbols are copied. The refkey of any instantiated
349
+ * symbols are set to a composite refkey of the target symbol's refkey and the
350
+ * instantiated symbol's refkey.
351
+ */
352
+ instantiateTo(targetSymbol: OutputSymbol): void {
353
+ if (this.#aliasTarget) {
354
+ return this.#aliasTarget.instantiateTo(targetSymbol);
355
+ }
356
+
357
+ trace(TracePhase.symbol.instantiate, () => {
358
+ return `${formatSymbolName(this)} -> ${formatSymbolName(targetSymbol)}`;
359
+ });
360
+
361
+ const from = this.#instanceMemberScope ?? this.#staticMemberScope;
362
+
363
+ if (from) {
364
+ targetSymbol.flags |= OutputSymbolFlags.StaticMemberContainer;
365
+ targetSymbol.#createStaticMemberScope();
366
+ targetSymbol.#staticMemberScope!.copySymbolsFrom(from, {
367
+ onAdd: (symbol) => {
368
+ const clone = symbol.copyToScope(
369
+ targetSymbol.#staticMemberScope!,
370
+ targetSymbol,
371
+ );
372
+ clone.#flags &= ~OutputSymbolFlags.InstanceMember;
373
+ clone.#flags |= OutputSymbolFlags.StaticMember;
374
+ return clone;
375
+ },
376
+ });
377
+ }
378
+ }
379
+
380
+ #instantiationRk(base: OutputSymbol, member: OutputSymbol) {
381
+ const instantiationRks = [];
382
+ for (const baseRk of base.refkeys) {
383
+ for (const targetRk of member.refkeys) {
384
+ instantiationRks.push(refkey(baseRk, targetRk));
385
+ }
386
+ }
387
+
388
+ return instantiationRks;
389
+ }
390
+
391
+ /**
392
+ * Copy member symbols from the target symbol into the target symbol. The
393
+ * copied symbols have their refkey set to
394
+ * `refkey(targetSymbol.refkey, this.refkey)`.
395
+ */
396
+ copyTo(targetSymbol: OutputSymbol): void {
397
+ if (this.#aliasTarget) {
398
+ return this.#aliasTarget.copyTo(targetSymbol);
399
+ }
400
+ if (this.staticMemberScope) {
401
+ targetSymbol.flags |= OutputSymbolFlags.StaticMemberContainer;
402
+ targetSymbol.staticMemberScope!.copySymbolsFrom(this.staticMemberScope);
403
+ }
404
+
405
+ if (this.instanceMemberScope) {
406
+ targetSymbol.flags |= OutputSymbolFlags.InstanceMemberContainer;
407
+ targetSymbol.instanceMemberScope!.copySymbolsFrom(
408
+ this.instanceMemberScope,
409
+ );
410
+ }
411
+ }
412
+
413
+ /**
414
+ * Move member symbols from this transient symbol to the target symbol.
415
+ */
416
+ moveTo(targetSymbol: OutputSymbol): void {
417
+ if (this.#aliasTarget) {
418
+ return this.#aliasTarget.moveTo(targetSymbol);
419
+ }
420
+
421
+ if (!(this.flags & OutputSymbolFlags.Transient)) {
422
+ throw new Error("Can only move members from transient symbols");
423
+ }
424
+ if (this.staticMemberScope) {
425
+ targetSymbol.flags |= OutputSymbolFlags.StaticMemberContainer;
426
+ targetSymbol.staticMemberScope!.moveSymbolsFrom(this.staticMemberScope);
427
+ }
428
+
429
+ if (this.instanceMemberScope) {
430
+ targetSymbol.flags |= OutputSymbolFlags.InstanceMemberContainer;
431
+ targetSymbol.instanceMemberScope!.moveSymbolsFrom(
432
+ this.instanceMemberScope,
433
+ );
434
+ }
435
+ }
436
+
437
+ /**
438
+ * Makes a copy of this symbol which will update the name and flags
439
+ * of the clone when the original symbol is updated.
440
+ *
441
+ * @remarks
442
+ *
443
+ * This is used to create a symbol that is a copy of this symbol, but
444
+ * with a different scope. Changes to the copy will not affect the
445
+ * original symbol, and changes to the original symbol's name and flags
446
+ * will overwrite the copy's name and flags.
447
+ *
448
+ * @param newScope - The scope to use for the copy.
449
+ */
450
+ copyToScope(newScope: OutputScope, baseSymbol?: OutputSymbol): OutputSymbol {
451
+ if (this.#aliasTarget) {
452
+ return this.#aliasTarget.copyToScope(newScope, baseSymbol);
453
+ }
454
+ trace(TracePhase.symbol.clone, () => {
455
+ return `${formatSymbolName(this)} -> ${formatScopeName(newScope)}`;
456
+ });
457
+ const clone = new OutputSymbol(this.#name, {
458
+ binder: this.#binder,
459
+ scope: newScope,
460
+ flags: this.#flags,
461
+ refkeys: baseSymbol ? this.#instantiationRk(baseSymbol, this) : [],
462
+ metadata: this.#metadata,
463
+ });
464
+
465
+ if (this.instanceMemberScope) {
466
+ clone.#instanceMemberScope = this.instanceMemberScope.clone({
467
+ owner: clone,
468
+ });
469
+ }
470
+
471
+ if (this.staticMemberScope) {
472
+ clone.#staticMemberScope = this.staticMemberScope.clone({ owner: clone });
473
+ }
474
+
475
+ watch(
476
+ () => this.name,
477
+ (newName) => (clone.name = newName),
478
+ );
479
+ watch(
480
+ () => this.flags,
481
+ (newFlags) => (clone.flags = newFlags),
482
+ );
483
+
484
+ return clone;
485
+ }
486
+
487
+ #defaultScope() {
488
+ if ((this.#flags & OutputSymbolFlags.Member) === 0) {
489
+ return useScope();
490
+ } else {
491
+ const memberScope = useMemberScope();
492
+ if (!memberScope) {
493
+ throw new Error("Cannot declare member symbols without a member scope");
494
+ }
495
+ if (this.#flags & OutputSymbolFlags.InstanceMember) {
496
+ if (!memberScope.instanceMembers) {
497
+ throw new Error(
498
+ "Cannot declare instance member symbols without an instance member scope",
499
+ );
500
+ }
501
+ return memberScope.instanceMembers;
502
+ } else {
503
+ if (!memberScope.staticMembers) {
504
+ throw new Error(
505
+ "Cannot declare static member symbols without a static member scope",
506
+ );
507
+ }
508
+ return memberScope.staticMembers;
509
+ }
510
+ }
511
+ }
512
+ }
@@ -0,0 +1,104 @@
1
+ import {
2
+ Context,
3
+ effect,
4
+ getContext,
5
+ onCleanup,
6
+ } from "@alloy-js/core/jsx-runtime";
7
+ import { isRef, Ref, shallowReactive } from "@vue/reactivity";
8
+
9
+ import { MemberScopeContext } from "../context/member-scope.js";
10
+ import { ScopeContext } from "../context/scope.js";
11
+ import { OutputSymbol, OutputSymbolFlags } from "./output-symbol.js";
12
+
13
+ export interface TakeSymbolCallback {
14
+ (symbol: OutputSymbol): void;
15
+ }
16
+
17
+ export interface TakeSymbolsCallback {
18
+ (symbols: Set<OutputSymbol>): void;
19
+ }
20
+
21
+ export function takeSymbols(cb?: (symbol: OutputSymbol) => void) {
22
+ const context = getContext()!;
23
+ context.takesSymbols = true;
24
+ context.takenSymbols = shallowReactive(new Set<OutputSymbol>());
25
+ if (cb) {
26
+ effect<Set<OutputSymbol>>((oldSymbols) => {
27
+ for (const symbol of context.takenSymbols!) {
28
+ if (oldSymbols && oldSymbols.has(symbol)) {
29
+ continue;
30
+ }
31
+ cb(symbol);
32
+ }
33
+
34
+ return new Set(context.takenSymbols!);
35
+ });
36
+ }
37
+ return context.takenSymbols;
38
+ }
39
+
40
+ export function emitSymbol(
41
+ symbol: OutputSymbol | Ref<OutputSymbol | undefined>,
42
+ ) {
43
+ let symbolTaker: Context | undefined;
44
+ let context = getContext()!.owner;
45
+ while (context) {
46
+ if (context.takesSymbols) {
47
+ symbolTaker = context;
48
+ break;
49
+ }
50
+
51
+ if (
52
+ context.context &&
53
+ (context.context[ScopeContext.id] ||
54
+ context.context[MemberScopeContext.id])
55
+ ) {
56
+ // don't cross scope boundaries.
57
+ break;
58
+ }
59
+
60
+ context = context.owner;
61
+ }
62
+
63
+ if (!symbolTaker) {
64
+ return;
65
+ }
66
+
67
+ if (isRef(symbol)) {
68
+ effect<OutputSymbol | undefined>((prevSymbol) => {
69
+ onCleanup(() => {
70
+ if (symbol.value) {
71
+ symbolTaker.takenSymbols!.delete(symbol.value);
72
+ }
73
+ });
74
+ if (symbol.value === undefined) {
75
+ symbolTaker.takenSymbols!.delete(prevSymbol!);
76
+ return undefined;
77
+ } else {
78
+ symbolTaker.takenSymbols!.add(symbol.value);
79
+ return symbol.value;
80
+ }
81
+ });
82
+ } else {
83
+ symbolTaker.takenSymbols!.add(symbol);
84
+ onCleanup(() => {
85
+ context!.takenSymbols!.delete(symbol);
86
+ });
87
+ }
88
+ }
89
+
90
+ export function moveTakenMembersTo(baseSymbol: OutputSymbol) {
91
+ const taken = takeSymbols();
92
+
93
+ effect(() => {
94
+ for (const symbol of taken) {
95
+ if (symbol.flags & OutputSymbolFlags.Transient) {
96
+ symbol.moveTo(baseSymbol);
97
+ }
98
+ }
99
+ });
100
+ }
101
+
102
+ export function instantiateTakenMembersTo(baseSymbol: OutputSymbol) {
103
+ takeSymbols((symbol) => symbol.instantiateTo(baseSymbol));
104
+ }
@@ -0,0 +1,47 @@
1
+ import { Ref, ShallowReactive, shallowRef } from "@vue/reactivity";
2
+ import { Children, effect, onCleanup } from "../jsx-runtime.js";
3
+ import { OutputSymbol } from "./output-symbol.js";
4
+ import { takeSymbols } from "./symbol-flow.js";
5
+
6
+ export function createSymbolSlot() {
7
+ const symbolSlotRef: Ref<ShallowReactive<Set<OutputSymbol>> | undefined> =
8
+ shallowRef();
9
+ function SymbolSlot(props: { children: Children }) {
10
+ const set = takeSymbols();
11
+ symbolSlotRef.value = set;
12
+
13
+ onCleanup(() => {
14
+ symbolSlotRef.value = undefined;
15
+ });
16
+
17
+ return props.children;
18
+ }
19
+
20
+ SymbolSlot.ref = symbolSlotRef;
21
+
22
+ SymbolSlot.instantiateInto = (baseSymbol: OutputSymbol) => {
23
+ effect(() => {
24
+ if (!symbolSlotRef.value) {
25
+ return;
26
+ }
27
+
28
+ for (const symbol of symbolSlotRef.value) {
29
+ symbol.instantiateTo(baseSymbol);
30
+ }
31
+ });
32
+ };
33
+
34
+ SymbolSlot.copyInto = (baseSymbol: OutputSymbol) => {
35
+ effect(() => {
36
+ if (!symbolSlotRef.value) {
37
+ return;
38
+ }
39
+
40
+ for (const symbol of symbolSlotRef.value) {
41
+ symbol.copyTo(baseSymbol);
42
+ }
43
+ });
44
+ };
45
+
46
+ return SymbolSlot;
47
+ }