@rlabs-inc/signals 1.2.1 → 1.4.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/README.md +114 -0
- package/dist/collections/map.d.ts.map +1 -1
- package/dist/collections/set.d.ts.map +1 -1
- package/dist/core/constants.d.ts +6 -0
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/deep/proxy.d.ts.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +504 -61
- package/dist/index.mjs +504 -61
- package/dist/primitives/bind.d.ts.map +1 -1
- package/dist/primitives/derived.d.ts.map +1 -1
- package/dist/primitives/effect.d.ts.map +1 -1
- package/dist/primitives/linked.d.ts +73 -0
- package/dist/primitives/linked.d.ts.map +1 -0
- package/dist/primitives/scope.d.ts +96 -0
- package/dist/primitives/scope.d.ts.map +1 -0
- package/dist/primitives/selector.d.ts +46 -0
- package/dist/primitives/selector.d.ts.map +1 -0
- package/dist/primitives/signal.d.ts +5 -0
- package/dist/primitives/signal.d.ts.map +1 -1
- package/dist/reactivity/scheduling.d.ts.map +1 -1
- package/dist/reactivity/tracking.d.ts +5 -0
- package/dist/reactivity/tracking.d.ts.map +1 -1
- package/dist/v2/bench-compare.d.ts +2 -0
- package/dist/v2/bench-compare.d.ts.map +1 -0
- package/dist/v2/bench.d.ts +5 -0
- package/dist/v2/bench.d.ts.map +1 -0
- package/dist/v2/bind.d.ts +94 -0
- package/dist/v2/bind.d.ts.map +1 -0
- package/dist/v2/collections.d.ts +133 -0
- package/dist/v2/collections.d.ts.map +1 -0
- package/dist/v2/compat-test.d.ts +2 -0
- package/dist/v2/compat-test.d.ts.map +1 -0
- package/dist/v2/debug-array.d.ts +2 -0
- package/dist/v2/debug-array.d.ts.map +1 -0
- package/dist/v2/debug-diamond.d.ts +2 -0
- package/dist/v2/debug-diamond.d.ts.map +1 -0
- package/dist/v2/index.d.ts +7 -0
- package/dist/v2/index.d.ts.map +1 -0
- package/dist/v2/primitives.d.ts +120 -0
- package/dist/v2/primitives.d.ts.map +1 -0
- package/dist/v2/proxy.d.ts +10 -0
- package/dist/v2/proxy.d.ts.map +1 -0
- package/dist/v2/registry.d.ts +35 -0
- package/dist/v2/registry.d.ts.map +1 -0
- package/dist/v2/stress.d.ts +7 -0
- package/dist/v2/stress.d.ts.map +1 -0
- package/dist/v2/test-suite.d.ts +2 -0
- package/dist/v2/test-suite.d.ts.map +1 -0
- package/dist/v2/test-v1.d.ts +2 -0
- package/dist/v2/test-v1.d.ts.map +1 -0
- package/package.json +7 -1
package/dist/index.js
CHANGED
|
@@ -54,10 +54,13 @@ __export(exports_src, {
|
|
|
54
54
|
readVersion: () => readVersion,
|
|
55
55
|
proxy: () => proxy,
|
|
56
56
|
peek: () => peek,
|
|
57
|
+
onScopeDispose: () => onScopeDispose,
|
|
57
58
|
neverEquals: () => neverEquals,
|
|
58
59
|
mutableSource: () => mutableSource,
|
|
59
60
|
markReactions: () => markReactions,
|
|
61
|
+
linkedSignal: () => linkedSignal,
|
|
60
62
|
isReactive: () => isReactive,
|
|
63
|
+
isLinkedSignal: () => isLinkedSignal,
|
|
61
64
|
isDirty: () => isDirty,
|
|
62
65
|
isBinding: () => isBinding,
|
|
63
66
|
incrementWriteVersion: () => incrementWriteVersion,
|
|
@@ -65,15 +68,18 @@ __export(exports_src, {
|
|
|
65
68
|
incrementBatchDepth: () => incrementBatchDepth,
|
|
66
69
|
getWriteVersion: () => getWriteVersion,
|
|
67
70
|
getReadVersion: () => getReadVersion,
|
|
71
|
+
getCurrentScope: () => getCurrentScope,
|
|
68
72
|
getBatchDepth: () => getBatchDepth,
|
|
69
73
|
get: () => get,
|
|
70
74
|
flushSync: () => flushSync,
|
|
71
75
|
equals: () => equals,
|
|
76
|
+
effectScope: () => effectScope,
|
|
72
77
|
effect: () => effect,
|
|
73
78
|
disconnectDerived: () => disconnectDerived,
|
|
74
79
|
destroyEffect: () => destroyEffect,
|
|
75
80
|
derived: () => derived,
|
|
76
81
|
decrementBatchDepth: () => decrementBatchDepth,
|
|
82
|
+
createSelector: () => createSelector,
|
|
77
83
|
createEquals: () => createEquals,
|
|
78
84
|
createEffect: () => createEffect,
|
|
79
85
|
createDerived: () => createDerived,
|
|
@@ -97,6 +103,7 @@ __export(exports_src, {
|
|
|
97
103
|
REACTIVE_MARKER: () => REACTIVE_MARKER,
|
|
98
104
|
REACTION_IS_UPDATING: () => REACTION_IS_UPDATING,
|
|
99
105
|
MAYBE_DIRTY: () => MAYBE_DIRTY,
|
|
106
|
+
LINKED_SYMBOL: () => LINKED_SYMBOL,
|
|
100
107
|
INERT: () => INERT,
|
|
101
108
|
EFFECT_RAN: () => EFFECT_RAN,
|
|
102
109
|
EFFECT_PRESERVED: () => EFFECT_PRESERVED,
|
|
@@ -107,7 +114,8 @@ __export(exports_src, {
|
|
|
107
114
|
DERIVED: () => DERIVED,
|
|
108
115
|
CLEAN: () => CLEAN,
|
|
109
116
|
BRANCH_EFFECT: () => BRANCH_EFFECT,
|
|
110
|
-
BLOCK_EFFECT: () => BLOCK_EFFECT
|
|
117
|
+
BLOCK_EFFECT: () => BLOCK_EFFECT,
|
|
118
|
+
BINDING_SYMBOL: () => BINDING_SYMBOL
|
|
111
119
|
});
|
|
112
120
|
module.exports = __toCommonJS(exports_src);
|
|
113
121
|
|
|
@@ -176,6 +184,9 @@ var UNINITIALIZED = Symbol.for("rlabs.signals.uninitialized");
|
|
|
176
184
|
var STALE_REACTION = Symbol.for("rlabs.signals.stale_reaction");
|
|
177
185
|
var STATE_SYMBOL = Symbol.for("rlabs.signals.state");
|
|
178
186
|
var REACTIVE_MARKER = Symbol.for("rlabs.signals.reactive");
|
|
187
|
+
var BINDING_SYMBOL = Symbol.for("rlabs.signals.binding");
|
|
188
|
+
var LINKED_SYMBOL = Symbol.for("rlabs.signals.linked");
|
|
189
|
+
var SOURCE = 1 << 0;
|
|
179
190
|
var STATUS_MASK = ~(DIRTY | MAYBE_DIRTY | CLEAN);
|
|
180
191
|
|
|
181
192
|
// src/core/globals.ts
|
|
@@ -300,6 +311,9 @@ function setUpdateEffectImpl(impl) {
|
|
|
300
311
|
function flushEffects() {
|
|
301
312
|
const roots = clearQueuedRootEffects();
|
|
302
313
|
for (const root of roots) {
|
|
314
|
+
if ((root.f & INERT) !== 0) {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
303
317
|
if (isDirty(root)) {
|
|
304
318
|
updateEffectImpl(root);
|
|
305
319
|
}
|
|
@@ -310,7 +324,7 @@ function processEffectTree(effect) {
|
|
|
310
324
|
let child = effect.first;
|
|
311
325
|
while (child !== null) {
|
|
312
326
|
const next = child.next;
|
|
313
|
-
if (isDirty(child)) {
|
|
327
|
+
if ((child.f & INERT) === 0 && isDirty(child)) {
|
|
314
328
|
updateEffectImpl(child);
|
|
315
329
|
}
|
|
316
330
|
if (child.first !== null) {
|
|
@@ -323,6 +337,9 @@ function flushPendingReactions() {
|
|
|
323
337
|
const reactions = [...pendingReactions];
|
|
324
338
|
clearPendingReactions();
|
|
325
339
|
for (const reaction of reactions) {
|
|
340
|
+
if ((reaction.f & INERT) !== 0) {
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
326
343
|
if (isDirty(reaction)) {
|
|
327
344
|
if ("parent" in reaction) {
|
|
328
345
|
updateEffectImpl(reaction);
|
|
@@ -354,6 +371,9 @@ function flushSync(fn) {
|
|
|
354
371
|
continue;
|
|
355
372
|
}
|
|
356
373
|
for (const root of roots) {
|
|
374
|
+
if ((root.f & INERT) !== 0) {
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
357
377
|
if (isDirty(root)) {
|
|
358
378
|
updateEffectImpl(root);
|
|
359
379
|
}
|
|
@@ -400,13 +420,63 @@ function get(signal) {
|
|
|
400
420
|
}
|
|
401
421
|
}
|
|
402
422
|
if ((signal.f & DERIVED) !== 0) {
|
|
403
|
-
|
|
404
|
-
if (isDirty(derived)) {
|
|
405
|
-
updateDerived(derived);
|
|
406
|
-
}
|
|
423
|
+
updateDerivedChain(signal);
|
|
407
424
|
}
|
|
408
425
|
return signal.v;
|
|
409
426
|
}
|
|
427
|
+
var updateCycleId = 0;
|
|
428
|
+
var processedInCycle = new WeakMap;
|
|
429
|
+
function updateDerivedChain(target) {
|
|
430
|
+
if ((target.f & (DIRTY | MAYBE_DIRTY)) === 0) {
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
const cycleId = ++updateCycleId;
|
|
434
|
+
const chain = [target];
|
|
435
|
+
processedInCycle.set(target, cycleId);
|
|
436
|
+
let idx = 0;
|
|
437
|
+
while (idx < chain.length) {
|
|
438
|
+
const current = chain[idx];
|
|
439
|
+
idx++;
|
|
440
|
+
if ((current.f & (DIRTY | MAYBE_DIRTY)) === 0) {
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
const deps = current.deps;
|
|
444
|
+
if (deps !== null) {
|
|
445
|
+
for (let i = 0;i < deps.length; i++) {
|
|
446
|
+
const dep = deps[i];
|
|
447
|
+
if ((dep.f & DERIVED) !== 0 && (dep.f & (DIRTY | MAYBE_DIRTY)) !== 0 && processedInCycle.get(dep) !== cycleId) {
|
|
448
|
+
chain.push(dep);
|
|
449
|
+
processedInCycle.set(dep, cycleId);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
for (let i = chain.length - 1;i >= 0; i--) {
|
|
455
|
+
const current = chain[i];
|
|
456
|
+
if ((current.f & (DIRTY | MAYBE_DIRTY)) === 0) {
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
if ((current.f & DIRTY) !== 0) {
|
|
460
|
+
updateDerived(current);
|
|
461
|
+
} else {
|
|
462
|
+
const deps = current.deps;
|
|
463
|
+
let needsUpdate = false;
|
|
464
|
+
if (deps !== null) {
|
|
465
|
+
for (let j = 0;j < deps.length; j++) {
|
|
466
|
+
if (deps[j].wv > current.wv) {
|
|
467
|
+
needsUpdate = true;
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
if (needsUpdate) {
|
|
473
|
+
updateDerived(current);
|
|
474
|
+
} else {
|
|
475
|
+
setSignalStatus(current, CLEAN);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
410
480
|
function set(signal, value) {
|
|
411
481
|
if (activeReaction !== null && (activeReaction.f & DERIVED) !== 0) {
|
|
412
482
|
throw new Error("Cannot write to signals inside a derived. " + "Deriveds should be pure computations with no side effects.");
|
|
@@ -422,20 +492,24 @@ function set(signal, value) {
|
|
|
422
492
|
return value;
|
|
423
493
|
}
|
|
424
494
|
function markReactions(signal, status) {
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
495
|
+
const stack = [{ signal, status }];
|
|
496
|
+
while (stack.length > 0) {
|
|
497
|
+
const { signal: currentSignal, status: currentStatus } = stack.pop();
|
|
498
|
+
const reactions = currentSignal.reactions;
|
|
499
|
+
if (reactions === null)
|
|
500
|
+
continue;
|
|
501
|
+
for (let i = 0;i < reactions.length; i++) {
|
|
502
|
+
const reaction = reactions[i];
|
|
503
|
+
const flags = reaction.f;
|
|
504
|
+
const notDirty = (flags & DIRTY) === 0;
|
|
505
|
+
if (notDirty) {
|
|
506
|
+
setSignalStatus(reaction, currentStatus);
|
|
507
|
+
}
|
|
508
|
+
if ((flags & DERIVED) !== 0) {
|
|
509
|
+
stack.push({ signal: reaction, status: MAYBE_DIRTY });
|
|
510
|
+
} else if (notDirty) {
|
|
511
|
+
scheduleEffect(reaction);
|
|
512
|
+
}
|
|
439
513
|
}
|
|
440
514
|
}
|
|
441
515
|
}
|
|
@@ -446,22 +520,66 @@ function isDirty(reaction) {
|
|
|
446
520
|
if ((reaction.f & DIRTY) !== 0) {
|
|
447
521
|
return true;
|
|
448
522
|
}
|
|
449
|
-
if ((reaction.f & MAYBE_DIRTY)
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
523
|
+
if ((reaction.f & MAYBE_DIRTY) === 0) {
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
const toCheck = [reaction];
|
|
527
|
+
const toUpdate = [];
|
|
528
|
+
let idx = 0;
|
|
529
|
+
while (idx < toCheck.length) {
|
|
530
|
+
const current = toCheck[idx];
|
|
531
|
+
idx++;
|
|
532
|
+
if ((current.f & DIRTY) !== 0) {
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
if ((current.f & MAYBE_DIRTY) === 0) {
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
const deps2 = current.deps;
|
|
539
|
+
if (deps2 !== null) {
|
|
540
|
+
for (let i = 0;i < deps2.length; i++) {
|
|
541
|
+
const dep = deps2[i];
|
|
542
|
+
if ((dep.f & DERIVED) !== 0 && (dep.f & (DIRTY | MAYBE_DIRTY)) !== 0) {
|
|
543
|
+
toCheck.push(dep);
|
|
458
544
|
}
|
|
459
|
-
|
|
460
|
-
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
for (let i = toCheck.length - 1;i >= 0; i--) {
|
|
549
|
+
const current = toCheck[i];
|
|
550
|
+
if ((current.f & DERIVED) === 0) {
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
if ((current.f & DIRTY) !== 0) {
|
|
554
|
+
updateDerived(current);
|
|
555
|
+
} else if ((current.f & MAYBE_DIRTY) !== 0) {
|
|
556
|
+
const deps2 = current.deps;
|
|
557
|
+
let needsUpdate = false;
|
|
558
|
+
if (deps2 !== null) {
|
|
559
|
+
for (let j = 0;j < deps2.length; j++) {
|
|
560
|
+
if (deps2[j].wv > current.wv) {
|
|
561
|
+
needsUpdate = true;
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
461
564
|
}
|
|
462
565
|
}
|
|
566
|
+
if (needsUpdate) {
|
|
567
|
+
updateDerived(current);
|
|
568
|
+
} else {
|
|
569
|
+
setSignalStatus(current, CLEAN);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
if ((reaction.f & DIRTY) !== 0) {
|
|
574
|
+
return true;
|
|
575
|
+
}
|
|
576
|
+
const deps = reaction.deps;
|
|
577
|
+
if (deps !== null) {
|
|
578
|
+
for (let i = 0;i < deps.length; i++) {
|
|
579
|
+
if (deps[i].wv > reaction.wv) {
|
|
580
|
+
return true;
|
|
581
|
+
}
|
|
463
582
|
}
|
|
464
|
-
setSignalStatus(reaction, CLEAN);
|
|
465
583
|
}
|
|
466
584
|
return false;
|
|
467
585
|
}
|
|
@@ -565,6 +683,7 @@ function updateReaction(reaction) {
|
|
|
565
683
|
}
|
|
566
684
|
|
|
567
685
|
// src/primitives/signal.ts
|
|
686
|
+
var SOURCE_SYMBOL = Symbol("signal.source");
|
|
568
687
|
function source(initialValue, options) {
|
|
569
688
|
return {
|
|
570
689
|
f: 0,
|
|
@@ -578,9 +697,13 @@ function source(initialValue, options) {
|
|
|
578
697
|
function mutableSource(initialValue) {
|
|
579
698
|
return source(initialValue, { equals: safeEquals });
|
|
580
699
|
}
|
|
700
|
+
var signalCleanup = new FinalizationRegistry((src) => {
|
|
701
|
+
src.reactions = null;
|
|
702
|
+
});
|
|
581
703
|
function signal(initialValue, options) {
|
|
582
704
|
const src = source(initialValue, options);
|
|
583
|
-
|
|
705
|
+
const sig = {
|
|
706
|
+
[SOURCE_SYMBOL]: src,
|
|
584
707
|
get value() {
|
|
585
708
|
return get(src);
|
|
586
709
|
},
|
|
@@ -588,6 +711,11 @@ function signal(initialValue, options) {
|
|
|
588
711
|
set(src, newValue);
|
|
589
712
|
}
|
|
590
713
|
};
|
|
714
|
+
signalCleanup.register(sig, src);
|
|
715
|
+
return sig;
|
|
716
|
+
}
|
|
717
|
+
function getSource(sig) {
|
|
718
|
+
return sig[SOURCE_SYMBOL];
|
|
591
719
|
}
|
|
592
720
|
var proxyFn = null;
|
|
593
721
|
function setProxyFn(fn) {
|
|
@@ -604,10 +732,21 @@ function stateRaw(initialValue) {
|
|
|
604
732
|
}
|
|
605
733
|
|
|
606
734
|
// src/deep/proxy.ts
|
|
735
|
+
var proxyCache = new WeakMap;
|
|
736
|
+
var proxyCleanup = new FinalizationRegistry((data) => {
|
|
737
|
+
data.version.reactions = null;
|
|
738
|
+
for (const src of data.sources.values()) {
|
|
739
|
+
src.reactions = null;
|
|
740
|
+
}
|
|
741
|
+
data.sources.clear();
|
|
742
|
+
});
|
|
607
743
|
function shouldProxy(value) {
|
|
608
744
|
if (value === null || typeof value !== "object") {
|
|
609
745
|
return false;
|
|
610
746
|
}
|
|
747
|
+
if (BINDING_SYMBOL in value) {
|
|
748
|
+
return false;
|
|
749
|
+
}
|
|
611
750
|
const proto = Object.getPrototypeOf(value);
|
|
612
751
|
return proto === Object.prototype || proto === Array.prototype || proto === null;
|
|
613
752
|
}
|
|
@@ -622,6 +761,10 @@ function proxy(value) {
|
|
|
622
761
|
if (!shouldProxy(value) || isProxy(value)) {
|
|
623
762
|
return value;
|
|
624
763
|
}
|
|
764
|
+
const cached = proxyCache.get(value);
|
|
765
|
+
if (cached) {
|
|
766
|
+
return cached;
|
|
767
|
+
}
|
|
625
768
|
const sources = new Map;
|
|
626
769
|
const version = source(0);
|
|
627
770
|
const isArray = Array.isArray(value);
|
|
@@ -641,7 +784,7 @@ function proxy(value) {
|
|
|
641
784
|
setActiveReaction(prevReaction);
|
|
642
785
|
}
|
|
643
786
|
};
|
|
644
|
-
const
|
|
787
|
+
const getSource2 = (prop, initialValue) => {
|
|
645
788
|
let s = sources.get(prop);
|
|
646
789
|
if (s === undefined) {
|
|
647
790
|
s = withParent(() => {
|
|
@@ -664,7 +807,7 @@ function proxy(value) {
|
|
|
664
807
|
return currentValue.bind(proxyObj);
|
|
665
808
|
}
|
|
666
809
|
if (exists || isWritable(target, prop)) {
|
|
667
|
-
const s =
|
|
810
|
+
const s = getSource2(prop, currentValue);
|
|
668
811
|
const val = get(s);
|
|
669
812
|
if (val === UNINITIALIZED) {
|
|
670
813
|
return;
|
|
@@ -673,7 +816,7 @@ function proxy(value) {
|
|
|
673
816
|
}
|
|
674
817
|
return currentValue;
|
|
675
818
|
},
|
|
676
|
-
set(target, prop, newValue
|
|
819
|
+
set(target, prop, newValue) {
|
|
677
820
|
const exists = prop in target;
|
|
678
821
|
let s = sources.get(prop);
|
|
679
822
|
if (s === undefined) {
|
|
@@ -683,29 +826,35 @@ function proxy(value) {
|
|
|
683
826
|
s = withParent(() => source(undefined));
|
|
684
827
|
sources.set(prop, s);
|
|
685
828
|
}
|
|
686
|
-
|
|
829
|
+
let proxied;
|
|
830
|
+
if (shouldProxy(newValue)) {
|
|
831
|
+
proxied = withParent(() => proxy(newValue));
|
|
832
|
+
} else {
|
|
833
|
+
proxied = newValue;
|
|
834
|
+
}
|
|
687
835
|
set(s, proxied);
|
|
688
|
-
|
|
689
|
-
if (isArray
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
836
|
+
target[prop] = newValue;
|
|
837
|
+
if (isArray) {
|
|
838
|
+
if (prop === "length") {
|
|
839
|
+
const oldLength = s.v;
|
|
840
|
+
const newLength = newValue;
|
|
841
|
+
for (let i = newLength;i < oldLength; i++) {
|
|
842
|
+
const indexKey = String(i);
|
|
843
|
+
const indexSource = sources.get(indexKey);
|
|
844
|
+
if (indexSource !== undefined) {
|
|
845
|
+
set(indexSource, UNINITIALIZED);
|
|
846
|
+
} else if (i in target) {
|
|
847
|
+
const deletedSource = withParent(() => source(UNINITIALIZED));
|
|
848
|
+
sources.set(indexKey, deletedSource);
|
|
849
|
+
}
|
|
700
850
|
}
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
set(lengthSource, index + 1);
|
|
851
|
+
} else if (typeof prop === "string") {
|
|
852
|
+
const index = Number(prop);
|
|
853
|
+
if (Number.isInteger(index) && index >= 0) {
|
|
854
|
+
const lengthSource = sources.get("length");
|
|
855
|
+
if (lengthSource !== undefined && index >= lengthSource.v) {
|
|
856
|
+
set(lengthSource, index + 1);
|
|
857
|
+
}
|
|
709
858
|
}
|
|
710
859
|
}
|
|
711
860
|
}
|
|
@@ -726,7 +875,7 @@ function proxy(value) {
|
|
|
726
875
|
}
|
|
727
876
|
set(version, get(version) + 1);
|
|
728
877
|
}
|
|
729
|
-
return
|
|
878
|
+
return delete target[prop];
|
|
730
879
|
},
|
|
731
880
|
has(target, prop) {
|
|
732
881
|
if (prop === STATE_SYMBOL) {
|
|
@@ -764,6 +913,8 @@ function proxy(value) {
|
|
|
764
913
|
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
765
914
|
}
|
|
766
915
|
});
|
|
916
|
+
proxyCleanup.register(proxyObj, { sources, version });
|
|
917
|
+
proxyCache.set(value, proxyObj);
|
|
767
918
|
return proxyObj;
|
|
768
919
|
}
|
|
769
920
|
function toRaw(value) {
|
|
@@ -776,6 +927,18 @@ function isReactive(value) {
|
|
|
776
927
|
return isProxy(value);
|
|
777
928
|
}
|
|
778
929
|
// src/primitives/derived.ts
|
|
930
|
+
var derivedCleanup = new FinalizationRegistry((d) => {
|
|
931
|
+
removeReactions(d, 0);
|
|
932
|
+
d.deps = null;
|
|
933
|
+
d.reactions = null;
|
|
934
|
+
const effects = d.effects;
|
|
935
|
+
if (effects !== null) {
|
|
936
|
+
d.effects = null;
|
|
937
|
+
for (let i = 0;i < effects.length; i++) {
|
|
938
|
+
destroyEffectImpl(effects[i]);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
});
|
|
779
942
|
function createDerived(fn, options) {
|
|
780
943
|
let flags = DERIVED | DIRTY;
|
|
781
944
|
const parentDerived = activeReaction !== null && (activeReaction.f & DERIVED) !== 0 ? activeReaction : null;
|
|
@@ -826,11 +989,13 @@ function destroyDerivedEffects(derived) {
|
|
|
826
989
|
}
|
|
827
990
|
function derived(fn, options) {
|
|
828
991
|
const d = createDerived(fn, options);
|
|
829
|
-
|
|
992
|
+
const wrapper = {
|
|
830
993
|
get value() {
|
|
831
994
|
return get(d);
|
|
832
995
|
}
|
|
833
996
|
};
|
|
997
|
+
derivedCleanup.register(wrapper, d);
|
|
998
|
+
return wrapper;
|
|
834
999
|
}
|
|
835
1000
|
derived.by = derived;
|
|
836
1001
|
function disconnectDerived(derived2) {
|
|
@@ -839,6 +1004,123 @@ function disconnectDerived(derived2) {
|
|
|
839
1004
|
derived2.reactions = null;
|
|
840
1005
|
destroyDerivedEffects(derived2);
|
|
841
1006
|
}
|
|
1007
|
+
// src/primitives/scope.ts
|
|
1008
|
+
var activeScope = null;
|
|
1009
|
+
function getCurrentScope() {
|
|
1010
|
+
return activeScope;
|
|
1011
|
+
}
|
|
1012
|
+
function setActiveScope(scope) {
|
|
1013
|
+
const prev = activeScope;
|
|
1014
|
+
activeScope = scope;
|
|
1015
|
+
return prev;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
class EffectScopeImpl {
|
|
1019
|
+
_active = true;
|
|
1020
|
+
_paused = false;
|
|
1021
|
+
effects = [];
|
|
1022
|
+
cleanups = [];
|
|
1023
|
+
parent = null;
|
|
1024
|
+
scopes = null;
|
|
1025
|
+
constructor(detached = false) {
|
|
1026
|
+
this.parent = activeScope;
|
|
1027
|
+
if (!detached && this.parent) {
|
|
1028
|
+
if (this.parent.scopes === null) {
|
|
1029
|
+
this.parent.scopes = [];
|
|
1030
|
+
}
|
|
1031
|
+
this.parent.scopes.push(this);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
get active() {
|
|
1035
|
+
return this._active;
|
|
1036
|
+
}
|
|
1037
|
+
get paused() {
|
|
1038
|
+
return this._paused;
|
|
1039
|
+
}
|
|
1040
|
+
run(fn) {
|
|
1041
|
+
if (!this._active) {
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
const prevScope = setActiveScope(this);
|
|
1045
|
+
try {
|
|
1046
|
+
return fn();
|
|
1047
|
+
} finally {
|
|
1048
|
+
setActiveScope(prevScope);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
stop() {
|
|
1052
|
+
if (!this._active)
|
|
1053
|
+
return;
|
|
1054
|
+
for (const effect of [...this.effects]) {
|
|
1055
|
+
destroyEffect(effect);
|
|
1056
|
+
}
|
|
1057
|
+
this.effects.length = 0;
|
|
1058
|
+
for (const cleanup of this.cleanups) {
|
|
1059
|
+
try {
|
|
1060
|
+
cleanup();
|
|
1061
|
+
} catch {}
|
|
1062
|
+
}
|
|
1063
|
+
this.cleanups.length = 0;
|
|
1064
|
+
if (this.scopes) {
|
|
1065
|
+
for (const scope of this.scopes) {
|
|
1066
|
+
scope.stop();
|
|
1067
|
+
}
|
|
1068
|
+
this.scopes.length = 0;
|
|
1069
|
+
}
|
|
1070
|
+
if (this.parent?.scopes) {
|
|
1071
|
+
const idx = this.parent.scopes.indexOf(this);
|
|
1072
|
+
if (idx !== -1) {
|
|
1073
|
+
this.parent.scopes.splice(idx, 1);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
this._active = false;
|
|
1077
|
+
}
|
|
1078
|
+
pause() {
|
|
1079
|
+
if (!this._active || this._paused)
|
|
1080
|
+
return;
|
|
1081
|
+
this._paused = true;
|
|
1082
|
+
for (const effect of this.effects) {
|
|
1083
|
+
effect.f |= INERT;
|
|
1084
|
+
}
|
|
1085
|
+
if (this.scopes) {
|
|
1086
|
+
for (const scope of this.scopes) {
|
|
1087
|
+
scope.pause();
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
resume() {
|
|
1092
|
+
if (!this._active || !this._paused)
|
|
1093
|
+
return;
|
|
1094
|
+
this._paused = false;
|
|
1095
|
+
for (const effect of this.effects) {
|
|
1096
|
+
effect.f &= ~INERT;
|
|
1097
|
+
if ((effect.f & DIRTY) !== 0) {
|
|
1098
|
+
scheduleEffect(effect);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
if (this.scopes) {
|
|
1102
|
+
for (const scope of this.scopes) {
|
|
1103
|
+
scope.resume();
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
function effectScope(detached) {
|
|
1109
|
+
return new EffectScopeImpl(detached);
|
|
1110
|
+
}
|
|
1111
|
+
function onScopeDispose(fn) {
|
|
1112
|
+
if (activeScope) {
|
|
1113
|
+
activeScope.cleanups.push(fn);
|
|
1114
|
+
} else {
|
|
1115
|
+
console.warn("onScopeDispose() called outside of scope context");
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
function registerEffectWithScope(effect) {
|
|
1119
|
+
if (activeScope) {
|
|
1120
|
+
activeScope.effects.push(effect);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
842
1124
|
// src/primitives/effect.ts
|
|
843
1125
|
function createEffect(type, fn, sync, push = true) {
|
|
844
1126
|
const parent = activeEffect;
|
|
@@ -854,6 +1136,7 @@ function createEffect(type, fn, sync, push = true) {
|
|
|
854
1136
|
next: null,
|
|
855
1137
|
wv: 0
|
|
856
1138
|
};
|
|
1139
|
+
registerEffectWithScope(effect);
|
|
857
1140
|
if (sync) {
|
|
858
1141
|
updateEffect(effect);
|
|
859
1142
|
effect.f |= EFFECT_RAN;
|
|
@@ -963,7 +1246,9 @@ effect.tracking = function effectTracking() {
|
|
|
963
1246
|
return activeEffect !== null;
|
|
964
1247
|
};
|
|
965
1248
|
// src/primitives/bind.ts
|
|
966
|
-
var
|
|
1249
|
+
var bindingCleanup = new FinalizationRegistry((internalSource) => {
|
|
1250
|
+
internalSource.reactions = null;
|
|
1251
|
+
});
|
|
967
1252
|
function isBinding(value) {
|
|
968
1253
|
return value !== null && typeof value === "object" && BINDING_SYMBOL in value;
|
|
969
1254
|
}
|
|
@@ -983,10 +1268,13 @@ function bind(source2) {
|
|
|
983
1268
|
};
|
|
984
1269
|
}
|
|
985
1270
|
let actualSource;
|
|
1271
|
+
let internalSource = null;
|
|
986
1272
|
if (isBinding(source2) || isSignal(source2)) {
|
|
987
1273
|
actualSource = source2;
|
|
988
1274
|
} else {
|
|
989
|
-
|
|
1275
|
+
const sig = signal(source2);
|
|
1276
|
+
actualSource = sig;
|
|
1277
|
+
internalSource = getSource(sig) ?? null;
|
|
990
1278
|
}
|
|
991
1279
|
const binding = {
|
|
992
1280
|
[BINDING_SYMBOL]: true,
|
|
@@ -997,6 +1285,9 @@ function bind(source2) {
|
|
|
997
1285
|
actualSource.value = v;
|
|
998
1286
|
}
|
|
999
1287
|
};
|
|
1288
|
+
if (internalSource !== null) {
|
|
1289
|
+
bindingCleanup.register(binding, internalSource);
|
|
1290
|
+
}
|
|
1000
1291
|
return binding;
|
|
1001
1292
|
}
|
|
1002
1293
|
function bindReadonly(source2) {
|
|
@@ -1043,7 +1334,140 @@ function untrack(fn) {
|
|
|
1043
1334
|
}
|
|
1044
1335
|
}
|
|
1045
1336
|
var peek = untrack;
|
|
1337
|
+
|
|
1338
|
+
// src/primitives/linked.ts
|
|
1339
|
+
function linkedSignal(config) {
|
|
1340
|
+
let sourceFn;
|
|
1341
|
+
let computation;
|
|
1342
|
+
let equalsFn = Object.is;
|
|
1343
|
+
if (typeof config === "function") {
|
|
1344
|
+
const fn = config;
|
|
1345
|
+
sourceFn = fn;
|
|
1346
|
+
computation = (s) => s;
|
|
1347
|
+
} else {
|
|
1348
|
+
sourceFn = config.source;
|
|
1349
|
+
computation = config.computation;
|
|
1350
|
+
if (config.equal) {
|
|
1351
|
+
equalsFn = config.equal;
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
let prevSource = undefined;
|
|
1355
|
+
let prevValue = undefined;
|
|
1356
|
+
let initialized = false;
|
|
1357
|
+
const valueSignal = signal(undefined, { equals: equalsFn });
|
|
1358
|
+
const sourceTracker = derived(() => {
|
|
1359
|
+
const newSource = sourceFn();
|
|
1360
|
+
return newSource;
|
|
1361
|
+
});
|
|
1362
|
+
let manualOverride = false;
|
|
1363
|
+
let lastKnownSource = undefined;
|
|
1364
|
+
const dispose = effect.pre(() => {
|
|
1365
|
+
const currentSource = sourceTracker.value;
|
|
1366
|
+
const sourceChanged = initialized && !Object.is(lastKnownSource, currentSource);
|
|
1367
|
+
if (!initialized || sourceChanged) {
|
|
1368
|
+
const previous = initialized ? { source: prevSource, value: prevValue } : undefined;
|
|
1369
|
+
const newValue = computation(currentSource, previous);
|
|
1370
|
+
prevSource = currentSource;
|
|
1371
|
+
prevValue = newValue;
|
|
1372
|
+
lastKnownSource = currentSource;
|
|
1373
|
+
initialized = true;
|
|
1374
|
+
manualOverride = false;
|
|
1375
|
+
untrack(() => {
|
|
1376
|
+
valueSignal.value = newValue;
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
});
|
|
1380
|
+
const accessor = {
|
|
1381
|
+
[LINKED_SYMBOL]: true,
|
|
1382
|
+
get value() {
|
|
1383
|
+
sourceTracker.value;
|
|
1384
|
+
const currentSource = untrack(() => sourceTracker.value);
|
|
1385
|
+
if (initialized && !Object.is(lastKnownSource, currentSource)) {
|
|
1386
|
+
flushSync();
|
|
1387
|
+
}
|
|
1388
|
+
return valueSignal.value;
|
|
1389
|
+
},
|
|
1390
|
+
set value(newValue) {
|
|
1391
|
+
manualOverride = true;
|
|
1392
|
+
prevValue = newValue;
|
|
1393
|
+
valueSignal.value = newValue;
|
|
1394
|
+
},
|
|
1395
|
+
get peek() {
|
|
1396
|
+
return untrack(() => valueSignal.value);
|
|
1397
|
+
}
|
|
1398
|
+
};
|
|
1399
|
+
return accessor;
|
|
1400
|
+
}
|
|
1401
|
+
function isLinkedSignal(value) {
|
|
1402
|
+
return value !== null && typeof value === "object" && LINKED_SYMBOL in value;
|
|
1403
|
+
}
|
|
1404
|
+
// src/primitives/selector.ts
|
|
1405
|
+
function createSelector(source2, fn = (k, v) => k === v) {
|
|
1406
|
+
const subscribers = new Map;
|
|
1407
|
+
const reactionKeys = new WeakMap;
|
|
1408
|
+
let prevValue;
|
|
1409
|
+
let initialized = false;
|
|
1410
|
+
effect.pre(() => {
|
|
1411
|
+
const value = source2();
|
|
1412
|
+
if (initialized && !Object.is(prevValue, value)) {
|
|
1413
|
+
for (const [key, reactions] of subscribers) {
|
|
1414
|
+
const wasSelected = fn(key, prevValue);
|
|
1415
|
+
const isSelected = fn(key, value);
|
|
1416
|
+
if (wasSelected !== isSelected) {
|
|
1417
|
+
const toRemove = [];
|
|
1418
|
+
for (const reaction of reactions) {
|
|
1419
|
+
if ((reaction.f & DESTROYED) !== 0) {
|
|
1420
|
+
toRemove.push(reaction);
|
|
1421
|
+
continue;
|
|
1422
|
+
}
|
|
1423
|
+
setSignalStatus(reaction, DIRTY);
|
|
1424
|
+
if ((reaction.f & EFFECT) !== 0 && (reaction.f & DERIVED) === 0) {
|
|
1425
|
+
scheduleEffect(reaction);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
for (const r of toRemove) {
|
|
1429
|
+
reactions.delete(r);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
prevValue = value;
|
|
1435
|
+
initialized = true;
|
|
1436
|
+
});
|
|
1437
|
+
return (key) => {
|
|
1438
|
+
const currentValue = prevValue;
|
|
1439
|
+
if (activeReaction !== null) {
|
|
1440
|
+
const reaction = activeReaction;
|
|
1441
|
+
if ((reaction.f & DESTROYED) === 0) {
|
|
1442
|
+
let keySubscribers = subscribers.get(key);
|
|
1443
|
+
if (!keySubscribers) {
|
|
1444
|
+
keySubscribers = new Set;
|
|
1445
|
+
subscribers.set(key, keySubscribers);
|
|
1446
|
+
}
|
|
1447
|
+
if (!keySubscribers.has(reaction)) {
|
|
1448
|
+
keySubscribers.add(reaction);
|
|
1449
|
+
let keys = reactionKeys.get(reaction);
|
|
1450
|
+
if (!keys) {
|
|
1451
|
+
keys = new Set;
|
|
1452
|
+
reactionKeys.set(reaction, keys);
|
|
1453
|
+
}
|
|
1454
|
+
keys.add(key);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
return fn(key, currentValue);
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1046
1461
|
// src/collections/map.ts
|
|
1462
|
+
var mapCleanup = new FinalizationRegistry((data) => {
|
|
1463
|
+
data.version.reactions = null;
|
|
1464
|
+
data.size.reactions = null;
|
|
1465
|
+
for (const sig of data.keySignals.values()) {
|
|
1466
|
+
sig.reactions = null;
|
|
1467
|
+
}
|
|
1468
|
+
data.keySignals.clear();
|
|
1469
|
+
});
|
|
1470
|
+
|
|
1047
1471
|
class ReactiveMap extends Map {
|
|
1048
1472
|
#keySignals = new Map;
|
|
1049
1473
|
#version = source(0);
|
|
@@ -1051,6 +1475,11 @@ class ReactiveMap extends Map {
|
|
|
1051
1475
|
constructor(entries) {
|
|
1052
1476
|
super(entries);
|
|
1053
1477
|
this.#size = source(super.size);
|
|
1478
|
+
mapCleanup.register(this, {
|
|
1479
|
+
keySignals: this.#keySignals,
|
|
1480
|
+
version: this.#version,
|
|
1481
|
+
size: this.#size
|
|
1482
|
+
});
|
|
1054
1483
|
}
|
|
1055
1484
|
#getKeySignal(key) {
|
|
1056
1485
|
let sig = this.#keySignals.get(key);
|
|
@@ -1161,6 +1590,15 @@ class ReactiveMap extends Map {
|
|
|
1161
1590
|
}
|
|
1162
1591
|
}
|
|
1163
1592
|
// src/collections/set.ts
|
|
1593
|
+
var setCleanup = new FinalizationRegistry((data) => {
|
|
1594
|
+
data.version.reactions = null;
|
|
1595
|
+
data.size.reactions = null;
|
|
1596
|
+
for (const sig of data.itemSignals.values()) {
|
|
1597
|
+
sig.reactions = null;
|
|
1598
|
+
}
|
|
1599
|
+
data.itemSignals.clear();
|
|
1600
|
+
});
|
|
1601
|
+
|
|
1164
1602
|
class ReactiveSet extends Set {
|
|
1165
1603
|
#itemSignals = new Map;
|
|
1166
1604
|
#version = source(0);
|
|
@@ -1168,6 +1606,11 @@ class ReactiveSet extends Set {
|
|
|
1168
1606
|
constructor(values) {
|
|
1169
1607
|
super(values);
|
|
1170
1608
|
this.#size = source(super.size);
|
|
1609
|
+
setCleanup.register(this, {
|
|
1610
|
+
itemSignals: this.#itemSignals,
|
|
1611
|
+
version: this.#version,
|
|
1612
|
+
size: this.#size
|
|
1613
|
+
});
|
|
1171
1614
|
}
|
|
1172
1615
|
#getItemSignal(item) {
|
|
1173
1616
|
let sig = this.#itemSignals.get(item);
|