@alloy-js/core 0.20.0-dev.4 → 0.20.0-dev.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/dist/src/binder.d.ts +62 -38
  2. package/dist/src/binder.d.ts.map +1 -1
  3. package/dist/src/binder.js +214 -173
  4. package/dist/src/components/Declaration.d.ts +2 -2
  5. package/dist/src/components/Declaration.d.ts.map +1 -1
  6. package/dist/src/components/Declaration.js +8 -2
  7. package/dist/src/components/MemberDeclaration.d.ts +2 -2
  8. package/dist/src/components/MemberDeclaration.d.ts.map +1 -1
  9. package/dist/src/components/MemberDeclaration.js +9 -5
  10. package/dist/src/components/MemberScope.d.ts +30 -13
  11. package/dist/src/components/MemberScope.d.ts.map +1 -1
  12. package/dist/src/components/MemberScope.js +37 -15
  13. package/dist/src/components/Output.d.ts.map +1 -1
  14. package/dist/src/components/Output.js +2 -5
  15. package/dist/src/components/ReferenceOrContent.d.ts +1 -1
  16. package/dist/src/components/ReferenceOrContent.d.ts.map +1 -1
  17. package/dist/src/components/Scope.d.ts +5 -5
  18. package/dist/src/components/Scope.d.ts.map +1 -1
  19. package/dist/src/components/Scope.js +9 -5
  20. package/dist/src/context/member-scope.d.ts +7 -8
  21. package/dist/src/context/member-scope.d.ts.map +1 -1
  22. package/dist/src/context/member-scope.js +5 -5
  23. package/dist/src/context/name-policy.d.ts.map +1 -1
  24. package/dist/src/context/name-policy.js +3 -0
  25. package/dist/src/context/scope.d.ts +1 -0
  26. package/dist/src/context/scope.d.ts.map +1 -1
  27. package/dist/src/context/scope.js +7 -0
  28. package/dist/src/inspect.browser.d.ts +5 -0
  29. package/dist/src/inspect.browser.d.ts.map +1 -0
  30. package/dist/src/inspect.browser.js +5 -0
  31. package/dist/src/inspect.d.ts +2 -0
  32. package/dist/src/inspect.d.ts.map +1 -0
  33. package/dist/src/inspect.js +1 -0
  34. package/dist/src/name-policy.d.ts +11 -0
  35. package/dist/src/name-policy.d.ts.map +1 -1
  36. package/dist/src/name-policy.js +3 -0
  37. package/dist/src/reactive-union-set.d.ts.map +1 -1
  38. package/dist/src/reactive-union-set.js +12 -8
  39. package/dist/src/refkey.d.ts +39 -3
  40. package/dist/src/refkey.d.ts.map +1 -1
  41. package/dist/src/refkey.js +52 -8
  42. package/dist/src/symbols/basic-scope.d.ts +14 -0
  43. package/dist/src/symbols/basic-scope.d.ts.map +1 -0
  44. package/dist/src/symbols/basic-scope.js +20 -0
  45. package/dist/src/symbols/basic-symbol.d.ts +19 -0
  46. package/dist/src/symbols/basic-symbol.d.ts.map +1 -0
  47. package/dist/src/symbols/basic-symbol.js +28 -0
  48. package/dist/src/symbols/index.d.ts +3 -1
  49. package/dist/src/symbols/index.d.ts.map +1 -1
  50. package/dist/src/symbols/index.js +3 -1
  51. package/dist/src/symbols/output-scope.d.ts +70 -41
  52. package/dist/src/symbols/output-scope.d.ts.map +1 -1
  53. package/dist/src/symbols/output-scope.js +98 -130
  54. package/dist/src/symbols/output-space.d.ts +25 -0
  55. package/dist/src/symbols/output-space.d.ts.map +1 -0
  56. package/dist/src/symbols/output-space.js +35 -0
  57. package/dist/src/symbols/output-symbol.d.ts +213 -37
  58. package/dist/src/symbols/output-symbol.d.ts.map +1 -1
  59. package/dist/src/symbols/output-symbol.js +323 -203
  60. package/dist/src/symbols/symbol-flow.d.ts +1 -1
  61. package/dist/src/symbols/symbol-flow.d.ts.map +1 -1
  62. package/dist/src/symbols/symbol-flow.js +22 -7
  63. package/dist/src/symbols/symbol-slot.d.ts +27 -9
  64. package/dist/src/symbols/symbol-slot.d.ts.map +1 -1
  65. package/dist/src/symbols/symbol-slot.js +20 -4
  66. package/dist/src/symbols/symbol-table.d.ts +19 -8
  67. package/dist/src/symbols/symbol-table.d.ts.map +1 -1
  68. package/dist/src/symbols/symbol-table.js +65 -16
  69. package/dist/src/tracer.d.ts +15 -3
  70. package/dist/src/tracer.d.ts.map +1 -1
  71. package/dist/src/tracer.js +39 -63
  72. package/dist/test/components/declaration.test.js +9 -14
  73. package/dist/test/components/reference-or-content.test.js +2 -2
  74. package/dist/test/symbols/output-scope.test.js +33 -198
  75. package/dist/test/symbols/output-symbol.test.js +139 -385
  76. package/dist/test/symbols/resolution.test.js +431 -114
  77. package/dist/test/symbols/symbol-table.test.d.ts +2 -0
  78. package/dist/test/symbols/symbol-table.test.d.ts.map +1 -0
  79. package/dist/test/symbols/symbol-table.test.js +14 -0
  80. package/dist/test/symbols/utils.d.ts +10 -24
  81. package/dist/test/symbols/utils.d.ts.map +1 -1
  82. package/dist/test/symbols/utils.js +23 -45
  83. package/dist/tsconfig.tsbuildinfo +1 -1
  84. package/package.json +4 -2
  85. package/src/binder.ts +348 -273
  86. package/src/components/Declaration.tsx +13 -3
  87. package/src/components/MemberDeclaration.tsx +15 -8
  88. package/src/components/MemberScope.tsx +61 -20
  89. package/src/components/Output.tsx +0 -4
  90. package/src/components/Scope.tsx +16 -9
  91. package/src/context/member-scope.ts +10 -10
  92. package/src/context/name-policy.ts +3 -0
  93. package/src/context/scope.ts +9 -0
  94. package/src/inspect.browser.ts +6 -0
  95. package/src/inspect.ts +1 -0
  96. package/src/name-policy.ts +14 -0
  97. package/src/reactive-union-set.ts +14 -8
  98. package/src/refkey.ts +88 -14
  99. package/src/symbols/basic-scope.ts +23 -0
  100. package/src/symbols/basic-symbol.ts +32 -0
  101. package/src/symbols/index.ts +3 -1
  102. package/src/symbols/output-scope.ts +131 -170
  103. package/src/symbols/output-space.ts +49 -0
  104. package/src/symbols/output-symbol.ts +434 -258
  105. package/src/symbols/symbol-flow.ts +38 -9
  106. package/src/symbols/symbol-slot.tsx +46 -8
  107. package/src/symbols/symbol-table.ts +95 -21
  108. package/src/tracer.ts +53 -83
  109. package/temp/api.json +5559 -3079
  110. package/test/components/declaration.test.tsx +6 -19
  111. package/test/components/reference-or-content.test.tsx +2 -2
  112. package/test/symbols/output-scope.test.ts +33 -125
  113. package/test/symbols/output-symbol.test.ts +128 -348
  114. package/test/symbols/resolution.test.ts +530 -117
  115. package/test/symbols/symbol-table.test.ts +15 -0
  116. package/test/symbols/utils.ts +38 -74
  117. package/tsdoc.json +4 -0
  118. package/dist/src/slot.d.ts +0 -15
  119. package/dist/src/slot.d.ts.map +0 -1
  120. package/dist/src/slot.js +0 -50
  121. package/dist/src/symbols/flags.d.ts +0 -70
  122. package/dist/src/symbols/flags.d.ts.map +0 -1
  123. package/dist/src/symbols/flags.js +0 -72
  124. package/dist/test/components/slot.test.d.ts +0 -2
  125. package/dist/test/components/slot.test.d.ts.map +0 -1
  126. package/dist/test/components/slot.test.js +0 -134
  127. package/src/slot.ts +0 -89
  128. package/src/symbols/flags.ts +0 -82
  129. package/test/components/slot.test.tsx +0 -174
@@ -1,170 +1,583 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { createOutputBinder, refkey } from "../../src/index.browser.js";
2
+ import { createOutputBinder } from "../../src/binder.js";
3
+ import { memberRefkey, refkey } from "../../src/refkey.js";
3
4
  import { flushJobs } from "../../src/scheduler.js";
4
- import { OutputSymbolFlags } from "../../src/symbols/flags.js";
5
- import { OutputSymbol } from "../../src/symbols/output-symbol.js";
6
- import { createScopeTree } from "./utils.js";
5
+ import { BasicScope } from "../../src/symbols/basic-scope.js";
6
+ import { BasicSymbol } from "../../src/symbols/basic-symbol.js";
7
+ import { binder, createScope, createSymbol } from "./utils.js";
7
8
 
8
- describe("Symbol name resolution", () => {
9
- it("resolves static symbols", () => {
9
+ describe("dynamic refkey resolution", () => {
10
+ it("resolves symbols by refkey when symbol is added later", () => {
11
+ const key = refkey();
10
12
  const binder = createOutputBinder();
11
- const {
12
- symbols: { static: staticSym },
13
- } = createScopeTree(binder, {
14
- root: {
15
- symbols: {
16
- root: {
17
- flags:
18
- OutputSymbolFlags.InstanceMemberContainer |
19
- OutputSymbolFlags.StaticMemberContainer,
20
- staticMembers: {
21
- static: {
22
- flags: OutputSymbolFlags.StaticMember,
23
- },
24
- },
25
- },
26
- },
27
- },
13
+ const scope = new BasicScope("global", undefined);
14
+
15
+ const resolvedSym = binder.resolveDeclarationByKey(undefined, key);
16
+
17
+ const sym = new BasicSymbol("foo", scope.symbols, {
18
+ binder,
19
+ refkeys: [key],
28
20
  });
29
21
 
30
- const result = binder.resolveFQN("root.root.static");
31
- expect(result.value).toEqual(staticSym);
22
+ expect(resolvedSym.value?.symbol).toBe(sym);
32
23
  });
33
24
 
34
- it("resolves static symbols that are added later", () => {
25
+ it("handles deleted symbols by updating resolutions", () => {
26
+ const key = refkey();
35
27
  const binder = createOutputBinder();
36
- const result = binder.resolveFQN("root.root.static");
37
- expect(result.value).toBeUndefined();
38
-
39
- const {
40
- symbols: { static: staticSym },
41
- } = createScopeTree(binder, {
42
- root: {
43
- symbols: {
44
- root: {
45
- flags:
46
- OutputSymbolFlags.InstanceMemberContainer |
47
- OutputSymbolFlags.StaticMemberContainer,
48
- staticMembers: {
49
- static: {
50
- flags: OutputSymbolFlags.StaticMember,
51
- },
52
- },
53
- },
54
- },
55
- },
28
+
29
+ const resolvedSym = binder.resolveDeclarationByKey(undefined, key);
30
+ const scope = new BasicScope("global", undefined);
31
+ const sym = new BasicSymbol("foo", scope.symbols, {
32
+ binder,
33
+ refkeys: [key],
56
34
  });
57
35
 
58
- expect(result.value).toEqual(staticSym);
36
+ flushJobs();
37
+ expect(resolvedSym.value?.symbol).toBe(sym);
38
+
39
+ sym.delete();
40
+ flushJobs();
41
+ expect(resolvedSym.value).toBe(undefined);
59
42
  });
43
+ });
60
44
 
61
- it("resolves instance symbols", () => {
45
+ describe("resolving lexical declarations by refkey", () => {
46
+ it("from the same scope", () => {
47
+ const key = refkey();
62
48
  const binder = createOutputBinder();
63
- const {
64
- symbols: { instance },
65
- } = createScopeTree(binder, {
66
- root: {
67
- symbols: {
68
- root: {
69
- flags: OutputSymbolFlags.InstanceMemberContainer,
70
- instanceMembers: {
71
- instance: {
72
- flags: OutputSymbolFlags.InstanceMember,
73
- },
74
- },
75
- },
76
- },
77
- },
49
+ const scope = new BasicScope("global", undefined);
50
+ const sym = new BasicSymbol("foo", scope.symbols, {
51
+ binder,
52
+ refkeys: [key],
78
53
  });
79
54
 
80
- const result = binder.resolveFQN("root.root#instance");
81
- expect(result.value).toEqual(instance);
55
+ const result = binder.resolveDeclarationByKey(scope, key).value!;
56
+
57
+ expect(result.symbol).toBe(sym);
58
+ expect(result.commonScope).toBe(scope);
59
+ expect(result.lexicalDeclaration).toBe(sym);
60
+ expect(result.pathDown).toEqual([]);
61
+ expect(result.pathUp).toEqual([]);
62
+ expect(result.memberPath).toEqual([]);
63
+ expect(result.fullReferencePath).toEqual([scope]);
64
+ expect(result.fullSymbolPath).toEqual([scope]);
82
65
  });
83
66
 
84
- it("resolves instance symbols that are added later", () => {
67
+ it("from a different scope for the same member", () => {
68
+ const key = refkey();
85
69
  const binder = createOutputBinder();
86
- const result = binder.resolveFQN("root.root#instance");
87
- expect(result.value).toBeUndefined();
88
-
89
- const {
90
- symbols: { instance },
91
- } = createScopeTree(binder, {
92
- root: {
93
- symbols: {
94
- root: {
95
- flags: OutputSymbolFlags.InstanceMemberContainer,
96
- instanceMembers: {
97
- instance: {
98
- flags: OutputSymbolFlags.InstanceMember,
99
- },
100
- },
101
- },
102
- },
103
- },
70
+ const globalSym = new BasicSymbol("global", undefined, { binder });
71
+ const scope = new BasicScope("global", undefined, {
72
+ binder,
73
+ ownerSymbol: globalSym,
74
+ });
75
+
76
+ const sym = new BasicSymbol("foo", scope.symbols, {
77
+ binder,
78
+ refkeys: [key],
79
+ });
80
+
81
+ const resolveScope = new BasicScope("other global", undefined, {
82
+ binder,
83
+ ownerSymbol: globalSym,
84
+ });
85
+ const result = binder.resolveDeclarationByKey(resolveScope, key).value!;
86
+
87
+ expect(result.symbol).toBe(sym);
88
+ expect(result.commonScope).toBe(resolveScope);
89
+ expect(result.lexicalDeclaration).toBe(sym);
90
+ expect(result.pathDown).toEqual([]);
91
+ expect(result.pathUp).toEqual([]);
92
+ expect(result.memberPath).toEqual([]);
93
+ expect(result.fullReferencePath).toEqual([scope]);
94
+ expect(result.fullSymbolPath).toEqual([scope]);
95
+ });
96
+
97
+ it("from a parent scope", () => {
98
+ const key = refkey();
99
+ const binder = createOutputBinder();
100
+ const scope = new BasicScope("global", undefined);
101
+ const childScope = new BasicScope("child", scope);
102
+ const sym = new BasicSymbol("foo", childScope.symbols, {
103
+ binder,
104
+ refkeys: [key],
105
+ });
106
+
107
+ const result = binder.resolveDeclarationByKey(scope, key).value!;
108
+
109
+ expect(result.symbol).toBe(sym);
110
+ expect(result.commonScope).toBe(scope);
111
+ expect(result.lexicalDeclaration).toBe(sym);
112
+ expect(result.pathDown).toEqual([childScope]);
113
+ expect(result.pathUp).toEqual([]);
114
+ expect(result.memberPath).toEqual([]);
115
+ expect(result.fullReferencePath).toEqual([scope]);
116
+ expect(result.fullSymbolPath).toEqual([scope, childScope]);
117
+ });
118
+
119
+ it("from a parent scope for the same member", () => {
120
+ const key = refkey();
121
+ const binder = createOutputBinder();
122
+ const globalSym = new BasicSymbol("global", undefined, { binder });
123
+ const scope = new BasicScope("global", undefined, {
124
+ ownerSymbol: globalSym,
125
+ });
126
+ const childScope = new BasicScope("child", scope);
127
+ const sym = new BasicSymbol("foo", childScope.symbols, {
128
+ binder,
129
+ refkeys: [key],
130
+ });
131
+
132
+ const referenceScope = new BasicScope("otherGlobal global", undefined, {
133
+ ownerSymbol: globalSym,
134
+ });
135
+ const result = binder.resolveDeclarationByKey(referenceScope, key).value!;
136
+
137
+ expect(result.symbol).toBe(sym);
138
+ expect(result.commonScope).toBe(referenceScope);
139
+ expect(result.lexicalDeclaration).toBe(sym);
140
+ expect(result.pathDown).toEqual([childScope]);
141
+ expect(result.pathUp).toEqual([]);
142
+ expect(result.memberPath).toEqual([]);
143
+ expect(result.fullReferencePath).toEqual([scope]);
144
+ expect(result.fullSymbolPath).toEqual([scope, childScope]);
145
+ });
146
+
147
+ it("from a child scope", () => {
148
+ const key = refkey();
149
+ const binder = createOutputBinder();
150
+ const scope = new BasicScope("global", undefined);
151
+ const childScope = new BasicScope("child", scope);
152
+ const sym = new BasicSymbol("foo", scope.symbols, {
153
+ binder,
154
+ refkeys: [key],
155
+ });
156
+
157
+ const result = binder.resolveDeclarationByKey(childScope, key).value!;
158
+
159
+ expect(result.symbol).toBe(sym);
160
+ expect(result.lexicalDeclaration).toBe(sym);
161
+ expect(result.commonScope).toBe(scope);
162
+ expect(result.pathDown).toEqual([]);
163
+ expect(result.pathUp).toEqual([childScope]);
164
+ expect(result.memberPath).toEqual([]);
165
+ expect(result.fullReferencePath).toEqual([scope, childScope]);
166
+ expect(result.fullSymbolPath).toEqual([scope]);
167
+ });
168
+
169
+ it("from a different child scope for the same member", () => {
170
+ const key = refkey();
171
+ const binder = createOutputBinder();
172
+ const globalSym = new BasicSymbol("global", undefined, { binder });
173
+ const scope = new BasicScope("global", undefined, {
174
+ ownerSymbol: globalSym,
175
+ });
176
+ const otherGlobalScope = new BasicScope("other global", undefined, {
177
+ ownerSymbol: globalSym,
178
+ });
179
+ const childMember = new BasicSymbol("child", scope.symbols);
180
+ const childScope = new BasicScope("child", otherGlobalScope, {
181
+ ownerSymbol: childMember,
182
+ });
183
+ const sym = new BasicSymbol("foo", scope.symbols, {
184
+ binder,
185
+ refkeys: [key],
186
+ });
187
+
188
+ const result = binder.resolveDeclarationByKey(childScope, key).value!;
189
+
190
+ expect(result.symbol).toBe(sym);
191
+ expect(result.lexicalDeclaration).toBe(sym);
192
+ expect(result.commonScope).toBe(otherGlobalScope);
193
+ expect(result.pathDown).toEqual([]);
194
+ expect(result.pathUp).toEqual([childScope]);
195
+ expect(result.memberPath).toEqual([]);
196
+ expect(result.fullReferencePath).toEqual([scope, childScope]);
197
+ expect(result.fullSymbolPath).toEqual([scope]);
198
+ });
199
+ it("from a different child scope for the same member with a different root scope", () => {
200
+ const key = refkey();
201
+ const binder = createOutputBinder();
202
+ const rootRefScope = new BasicScope("root", undefined, { binder });
203
+ const globalSym = new BasicSymbol("global", undefined, { binder });
204
+ const scope = new BasicScope("global", undefined, {
205
+ ownerSymbol: globalSym,
206
+ });
207
+ const otherGlobalScope = new BasicScope("other global", rootRefScope, {
208
+ ownerSymbol: globalSym,
209
+ });
210
+ const childMember = new BasicSymbol("child", scope.symbols);
211
+ const childScope = new BasicScope("child", otherGlobalScope, {
212
+ ownerSymbol: childMember,
213
+ });
214
+ const sym = new BasicSymbol("foo", scope.symbols, {
215
+ binder,
216
+ refkeys: [key],
217
+ });
218
+
219
+ const result = binder.resolveDeclarationByKey(childScope, key).value!;
220
+
221
+ expect(result.symbol).toBe(sym);
222
+ expect(result.lexicalDeclaration).toBe(sym);
223
+ expect(result.commonScope).toBe(otherGlobalScope);
224
+ expect(result.pathDown).toEqual([]);
225
+ expect(result.pathUp).toEqual([childScope]);
226
+ expect(result.memberPath).toEqual([]);
227
+ expect(result.fullReferencePath).toEqual([rootRefScope, scope, childScope]);
228
+ expect(result.fullSymbolPath).toEqual([rootRefScope, scope]);
229
+ });
230
+ it("from a parallel scope", () => {
231
+ const key = refkey();
232
+ const binder = createOutputBinder();
233
+ const scope = new BasicScope("global", undefined);
234
+ const childScope1 = new BasicScope("child", scope);
235
+ const childScope2 = new BasicScope("child2", scope);
236
+
237
+ const sym = new BasicSymbol("foo", childScope1.symbols, {
238
+ binder,
239
+ refkeys: [key],
104
240
  });
105
241
 
106
- expect(result.value).toEqual(instance);
242
+ const result = binder.resolveDeclarationByKey(childScope2, key).value!;
243
+
244
+ expect(result.symbol).toBe(sym);
245
+ expect(result.lexicalDeclaration).toBe(sym);
246
+ expect(result.pathDown).toEqual([childScope1]);
247
+ expect(result.pathUp).toEqual([childScope2]);
248
+ expect(result.commonScope).toBe(scope);
249
+ expect(result.memberPath).toEqual([]);
250
+ expect(result.fullReferencePath).toEqual([scope, childScope2]);
251
+ expect(result.fullSymbolPath).toEqual([scope, childScope1]);
107
252
  });
253
+
254
+ it("from a member scope", () => {
255
+ const key = refkey();
256
+ const binder = createOutputBinder();
257
+ const globalScope = new BasicScope("global", undefined, { binder });
258
+ const object = new BasicSymbol("object", globalScope.symbols, {
259
+ binder,
260
+ refkeys: key,
261
+ });
262
+ const memberScope = new BasicScope("object members", globalScope, {
263
+ binder,
264
+ ownerSymbol: object,
265
+ });
266
+
267
+ const result = binder.resolveDeclarationByKey(memberScope, key).value!;
268
+
269
+ expect(result.symbol).toBe(object);
270
+ expect(result.lexicalDeclaration).toBe(object);
271
+ expect(result.commonScope).toBe(globalScope);
272
+ expect(result.pathDown).toEqual([]);
273
+ expect(result.pathUp).toEqual([memberScope]);
274
+ expect(result.memberPath).toEqual([]);
275
+ expect(result.fullReferencePath).toEqual([globalScope, memberScope]);
276
+ expect(result.fullSymbolPath).toEqual([globalScope]);
277
+ });
278
+
279
+ it("from another scope for the same member", () => {});
108
280
  });
109
281
 
110
- describe("refkey resolution", () => {
111
- it("resolves existing symbols by refkey", () => {
282
+ describe("resolving members by refkey", () => {
283
+ it("simple member", () => {
112
284
  const key = refkey();
113
285
  const binder = createOutputBinder();
114
- const sym = new OutputSymbol("foo", {
286
+ const globalScope = new BasicScope("global", undefined, { binder });
287
+ const foo = new BasicSymbol("foo", globalScope.symbols, {
288
+ binder,
289
+ });
290
+
291
+ const bar = new BasicSymbol("bar", foo.staticMembers, {
115
292
  binder,
116
- scope: binder.globalScope,
117
293
  refkeys: [key],
118
294
  });
119
295
 
120
- const resolvedSym = binder.resolveDeclarationByKey(
121
- undefined,
122
- undefined,
123
- key,
124
- );
125
- expect(resolvedSym.value?.targetDeclaration).toBe(sym);
296
+ const result = binder.resolveDeclarationByKey(globalScope, key).value!;
297
+
298
+ // we successfully resolve the symbol, so:
299
+ expect(result.symbol).toBe(bar);
300
+
301
+ // the member is off of a declaration in our current scope, so:
302
+ expect(result.commonScope).toBe(globalScope);
303
+ expect(result.pathUp.length).toBe(0);
304
+ expect(result.pathDown.length).toBe(0);
305
+
306
+ // the declaration symbol carrying the resolved member is:
307
+ expect(result.lexicalDeclaration).toBe(foo);
308
+
309
+ // the path to the resolved symbol is
310
+ expect(result.memberPath).toEqual([bar]);
311
+ expect(result.fullReferencePath).toEqual([globalScope]);
312
+ expect(result.fullSymbolPath).toEqual([globalScope]);
126
313
  });
127
314
 
128
- it("resolves symbols by refkey when symbol is added later", () => {
315
+ it("nested members", () => {
129
316
  const key = refkey();
130
317
  const binder = createOutputBinder();
318
+ const globalScope = new BasicScope("global", undefined, { binder });
319
+ const foo = new BasicSymbol("foo", globalScope.symbols, {
320
+ binder,
321
+ });
131
322
 
132
- const resolvedSym = binder.resolveDeclarationByKey(
133
- undefined,
134
- undefined,
135
- key,
136
- );
323
+ const bar = new BasicSymbol("bar", foo.staticMembers, {
324
+ binder,
325
+ });
137
326
 
138
- const sym = new OutputSymbol("foo", {
327
+ const baz = new BasicSymbol("baz", bar.staticMembers, {
139
328
  binder,
140
- scope: binder.globalScope,
141
329
  refkeys: [key],
142
330
  });
143
331
 
144
- expect(resolvedSym.value?.targetDeclaration).toBe(sym);
332
+ const result = binder.resolveDeclarationByKey(globalScope, key).value!;
333
+
334
+ expect(result.symbol).toBe(baz);
335
+ expect(result.commonScope).toBe(globalScope);
336
+ expect(result.pathUp.length).toBe(0);
337
+ expect(result.pathDown.length).toBe(0);
338
+ expect(result.lexicalDeclaration).toBe(foo);
339
+ expect(result.memberPath).toEqual([bar, baz]);
340
+ expect(result.fullReferencePath).toEqual([globalScope]);
341
+ expect(result.fullSymbolPath).toEqual([globalScope]);
145
342
  });
146
343
 
147
- it("handles deleted symbols by updating resolutions", () => {
344
+ it("nested members, while declaring a neighboring member", () => {
148
345
  const key = refkey();
149
346
  const binder = createOutputBinder();
347
+ const globalScope = new BasicScope("global", undefined, { binder });
348
+ const foo = new BasicSymbol("foo", globalScope.symbols, {
349
+ binder,
350
+ });
150
351
 
151
- const resolvedSym = binder.resolveDeclarationByKey(
152
- undefined,
153
- undefined,
154
- key,
155
- );
352
+ const fooMemberScope = new BasicScope("foo members", globalScope, {
353
+ ownerSymbol: foo,
354
+ });
156
355
 
157
- const sym = new OutputSymbol("foo", {
356
+ const bar = new BasicSymbol("bar", foo.staticMembers, {
357
+ binder,
358
+ });
359
+
360
+ const barMemberScope = new BasicScope("bar members", fooMemberScope, {
361
+ ownerSymbol: bar,
362
+ });
363
+
364
+ const baz = new BasicSymbol("baz", bar.staticMembers, {
158
365
  binder,
159
- scope: binder.globalScope,
160
366
  refkeys: [key],
161
367
  });
162
368
 
163
- flushJobs();
164
- expect(resolvedSym.value?.targetDeclaration).toBe(sym);
369
+ const result = binder.resolveDeclarationByKey(barMemberScope, key).value!;
165
370
 
166
- sym.delete();
167
- flushJobs();
168
- expect(resolvedSym.value).toBe(undefined);
371
+ expect(result.symbol).toBe(baz);
372
+ expect(result.commonScope).toBe(barMemberScope);
373
+ expect(result.pathUp.length).toBe(0);
374
+ expect(result.pathDown.length).toBe(0);
375
+ expect(result.lexicalDeclaration).toBe(baz);
376
+ expect(result.memberPath).toEqual([]);
377
+ expect(result.fullReferencePath).toEqual([
378
+ globalScope,
379
+ fooMemberScope,
380
+ barMemberScope,
381
+ ]);
382
+ expect(result.fullSymbolPath).toEqual([
383
+ globalScope,
384
+ fooMemberScope,
385
+ barMemberScope,
386
+ ]);
387
+ });
388
+
389
+ it("nested members, while declaring a neighboring nested member", () => {
390
+ const globalScope = createScope("global");
391
+ const [foo] = createSymbol("foo", globalScope);
392
+ const fooMemberScope = createScope("foo members", globalScope, {
393
+ ownerSymbol: foo,
394
+ });
395
+ const [bar] = createSymbol("bar", foo.staticMembers);
396
+ const barMemberScope = createScope("bar members", fooMemberScope, {
397
+ ownerSymbol: bar,
398
+ });
399
+ const [baz, bazKey] = createSymbol("baz", bar.staticMembers);
400
+ const bazMemberScope = createScope("baz members", barMemberScope, {
401
+ ownerSymbol: baz,
402
+ });
403
+ createSymbol("otherBaz", bar.staticMembers);
404
+
405
+ const result = binder.resolveDeclarationByKey(
406
+ bazMemberScope,
407
+ bazKey,
408
+ ).value!;
409
+
410
+ expect(result.symbol).toBe(baz);
411
+ expect(result.commonScope).toBe(barMemberScope);
412
+ expect(result.pathUp).toEqual([bazMemberScope]);
413
+ expect(result.pathDown.length).toBe(0);
414
+ expect(result.lexicalDeclaration).toBe(baz);
415
+ expect(result.memberPath).toEqual([]);
416
+ expect(result.fullReferencePath).toEqual([
417
+ globalScope,
418
+ fooMemberScope,
419
+ barMemberScope,
420
+ bazMemberScope,
421
+ ]);
422
+ expect(result.fullSymbolPath).toEqual([
423
+ globalScope,
424
+ fooMemberScope,
425
+ barMemberScope,
426
+ ]);
427
+ });
428
+ });
429
+
430
+ describe("resolving type members by refkey", () => {
431
+ it("simple member", () => {
432
+ const globalScope = createScope("global");
433
+ const [typeSymbol, typeKey] = createSymbol("MyType", globalScope);
434
+ const [staticProp, staticKey] = createSymbol(
435
+ "staticProp",
436
+ typeSymbol.staticMembers,
437
+ );
438
+
439
+ // resolve a member of type
440
+ const result = binder.resolveDeclarationByKey(
441
+ globalScope,
442
+ memberRefkey(typeKey, staticKey),
443
+ ).value!;
444
+
445
+ expect(result.symbol).toBe(staticProp);
446
+ expect(result.lexicalDeclaration).toBe(typeSymbol);
447
+ expect(result.memberPath).toEqual([staticProp]);
448
+ });
449
+
450
+ it("nested member", () => {
451
+ const globalScope = createScope("global");
452
+ const [typeSymbol, typeKey] = createSymbol("MyType", globalScope);
453
+ const [staticProp, staticPropKey] = createSymbol(
454
+ "staticProp",
455
+ typeSymbol.staticMembers,
456
+ );
457
+ const [nestedProp, nestedKey] = createSymbol(
458
+ "nestedProp",
459
+ staticProp.staticMembers,
460
+ );
461
+
462
+ // resolve a member of type directly
463
+ const result = binder.resolveDeclarationByKey(
464
+ globalScope,
465
+ memberRefkey(staticPropKey, nestedKey),
466
+ ).value!;
467
+
468
+ expect(result.symbol).toBe(nestedProp);
469
+ expect(result.lexicalDeclaration).toBe(typeSymbol);
470
+ expect(result.memberPath).toEqual([staticProp, nestedProp]);
471
+
472
+ // resolve from a member refkey
473
+ const result2 = binder.resolveDeclarationByKey(
474
+ globalScope,
475
+ memberRefkey(memberRefkey(typeKey, staticPropKey), nestedKey),
476
+ ).value!;
477
+
478
+ expect(result2.symbol).toBe(nestedProp);
479
+ expect(result2.lexicalDeclaration).toBe(typeSymbol);
480
+ expect(result2.memberPath).toEqual([staticProp, nestedProp]);
481
+ });
482
+
483
+ it("member of type", () => {
484
+ const globalScope = createScope("global");
485
+ const [typeSymbol] = createSymbol("MyType", globalScope);
486
+ const [staticProp, staticKey] = createSymbol(
487
+ "staticProp",
488
+ typeSymbol.staticMembers,
489
+ );
490
+
491
+ const [value, valueKey] = createSymbol("myValue", globalScope, {
492
+ type: typeSymbol,
493
+ });
494
+
495
+ // resolve a member of type
496
+ const result = binder.resolveDeclarationByKey(
497
+ globalScope,
498
+ memberRefkey(valueKey, staticKey),
499
+ ).value!;
500
+
501
+ expect(result.symbol).toBe(staticProp);
502
+ expect(result.lexicalDeclaration).toBe(value);
503
+ expect(result.memberPath).toEqual([staticProp]);
504
+ });
505
+
506
+ it("nested member of type", () => {
507
+ const globalScope = createScope("global");
508
+ const [typeSymbol] = createSymbol("MyType", globalScope);
509
+ const [staticProp, staticKey] = createSymbol(
510
+ "staticProp",
511
+ typeSymbol.staticMembers,
512
+ );
513
+ const [nestedProp, nestedKey] = createSymbol(
514
+ "nestedProp",
515
+ staticProp.staticMembers,
516
+ );
517
+
518
+ const [value, valueKey] = createSymbol("myValue", globalScope, {
519
+ type: typeSymbol,
520
+ });
521
+
522
+ // resolve a member of type
523
+ const result = binder.resolveDeclarationByKey(
524
+ globalScope,
525
+ memberRefkey(memberRefkey(valueKey, staticKey), nestedKey),
526
+ ).value!;
527
+
528
+ expect(result.symbol).toBe(nestedProp);
529
+ expect(result.lexicalDeclaration).toBe(value);
530
+ expect(result.memberPath).toEqual([staticProp, nestedProp]);
531
+ });
532
+
533
+ it("nested member of nested type", () => {
534
+ const globalScope = createScope("global");
535
+ const [typeSymbol] = createSymbol("MyType", globalScope);
536
+ const [staticProp, staticKey] = createSymbol(
537
+ "staticProp",
538
+ typeSymbol.staticMembers,
539
+ );
540
+ const [nestedProp, nestedKey] = createSymbol(
541
+ "nestedProp",
542
+ staticProp.staticMembers,
543
+ );
544
+
545
+ const [value, valueKey] = createSymbol("myValue", globalScope);
546
+ const [regularProp, regularPropKey] = createSymbol(
547
+ "regularProp",
548
+ value.staticMembers,
549
+ {
550
+ type: typeSymbol,
551
+ },
552
+ );
553
+
554
+ // resolve a member of type
555
+ const result = binder.resolveDeclarationByKey(
556
+ globalScope,
557
+ memberRefkey(
558
+ memberRefkey(memberRefkey(valueKey, regularPropKey), staticKey),
559
+ nestedKey,
560
+ ),
561
+ ).value!;
562
+
563
+ expect(result.symbol).toBe(nestedProp);
564
+ expect(result.lexicalDeclaration).toBe(value);
565
+ expect(result.memberPath).toEqual([regularProp, staticProp, nestedProp]);
566
+ });
567
+
568
+ it("throws an error when resolving something that isn't a member", () => {
569
+ const globalScope = createScope("global");
570
+ const [typeSymbol] = createSymbol("MyType", globalScope);
571
+ const [, ts2Key] = createSymbol("MyType2", globalScope);
572
+ const [, staticKey] = createSymbol("staticProp", typeSymbol.staticMembers);
573
+
574
+ expect(() => {
575
+ const result = binder.resolveDeclarationByKey(
576
+ globalScope,
577
+ memberRefkey(ts2Key, staticKey),
578
+ );
579
+
580
+ return result.value; // force evaluation
581
+ }).toThrow(/is not a member/);
169
582
  });
170
583
  });