@alloy-js/core 0.11.0 → 0.13.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.
- package/CHANGELOG.md +22 -0
- package/dist/src/binder.d.ts.map +1 -1
- package/dist/src/binder.js +79 -22
- package/dist/src/components/For.d.ts +1 -1
- package/dist/src/components/For.d.ts.map +1 -1
- package/dist/src/jsx-runtime.d.ts.map +1 -1
- package/dist/src/jsx-runtime.js +9 -3
- package/dist/src/render.d.ts.map +1 -1
- package/dist/src/render.js +5 -0
- package/dist/src/scheduler.d.ts +8 -0
- package/dist/src/scheduler.d.ts.map +1 -0
- package/dist/src/scheduler.js +17 -0
- package/dist/test/components/declaration.test.js +2 -0
- package/dist/test/control-flow/for.test.js +36 -2
- package/dist/test/reactivity/circular-reactives.test.d.ts +2 -0
- package/dist/test/reactivity/circular-reactives.test.d.ts.map +1 -0
- package/dist/test/reactivity/circular-reactives.test.js +31 -0
- package/dist/test/reactivity/cleanup.test.js +5 -0
- package/dist/test/reactivity/untrack.test.js +3 -0
- package/dist/test/rendering/memoization.test.js +2 -0
- package/dist/test/symbols.test.js +391 -11
- package/dist/test/utils.test.d.ts.map +1 -1
- package/dist/test/utils.test.js +2 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/binder.ts +116 -22
- package/src/components/For.tsx +4 -4
- package/src/jsx-runtime.ts +22 -12
- package/src/render.ts +5 -0
- package/src/scheduler.ts +24 -0
- package/temp/api.json +8 -8
- package/test/components/declaration.test.tsx +2 -0
- package/test/components/list.test.tsx +0 -1
- package/test/control-flow/for.test.tsx +34 -4
- package/test/reactivity/circular-reactives.test.tsx +32 -0
- package/test/reactivity/cleanup.test.tsx +5 -0
- package/test/reactivity/untrack.test.ts +3 -0
- package/test/rendering/memoization.test.tsx +2 -0
- package/test/symbols.test.ts +401 -13
- package/test/utils.test.tsx +2 -0
package/test/symbols.test.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
OutputSymbolFlags,
|
|
9
9
|
} from "../src/binder.js";
|
|
10
10
|
import { Refkey, refkey } from "../src/refkey.js";
|
|
11
|
+
import { flushJobs } from "../src/scheduler.js";
|
|
11
12
|
|
|
12
13
|
it("works", () => {
|
|
13
14
|
const binder = createOutputBinder();
|
|
@@ -22,10 +23,11 @@ it("works", () => {
|
|
|
22
23
|
scope,
|
|
23
24
|
});
|
|
24
25
|
|
|
26
|
+
flushJobs();
|
|
25
27
|
expect([...scope.getSymbolNames()]).toEqual(["sym"]);
|
|
26
28
|
|
|
27
29
|
symbol.name = "bar";
|
|
28
|
-
|
|
30
|
+
flushJobs();
|
|
29
31
|
expect([...scope.getSymbolNames()]).toEqual(["bar"]);
|
|
30
32
|
});
|
|
31
33
|
|
|
@@ -47,7 +49,16 @@ it("resolves symbol conflicts", () => {
|
|
|
47
49
|
scope,
|
|
48
50
|
});
|
|
49
51
|
|
|
52
|
+
const s3 = binder.createSymbol({
|
|
53
|
+
name: "sym",
|
|
54
|
+
scope,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
flushJobs();
|
|
58
|
+
|
|
59
|
+
expect(_s1.name).toEqual("sym");
|
|
50
60
|
expect(s2.name).toEqual("sym_2");
|
|
61
|
+
expect(s3.name).toEqual("sym_3");
|
|
51
62
|
});
|
|
52
63
|
|
|
53
64
|
type ScopeRecords = Record<string, ScopeDescriptor>;
|
|
@@ -299,8 +310,25 @@ describe("instance members", () => {
|
|
|
299
310
|
});
|
|
300
311
|
|
|
301
312
|
describe("instantiating members", () => {
|
|
302
|
-
it("instantiates
|
|
313
|
+
it("instantiates instance members", () => {
|
|
303
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
|
+
*/
|
|
304
332
|
const {
|
|
305
333
|
symbols: { rootSymbol, instance, instantiation },
|
|
306
334
|
} = createScopeTree(binder, {
|
|
@@ -310,7 +338,7 @@ describe("instantiating members", () => {
|
|
|
310
338
|
flags: OutputSymbolFlags.InstanceMemberContainer,
|
|
311
339
|
instanceMembers: {
|
|
312
340
|
instance: {
|
|
313
|
-
flags: OutputSymbolFlags.
|
|
341
|
+
flags: OutputSymbolFlags.InstanceMember,
|
|
314
342
|
},
|
|
315
343
|
},
|
|
316
344
|
},
|
|
@@ -321,20 +349,107 @@ describe("instantiating members", () => {
|
|
|
321
349
|
|
|
322
350
|
binder.instantiateSymbolInto(rootSymbol, instantiation);
|
|
323
351
|
expect(
|
|
324
|
-
instantiation.flags & OutputSymbolFlags.
|
|
352
|
+
instantiation.flags & OutputSymbolFlags.StaticMemberContainer,
|
|
325
353
|
).toBeTruthy();
|
|
326
|
-
expect(instantiation.
|
|
354
|
+
expect(instantiation.staticMemberScope).toBeDefined();
|
|
327
355
|
const expectedRefkey = refkey(
|
|
328
356
|
instantiation.refkeys[0],
|
|
329
357
|
instance.refkeys[0],
|
|
330
358
|
);
|
|
331
359
|
expect(
|
|
332
|
-
instantiation.
|
|
360
|
+
instantiation.staticMemberScope!.symbolsByRefkey.get(expectedRefkey),
|
|
333
361
|
).toBeDefined();
|
|
334
362
|
});
|
|
335
363
|
|
|
336
|
-
it("
|
|
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", () => {
|
|
337
451
|
const binder = createOutputBinder();
|
|
452
|
+
|
|
338
453
|
const {
|
|
339
454
|
symbols: { rootSymbol, instance, instantiation },
|
|
340
455
|
} = createScopeTree(binder, {
|
|
@@ -344,7 +459,7 @@ describe("instantiating members", () => {
|
|
|
344
459
|
flags: OutputSymbolFlags.InstanceMemberContainer,
|
|
345
460
|
instanceMembers: {
|
|
346
461
|
instance: {
|
|
347
|
-
flags: OutputSymbolFlags.
|
|
462
|
+
flags: OutputSymbolFlags.InstanceMember,
|
|
348
463
|
},
|
|
349
464
|
},
|
|
350
465
|
},
|
|
@@ -354,16 +469,17 @@ describe("instantiating members", () => {
|
|
|
354
469
|
});
|
|
355
470
|
|
|
356
471
|
binder.instantiateSymbolInto(rootSymbol, instantiation);
|
|
472
|
+
flushJobs();
|
|
357
473
|
expect(
|
|
358
|
-
instantiation.flags & OutputSymbolFlags.
|
|
474
|
+
instantiation.flags & OutputSymbolFlags.StaticMemberContainer,
|
|
359
475
|
).toBeTruthy();
|
|
360
|
-
expect(instantiation.
|
|
476
|
+
expect(instantiation.staticMemberScope).toBeDefined();
|
|
361
477
|
const expectedRefkey = refkey(
|
|
362
478
|
instantiation.refkeys[0],
|
|
363
479
|
instance.refkeys[0],
|
|
364
480
|
);
|
|
365
481
|
expect(
|
|
366
|
-
instantiation.
|
|
482
|
+
instantiation.staticMemberScope!.symbolsByRefkey.get(expectedRefkey),
|
|
367
483
|
).toBeDefined();
|
|
368
484
|
|
|
369
485
|
const newInstanceMemberRefkey = refkey();
|
|
@@ -377,10 +493,280 @@ describe("instantiating members", () => {
|
|
|
377
493
|
instantiation.refkeys[0],
|
|
378
494
|
newInstanceMemberRefkey,
|
|
379
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]);
|
|
380
581
|
expect(
|
|
381
|
-
|
|
582
|
+
target.staticMemberScope!.symbolsByRefkey.get(expectedKey),
|
|
382
583
|
).toBeDefined();
|
|
383
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
|
+
});
|
|
384
770
|
});
|
|
385
771
|
|
|
386
772
|
describe("symbol name resolution", () => {
|
|
@@ -540,6 +926,7 @@ describe("refkey resolution", () => {
|
|
|
540
926
|
expect(resolvedSym.value).toBe(undefined);
|
|
541
927
|
|
|
542
928
|
sym.refkeys[0] = key;
|
|
929
|
+
flushJobs();
|
|
543
930
|
expect(resolvedSym.value?.targetDeclaration).toBe(sym);
|
|
544
931
|
});
|
|
545
932
|
});
|
|
@@ -563,10 +950,11 @@ describe("Deleting symbols", () => {
|
|
|
563
950
|
expect(resolvedSym.value).toBe(undefined);
|
|
564
951
|
|
|
565
952
|
sym.refkeys[0] = key;
|
|
953
|
+
flushJobs();
|
|
566
954
|
expect(resolvedSym.value?.targetDeclaration).toBe(sym);
|
|
567
955
|
|
|
568
956
|
binder.deleteSymbol(sym);
|
|
569
|
-
|
|
957
|
+
flushJobs();
|
|
570
958
|
expect(resolvedSym.value).toBe(undefined);
|
|
571
959
|
});
|
|
572
960
|
|
package/test/utils.test.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import { Children } from "@alloy-js/core/jsx-runtime";
|
|
|
2
2
|
import { computed, ref, triggerRef } from "@vue/reactivity";
|
|
3
3
|
import { describe, expect, it } from "vitest";
|
|
4
4
|
import { renderTree } from "../src/render.js";
|
|
5
|
+
import { flushJobs } from "../src/scheduler.js";
|
|
5
6
|
import { children, join, mapJoin } from "../src/utils.js";
|
|
6
7
|
import "../testing/extend-expect.js";
|
|
7
8
|
|
|
@@ -93,6 +94,7 @@ describe("mapJoin", () => {
|
|
|
93
94
|
expect(callCount).toBe(2);
|
|
94
95
|
arr.value.push(3);
|
|
95
96
|
triggerRef(arr);
|
|
97
|
+
flushJobs();
|
|
96
98
|
expect(callCount).toBe(3);
|
|
97
99
|
});
|
|
98
100
|
it("can map a joiner", () => {
|