@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,446 @@
1
+ import { reactive, watch } from "@vue/reactivity";
2
+ import { beforeEach, describe, expect, it, vi } from "vitest";
3
+ import { createOutputBinder } from "../../src/binder.js";
4
+ import { ScopeContext } from "../../src/index.browser.js";
5
+ import { renderTree } from "../../src/render.js";
6
+ import { flushJobs } from "../../src/scheduler.js";
7
+ import { OutputScope, OutputScopeFlags } from "../../src/symbols/output-scope.js";
8
+ import { OutputSymbol, OutputSymbolFlags } from "../../src/symbols/output-symbol.js";
9
+ import { MemberScopeContext } from "../../src/context/member-scope.js";
10
+ let binder;
11
+ beforeEach(() => {
12
+ binder = createOutputBinder();
13
+ });
14
+ describe("OutputSymbol reactivity", () => {
15
+ it("keeps symbol names up-to-date", () => {
16
+ const scope = new OutputScope("scope", {
17
+ binder
18
+ });
19
+ const symbol = new OutputSymbol("sym", {
20
+ binder,
21
+ scope
22
+ });
23
+ flushJobs();
24
+ expect(scope.symbolNames.has("sym")).toBe(true);
25
+ symbol.name = "bar";
26
+ flushJobs();
27
+ expect(scope.symbolNames.has("bar")).toBe(true);
28
+ });
29
+ it("resolves symbol conflicts", () => {
30
+ const scope = new OutputScope("scope", {
31
+ binder
32
+ });
33
+ const s1 = new OutputSymbol("sym", {
34
+ binder,
35
+ scope
36
+ });
37
+ const s2 = new OutputSymbol("sym", {
38
+ binder,
39
+ scope
40
+ });
41
+ const s3 = new OutputSymbol("sym", {
42
+ binder,
43
+ scope
44
+ });
45
+ flushJobs();
46
+ expect(s1.name).toEqual("sym");
47
+ expect(s2.name).toEqual("sym_2");
48
+ expect(s3.name).toEqual("sym_3");
49
+ });
50
+ it("is reactive on name, flags, scope, instanceMemberScope, and staticMemberScope", () => {
51
+ const scope = new OutputScope("scope", {
52
+ binder
53
+ });
54
+ const symbol = new OutputSymbol("sym", {
55
+ binder,
56
+ scope
57
+ });
58
+ const nameSpy = vi.fn();
59
+ watch(() => symbol.name, nameSpy);
60
+ const flagsSpy = vi.fn();
61
+ watch(() => symbol.flags, flagsSpy);
62
+ const scopeSpy = vi.fn();
63
+ watch(() => symbol.scope, scopeSpy);
64
+ const instanceMemberScopeSpy = vi.fn();
65
+ watch(() => symbol.instanceMemberScope, instanceMemberScopeSpy);
66
+ const staticMemberScopeSpy = vi.fn();
67
+ watch(() => symbol.staticMemberScope, staticMemberScopeSpy);
68
+ symbol.name = "foo";
69
+ symbol.flags = 0;
70
+ symbol.scope = new OutputScope("new-scope", {
71
+ binder
72
+ });
73
+ symbol.flags |= OutputSymbolFlags.InstanceMemberContainer | OutputSymbolFlags.StaticMemberContainer;
74
+ expect(nameSpy).toHaveBeenCalled();
75
+ expect(flagsSpy).toHaveBeenCalled();
76
+ expect(scopeSpy).toHaveBeenCalled();
77
+ expect(instanceMemberScopeSpy).toHaveBeenCalled();
78
+ expect(staticMemberScopeSpy).toHaveBeenCalled();
79
+ });
80
+ it("doesn't get wrapped in a reactive proxy", () => {
81
+ const scope = new OutputScope("scope", {
82
+ binder
83
+ });
84
+ const symbol = new OutputSymbol("sym", {
85
+ binder,
86
+ scope
87
+ });
88
+ const rSymbol = reactive(symbol);
89
+ expect(rSymbol).toBe(symbol);
90
+ });
91
+ });
92
+ describe("OutputSymbol#flags", () => {
93
+ it("sets member flags based on parent scope", () => {
94
+ const scope = new OutputScope("scope", {
95
+ binder
96
+ });
97
+ const symbol = new OutputSymbol("sym", {
98
+ binder,
99
+ scope
100
+ });
101
+ expect(symbol.flags & OutputSymbolFlags.Member).toBeFalsy();
102
+ const memberScope = new OutputScope("member-scope", {
103
+ binder,
104
+ owner: symbol,
105
+ flags: OutputScopeFlags.InstanceMemberScope
106
+ });
107
+ const memberSymbol = new OutputSymbol("member-sym", {
108
+ binder,
109
+ scope: memberScope
110
+ });
111
+ expect(memberSymbol.flags & OutputSymbolFlags.InstanceMember).toBeTruthy();
112
+ });
113
+ });
114
+ describe("OutputSymbol#staticMemberScope", () => {
115
+ it("is created when needed", () => {
116
+ const scope = new OutputScope("scope", {
117
+ binder
118
+ });
119
+ const symbol = new OutputSymbol("sym", {
120
+ binder,
121
+ scope,
122
+ flags: OutputSymbolFlags.StaticMemberContainer
123
+ });
124
+ expect(symbol.staticMemberScope).toBeDefined();
125
+ expect(symbol.staticMemberScope.symbols.size).toEqual(0);
126
+ });
127
+ });
128
+ describe("OutputSymbol#instanceMemberScope", () => {
129
+ it("is created when needed", () => {
130
+ const scope = new OutputScope("scope", {
131
+ binder
132
+ });
133
+ const symbol = new OutputSymbol("sym", {
134
+ binder,
135
+ scope,
136
+ flags: OutputSymbolFlags.InstanceMemberContainer
137
+ });
138
+ expect(symbol.instanceMemberScope).toBeDefined();
139
+ expect(symbol.instanceMemberScope.symbols.size).toEqual(0);
140
+ });
141
+ });
142
+ describe("OutputSymbol#metadata", () => {
143
+ it("is reactive", () => {
144
+ const scope = new OutputScope("scope", {
145
+ binder
146
+ });
147
+ const symbol = new OutputSymbol("sym", {
148
+ binder,
149
+ scope,
150
+ metadata: {
151
+ foo: "bar"
152
+ }
153
+ });
154
+ const metadataSpy = vi.fn();
155
+ watch(() => symbol.metadata.foo, metadataSpy);
156
+ symbol.metadata.foo = "baz";
157
+ expect(metadataSpy).toHaveBeenCalled();
158
+ expect(symbol.metadata.foo).toEqual("baz");
159
+ });
160
+ });
161
+ describe("OutputSymbol#scope", () => {
162
+ it("adds to parent scope", () => {
163
+ const scope = new OutputScope("parent", {
164
+ binder
165
+ });
166
+ const symbol = new OutputSymbol("sym", {
167
+ binder,
168
+ scope
169
+ });
170
+ expect(scope.symbols.has(symbol)).toBe(true);
171
+ });
172
+ it("defaults to the current lexical scope when not a member", () => {
173
+ const scope = new OutputScope("parent", {
174
+ binder
175
+ });
176
+ withContext([[ScopeContext, scope]], () => {
177
+ const symbol = new OutputSymbol("sym", {
178
+ binder
179
+ });
180
+ expect(scope.symbols.has(symbol)).toBe(true);
181
+ });
182
+ });
183
+ it("defaults to the current member scope when a member", () => {
184
+ const symbol = new OutputSymbol("Class", {
185
+ binder,
186
+ scope: binder.globalScope,
187
+ flags: OutputSymbolFlags.MemberContainer
188
+ });
189
+ withContext([[MemberScopeContext, {
190
+ instanceMembers: symbol.instanceMemberScope,
191
+ staticMembers: symbol.staticMemberScope
192
+ }]], () => {
193
+ const ms = new OutputSymbol("ms", {
194
+ binder,
195
+ flags: OutputSymbolFlags.InstanceMember
196
+ });
197
+ const ss = new OutputSymbol("ss", {
198
+ binder,
199
+ flags: OutputSymbolFlags.StaticMember
200
+ });
201
+ expect(symbol.instanceMemberScope.symbols.has(ms)).toBe(true);
202
+ expect(symbol.staticMemberScope.symbols.has(ss)).toBe(true);
203
+ });
204
+ });
205
+ });
206
+ function withContext(contexts, fn) {
207
+ let children = fn;
208
+ for (let i = 0; i < contexts.length; i++) {
209
+ const [context, value] = contexts[i];
210
+ children = context.ProviderStc({
211
+ value
212
+ }).children(children);
213
+ }
214
+ renderTree(children);
215
+ }
216
+ describe("Symbol#delete", () => {
217
+ it("deletes from parent scope", () => {
218
+ const scope = new OutputScope("parent", {
219
+ binder
220
+ });
221
+ const symbol = new OutputSymbol("sym", {
222
+ binder,
223
+ scope
224
+ });
225
+ expect(scope.symbols.has(symbol)).toBe(true);
226
+ symbol.delete();
227
+ expect(scope.symbols.has(symbol)).toBe(false);
228
+ });
229
+ it("updates resolution");
230
+ });
231
+ describe("OutputSymbol#cloneInto", () => {
232
+ it("copies values and propagates updates", () => {
233
+ const scope = new OutputScope("scope", {
234
+ binder
235
+ });
236
+ const scope2 = new OutputScope("scope2", {
237
+ binder
238
+ });
239
+ const symbol = new OutputSymbol("sym", {
240
+ binder,
241
+ scope
242
+ });
243
+ const clone = symbol.copyToScope(scope2);
244
+ expect(clone.name).toEqual("sym");
245
+ expect(clone.flags).toEqual(symbol.flags);
246
+ expect(clone.originalName).toEqual(symbol.originalName);
247
+ symbol.name = "bar";
248
+ symbol.flags = OutputSymbolFlags.InstanceMemberContainer;
249
+ flushJobs();
250
+ expect(clone.name).toEqual("bar");
251
+ expect(clone.flags).toEqual(OutputSymbolFlags.InstanceMemberContainer);
252
+ });
253
+ it("works simply", () => {
254
+ const scope = new OutputScope("scope", {
255
+ binder
256
+ });
257
+ const symbol = new OutputSymbol("sym", {
258
+ binder,
259
+ scope,
260
+ flags: OutputSymbolFlags.StaticMemberContainer
261
+ });
262
+ const sourceStaticMember = new OutputSymbol("static-member", {
263
+ binder,
264
+ scope: symbol.staticMemberScope
265
+ });
266
+ const scope2 = new OutputScope("scope2", {
267
+ binder
268
+ });
269
+ const clone = symbol.copyToScope(scope2);
270
+ expect(clone.staticMemberScope.symbols.size).toBe(1);
271
+ sourceStaticMember.delete();
272
+ flushJobs();
273
+ expect(clone.staticMemberScope.symbols.size).toBe(0);
274
+ });
275
+ it("clones instance and static member scopes", () => {
276
+ const scope = new OutputScope("scope", {
277
+ binder
278
+ });
279
+ const symbol = new OutputSymbol("sym", {
280
+ binder,
281
+ scope,
282
+ flags: OutputSymbolFlags.MemberContainer
283
+ });
284
+ const sourceStaticMember = new OutputSymbol("static-member", {
285
+ binder,
286
+ scope: symbol.staticMemberScope,
287
+ flags: OutputSymbolFlags.StaticMemberContainer
288
+ });
289
+ const sourceInstanceMember = new OutputSymbol("instance-member", {
290
+ binder,
291
+ scope: symbol.instanceMemberScope
292
+ });
293
+ const scope2 = new OutputScope("scope2", {
294
+ binder
295
+ });
296
+ const clone = symbol.copyToScope(scope2);
297
+ expect(clone.instanceMemberScope).toBeDefined();
298
+ expect(clone.staticMemberScope).toBeDefined();
299
+ const clonedStaticMember = [...clone.staticMemberScope.symbols][0];
300
+ expect(clonedStaticMember.name).toBe("static-member");
301
+ expect(clonedStaticMember).toBeDefined();
302
+ expect(clonedStaticMember.flags).toBe(sourceStaticMember.flags);
303
+ const clonedInstanceMember = [...clone.instanceMemberScope.symbols][0];
304
+ expect(clonedInstanceMember.name).toBe("instance-member");
305
+ expect(clonedInstanceMember).toBeDefined();
306
+ expect(clonedInstanceMember.flags).toBe(sourceInstanceMember.flags);
307
+ expect(clonedInstanceMember.staticMemberScope).toBeUndefined();
308
+
309
+ // test reactivity
310
+ const newStaticSym = new OutputSymbol("new-sym", {
311
+ binder,
312
+ scope: symbol.staticMemberScope
313
+ });
314
+ const newInstanceSym = new OutputSymbol("new-sym", {
315
+ binder,
316
+ scope: symbol.instanceMemberScope
317
+ });
318
+ flushJobs();
319
+ expect(clone.staticMemberScope.symbolNames.has("new-sym")).toBe(true);
320
+ expect(clone.instanceMemberScope.symbolNames.has("new-sym")).toBe(true);
321
+ newStaticSym.delete();
322
+ newInstanceSym.delete();
323
+ flushJobs();
324
+ expect(clone.staticMemberScope.symbolNames.has("new-sym")).toBe(false);
325
+ expect(clone.instanceMemberScope.symbolNames.has("new-sym")).toBe(false);
326
+ });
327
+ });
328
+ describe("OutputSymbol#instantiateInto", () => {
329
+ it("copies instance members to static member scope", () => {
330
+ const scope = new OutputScope("scope", {
331
+ binder
332
+ });
333
+ const classSym = new OutputSymbol("Class", {
334
+ binder,
335
+ scope,
336
+ flags: OutputSymbolFlags.MemberContainer
337
+ });
338
+ new OutputSymbol("instance-member", {
339
+ binder,
340
+ scope: classSym.instanceMemberScope
341
+ });
342
+ new OutputSymbol("static-member", {
343
+ binder,
344
+ scope: classSym.staticMemberScope
345
+ });
346
+ const targetSym = new OutputSymbol("Target", {
347
+ binder,
348
+ scope
349
+ });
350
+ classSym.instantiateTo(targetSym);
351
+ expect(targetSym.staticMemberScope).toBeDefined();
352
+ const staticNames = targetSym.staticMemberScope.symbolNames;
353
+ expect(staticNames.size).toEqual(1);
354
+ expect(staticNames.has("instance-member")).toBe(true);
355
+ const instantiatedSym = [...targetSym.staticMemberScope.symbols][0];
356
+ expect(instantiatedSym.flags & OutputSymbolFlags.StaticMember).toBeTruthy();
357
+ });
358
+ it("is reactive to new instance members", () => {
359
+ const scope = new OutputScope("scope", {
360
+ binder
361
+ });
362
+ const classSym = new OutputSymbol("Class", {
363
+ binder,
364
+ scope,
365
+ flags: OutputSymbolFlags.MemberContainer
366
+ });
367
+ new OutputSymbol("instance-member", {
368
+ binder,
369
+ scope: classSym.instanceMemberScope
370
+ });
371
+ const targetSym = new OutputSymbol("Target", {
372
+ binder,
373
+ scope
374
+ });
375
+ classSym.instantiateTo(targetSym);
376
+ new OutputSymbol("new-instance-member", {
377
+ binder,
378
+ scope: classSym.instanceMemberScope
379
+ });
380
+ expect(targetSym.staticMemberScope.symbolNames.has("new-instance-member")).toBeDefined();
381
+ expect(targetSym.instanceMemberScope).toBeUndefined();
382
+ });
383
+ it("copies static members of instance members", () => {
384
+ const scope = new OutputScope("scope", {
385
+ binder
386
+ });
387
+ const classSym = new OutputSymbol("Class", {
388
+ binder,
389
+ scope,
390
+ flags: OutputSymbolFlags.MemberContainer
391
+ });
392
+ const instanceMemberSym = new OutputSymbol("instance-member", {
393
+ binder,
394
+ scope: classSym.instanceMemberScope,
395
+ flags: OutputSymbolFlags.StaticMemberContainer
396
+ });
397
+ new OutputSymbol("static-of-instance", {
398
+ binder,
399
+ scope: instanceMemberSym.staticMemberScope
400
+ });
401
+ const targetSym = new OutputSymbol("Target", {
402
+ binder,
403
+ scope
404
+ });
405
+ classSym.instantiateTo(targetSym);
406
+ expect(targetSym.staticMemberScope.symbolNames.has("instance-member")).toBeTruthy();
407
+ expect(targetSym.instanceMemberScope).toBeUndefined();
408
+ const instantiatedSS = [...targetSym.staticMemberScope.symbols][0];
409
+ expect(instantiatedSS.staticMemberScope).toBeDefined();
410
+ expect(instantiatedSS.staticMemberScope.symbolNames.has("static-of-instance")).toBeTruthy();
411
+
412
+ // check reactivity
413
+ const newSym = new OutputSymbol("new-static-of-instance", {
414
+ binder,
415
+ scope: instanceMemberSym.staticMemberScope
416
+ });
417
+ flushJobs();
418
+ expect(instantiatedSS.staticMemberScope.symbolNames.has("new-static-of-instance")).toBeTruthy();
419
+ newSym.delete();
420
+ flushJobs();
421
+ expect(instantiatedSS.staticMemberScope.symbolNames.has("static-member-2")).toBeFalsy();
422
+ });
423
+ it("is idempotent", () => {
424
+ const scope = new OutputScope("scope", {
425
+ binder
426
+ });
427
+ const source = new OutputSymbol("sym", {
428
+ binder,
429
+ scope,
430
+ flags: OutputSymbolFlags.InstanceMemberContainer
431
+ });
432
+ new OutputSymbol("instance-member", {
433
+ binder,
434
+ scope: source.instanceMemberScope
435
+ });
436
+ const target = new OutputSymbol("target", {
437
+ binder,
438
+ scope
439
+ });
440
+ source.instantiateTo(target);
441
+ source.instantiateTo(target);
442
+ expect(target.staticMemberScope).toBeDefined();
443
+ expect(target.staticMemberScope.symbolNames.size).toEqual(1);
444
+ expect(target.staticMemberScope.symbolNames.has("instance-member")).toBe(true);
445
+ });
446
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=resolution.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolution.test.d.ts","sourceRoot":"","sources":["../../../test/symbols/resolution.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,140 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createOutputBinder, refkey } from "../../src/index.browser.js";
3
+ import { flushJobs } from "../../src/scheduler.js";
4
+ import { OutputSymbol, OutputSymbolFlags } from "../../src/symbols/output-symbol.js";
5
+ import { createScopeTree } from "./utils.js";
6
+ describe("Symbol name resolution", () => {
7
+ it("resolves static symbols", () => {
8
+ const binder = createOutputBinder();
9
+ const {
10
+ symbols: {
11
+ static: staticSym
12
+ }
13
+ } = createScopeTree(binder, {
14
+ root: {
15
+ symbols: {
16
+ root: {
17
+ flags: OutputSymbolFlags.InstanceMemberContainer | OutputSymbolFlags.StaticMemberContainer,
18
+ staticMembers: {
19
+ static: {
20
+ flags: OutputSymbolFlags.StaticMember
21
+ }
22
+ }
23
+ }
24
+ }
25
+ }
26
+ });
27
+ const result = binder.resolveFQN("root.root.static");
28
+ expect(result.value).toEqual(staticSym);
29
+ });
30
+ it("resolves static symbols that are added later", () => {
31
+ const binder = createOutputBinder();
32
+ const result = binder.resolveFQN("root.root.static");
33
+ expect(result.value).toBeUndefined();
34
+ const {
35
+ symbols: {
36
+ static: staticSym
37
+ }
38
+ } = createScopeTree(binder, {
39
+ root: {
40
+ symbols: {
41
+ root: {
42
+ flags: OutputSymbolFlags.InstanceMemberContainer | OutputSymbolFlags.StaticMemberContainer,
43
+ staticMembers: {
44
+ static: {
45
+ flags: OutputSymbolFlags.StaticMember
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
51
+ });
52
+ expect(result.value).toEqual(staticSym);
53
+ });
54
+ it("resolves instance symbols", () => {
55
+ const binder = createOutputBinder();
56
+ const {
57
+ symbols: {
58
+ instance
59
+ }
60
+ } = createScopeTree(binder, {
61
+ root: {
62
+ symbols: {
63
+ root: {
64
+ flags: OutputSymbolFlags.InstanceMemberContainer,
65
+ instanceMembers: {
66
+ instance: {
67
+ flags: OutputSymbolFlags.InstanceMember
68
+ }
69
+ }
70
+ }
71
+ }
72
+ }
73
+ });
74
+ const result = binder.resolveFQN("root.root#instance");
75
+ expect(result.value).toEqual(instance);
76
+ });
77
+ it("resolves instance symbols that are added later", () => {
78
+ const binder = createOutputBinder();
79
+ const result = binder.resolveFQN("root.root#instance");
80
+ expect(result.value).toBeUndefined();
81
+ const {
82
+ symbols: {
83
+ instance
84
+ }
85
+ } = createScopeTree(binder, {
86
+ root: {
87
+ symbols: {
88
+ root: {
89
+ flags: OutputSymbolFlags.InstanceMemberContainer,
90
+ instanceMembers: {
91
+ instance: {
92
+ flags: OutputSymbolFlags.InstanceMember
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }
98
+ });
99
+ expect(result.value).toEqual(instance);
100
+ });
101
+ });
102
+ describe("refkey resolution", () => {
103
+ it("resolves existing symbols by refkey", () => {
104
+ const key = refkey();
105
+ const binder = createOutputBinder();
106
+ const sym = new OutputSymbol("foo", {
107
+ binder,
108
+ scope: binder.globalScope,
109
+ refkeys: [key]
110
+ });
111
+ const resolvedSym = binder.resolveDeclarationByKey(undefined, undefined, key);
112
+ expect(resolvedSym.value?.targetDeclaration).toBe(sym);
113
+ });
114
+ it("resolves symbols by refkey when symbol is added later", () => {
115
+ const key = refkey();
116
+ const binder = createOutputBinder();
117
+ const resolvedSym = binder.resolveDeclarationByKey(undefined, undefined, key);
118
+ const sym = new OutputSymbol("foo", {
119
+ binder,
120
+ scope: binder.globalScope,
121
+ refkeys: [key]
122
+ });
123
+ expect(resolvedSym.value?.targetDeclaration).toBe(sym);
124
+ });
125
+ it("handles deleted symbols by updating resolutions", () => {
126
+ const key = refkey();
127
+ const binder = createOutputBinder();
128
+ const resolvedSym = binder.resolveDeclarationByKey(undefined, undefined, key);
129
+ const sym = new OutputSymbol("foo", {
130
+ binder,
131
+ scope: binder.globalScope,
132
+ refkeys: [key]
133
+ });
134
+ flushJobs();
135
+ expect(resolvedSym.value?.targetDeclaration).toBe(sym);
136
+ sym.delete();
137
+ flushJobs();
138
+ expect(resolvedSym.value).toBe(undefined);
139
+ });
140
+ });
@@ -0,0 +1,24 @@
1
+ import { Binder } from "../../src/index.browser.js";
2
+ import { Refkey } from "../../src/refkey.js";
3
+ import { OutputScope, OutputScopeFlags } from "../../src/symbols/output-scope.js";
4
+ import { OutputSymbol, OutputSymbolFlags } from "../../src/symbols/output-symbol.js";
5
+ type ScopeRecords = Record<string, ScopeDescriptor>;
6
+ type SymbolRecords = Record<string, SymbolDescriptor>;
7
+ interface ScopeDescriptor {
8
+ flags?: OutputScopeFlags;
9
+ scopes?: ScopeRecords;
10
+ symbols: SymbolRecords;
11
+ }
12
+ interface SymbolDescriptor {
13
+ refkey?: Refkey;
14
+ flags?: OutputSymbolFlags;
15
+ instanceMembers?: SymbolRecords;
16
+ staticMembers?: SymbolRecords;
17
+ }
18
+ interface ScopeTreeResult {
19
+ symbols: Record<string, OutputSymbol>;
20
+ scopes: Record<string, OutputScope>;
21
+ }
22
+ export declare function createScopeTree(binder: Binder, tree: ScopeRecords): ScopeTreeResult;
23
+ export {};
24
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../test/symbols/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,EAAE,MAAM,EAAU,MAAM,qBAAqB,CAAC;AACrD,OAAO,EACL,WAAW,EACX,gBAAgB,EACjB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,YAAY,EACZ,iBAAiB,EAClB,MAAM,oCAAoC,CAAC;AAE5C,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AACpD,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAEtD,UAAU,eAAe;IACvB,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,aAAa,CAAC;CACxB;AAED,UAAU,gBAAgB;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,eAAe,CAAC,EAAE,aAAa,CAAC;IAChC,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACrC;AACD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,YAAY,GACjB,eAAe,CA4DjB"}
@@ -0,0 +1,46 @@
1
+ import { refkey } from "../../src/refkey.js";
2
+ import { OutputScope } from "../../src/symbols/output-scope.js";
3
+ import { OutputSymbol, OutputSymbolFlags } from "../../src/symbols/output-symbol.js";
4
+ export function createScopeTree(binder, tree) {
5
+ const createdItems = {
6
+ symbols: {},
7
+ scopes: {}
8
+ };
9
+ for (const [name, desc] of Object.entries(tree)) {
10
+ createScope(name, desc);
11
+ }
12
+ return createdItems;
13
+ function createScope(name, descriptor, parent = binder.globalScope) {
14
+ const scope = new OutputScope(name, {
15
+ binder,
16
+ parent,
17
+ flags: descriptor.flags
18
+ });
19
+ createdItems.scopes[name] = scope;
20
+ for (const [name, desc] of Object.entries(descriptor.symbols)) {
21
+ createSymbol(name, desc, scope);
22
+ }
23
+ for (const [name, desc] of Object.entries(descriptor.scopes ?? {})) {
24
+ createScope(name, desc, scope);
25
+ }
26
+ }
27
+ function createSymbol(name, descriptor, parent) {
28
+ const symbol = new OutputSymbol(name, {
29
+ binder,
30
+ scope: parent,
31
+ refkeys: [descriptor.refkey ?? refkey()],
32
+ flags: descriptor.flags ?? OutputSymbolFlags.None
33
+ });
34
+ createdItems.symbols[name] = symbol;
35
+ if (descriptor.instanceMembers) {
36
+ for (const [name, desc] of Object.entries(descriptor.instanceMembers)) {
37
+ createSymbol(name, desc, symbol.instanceMemberScope);
38
+ }
39
+ }
40
+ if (descriptor.staticMembers) {
41
+ for (const [name, desc] of Object.entries(descriptor.staticMembers)) {
42
+ createSymbol(name, desc, symbol.staticMemberScope);
43
+ }
44
+ }
45
+ }
46
+ }