@alloy-js/core 0.15.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 +23 -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 +15 -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
@@ -1,1006 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import {
3
- Binder,
4
- createOutputBinder,
5
- OutputScope,
6
- OutputScopeFlags,
7
- OutputSymbol,
8
- OutputSymbolFlags,
9
- } from "../src/binder.js";
10
- import { Refkey, refkey } from "../src/refkey.js";
11
- import { flushJobs } from "../src/scheduler.js";
12
-
13
- it("works", () => {
14
- const binder = createOutputBinder();
15
- const scope = binder.createScope({
16
- kind: "foo",
17
- name: "scope",
18
- parent: binder.globalScope,
19
- });
20
-
21
- const symbol = binder.createSymbol({
22
- name: "sym",
23
- scope,
24
- });
25
-
26
- flushJobs();
27
- expect([...scope.getSymbolNames()]).toEqual(["sym"]);
28
-
29
- symbol.name = "bar";
30
- flushJobs();
31
- expect([...scope.getSymbolNames()]).toEqual(["bar"]);
32
- });
33
-
34
- it("resolves symbol conflicts", () => {
35
- const binder = createOutputBinder();
36
- const scope = binder.createScope({
37
- kind: "foo",
38
- name: "scope",
39
- parent: binder.globalScope,
40
- });
41
-
42
- const _s1 = binder.createSymbol({
43
- name: "sym",
44
- scope,
45
- });
46
-
47
- const s2 = binder.createSymbol({
48
- name: "sym",
49
- scope,
50
- });
51
-
52
- const s3 = binder.createSymbol({
53
- name: "sym",
54
- scope,
55
- });
56
-
57
- flushJobs();
58
-
59
- expect(_s1.name).toEqual("sym");
60
- expect(s2.name).toEqual("sym_2");
61
- expect(s3.name).toEqual("sym_3");
62
- });
63
-
64
- type ScopeRecords = Record<string, ScopeDescriptor>;
65
- type SymbolRecords = Record<string, SymbolDescriptor>;
66
-
67
- interface ScopeDescriptor {
68
- flags?: OutputScopeFlags;
69
- scopes?: ScopeRecords;
70
- symbols: SymbolRecords;
71
- }
72
-
73
- interface SymbolDescriptor {
74
- refkey?: Refkey;
75
- flags?: OutputSymbolFlags;
76
- instanceMembers?: SymbolRecords;
77
- staticMembers?: SymbolRecords;
78
- }
79
-
80
- interface ScopeTreeResult {
81
- symbols: Record<string, OutputSymbol>;
82
- scopes: Record<string, OutputScope>;
83
- }
84
- function createScopeTree(binder: Binder, tree: ScopeRecords): ScopeTreeResult {
85
- const createdItems: ScopeTreeResult = {
86
- symbols: {},
87
- scopes: {},
88
- };
89
-
90
- for (const [name, desc] of Object.entries(tree)) {
91
- createScope(name, desc);
92
- }
93
-
94
- return createdItems;
95
-
96
- function createScope(
97
- name: string,
98
- descriptor: ScopeDescriptor,
99
- parent = binder.globalScope,
100
- ) {
101
- const scope = binder.createScope({
102
- kind: "useless",
103
- name,
104
- parent,
105
- flags: descriptor.flags ?? OutputScopeFlags.None,
106
- });
107
-
108
- createdItems.scopes[name] = scope;
109
-
110
- for (const [name, desc] of Object.entries(descriptor.symbols)) {
111
- createSymbol(name, desc, scope);
112
- }
113
-
114
- for (const [name, desc] of Object.entries(descriptor.scopes ?? {})) {
115
- createScope(name, desc, scope);
116
- }
117
- }
118
-
119
- function createSymbol(
120
- name: string,
121
- descriptor: SymbolDescriptor,
122
- parent: OutputScope,
123
- ) {
124
- const symbol = binder.createSymbol({
125
- name,
126
- scope: parent,
127
- refkey: descriptor.refkey ?? refkey(),
128
- flags: descriptor.flags ?? OutputSymbolFlags.None,
129
- });
130
-
131
- createdItems.symbols[name] = symbol;
132
-
133
- if (descriptor.instanceMembers) {
134
- for (const [name, desc] of Object.entries(descriptor.instanceMembers)) {
135
- createSymbol(name, desc, symbol.instanceMemberScope!);
136
- }
137
- }
138
-
139
- if (descriptor.staticMembers) {
140
- for (const [name, desc] of Object.entries(descriptor.staticMembers)) {
141
- createSymbol(name, desc, symbol.staticMemberScope!);
142
- }
143
- }
144
- }
145
- }
146
- describe("static members", () => {
147
- it("resolves static symbols", () => {
148
- const binder = createOutputBinder();
149
- const {
150
- scopes: { root },
151
- symbols: { root: rootSym, static: staticSym },
152
- } = createScopeTree(binder, {
153
- root: {
154
- symbols: {
155
- root: {
156
- flags:
157
- OutputSymbolFlags.InstanceMemberContainer |
158
- OutputSymbolFlags.StaticMemberContainer,
159
- staticMembers: {
160
- static: {
161
- flags: OutputSymbolFlags.StaticMember,
162
- },
163
- },
164
- },
165
- },
166
- },
167
- });
168
-
169
- const resolution = binder.resolveDeclarationByKey(
170
- root,
171
- undefined,
172
- staticSym.refkeys[0],
173
- );
174
- expect(resolution.value).toBeDefined();
175
- const { commonScope, pathUp, pathDown, targetDeclaration, memberPath } =
176
- resolution.value!;
177
- expect(commonScope).toBe(root);
178
- expect(targetDeclaration).toBe(rootSym);
179
- expect(pathDown).toEqual([]);
180
- expect(pathUp).toEqual([]);
181
- expect(memberPath!.map((s) => s.name)).toEqual(["root", "static"]);
182
- });
183
-
184
- it("resolves deeply nested static symbols", () => {
185
- const binder = createOutputBinder();
186
- const {
187
- scopes: { root },
188
- symbols: { root: rootSym, nested_static },
189
- } = createScopeTree(binder, {
190
- root: {
191
- symbols: {
192
- root: {
193
- flags:
194
- OutputSymbolFlags.InstanceMemberContainer |
195
- OutputSymbolFlags.StaticMemberContainer,
196
- staticMembers: {
197
- static: {
198
- flags:
199
- OutputSymbolFlags.StaticMember |
200
- OutputSymbolFlags.StaticMemberContainer,
201
- staticMembers: {
202
- nested_static: {
203
- flags: OutputSymbolFlags.StaticMember,
204
- },
205
- },
206
- },
207
- },
208
- },
209
- },
210
- },
211
- });
212
-
213
- const resolution = binder.resolveDeclarationByKey(
214
- root,
215
- undefined,
216
- nested_static.refkeys[0],
217
- );
218
- expect(resolution.value).toBeDefined();
219
- const { commonScope, pathUp, pathDown, targetDeclaration, memberPath } =
220
- resolution.value!;
221
- expect(commonScope).toBe(root);
222
- expect(targetDeclaration).toBe(rootSym);
223
- expect(pathDown).toEqual([]);
224
- expect(pathUp).toEqual([]);
225
- expect(memberPath!.map((s) => s.name)).toEqual([
226
- "root",
227
- "static",
228
- "nested_static",
229
- ]);
230
- });
231
-
232
- it("resolves static symbols lazily", () => {
233
- const staticSymRefkey = refkey();
234
-
235
- const binder = createOutputBinder();
236
- const {
237
- scopes: { root },
238
- symbols: { root: rootSym },
239
- } = createScopeTree(binder, {
240
- root: {
241
- symbols: {
242
- root: {
243
- flags:
244
- OutputSymbolFlags.InstanceMemberContainer |
245
- OutputSymbolFlags.StaticMemberContainer,
246
- },
247
- },
248
- },
249
- });
250
-
251
- const resolution = binder.resolveDeclarationByKey(
252
- root,
253
- undefined,
254
- staticSymRefkey,
255
- );
256
- expect(resolution.value).toBeUndefined();
257
- binder.createSymbol({
258
- name: "static",
259
- scope: rootSym.staticMemberScope!,
260
- refkey: staticSymRefkey,
261
- flags: OutputSymbolFlags.StaticMember,
262
- });
263
-
264
- expect(resolution.value).toBeDefined();
265
- const { commonScope, pathUp, pathDown, targetDeclaration, memberPath } =
266
- resolution.value!;
267
- expect(commonScope).toBe(root);
268
- expect(targetDeclaration).toBe(rootSym);
269
- expect(pathDown).toEqual([]);
270
- expect(pathUp).toEqual([]);
271
- expect(memberPath!.map((s) => s.name)).toEqual(["root", "static"]);
272
- });
273
- });
274
-
275
- describe("instance members", () => {
276
- it("resolves", () => {
277
- const binder = createOutputBinder();
278
- const {
279
- symbols: { root: rootSym, instance },
280
- } = createScopeTree(binder, {
281
- root: {
282
- symbols: {
283
- root: {
284
- flags: OutputSymbolFlags.InstanceMemberContainer,
285
- instanceMembers: {
286
- instance: {
287
- flags: OutputSymbolFlags.InstanceMember,
288
- },
289
- },
290
- },
291
- },
292
- },
293
- });
294
-
295
- const resolution = binder.resolveDeclarationByKey(
296
- undefined,
297
- rootSym.instanceMemberScope!,
298
- instance.refkeys[0],
299
- );
300
- expect(resolution.value).toBeDefined();
301
- const { commonScope, pathUp, pathDown, targetDeclaration, memberPath } =
302
- resolution.value!;
303
-
304
- expect(commonScope).toBe(rootSym.instanceMemberScope);
305
- expect(targetDeclaration).toBe(instance);
306
- expect(pathDown).toEqual([]);
307
- expect(pathUp).toEqual([]);
308
- expect(memberPath).toEqual([instance]);
309
- });
310
- });
311
-
312
- describe("instantiating members", () => {
313
- it("instantiates instance members", () => {
314
- const binder = createOutputBinder();
315
-
316
- /**
317
- * The following structure would match code like this:
318
- * ```ts
319
- * // A class with instance members
320
- * class Source {
321
- * instance() {
322
- * print("instance");
323
- * }
324
- * }
325
- *
326
- * // Instantiates into t
327
- * var t = new Source();
328
- *
329
- * t.instance();
330
- * ```
331
- */
332
- const {
333
- symbols: { rootSymbol, instance, instantiation },
334
- } = createScopeTree(binder, {
335
- rootScope: {
336
- symbols: {
337
- rootSymbol: {
338
- flags: OutputSymbolFlags.InstanceMemberContainer,
339
- instanceMembers: {
340
- instance: {
341
- flags: OutputSymbolFlags.InstanceMember,
342
- },
343
- },
344
- },
345
- instantiation: {},
346
- },
347
- },
348
- });
349
-
350
- binder.instantiateSymbolInto(rootSymbol, instantiation);
351
- expect(
352
- instantiation.flags & OutputSymbolFlags.StaticMemberContainer,
353
- ).toBeTruthy();
354
- expect(instantiation.staticMemberScope).toBeDefined();
355
- const expectedRefkey = refkey(
356
- instantiation.refkeys[0],
357
- instance.refkeys[0],
358
- );
359
- expect(
360
- instantiation.staticMemberScope!.symbolsByRefkey.get(expectedRefkey),
361
- ).toBeDefined();
362
- });
363
-
364
- it("doesn't duplicate symbols", () => {
365
- const binder = createOutputBinder();
366
-
367
- const {
368
- symbols: { rootSymbol, instantiation },
369
- } = createScopeTree(binder, {
370
- rootScope: {
371
- symbols: {
372
- rootSymbol: {
373
- flags: OutputSymbolFlags.InstanceMemberContainer,
374
- instanceMembers: {
375
- instance: {
376
- flags: OutputSymbolFlags.InstanceMember,
377
- },
378
- },
379
- },
380
- instantiation: {},
381
- },
382
- },
383
- });
384
-
385
- binder.instantiateSymbolInto(rootSymbol, instantiation);
386
- flushJobs();
387
- expect(instantiation.staticMemberScope!.symbols.size).toBe(1);
388
-
389
- const lateKey = refkey();
390
- // now add a brand‐new static member to source
391
- binder.createSymbol({
392
- name: "lateChild",
393
- scope: rootSymbol.instanceMemberScope!,
394
- refkey: lateKey,
395
- flags: OutputSymbolFlags.InstanceMember,
396
- });
397
-
398
- flushJobs();
399
-
400
- expect(rootSymbol.instanceMemberScope!.symbols.size).toBe(2);
401
- expect(instantiation.staticMemberScope!.symbols.size).toBe(2);
402
- });
403
-
404
- it("should remove members in instance when source deleted them", () => {
405
- const binder = createOutputBinder();
406
-
407
- const {
408
- symbols: { rootSymbol, instantiation },
409
- } = createScopeTree(binder, {
410
- rootScope: {
411
- symbols: {
412
- rootSymbol: {
413
- flags: OutputSymbolFlags.InstanceMemberContainer,
414
- instanceMembers: {
415
- instance: {
416
- flags: OutputSymbolFlags.InstanceMember,
417
- },
418
- },
419
- },
420
- instantiation: {},
421
- },
422
- },
423
- });
424
-
425
- binder.instantiateSymbolInto(rootSymbol, instantiation);
426
- expect(instantiation.staticMemberScope!.symbols.size).toBe(1);
427
-
428
- const lateKey = refkey();
429
- // now add a brand‐new static member to source
430
- binder.createSymbol({
431
- name: "lateChild",
432
- scope: rootSymbol.instanceMemberScope!,
433
- refkey: lateKey,
434
- flags: OutputSymbolFlags.InstanceMember,
435
- });
436
-
437
- flushJobs();
438
-
439
- expect(rootSymbol.instanceMemberScope!.symbols.size).toBe(2);
440
- expect(instantiation.staticMemberScope!.symbols.size).toBe(2);
441
-
442
- binder.deleteSymbol(
443
- rootSymbol.instanceMemberScope!.symbols.values().next().value!,
444
- );
445
- flushJobs();
446
- expect(rootSymbol.instanceMemberScope!.symbols.size).toBe(1);
447
- expect(instantiation.staticMemberScope!.symbols.size).toBe(1);
448
- });
449
-
450
- it("instantiates instance members added after the instantiation", () => {
451
- const binder = createOutputBinder();
452
-
453
- const {
454
- symbols: { rootSymbol, instance, instantiation },
455
- } = createScopeTree(binder, {
456
- rootScope: {
457
- symbols: {
458
- rootSymbol: {
459
- flags: OutputSymbolFlags.InstanceMemberContainer,
460
- instanceMembers: {
461
- instance: {
462
- flags: OutputSymbolFlags.InstanceMember,
463
- },
464
- },
465
- },
466
- instantiation: {},
467
- },
468
- },
469
- });
470
-
471
- binder.instantiateSymbolInto(rootSymbol, instantiation);
472
- flushJobs();
473
- expect(
474
- instantiation.flags & OutputSymbolFlags.StaticMemberContainer,
475
- ).toBeTruthy();
476
- expect(instantiation.staticMemberScope).toBeDefined();
477
- const expectedRefkey = refkey(
478
- instantiation.refkeys[0],
479
- instance.refkeys[0],
480
- );
481
- expect(
482
- instantiation.staticMemberScope!.symbolsByRefkey.get(expectedRefkey),
483
- ).toBeDefined();
484
-
485
- const newInstanceMemberRefkey = refkey();
486
- binder.createSymbol({
487
- name: "newInstanceMember",
488
- scope: rootSymbol.instanceMemberScope!,
489
- refkey: newInstanceMemberRefkey,
490
- flags: OutputSymbolFlags.InstanceMember,
491
- });
492
- const newExpectedRefkey = refkey(
493
- instantiation.refkeys[0],
494
- newInstanceMemberRefkey,
495
- );
496
- flushJobs();
497
- expect(
498
- instantiation.staticMemberScope!.symbolsByRefkey.get(newExpectedRefkey),
499
- ).toBeDefined();
500
- });
501
-
502
- it("instantiates static symbols for a static container source", () => {
503
- const binder = createOutputBinder();
504
-
505
- /**
506
- * The following structure would match code like this:
507
- * ```ts
508
- * // A class with instance members
509
- * class Source {
510
- * static child() {
511
- * print("child");
512
- * }
513
- * }
514
- *
515
- *
516
- * var printChild = Source.child;
517
- *
518
- * printChild();
519
- * ```
520
- */
521
- const {
522
- symbols: { source, child, target },
523
- } = createScopeTree(binder, {
524
- root: {
525
- symbols: {
526
- source: {
527
- flags: OutputSymbolFlags.StaticMemberContainer,
528
- staticMembers: {
529
- child: { flags: OutputSymbolFlags.StaticMember },
530
- },
531
- },
532
- target: {},
533
- },
534
- },
535
- });
536
-
537
- binder.instantiateSymbolInto(source, target);
538
-
539
- // target must now be a StaticMemberContainer too
540
- expect(target.flags & OutputSymbolFlags.StaticMemberContainer).toBeTruthy();
541
- expect(target.staticMemberScope).toBeDefined();
542
-
543
- const expectedKey = refkey(target.refkeys[0], child.refkeys[0]);
544
- expect(
545
- target.staticMemberScope!.symbolsByRefkey.get(expectedKey),
546
- ).toBeDefined();
547
- });
548
-
549
- it("instantiates static symbols added after instantiation", () => {
550
- const binder = createOutputBinder();
551
- const lateKey = refkey();
552
-
553
- const {
554
- symbols: { source, target },
555
- } = createScopeTree(binder, {
556
- root: {
557
- symbols: {
558
- source: {
559
- flags: OutputSymbolFlags.StaticMemberContainer,
560
- },
561
- target: {},
562
- },
563
- },
564
- });
565
-
566
- // hook up instantiation
567
- binder.instantiateSymbolInto(source, target);
568
-
569
- // now add a brand‐new static member to source
570
- const late = binder.createSymbol({
571
- name: "lateChild",
572
- scope: source.staticMemberScope!,
573
- refkey: lateKey,
574
- flags: OutputSymbolFlags.StaticMember,
575
- });
576
-
577
- flushJobs();
578
-
579
- // it should *automatically* show up on target.staticMemberScope
580
- const expectedKey = refkey(target.refkeys[0], late.refkeys[0]);
581
- expect(
582
- target.staticMemberScope!.symbolsByRefkey.get(expectedKey),
583
- ).toBeDefined();
584
- });
585
-
586
- it("recursively instantiates nested static members", () => {
587
- const binder = createOutputBinder();
588
-
589
- /**
590
- * The following structure would match code like this:
591
- * ```ts
592
- * class Source {
593
- * static Level1 = class {
594
- * static level2() { print("deep"); }
595
- * }
596
- * }
597
- *
598
- * var target = Source;
599
- *
600
- * target.Level1.level2()
601
- * ```
602
- */
603
- const {
604
- symbols: { source, level1, level2, target },
605
- } = createScopeTree(binder, {
606
- root: {
607
- symbols: {
608
- source: {
609
- flags: OutputSymbolFlags.StaticMemberContainer,
610
- staticMembers: {
611
- level1: {
612
- flags:
613
- OutputSymbolFlags.StaticMember |
614
- OutputSymbolFlags.StaticMemberContainer,
615
- staticMembers: {
616
- level2: { flags: OutputSymbolFlags.StaticMember },
617
- },
618
- },
619
- },
620
- },
621
- target: {},
622
- },
623
- },
624
- });
625
-
626
- binder.instantiateSymbolInto(source, target);
627
-
628
- // level1 should appear under target.staticMemberScope
629
- const key1 = refkey(target.refkeys[0], level1.refkeys[0]);
630
- const instantiated1 = target.staticMemberScope!.symbolsByRefkey.get(key1)!;
631
- expect(instantiated1.name).toBe(level1.name);
632
-
633
- // and level2 should appear under the *child* staticMemberScope of that instantiated level1
634
- const childScope = instantiated1.staticMemberScope!;
635
- const key2 = refkey(instantiated1.refkeys[0], level2.refkeys[0]);
636
- expect(childScope.symbolsByRefkey.get(key2)).toBeDefined();
637
- });
638
-
639
- it("copies both instance *and* static members when source has both flags", () => {
640
- const binder = createOutputBinder();
641
-
642
- /**
643
- * ```ts
644
- * class Source {
645
- * instance() { print("inst"); }
646
- * static s1() { print("static"); }
647
- * }
648
- *
649
- * let t = new Source()
650
- * t.instance()
651
- * t.s1()
652
- * ```
653
- */
654
- const {
655
- symbols: { source, inst },
656
- } = createScopeTree(binder, {
657
- root: {
658
- symbols: {
659
- source: {
660
- flags:
661
- OutputSymbolFlags.InstanceMemberContainer |
662
- OutputSymbolFlags.StaticMemberContainer,
663
- instanceMembers: {
664
- i1: { flags: OutputSymbolFlags.InstanceMember },
665
- },
666
- staticMembers: {
667
- s1: { flags: OutputSymbolFlags.StaticMember },
668
- },
669
- },
670
- inst: {},
671
- },
672
- },
673
- });
674
-
675
- binder.instantiateSymbolInto(source, inst);
676
-
677
- expect(inst.staticMemberScope).toBeDefined();
678
- expect(
679
- [...inst.staticMemberScope!.symbols].some((s) => s.name === "i1"),
680
- ).toBe(true);
681
-
682
- // static side
683
- const symbols = [...source.staticMemberScope!.symbols];
684
- expect(inst.staticMemberScope).toBeDefined();
685
- const sKey = refkey(inst.refkeys[0], symbols[0].refkeys[0]);
686
- expect(inst.staticMemberScope!.symbolsByRefkey.has(sKey)).toBe(true);
687
- });
688
-
689
- it("is idempotent, calling twice does not duplicate", () => {
690
- const binder = createOutputBinder();
691
- const {
692
- symbols: { source, target },
693
- } = createScopeTree(binder, {
694
- root: {
695
- symbols: {
696
- source: {
697
- flags: OutputSymbolFlags.StaticMemberContainer,
698
- staticMembers: {
699
- a: { flags: OutputSymbolFlags.StaticMember },
700
- },
701
- },
702
- target: {},
703
- },
704
- },
705
- });
706
-
707
- binder.instantiateSymbolInto(source, target);
708
- flushJobs();
709
- const initialCount = target.staticMemberScope!.symbols.size;
710
- binder.instantiateSymbolInto(source, target);
711
- flushJobs();
712
- expect(target.staticMemberScope!.symbols.size).toBe(initialCount);
713
- });
714
-
715
- it("instantiates static children of instance members under the instance scope", () => {
716
- const binder = createOutputBinder();
717
- /**
718
- * ```ts
719
- * class Source {
720
- * instM = class {
721
- * static deep() { print("deep"); }
722
- * }
723
- * }
724
- *
725
- * var t = new Source();
726
- * t.instM.deep();
727
- * ```
728
- */
729
- const {
730
- symbols: { source, deep, target },
731
- } = createScopeTree(binder, {
732
- root: {
733
- symbols: {
734
- source: {
735
- flags: OutputSymbolFlags.InstanceMemberContainer,
736
- instanceMembers: {
737
- instM: {
738
- flags:
739
- OutputSymbolFlags.InstanceMember |
740
- OutputSymbolFlags.StaticMemberContainer,
741
- staticMembers: {
742
- deep: { flags: OutputSymbolFlags.StaticMember },
743
- },
744
- },
745
- },
746
- },
747
- target: {},
748
- },
749
- },
750
- });
751
-
752
- binder.instantiateSymbolInto(source, target);
753
-
754
- // Find the instantiated copy of instM under target.instanceMemberScope
755
- const instMSym = [...target.staticMemberScope!.symbols].find(
756
- (s) => s.name === "instM",
757
- )!;
758
-
759
- // instMSym should have gotten its own staticMemberScope via the StaticMemberContainer flag
760
- expect(instMSym.staticMemberScope).toBeDefined();
761
-
762
- // compute the expected key for the deep child:
763
- // (<target>, <instM>) then (on that) (<deep original>)
764
- const expectedDeepKey = refkey(instMSym.refkeys[0], deep.refkeys[0]);
765
-
766
- expect(
767
- instMSym.staticMemberScope!.symbolsByRefkey.has(expectedDeepKey),
768
- ).toBe(true);
769
- });
770
- });
771
-
772
- describe("symbol name resolution", () => {
773
- it("resolves static symbols", () => {
774
- const binder = createOutputBinder();
775
- const {
776
- symbols: { static: staticSym },
777
- } = createScopeTree(binder, {
778
- root: {
779
- symbols: {
780
- root: {
781
- flags:
782
- OutputSymbolFlags.InstanceMemberContainer |
783
- OutputSymbolFlags.StaticMemberContainer,
784
- staticMembers: {
785
- static: {
786
- flags: OutputSymbolFlags.StaticMember,
787
- },
788
- },
789
- },
790
- },
791
- },
792
- });
793
-
794
- const result = binder.resolveFQN("root.root.static");
795
- expect(result.value).toEqual(staticSym);
796
- });
797
-
798
- it("resolves static symbols that are added later", () => {
799
- const binder = createOutputBinder();
800
- const result = binder.resolveFQN("root.root.static");
801
- expect(result.value).toBeUndefined();
802
-
803
- const {
804
- symbols: { static: staticSym },
805
- } = createScopeTree(binder, {
806
- root: {
807
- symbols: {
808
- root: {
809
- flags:
810
- OutputSymbolFlags.InstanceMemberContainer |
811
- OutputSymbolFlags.StaticMemberContainer,
812
- staticMembers: {
813
- static: {
814
- flags: OutputSymbolFlags.StaticMember,
815
- },
816
- },
817
- },
818
- },
819
- },
820
- });
821
-
822
- expect(result.value).toEqual(staticSym);
823
- });
824
-
825
- it("resolves instance symbols", () => {
826
- const binder = createOutputBinder();
827
- const {
828
- symbols: { instance },
829
- } = createScopeTree(binder, {
830
- root: {
831
- symbols: {
832
- root: {
833
- flags: OutputSymbolFlags.InstanceMemberContainer,
834
- instanceMembers: {
835
- instance: {
836
- flags: OutputSymbolFlags.InstanceMember,
837
- },
838
- },
839
- },
840
- },
841
- },
842
- });
843
-
844
- const result = binder.resolveFQN("root.root#instance");
845
- expect(result.value).toEqual(instance);
846
- });
847
-
848
- it("resolves instance symbols that are added later", () => {
849
- const binder = createOutputBinder();
850
- const result = binder.resolveFQN("root.root#instance");
851
- expect(result.value).toBeUndefined();
852
-
853
- const {
854
- symbols: { instance },
855
- } = createScopeTree(binder, {
856
- root: {
857
- symbols: {
858
- root: {
859
- flags: OutputSymbolFlags.InstanceMemberContainer,
860
- instanceMembers: {
861
- instance: {
862
- flags: OutputSymbolFlags.InstanceMember,
863
- },
864
- },
865
- },
866
- },
867
- },
868
- });
869
-
870
- expect(result.value).toEqual(instance);
871
- });
872
- });
873
-
874
- describe("refkey resolution", () => {
875
- it("resolves existing symbols by refkey", () => {
876
- const key = refkey();
877
- const binder = createOutputBinder();
878
- const sym = binder.createSymbol({
879
- name: "foo",
880
- refkey: key,
881
- scope: binder.globalScope,
882
- });
883
-
884
- const resolvedSym = binder.resolveDeclarationByKey(
885
- undefined,
886
- undefined,
887
- key,
888
- );
889
- expect(resolvedSym.value?.targetDeclaration).toBe(sym);
890
- });
891
-
892
- it("resolves symbols by refkey when symbol is added later", () => {
893
- const key = refkey();
894
- const binder = createOutputBinder();
895
-
896
- const resolvedSym = binder.resolveDeclarationByKey(
897
- undefined,
898
- undefined,
899
- key,
900
- );
901
-
902
- const sym = binder.createSymbol({
903
- name: "foo",
904
- refkey: key,
905
- scope: binder.globalScope,
906
- });
907
-
908
- expect(resolvedSym.value?.targetDeclaration).toBe(sym);
909
- });
910
-
911
- it("resolves symbols by refkey when refkey is added later", () => {
912
- const key = refkey();
913
- const binder = createOutputBinder();
914
-
915
- const resolvedSym = binder.resolveDeclarationByKey(
916
- undefined,
917
- undefined,
918
- key,
919
- );
920
-
921
- const sym = binder.createSymbol({
922
- name: "foo",
923
- scope: binder.globalScope,
924
- });
925
-
926
- expect(resolvedSym.value).toBe(undefined);
927
-
928
- sym.refkeys[0] = key;
929
- flushJobs();
930
- expect(resolvedSym.value?.targetDeclaration).toBe(sym);
931
- });
932
- });
933
-
934
- describe("Deleting symbols", () => {
935
- it("updates resolutions", () => {
936
- const key = refkey();
937
- const binder = createOutputBinder();
938
-
939
- const resolvedSym = binder.resolveDeclarationByKey(
940
- undefined,
941
- undefined,
942
- key,
943
- );
944
-
945
- const sym = binder.createSymbol({
946
- name: "foo",
947
- scope: binder.globalScope,
948
- });
949
-
950
- expect(resolvedSym.value).toBe(undefined);
951
-
952
- sym.refkeys[0] = key;
953
- flushJobs();
954
- expect(resolvedSym.value?.targetDeclaration).toBe(sym);
955
-
956
- binder.deleteSymbol(sym);
957
- flushJobs();
958
- expect(resolvedSym.value).toBe(undefined);
959
- });
960
-
961
- it("removes from parent scopes", () => {
962
- const binder = createOutputBinder();
963
- const result = binder.resolveFQN("root.root#instance");
964
- expect(result.value).toBeUndefined();
965
-
966
- const {
967
- symbols: { instance, root, staticc },
968
- scopes: { rootScope },
969
- } = createScopeTree(binder, {
970
- rootScope: {
971
- symbols: {
972
- root: {
973
- flags:
974
- OutputSymbolFlags.InstanceMemberContainer |
975
- OutputSymbolFlags.StaticMemberContainer,
976
- instanceMembers: {
977
- instance: {
978
- flags: OutputSymbolFlags.InstanceMember,
979
- },
980
- },
981
- staticMembers: {
982
- staticc: {
983
- flags: OutputSymbolFlags.StaticMember,
984
- },
985
- },
986
- },
987
- },
988
- },
989
- });
990
-
991
- const staticScope = root.staticMemberScope!;
992
- const instanceScope = root.instanceMemberScope!;
993
-
994
- expect(staticScope.symbols.size).toBe(1);
995
- binder.deleteSymbol(staticc);
996
- expect(staticScope.symbols.size).toBe(0);
997
-
998
- expect(instanceScope.symbols.size).toBe(1);
999
- binder.deleteSymbol(instance);
1000
- expect(instanceScope.symbols.size).toBe(0);
1001
-
1002
- expect(rootScope.symbols.size).toBe(1);
1003
- binder.deleteSymbol(root);
1004
- expect(rootScope.symbols.size).toBe(0);
1005
- });
1006
- });