@solidjs/signals 2.0.0-beta.24 → 2.0.0-beta.25
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/dist/dev.js +465 -81
- package/dist/node.cjs +990 -652
- package/dist/prod/core/core.js +110 -76
- package/dist/prod/core/effect.js +9 -9
- package/dist/prod/core/graph.js +3 -3
- package/dist/prod/core/heap.js +23 -23
- package/dist/prod/core/optimistic.js +6 -4
- package/dist/prod/core/owner.js +10 -10
- package/dist/prod/core/scheduler.js +12 -12
- package/dist/prod/core/verdict.js +3 -3
- package/dist/prod/store/optimistic.js +12 -5
- package/dist/prod/store/projection.js +25 -18
- package/dist/prod/store/reconcile.js +405 -211
- package/dist/prod/store/store.js +196 -102
- package/dist/prod/store/utils.js +22 -22
- package/dist/types/core/core.d.ts +15 -0
- package/dist/types/store/optimistic.d.ts +1 -1
- package/dist/types/store/store.d.ts +20 -2
- package/dist/types-cjs/core/core.d.cts +15 -0
- package/dist/types-cjs/store/optimistic.d.cts +1 -1
- package/dist/types-cjs/store/store.d.cts +20 -2
- package/package.json +1 -1
package/dist/node.cjs
CHANGED
|
@@ -223,7 +223,7 @@ const activeLanes = new Set;
|
|
|
223
223
|
l: [ [], [] ],
|
|
224
224
|
S: null,
|
|
225
225
|
T: activeTransition,
|
|
226
|
-
|
|
226
|
+
O: r
|
|
227
227
|
};
|
|
228
228
|
signalLanes.set(e, t);
|
|
229
229
|
activeLanes.add(t);
|
|
@@ -233,7 +233,7 @@ const activeLanes = new Set;
|
|
|
233
233
|
// parent-child is a property of the nodes, not of write order — otherwise
|
|
234
234
|
// the owner's write merges the companion's subscribers into this lane and
|
|
235
235
|
// their effects wait on its async instead of flushing immediately.
|
|
236
|
-
adoptCompanionLane(e.
|
|
236
|
+
adoptCompanionLane(e._, t);
|
|
237
237
|
adoptCompanionLane(e.p, t);
|
|
238
238
|
return t;
|
|
239
239
|
}
|
|
@@ -245,7 +245,7 @@ function adoptCompanionLane(e, t) {
|
|
|
245
245
|
const r = findLane(n);
|
|
246
246
|
// Only the companion's own unmerged root is safely re-parentable: a root
|
|
247
247
|
// that absorbed other lanes carries work that is not a child of this owner.
|
|
248
|
-
if (r !== t && r.o === e && !r.
|
|
248
|
+
if (r !== t && r.o === e && !r.O) r.O = t;
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
/**
|
|
@@ -324,9 +324,9 @@ function resolveTransition(e) {
|
|
|
324
324
|
if (i !== n && !hasActiveOverride(e)) {
|
|
325
325
|
// Parent-child lanes stay independent so isPending resolves without
|
|
326
326
|
// waiting for the parent's async. The child keeps ownership.
|
|
327
|
-
if (n.
|
|
327
|
+
if (n.O && findLane(n.O) === i) {
|
|
328
328
|
e.i = t;
|
|
329
|
-
} else if (i.
|
|
329
|
+
} else if (i.O && findLane(i.O) === n) ; else mergeLanes(n, i);
|
|
330
330
|
}
|
|
331
331
|
return;
|
|
332
332
|
}
|
|
@@ -376,24 +376,24 @@ function registerTransientStoreNode(e) {
|
|
|
376
376
|
|
|
377
377
|
function canUseSimpleSyncFlush(e) {
|
|
378
378
|
const t = e.D;
|
|
379
|
-
return transitions.size === 0 && activeLanes.size === 0 && e.m.length === 0 && t.v.length === 0 && t.
|
|
379
|
+
return transitions.size === 0 && activeLanes.size === 0 && e.m.length === 0 && t.v.length === 0 && t.L.length === 0 && t.V.size === 0 && transientStoreNodes.size === 0;
|
|
380
380
|
}
|
|
381
381
|
|
|
382
382
|
function sweepTransientStoreNodes() {
|
|
383
383
|
if (transientStoreNodes.size === 0) return;
|
|
384
384
|
for (const e of transientStoreNodes) {
|
|
385
|
-
if (e.
|
|
385
|
+
if (e.G !== null) {
|
|
386
386
|
transientStoreNodes.delete(e);
|
|
387
387
|
continue;
|
|
388
388
|
}
|
|
389
|
-
if (e.
|
|
389
|
+
if (e.U !== NOT_PENDING) continue;
|
|
390
390
|
if (e.A !== undefined && e.A !== NOT_PENDING) continue;
|
|
391
391
|
// A live affects() mark keeps the node addressable: sweeping it would
|
|
392
392
|
// detach the refcount from the slot (a fresh probe would upsert a new,
|
|
393
393
|
// unmarked node for the same property).
|
|
394
394
|
if (e.k) continue;
|
|
395
395
|
transientStoreNodes.delete(e);
|
|
396
|
-
e.
|
|
396
|
+
e.W?.();
|
|
397
397
|
}
|
|
398
398
|
}
|
|
399
399
|
|
|
@@ -420,12 +420,12 @@ function setProjectionWriteActive(e) {
|
|
|
420
420
|
* land there directly — no per-field aliasing.
|
|
421
421
|
*/ function createBatch() {
|
|
422
422
|
return {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
423
|
+
F: clock,
|
|
424
|
+
H: [],
|
|
425
|
+
M: new Map,
|
|
426
426
|
v: [],
|
|
427
|
-
|
|
428
|
-
|
|
427
|
+
L: [],
|
|
428
|
+
V: new Set,
|
|
429
429
|
$: [],
|
|
430
430
|
j: {
|
|
431
431
|
K: [ [], [] ],
|
|
@@ -447,17 +447,17 @@ function mergeTransitionState(e, t) {
|
|
|
447
447
|
e.v.push(...t.v);
|
|
448
448
|
t.v.length = 0;
|
|
449
449
|
}
|
|
450
|
-
if (t.
|
|
450
|
+
if (t.L.length) {
|
|
451
451
|
// Move (don't copy): the global queue's batch may still be the outgoing
|
|
452
452
|
// transition, and the adoption pass in initTransition would re-push its
|
|
453
453
|
// contents into the target — double-releasing every mark.
|
|
454
|
-
e.
|
|
455
|
-
t.
|
|
454
|
+
e.L.push(...t.L);
|
|
455
|
+
t.L.length = 0;
|
|
456
456
|
}
|
|
457
|
-
for (const n of t.
|
|
458
|
-
for (const [n, r] of t.
|
|
459
|
-
let t = e.
|
|
460
|
-
if (!t) e.
|
|
457
|
+
for (const n of t.V) e.V.add(n);
|
|
458
|
+
for (const [n, r] of t.M) {
|
|
459
|
+
let t = e.M.get(n);
|
|
460
|
+
if (!t) e.M.set(n, t = new Set);
|
|
461
461
|
for (const e of r) t.add(e);
|
|
462
462
|
}
|
|
463
463
|
for (const n of t.Y) e.Y.add(n);
|
|
@@ -599,14 +599,14 @@ class GlobalQueue extends Queue {
|
|
|
599
599
|
// isPending()/latest()).
|
|
600
600
|
static ue=null;
|
|
601
601
|
static le=null;
|
|
602
|
-
static ce=null;
|
|
603
602
|
static ae=null;
|
|
603
|
+
static ce=null;
|
|
604
604
|
static fe=null;
|
|
605
605
|
static Ee=null;
|
|
606
606
|
static de=null;
|
|
607
607
|
static Se=null;
|
|
608
608
|
static Te=null;
|
|
609
|
-
static
|
|
609
|
+
static Oe=null;
|
|
610
610
|
// Optimistic-engine hooks (wired by core/optimistic.ts via
|
|
611
611
|
// installOptimisticEngine(), called from verdict.ts / createOptimistic /
|
|
612
612
|
// createOptimisticStore — every module that can create optimistic state).
|
|
@@ -614,7 +614,7 @@ class GlobalQueue extends Queue {
|
|
|
614
614
|
// `_overrideValue` slot, a lane in `activeLanes`, an `_optimisticNodes`
|
|
615
615
|
// entry, or a non-null `currentOptimisticLane`, so `!` invocations are safe
|
|
616
616
|
// once the gate holds.
|
|
617
|
-
static
|
|
617
|
+
static _e=null;
|
|
618
618
|
static pe=null;
|
|
619
619
|
static Re=null;
|
|
620
620
|
static Ie=null;
|
|
@@ -654,29 +654,29 @@ class GlobalQueue extends Queue {
|
|
|
654
654
|
// A kept ambient batch may hold pending nodes (#2916): stay
|
|
655
655
|
// scheduled so the outer drain loop commits them via the plain
|
|
656
656
|
// flush path instead of leaving them until the next natural flush.
|
|
657
|
-
scheduled = dirtyQueue.C >= dirtyQueue.P || this.D.
|
|
658
|
-
reassignPendingTransition(e.
|
|
657
|
+
scheduled = dirtyQueue.C >= dirtyQueue.P || this.D.H.length > 0;
|
|
658
|
+
reassignPendingTransition(e.H);
|
|
659
659
|
activeTransition = null;
|
|
660
660
|
finalizePureQueue(null, true);
|
|
661
661
|
return;
|
|
662
662
|
}
|
|
663
663
|
const t = activeTransition;
|
|
664
664
|
const n = this.D;
|
|
665
|
-
n !== t && n.
|
|
665
|
+
n !== t && n.H.push(...t.H);
|
|
666
666
|
this.restoreQueues(t.j);
|
|
667
667
|
transitions.delete(t);
|
|
668
668
|
activeTransition = null;
|
|
669
|
-
reassignPendingTransition(n.
|
|
669
|
+
reassignPendingTransition(n.H);
|
|
670
670
|
finalizePureQueue(t);
|
|
671
671
|
if (n === t) {
|
|
672
672
|
// Drop the dead Transition wrapper but keep its (drained) containers
|
|
673
673
|
// as the ambient batch — late registrations during finalization live
|
|
674
674
|
// there and must survive to the next flush.
|
|
675
675
|
const e = createBatch();
|
|
676
|
-
e.
|
|
676
|
+
e.H = n.H;
|
|
677
677
|
e.v = n.v;
|
|
678
|
-
e.G = n.G;
|
|
679
678
|
e.L = n.L;
|
|
679
|
+
e.V = n.V;
|
|
680
680
|
currentBatch = this.D = e;
|
|
681
681
|
}
|
|
682
682
|
} else {
|
|
@@ -715,11 +715,11 @@ class GlobalQueue extends Queue {
|
|
|
715
715
|
// channel) updates display state on its way up but must be invisible
|
|
716
716
|
// to completion accounting BY CONSTRUCTION: it never registers a
|
|
717
717
|
// reporter and never counts toward the loading-boundary diagnostic.
|
|
718
|
-
if (t?.
|
|
718
|
+
if (t?.we) return true;
|
|
719
719
|
if (activeTransition && t) {
|
|
720
720
|
const n = t.source;
|
|
721
|
-
let r = activeTransition.
|
|
722
|
-
if (!r) activeTransition.
|
|
721
|
+
let r = activeTransition.M.get(n);
|
|
722
|
+
if (!r) activeTransition.M.set(n, r = new Set);
|
|
723
723
|
const i = r.size;
|
|
724
724
|
r.add(e);
|
|
725
725
|
if (r.size !== i) schedule();
|
|
@@ -732,7 +732,7 @@ class GlobalQueue extends Queue {
|
|
|
732
732
|
initTransition(e) {
|
|
733
733
|
if (e) e = currentTransition(e);
|
|
734
734
|
if (e && e === activeTransition) return;
|
|
735
|
-
if (!e && activeTransition && activeTransition.
|
|
735
|
+
if (!e && activeTransition && activeTransition.F === clock) return;
|
|
736
736
|
if (!activeTransition) {
|
|
737
737
|
activeTransition = e ?? createBatch();
|
|
738
738
|
} else if (e) {
|
|
@@ -742,7 +742,7 @@ class GlobalQueue extends Queue {
|
|
|
742
742
|
activeTransition = e;
|
|
743
743
|
}
|
|
744
744
|
transitions.add(activeTransition);
|
|
745
|
-
activeTransition.
|
|
745
|
+
activeTransition.F = clock;
|
|
746
746
|
const t = this.D;
|
|
747
747
|
if (t !== activeTransition) {
|
|
748
748
|
// Adopt the ambient batch into the transaction, then make the
|
|
@@ -752,18 +752,18 @@ class GlobalQueue extends Queue {
|
|
|
752
752
|
// must not entangle unrelated writes to it; the same rule holds one hop
|
|
753
753
|
// downstream: propagation never queues pended subscribers as pending
|
|
754
754
|
// nodes, see propagateAffectsMark, #2893.
|
|
755
|
-
for (let e = 0; e < t.
|
|
756
|
-
const n = t.
|
|
755
|
+
for (let e = 0; e < t.H.length; e++) {
|
|
756
|
+
const n = t.H[e];
|
|
757
757
|
n.T = activeTransition;
|
|
758
|
-
activeTransition.
|
|
758
|
+
activeTransition.H.push(n);
|
|
759
759
|
}
|
|
760
760
|
for (let e = 0; e < t.v.length; e++) {
|
|
761
761
|
const n = t.v[e];
|
|
762
762
|
n.T = activeTransition;
|
|
763
763
|
activeTransition.v.push(n);
|
|
764
764
|
}
|
|
765
|
-
if (t.
|
|
766
|
-
for (const e of t.
|
|
765
|
+
if (t.L.length) activeTransition.L.push(...t.L);
|
|
766
|
+
for (const e of t.V) activeTransition.V.add(e);
|
|
767
767
|
currentBatch = this.D = activeTransition;
|
|
768
768
|
}
|
|
769
769
|
for (const e of activeLanes) {
|
|
@@ -773,7 +773,7 @@ class GlobalQueue extends Queue {
|
|
|
773
773
|
}
|
|
774
774
|
|
|
775
775
|
function queuePendingNode(e) {
|
|
776
|
-
currentBatch.
|
|
776
|
+
currentBatch.H.push(e);
|
|
777
777
|
}
|
|
778
778
|
|
|
779
779
|
// Sticky: flips true on the first refresh() ever (the only setter of
|
|
@@ -789,52 +789,52 @@ function insertSubs(e, t = false) {
|
|
|
789
789
|
// Get source lane: prefer node's own lane over current context
|
|
790
790
|
// This is important for isPending signals which need their own lane to flush immediately
|
|
791
791
|
const n = e.i || currentOptimisticLane;
|
|
792
|
-
const r = e.
|
|
792
|
+
const r = e.me !== undefined;
|
|
793
793
|
const i = reaskArmed;
|
|
794
|
-
for (let o = e.
|
|
794
|
+
for (let o = e.G; o !== null; o = o.ve) {
|
|
795
795
|
// A value-change notification is a new question for the subscriber: any
|
|
796
796
|
// pending re-ask mark (refresh) it carried is superseded.
|
|
797
|
-
if (i) o.Le
|
|
798
|
-
if (r && o.
|
|
799
|
-
o.Le
|
|
797
|
+
if (i) o.Ve.Le &= ~REACTIVE_REASK;
|
|
798
|
+
if (r && o.Ve.Ge & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
799
|
+
o.Ve.Le |= REACTIVE_SNAPSHOT_STALE;
|
|
800
800
|
continue;
|
|
801
801
|
}
|
|
802
802
|
if (t && n) {
|
|
803
|
-
o.Le
|
|
804
|
-
assignOrMergeLane(o.
|
|
803
|
+
o.Ve.Le |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
804
|
+
assignOrMergeLane(o.Ve, n);
|
|
805
805
|
} else if (t) {
|
|
806
|
-
o.Le
|
|
806
|
+
o.Ve.Le |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
807
807
|
// No source lane means reversion - clear subscriber's lane so effects go to regular queue
|
|
808
|
-
o.
|
|
808
|
+
o.Ve.i = undefined;
|
|
809
809
|
}
|
|
810
|
-
enqueueSub(o.
|
|
810
|
+
enqueueSub(o.Ve);
|
|
811
811
|
}
|
|
812
812
|
}
|
|
813
813
|
|
|
814
814
|
function commitPendingNode(e) {
|
|
815
815
|
const t = e;
|
|
816
|
-
if (!t.
|
|
817
|
-
if (e.
|
|
818
|
-
e.ke = e.
|
|
819
|
-
e.
|
|
816
|
+
if (!t.Ue) {
|
|
817
|
+
if (e.U !== NOT_PENDING) {
|
|
818
|
+
e.ke = e.U;
|
|
819
|
+
e.U = NOT_PENDING;
|
|
820
820
|
}
|
|
821
|
-
if (e.
|
|
821
|
+
if (e._ || e.p) GlobalQueue.ce(e);
|
|
822
822
|
return;
|
|
823
823
|
}
|
|
824
|
-
if (e.
|
|
825
|
-
e.ke = e.
|
|
826
|
-
e.
|
|
824
|
+
if (e.U !== NOT_PENDING) {
|
|
825
|
+
e.ke = e.U;
|
|
826
|
+
e.U = NOT_PENDING;
|
|
827
827
|
// Set _modified for effects, but not for tracked effects (they handle their own scheduling)
|
|
828
|
-
if (e.
|
|
828
|
+
if (e.We && e.We !== EFFECT_TRACKED) e.Fe = true;
|
|
829
829
|
}
|
|
830
|
-
t.
|
|
831
|
-
if (!(t.
|
|
832
|
-
if (t.
|
|
833
|
-
if (e.
|
|
830
|
+
t.Le &= ~REACTIVE_MANUAL_WRITE;
|
|
831
|
+
if (!(t.xe & STATUS_PENDING)) t.xe &= ~STATUS_UNINITIALIZED;
|
|
832
|
+
if (t.Qe !== null || t.He !== null) GlobalQueue.X(t, false, true);
|
|
833
|
+
if (e._ || e.p) GlobalQueue.ce(e);
|
|
834
834
|
}
|
|
835
835
|
|
|
836
836
|
function commitPendingNodes() {
|
|
837
|
-
const e = currentBatch.
|
|
837
|
+
const e = currentBatch.H;
|
|
838
838
|
for (let t = 0; t < e.length; t++) {
|
|
839
839
|
commitPendingNode(e[t]);
|
|
840
840
|
}
|
|
@@ -860,7 +860,7 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
860
860
|
// so they re-run with the now-committed values visible.
|
|
861
861
|
if (e && e.Y.size) {
|
|
862
862
|
for (const t of e.Y) {
|
|
863
|
-
if (t.
|
|
863
|
+
if (t.Le & REACTIVE_DISPOSED) continue;
|
|
864
864
|
enqueueSub(t);
|
|
865
865
|
}
|
|
866
866
|
e.Y.clear();
|
|
@@ -871,15 +871,15 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
871
871
|
// held boundary display state through the visual channel, and their
|
|
872
872
|
// release is the display-state update point — re-run the boundary sweep
|
|
873
873
|
// (the earlier sweep above ran while the marks were still live).
|
|
874
|
-
if (t.
|
|
875
|
-
GlobalQueue.ne(t.
|
|
874
|
+
if (t.L.length) {
|
|
875
|
+
GlobalQueue.ne(t.L);
|
|
876
876
|
if (globalQueue.m.length) checkBoundaryChildren(globalQueue);
|
|
877
877
|
}
|
|
878
878
|
// A non-empty set means trackOptimisticStore ran, which installed the
|
|
879
879
|
// hook; the hook iterates, clears, and schedules (keeping the loop out of
|
|
880
880
|
// core lets esbuild shake it — rollup already folds the null guard). The
|
|
881
881
|
// completing transition scopes the clear to its own layer keys (#2899).
|
|
882
|
-
if (t.
|
|
882
|
+
if (t.V.size) GlobalQueue.ee(t.V, e);
|
|
883
883
|
sweepTransientStoreNodes();
|
|
884
884
|
// Lanes only enter activeLanes through the engine's getOrCreateLane.
|
|
885
885
|
if (activeLanes.size) GlobalQueue.Ie(e);
|
|
@@ -888,7 +888,7 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
888
888
|
|
|
889
889
|
function checkBoundaryChildren(e) {
|
|
890
890
|
for (const t of e.m) {
|
|
891
|
-
t.
|
|
891
|
+
t.Me?.();
|
|
892
892
|
checkBoundaryChildren(t);
|
|
893
893
|
}
|
|
894
894
|
}
|
|
@@ -955,7 +955,7 @@ function runQueue$1(e, t) {
|
|
|
955
955
|
}
|
|
956
956
|
|
|
957
957
|
function reporterBlocksSource(e, t) {
|
|
958
|
-
if (e.
|
|
958
|
+
if (e.Le & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
|
|
959
959
|
if (e.$e?.has(t)) return true;
|
|
960
960
|
for (let n = e.je; n; n = n.Ke) {
|
|
961
961
|
let e = n.Ye;
|
|
@@ -964,14 +964,14 @@ function reporterBlocksSource(e, t) {
|
|
|
964
964
|
e = e.t;
|
|
965
965
|
}
|
|
966
966
|
}
|
|
967
|
-
return !!(e.
|
|
967
|
+
return !!(e.xe & STATUS_PENDING && e.De instanceof NotReadyError && e.De.source === t);
|
|
968
968
|
}
|
|
969
969
|
|
|
970
970
|
function transitionComplete(e) {
|
|
971
971
|
if (e.I) return true;
|
|
972
972
|
if (e.$.length) return false;
|
|
973
973
|
let t = true;
|
|
974
|
-
for (const [n, r] of e.
|
|
974
|
+
for (const [n, r] of e.M) {
|
|
975
975
|
let i = false;
|
|
976
976
|
for (const e of r) {
|
|
977
977
|
if (reporterBlocksSource(e, n)) {
|
|
@@ -980,7 +980,7 @@ function transitionComplete(e) {
|
|
|
980
980
|
}
|
|
981
981
|
r.delete(e);
|
|
982
982
|
}
|
|
983
|
-
if (!i) e.
|
|
983
|
+
if (!i) e.M.delete(n); else if (n.xe & STATUS_PENDING && n.De?.source === n) {
|
|
984
984
|
t = false;
|
|
985
985
|
break;
|
|
986
986
|
}
|
|
@@ -1013,7 +1013,7 @@ function runInTransition(e, t) {
|
|
|
1013
1013
|
}
|
|
1014
1014
|
|
|
1015
1015
|
/** The queue a node belongs to, picked from its own zombie flag. */ function queueFor(e) {
|
|
1016
|
-
return e.
|
|
1016
|
+
return e.Le & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
|
|
1017
1017
|
}
|
|
1018
1018
|
|
|
1019
1019
|
/**
|
|
@@ -1021,10 +1021,10 @@ function runInTransition(e, t) {
|
|
|
1021
1021
|
* the heap and go directly to their effect queue; everything else is inserted
|
|
1022
1022
|
* into its own (zombie-flag-routed) heap with the `_min` cursor pulled down.
|
|
1023
1023
|
*/ function enqueueSub(e) {
|
|
1024
|
-
if (e.
|
|
1024
|
+
if (e.We === EFFECT_TRACKED) {
|
|
1025
1025
|
const t = e;
|
|
1026
|
-
if (!t.
|
|
1027
|
-
t.
|
|
1026
|
+
if (!t.Fe) {
|
|
1027
|
+
t.Fe = true;
|
|
1028
1028
|
t.Be.enqueue(EFFECT_USER, t.Ze);
|
|
1029
1029
|
}
|
|
1030
1030
|
return;
|
|
@@ -1049,12 +1049,12 @@ function actualInsertIntoHeap(e, t) {
|
|
|
1049
1049
|
}
|
|
1050
1050
|
|
|
1051
1051
|
function insertIntoHeap(e, t) {
|
|
1052
|
-
let n = e.
|
|
1052
|
+
let n = e.Le;
|
|
1053
1053
|
if (n & (REACTIVE_IN_HEAP | REACTIVE_RECOMPUTING_DEPS | REACTIVE_MANUAL_WRITE)) return;
|
|
1054
1054
|
if (n & REACTIVE_CHECK) {
|
|
1055
|
-
e.
|
|
1055
|
+
e.Le = n & -4 | REACTIVE_DIRTY | REACTIVE_IN_HEAP;
|
|
1056
1056
|
} else {
|
|
1057
|
-
e.
|
|
1057
|
+
e.Le = n | REACTIVE_IN_HEAP;
|
|
1058
1058
|
// An unmarked node entering a marked heap invalidates the markHeap memo:
|
|
1059
1059
|
// `_marked` is only reset by runHeap, so a write between two mid-tick
|
|
1060
1060
|
// pulls (read-time markHeap + updateIfNecessary) would otherwise leave
|
|
@@ -1066,16 +1066,16 @@ function insertIntoHeap(e, t) {
|
|
|
1066
1066
|
}
|
|
1067
1067
|
|
|
1068
1068
|
function insertIntoHeapHeight(e, t) {
|
|
1069
|
-
let n = e.
|
|
1069
|
+
let n = e.Le;
|
|
1070
1070
|
if (n & (REACTIVE_IN_HEAP | REACTIVE_RECOMPUTING_DEPS | REACTIVE_IN_HEAP_HEIGHT | REACTIVE_MANUAL_WRITE)) return;
|
|
1071
|
-
e.
|
|
1071
|
+
e.Le = n | REACTIVE_IN_HEAP_HEIGHT;
|
|
1072
1072
|
actualInsertIntoHeap(e, t);
|
|
1073
1073
|
}
|
|
1074
1074
|
|
|
1075
1075
|
function deleteFromHeap(e, t) {
|
|
1076
|
-
const n = e.
|
|
1076
|
+
const n = e.Le;
|
|
1077
1077
|
if (!(n & (REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT))) return;
|
|
1078
|
-
e.
|
|
1078
|
+
e.Le = n & -25;
|
|
1079
1079
|
const r = e.Xe;
|
|
1080
1080
|
if (e.et === e) t.h[r] = undefined; else {
|
|
1081
1081
|
const n = e.tt;
|
|
@@ -1093,22 +1093,22 @@ function markHeap(e) {
|
|
|
1093
1093
|
e.N = true;
|
|
1094
1094
|
for (let t = 0; t <= e.C; t++) {
|
|
1095
1095
|
for (let n = e.h[t]; n !== undefined; n = n.tt) {
|
|
1096
|
-
if (n.
|
|
1096
|
+
if (n.Le & REACTIVE_IN_HEAP) markNode(n);
|
|
1097
1097
|
}
|
|
1098
1098
|
}
|
|
1099
1099
|
}
|
|
1100
1100
|
|
|
1101
1101
|
function markNode(e, t = REACTIVE_DIRTY) {
|
|
1102
|
-
const n = e.
|
|
1102
|
+
const n = e.Le;
|
|
1103
1103
|
if ((n & (REACTIVE_CHECK | REACTIVE_DIRTY)) >= t) return;
|
|
1104
|
-
e.
|
|
1105
|
-
for (let t = e.
|
|
1106
|
-
markNode(t.
|
|
1104
|
+
e.Le = n & -4 | t;
|
|
1105
|
+
for (let t = e.G; t !== null; t = t.ve) {
|
|
1106
|
+
markNode(t.Ve, REACTIVE_CHECK);
|
|
1107
1107
|
}
|
|
1108
1108
|
if (e.nt !== null) {
|
|
1109
1109
|
for (let t = e.nt; t !== null; t = t.rt) {
|
|
1110
|
-
for (let e = t.
|
|
1111
|
-
markNode(e.
|
|
1110
|
+
for (let e = t.G; e !== null; e = e.ve) {
|
|
1111
|
+
markNode(e.Ve, REACTIVE_CHECK);
|
|
1112
1112
|
}
|
|
1113
1113
|
}
|
|
1114
1114
|
}
|
|
@@ -1119,7 +1119,7 @@ function runHeap(e, t) {
|
|
|
1119
1119
|
for (e.P = 0; e.P <= e.C; e.P++) {
|
|
1120
1120
|
let n = e.h[e.P];
|
|
1121
1121
|
while (n !== undefined) {
|
|
1122
|
-
if (n.
|
|
1122
|
+
if (n.Le & REACTIVE_IN_HEAP) t(n); else adjustHeight(n, e);
|
|
1123
1123
|
n = e.h[e.P];
|
|
1124
1124
|
}
|
|
1125
1125
|
}
|
|
@@ -1132,17 +1132,17 @@ function adjustHeight(e, t) {
|
|
|
1132
1132
|
for (let t = e.je; t; t = t.Ke) {
|
|
1133
1133
|
const e = t.Ye;
|
|
1134
1134
|
const r = e.qe || e;
|
|
1135
|
-
if (r.
|
|
1135
|
+
if (r.Ue && r.Xe >= n) n = r.Xe + 1;
|
|
1136
1136
|
}
|
|
1137
1137
|
if (e.Xe !== n) {
|
|
1138
1138
|
e.Xe = n;
|
|
1139
|
-
for (let t = e.
|
|
1139
|
+
for (let t = e.G; t !== null; t = t.ve) {
|
|
1140
1140
|
// Route each subscriber by its own zombie flag, mirroring the
|
|
1141
1141
|
// post-recompute height-adjust path. Inserting into the running `heap`
|
|
1142
1142
|
// unconditionally can park a zombie in `dirtyQueue` (or a live node in
|
|
1143
1143
|
// `zombieQueue`), breaking the flag/queue invariant `deleteFromHeap`
|
|
1144
1144
|
// relies on — the same corruption class as #2759.
|
|
1145
|
-
insertIntoHeapHeight(t.
|
|
1145
|
+
insertIntoHeapHeight(t.Ve, queueFor(t.Ve));
|
|
1146
1146
|
}
|
|
1147
1147
|
}
|
|
1148
1148
|
}
|
|
@@ -1153,8 +1153,8 @@ const PENDING_OWNER = {};
|
|
|
1153
1153
|
function markDisposal(e) {
|
|
1154
1154
|
let t = e.it;
|
|
1155
1155
|
while (t) {
|
|
1156
|
-
const e = t.
|
|
1157
|
-
t.
|
|
1156
|
+
const e = t.Le;
|
|
1157
|
+
t.Le = e | REACTIVE_ZOMBIE;
|
|
1158
1158
|
// migrate height-adjust entries too, not just recompute entries: every
|
|
1159
1159
|
// `deleteFromHeap` call site picks the queue from the zombie flag, so a
|
|
1160
1160
|
// node left physically linked in `dirtyQueue` after being zombified gets
|
|
@@ -1180,20 +1180,20 @@ function dispose(e) {
|
|
|
1180
1180
|
}
|
|
1181
1181
|
|
|
1182
1182
|
function disposeChildren(e, t = false, n) {
|
|
1183
|
-
const r = e.
|
|
1183
|
+
const r = e.Le;
|
|
1184
1184
|
if (r & REACTIVE_DISPOSED) return;
|
|
1185
1185
|
if (t) {
|
|
1186
|
-
e.
|
|
1186
|
+
e.Le = r | REACTIVE_DISPOSED;
|
|
1187
1187
|
// Companions are created detached and outlive their owner, but a verdict
|
|
1188
1188
|
// must not: a disposed source can never settle, so an isPending companion
|
|
1189
1189
|
// latched `true` here would hold a spinner forever (INV-9, the PR #2845
|
|
1190
1190
|
// edge). Snap runs after the DISPOSED flag is set so the oracle reads
|
|
1191
1191
|
// false, and notifies subscribers still watching the companion.
|
|
1192
1192
|
const t = e;
|
|
1193
|
-
if (t.
|
|
1193
|
+
if (t._ || t.p) GlobalQueue.ce(t);
|
|
1194
1194
|
}
|
|
1195
|
-
if (t && e.
|
|
1196
|
-
let i = n ? e.
|
|
1195
|
+
if (t && e.Ue) e.ut = null;
|
|
1196
|
+
let i = n ? e.Qe : e.it;
|
|
1197
1197
|
while (i) {
|
|
1198
1198
|
const e = i.ot;
|
|
1199
1199
|
if (i.je) {
|
|
@@ -1210,7 +1210,7 @@ function disposeChildren(e, t = false, n) {
|
|
|
1210
1210
|
i = e;
|
|
1211
1211
|
}
|
|
1212
1212
|
if (n) {
|
|
1213
|
-
e.
|
|
1213
|
+
e.Qe = null;
|
|
1214
1214
|
} else {
|
|
1215
1215
|
e.it = null;
|
|
1216
1216
|
e.lt = 0;
|
|
@@ -1219,7 +1219,7 @@ function disposeChildren(e, t = false, n) {
|
|
|
1219
1219
|
// batch dispose (parent already disposed) and zombie disposal (node sits on
|
|
1220
1220
|
// parent's _pendingFirstChild). We leave node._nextSibling intact so outer
|
|
1221
1221
|
// walks that already advanced past us still reach later siblings.
|
|
1222
|
-
if (t && !n && !(r & REACTIVE_ZOMBIE) && e.B !== null && !(e.B.
|
|
1222
|
+
if (t && !n && !(r & REACTIVE_ZOMBIE) && e.B !== null && !(e.B.Le & REACTIVE_DISPOSED)) {
|
|
1223
1223
|
const t = e.ct;
|
|
1224
1224
|
const n = e.ot;
|
|
1225
1225
|
if (t !== null) t.ot = n; else e.B.it = n;
|
|
@@ -1237,7 +1237,7 @@ function disposeChildren(e, t = false, n) {
|
|
|
1237
1237
|
}
|
|
1238
1238
|
|
|
1239
1239
|
function runDisposal(e, t) {
|
|
1240
|
-
let n = t ? e.
|
|
1240
|
+
let n = t ? e.He : e.Et;
|
|
1241
1241
|
if (!n) return;
|
|
1242
1242
|
if (Array.isArray(n)) {
|
|
1243
1243
|
for (let e = 0; e < n.length; e++) {
|
|
@@ -1247,12 +1247,12 @@ function runDisposal(e, t) {
|
|
|
1247
1247
|
} else {
|
|
1248
1248
|
n.call(n);
|
|
1249
1249
|
}
|
|
1250
|
-
t ? e.
|
|
1250
|
+
t ? e.He = null : e.Et = null;
|
|
1251
1251
|
}
|
|
1252
1252
|
|
|
1253
1253
|
function childId(e, t) {
|
|
1254
1254
|
let n = e;
|
|
1255
|
-
while (n.
|
|
1255
|
+
while (n.Ge & CONFIG_TRANSPARENT && n.B) n = n.B;
|
|
1256
1256
|
if (n.id != null) return formatId(n.id, t ? n.lt++ : n.lt);
|
|
1257
1257
|
throw new Error("");
|
|
1258
1258
|
}
|
|
@@ -1354,7 +1354,7 @@ function formatId(e, t) {
|
|
|
1354
1354
|
* }
|
|
1355
1355
|
* ```
|
|
1356
1356
|
*/ function isDisposed(e) {
|
|
1357
|
-
return !!(e.
|
|
1357
|
+
return !!(e.Le & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE));
|
|
1358
1358
|
}
|
|
1359
1359
|
|
|
1360
1360
|
function disposeRootSelf(e = true) {
|
|
@@ -1373,7 +1373,7 @@ function disposeRootSelf(e = true) {
|
|
|
1373
1373
|
const n = e?.transparent ?? false;
|
|
1374
1374
|
const r = {
|
|
1375
1375
|
id: inheritId(e, n, t),
|
|
1376
|
-
|
|
1376
|
+
Ge: n ? CONFIG_TRANSPARENT : 0,
|
|
1377
1377
|
ze: true,
|
|
1378
1378
|
Je: t?.ze ? t.Je : t,
|
|
1379
1379
|
it: null,
|
|
@@ -1383,8 +1383,8 @@ function disposeRootSelf(e = true) {
|
|
|
1383
1383
|
Be: t?.Be ?? globalQueue,
|
|
1384
1384
|
dt: t?.dt || defaultContext,
|
|
1385
1385
|
lt: 0,
|
|
1386
|
-
|
|
1387
|
-
|
|
1386
|
+
He: null,
|
|
1387
|
+
Qe: null,
|
|
1388
1388
|
B: t,
|
|
1389
1389
|
dispose: disposeRootSelf
|
|
1390
1390
|
};
|
|
@@ -1433,13 +1433,13 @@ function disposeRootSelf(e = true) {
|
|
|
1433
1433
|
function unlinkSubs(e) {
|
|
1434
1434
|
const t = e.Ye;
|
|
1435
1435
|
const n = e.Ke;
|
|
1436
|
-
const r = e.
|
|
1436
|
+
const r = e.ve;
|
|
1437
1437
|
const i = e.St;
|
|
1438
1438
|
if (r !== null) r.St = i; else t.Tt = i;
|
|
1439
|
-
if (i !== null) i.
|
|
1440
|
-
t.
|
|
1439
|
+
if (i !== null) i.ve = r; else {
|
|
1440
|
+
t.G = r;
|
|
1441
1441
|
if (r === null) {
|
|
1442
|
-
t.
|
|
1442
|
+
t.W?.();
|
|
1443
1443
|
// No more subscribers; only tear down if CONFIG_AUTO_DISPOSE is set.
|
|
1444
1444
|
// A pending node is exempt: its in-flight async work (or the
|
|
1445
1445
|
// transition holding it) is an observer — tearing down would orphan
|
|
@@ -1447,7 +1447,7 @@ function unlinkSubs(e) {
|
|
|
1447
1447
|
// this same last-one-out check when that observer releases (the
|
|
1448
1448
|
// untracked-read dispose in core.ts guards on pending identically).
|
|
1449
1449
|
const e = t;
|
|
1450
|
-
e.
|
|
1450
|
+
e.Ue && e.Ge & CONFIG_AUTO_DISPOSE && !(e.Le & REACTIVE_ZOMBIE) && !(e.xe & STATUS_PENDING) && unobserved(e);
|
|
1451
1451
|
}
|
|
1452
1452
|
}
|
|
1453
1453
|
return n;
|
|
@@ -1484,18 +1484,18 @@ function link(e, t, n = false) {
|
|
|
1484
1484
|
// read order within the computation.
|
|
1485
1485
|
const r = t.st;
|
|
1486
1486
|
if (r !== null && r.Ye === e) {
|
|
1487
|
-
r.
|
|
1487
|
+
r.Ot &&= n;
|
|
1488
1488
|
return;
|
|
1489
1489
|
}
|
|
1490
1490
|
let i = null;
|
|
1491
|
-
const o = t.
|
|
1491
|
+
const o = t.Le & REACTIVE_RECOMPUTING_DEPS;
|
|
1492
1492
|
if (o) {
|
|
1493
1493
|
i = r !== null ? r.Ke : t.je;
|
|
1494
1494
|
if (i !== null && i.Ye === e) {
|
|
1495
|
-
i.
|
|
1495
|
+
i._t = t.Rt;
|
|
1496
1496
|
t.st = i;
|
|
1497
1497
|
// First touch of this pass: the previous pass's label is stale.
|
|
1498
|
-
i.
|
|
1498
|
+
i.Ot = n;
|
|
1499
1499
|
return;
|
|
1500
1500
|
}
|
|
1501
1501
|
}
|
|
@@ -1505,23 +1505,23 @@ function link(e, t, n = false) {
|
|
|
1505
1505
|
// (the old alien-signals `isValidLink` walk, O(n²) when a computation
|
|
1506
1506
|
// re-reads earlier deps non-consecutively, e.g. store leaf reads).
|
|
1507
1507
|
const s = e.Tt;
|
|
1508
|
-
if (s !== null && s.
|
|
1508
|
+
if (s !== null && s.Ve === t && (!o || s._t === t.Rt)) {
|
|
1509
1509
|
// Gen-matched during a recompute = repeat touch this pass (AND); outside
|
|
1510
1510
|
// a recompute there is no pass boundary, so the latest read labels it.
|
|
1511
|
-
if (o) s.
|
|
1511
|
+
if (o) s.Ot &&= n; else s.Ot = n;
|
|
1512
1512
|
return;
|
|
1513
1513
|
}
|
|
1514
1514
|
const u = t.st = e.Tt = {
|
|
1515
1515
|
Ye: e,
|
|
1516
|
-
|
|
1516
|
+
Ve: t,
|
|
1517
1517
|
Ke: i,
|
|
1518
1518
|
St: s,
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1519
|
+
ve: null,
|
|
1520
|
+
_t: t.Rt,
|
|
1521
|
+
Ot: n
|
|
1522
1522
|
};
|
|
1523
1523
|
if (r !== null) r.Ke = u; else t.je = u;
|
|
1524
|
-
if (s !== null) s.
|
|
1524
|
+
if (s !== null) s.ve = u; else e.G = u;
|
|
1525
1525
|
}
|
|
1526
1526
|
|
|
1527
1527
|
// The lazily-created Set is the ONE container for pending sources. Its
|
|
@@ -1562,10 +1562,10 @@ function setPendingError(e, t, n) {
|
|
|
1562
1562
|
}
|
|
1563
1563
|
|
|
1564
1564
|
function forEachDependent(e, t) {
|
|
1565
|
-
for (let n = e.
|
|
1565
|
+
for (let n = e.G; n !== null; n = n.ve) t(n.Ve, n);
|
|
1566
1566
|
// `?? null`: affects() marks route plain signals (no `_child` slot) through here.
|
|
1567
1567
|
for (let n = e.nt ?? null; n !== null; n = n.rt) {
|
|
1568
|
-
for (let e = n.
|
|
1568
|
+
for (let e = n.G; e !== null; e = e.ve) t(e.Ve, e);
|
|
1569
1569
|
}
|
|
1570
1570
|
}
|
|
1571
1571
|
|
|
@@ -1580,13 +1580,13 @@ function settlePendingSource(e) {
|
|
|
1580
1580
|
const settle = i => {
|
|
1581
1581
|
if (n.has(i) || !removePendingSource(i, e)) return;
|
|
1582
1582
|
n.add(i);
|
|
1583
|
-
i.
|
|
1583
|
+
i.F = clock;
|
|
1584
1584
|
const o = i.$e?.values().next().value;
|
|
1585
1585
|
if (o) {
|
|
1586
1586
|
setPendingError(i, o);
|
|
1587
1587
|
r !== null && r(i);
|
|
1588
1588
|
} else {
|
|
1589
|
-
i.
|
|
1589
|
+
i.xe &= ~STATUS_PENDING;
|
|
1590
1590
|
setPendingError(i);
|
|
1591
1591
|
r !== null && r(i);
|
|
1592
1592
|
if (i.It) {
|
|
@@ -1626,16 +1626,16 @@ function handleAsync(e, t, n) {
|
|
|
1626
1626
|
globalQueue.initTransition(resolveTransition(e));
|
|
1627
1627
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
1628
1628
|
notifyStatus(e, n instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, n);
|
|
1629
|
-
e.
|
|
1629
|
+
e.F = clock;
|
|
1630
1630
|
};
|
|
1631
1631
|
const asyncWrite = (r, i) => {
|
|
1632
1632
|
if (e.ut !== t) return;
|
|
1633
1633
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
1634
1634
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
1635
1635
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
1636
|
-
if (e.
|
|
1636
|
+
if (e.Le & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
1637
1637
|
globalQueue.initTransition(resolveTransition(e));
|
|
1638
|
-
const o = !!(e.
|
|
1638
|
+
const o = !!(e.xe & STATUS_UNINITIALIZED);
|
|
1639
1639
|
trimStaleDeps(e);
|
|
1640
1640
|
clearStatus(e);
|
|
1641
1641
|
const s = resolveLane(e);
|
|
@@ -1653,8 +1653,8 @@ function handleAsync(e, t, n) {
|
|
|
1653
1653
|
// (A17 — every reader sees the override); the revert reveals whatever
|
|
1654
1654
|
// has committed by then, so corrections reveal atomically with their
|
|
1655
1655
|
// transition rather than escaping it.
|
|
1656
|
-
if (e.
|
|
1657
|
-
e.
|
|
1656
|
+
if (e.U === NOT_PENDING) queuePendingNode(e);
|
|
1657
|
+
e.U = r;
|
|
1658
1658
|
// The hold is a companion-visible write like any other (A13/A19): the
|
|
1659
1659
|
// clearStatus() above computed its verdict before the hold existed, so
|
|
1660
1660
|
// isPending must re-derive (the value is not final until commit — V1)
|
|
@@ -1664,16 +1664,16 @@ function handleAsync(e, t, n) {
|
|
|
1664
1664
|
// re-show an unchanged view — the revert is the notification point.
|
|
1665
1665
|
GlobalQueue.ue !== null && GlobalQueue.ue(e, r);
|
|
1666
1666
|
if (!hasActiveOverride(e)) insertSubs(e);
|
|
1667
|
-
e.
|
|
1667
|
+
e.F = clock;
|
|
1668
1668
|
} else if (s) {
|
|
1669
1669
|
// Route through lane's effect queue for independent flushing
|
|
1670
|
-
const t = e.
|
|
1670
|
+
const t = e.We;
|
|
1671
1671
|
const n = e.ke;
|
|
1672
1672
|
const i = e.At;
|
|
1673
1673
|
try {
|
|
1674
1674
|
if (!t && o || !i || !i(r, n)) {
|
|
1675
1675
|
e.ke = r;
|
|
1676
|
-
e.
|
|
1676
|
+
e.F = clock;
|
|
1677
1677
|
// The latest() shadow write gives latest() effects independent lanes; the
|
|
1678
1678
|
// _pendingSignal update is a no-op repeat of the clearStatus() call above
|
|
1679
1679
|
// (computePendingState doesn't read _value).
|
|
@@ -1707,7 +1707,7 @@ function handleAsync(e, t, n) {
|
|
|
1707
1707
|
// fetch per suspended re-read). Settling is that observer's release, so
|
|
1708
1708
|
// it runs the same last-one-out check the other release sites run.
|
|
1709
1709
|
const settleAutodispose = () => {
|
|
1710
|
-
if (e.
|
|
1710
|
+
if (e.Ge & CONFIG_AUTO_DISPOSE && !e.G && !(e.xe & STATUS_PENDING)) {
|
|
1711
1711
|
unobserved(e);
|
|
1712
1712
|
}
|
|
1713
1713
|
};
|
|
@@ -1756,11 +1756,11 @@ function handleAsync(e, t, n) {
|
|
|
1756
1756
|
} catch {}
|
|
1757
1757
|
});
|
|
1758
1758
|
const iterate = () => {
|
|
1759
|
-
let u, l,
|
|
1759
|
+
let u, l, a = false, c = false, f = true;
|
|
1760
1760
|
n.next().then(n => {
|
|
1761
1761
|
if (f) {
|
|
1762
1762
|
u = n;
|
|
1763
|
-
|
|
1763
|
+
a = true;
|
|
1764
1764
|
if (n.done) i = true;
|
|
1765
1765
|
} else if (e.ut !== t) {
|
|
1766
1766
|
return;
|
|
@@ -1780,26 +1780,26 @@ function handleAsync(e, t, n) {
|
|
|
1780
1780
|
}, n => {
|
|
1781
1781
|
if (f) {
|
|
1782
1782
|
l = n;
|
|
1783
|
-
|
|
1783
|
+
c = true;
|
|
1784
1784
|
} else if (e.ut === t) {
|
|
1785
1785
|
i = true;
|
|
1786
1786
|
handleError(n);
|
|
1787
1787
|
}
|
|
1788
1788
|
});
|
|
1789
1789
|
f = false;
|
|
1790
|
-
if (
|
|
1790
|
+
if (c) {
|
|
1791
1791
|
// Match the promise branch, but only rethrow during the initial read.
|
|
1792
1792
|
i = true;
|
|
1793
1793
|
handleError(l);
|
|
1794
1794
|
if (s) throw l;
|
|
1795
1795
|
return true;
|
|
1796
1796
|
}
|
|
1797
|
-
if (
|
|
1797
|
+
if (a && !u.done) {
|
|
1798
1798
|
o = u.value;
|
|
1799
1799
|
r = true;
|
|
1800
1800
|
return iterate();
|
|
1801
1801
|
}
|
|
1802
|
-
return
|
|
1802
|
+
return a && u.done;
|
|
1803
1803
|
};
|
|
1804
1804
|
const u = iterate();
|
|
1805
1805
|
// Later iterate() calls run from asyncWrite, where rethrowing would be unhandled.
|
|
@@ -1819,12 +1819,12 @@ function clearStatus(e, t = false) {
|
|
|
1819
1819
|
// (Unconditional: _reask is baked into the node literals, so this is a
|
|
1820
1820
|
// plain store to an existing slot — no shape change.)
|
|
1821
1821
|
e.ht = false;
|
|
1822
|
-
e.
|
|
1822
|
+
e.xe = t ? 0 : e.xe & STATUS_UNINITIALIZED;
|
|
1823
1823
|
if (e.De) setPendingError(e);
|
|
1824
1824
|
// Update pending signal for isPending() reactivity (companions only exist
|
|
1825
1825
|
// once the verdict layer created them, which installs the hooks).
|
|
1826
|
-
if (e.
|
|
1827
|
-
if (e.nt && GlobalQueue.
|
|
1826
|
+
if (e._ || e.p) GlobalQueue.le(e);
|
|
1827
|
+
if (e.nt && GlobalQueue.ae !== null) GlobalQueue.ae(e);
|
|
1828
1828
|
if (e.Nt) e.Nt();
|
|
1829
1829
|
}
|
|
1830
1830
|
|
|
@@ -1838,28 +1838,28 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
1838
1838
|
if (!r) {
|
|
1839
1839
|
if (t === STATUS_PENDING && o) {
|
|
1840
1840
|
addPendingSource(e, o);
|
|
1841
|
-
e.
|
|
1841
|
+
e.xe = STATUS_PENDING | e.xe & STATUS_UNINITIALIZED;
|
|
1842
1842
|
// Preserve the current source on this propagation so render-effect notification
|
|
1843
1843
|
// can register every distinct pending source with the transition.
|
|
1844
1844
|
setPendingError(e, o, n);
|
|
1845
1845
|
} else {
|
|
1846
1846
|
clearPendingSources(e);
|
|
1847
|
-
e.
|
|
1847
|
+
e.xe = t | (t !== STATUS_ERROR ? e.xe & STATUS_UNINITIALIZED : 0);
|
|
1848
1848
|
e.De = n;
|
|
1849
1849
|
}
|
|
1850
1850
|
GlobalQueue.le !== null && GlobalQueue.le(e);
|
|
1851
|
-
if (e.nt && GlobalQueue.
|
|
1851
|
+
if (e.nt && GlobalQueue.ae !== null) GlobalQueue.ae(e);
|
|
1852
1852
|
}
|
|
1853
1853
|
if (i && !r) {
|
|
1854
1854
|
assignOrMergeLane(e, i);
|
|
1855
1855
|
}
|
|
1856
|
-
const
|
|
1857
|
-
const
|
|
1856
|
+
const a = r || l;
|
|
1857
|
+
const c = r || u ? undefined : i;
|
|
1858
1858
|
if (e.Nt) {
|
|
1859
1859
|
if (r && t === STATUS_PENDING) {
|
|
1860
1860
|
return;
|
|
1861
1861
|
}
|
|
1862
|
-
if (
|
|
1862
|
+
if (a) {
|
|
1863
1863
|
e.Nt(t, n);
|
|
1864
1864
|
} else {
|
|
1865
1865
|
e.Nt();
|
|
@@ -1867,20 +1867,20 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
1867
1867
|
return;
|
|
1868
1868
|
}
|
|
1869
1869
|
forEachDependent(e, (e, r) => {
|
|
1870
|
-
e.
|
|
1870
|
+
e.F = clock;
|
|
1871
1871
|
if (t === STATUS_PENDING && o && !e.$e?.has(o) || t !== STATUS_PENDING && (e.De !== n || e.$e)) {
|
|
1872
1872
|
// A pending-observer link is the subscription an `isPending` read created.
|
|
1873
1873
|
// It exists so the observer re-runs when the source settles, but it must
|
|
1874
1874
|
// not carry a real (non-NotReadyError) error — the synchronous `isPending`
|
|
1875
1875
|
// read swallows those, and the async path must match. Re-run the observer
|
|
1876
1876
|
// so `isPending` re-evaluates (to not-pending) instead of forwarding.
|
|
1877
|
-
if (r.
|
|
1877
|
+
if (r.Ot && t !== STATUS_PENDING && !(n instanceof NotReadyError)) {
|
|
1878
1878
|
enqueueSub(e);
|
|
1879
1879
|
schedule();
|
|
1880
1880
|
return;
|
|
1881
1881
|
}
|
|
1882
|
-
if (!
|
|
1883
|
-
notifyStatus(e, t, n,
|
|
1882
|
+
if (!a && !e.T) queuePendingNode(e);
|
|
1883
|
+
notifyStatus(e, t, n, a, c);
|
|
1884
1884
|
}
|
|
1885
1885
|
});
|
|
1886
1886
|
}
|
|
@@ -1947,12 +1947,12 @@ function releaseSubtree(e) {
|
|
|
1947
1947
|
t = t.ot;
|
|
1948
1948
|
continue;
|
|
1949
1949
|
}
|
|
1950
|
-
if (t.
|
|
1950
|
+
if (t.Ue) {
|
|
1951
1951
|
const e = t;
|
|
1952
|
-
e.
|
|
1953
|
-
if (e.
|
|
1954
|
-
e.
|
|
1955
|
-
e.
|
|
1952
|
+
e.Ge &= ~CONFIG_IN_SNAPSHOT_SCOPE;
|
|
1953
|
+
if (e.Le & REACTIVE_SNAPSHOT_STALE) {
|
|
1954
|
+
e.Le &= ~REACTIVE_SNAPSHOT_STALE;
|
|
1955
|
+
e.Le |= REACTIVE_DIRTY;
|
|
1956
1956
|
if (dirtyQueue.P > e.Xe) dirtyQueue.P = e.Xe;
|
|
1957
1957
|
insertIntoHeap(e, dirtyQueue);
|
|
1958
1958
|
}
|
|
@@ -1965,7 +1965,7 @@ function releaseSubtree(e) {
|
|
|
1965
1965
|
function clearSnapshots() {
|
|
1966
1966
|
if (snapshotSources) {
|
|
1967
1967
|
for (const e of snapshotSources) {
|
|
1968
|
-
delete e.
|
|
1968
|
+
delete e.me;
|
|
1969
1969
|
// StoreNode targets share one pre-initialized hidden class (see
|
|
1970
1970
|
// createStoreProxy) — assign undefined instead of deleting, and only
|
|
1971
1971
|
// when present so signal-node sources don't grow the field.
|
|
@@ -1977,7 +1977,7 @@ function clearSnapshots() {
|
|
|
1977
1977
|
}
|
|
1978
1978
|
|
|
1979
1979
|
function recompute(e, t = false) {
|
|
1980
|
-
const n = e.
|
|
1980
|
+
const n = e.We;
|
|
1981
1981
|
if (!t) {
|
|
1982
1982
|
if (e.T && (!n || activeTransition) && activeTransition !== e.T) globalQueue.initTransition(e.T);
|
|
1983
1983
|
deleteFromHeap(e, queueFor(e));
|
|
@@ -1985,28 +1985,28 @@ function recompute(e, t = false) {
|
|
|
1985
1985
|
// Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
|
|
1986
1986
|
if (e.T || n === EFFECT_TRACKED) disposeChildren(e); else if (e.it !== null || e.Et !== null) {
|
|
1987
1987
|
markDisposal(e);
|
|
1988
|
-
e.
|
|
1989
|
-
e.
|
|
1988
|
+
e.He = e.Et;
|
|
1989
|
+
e.Qe = e.it;
|
|
1990
1990
|
e.Et = null;
|
|
1991
1991
|
e.it = null;
|
|
1992
1992
|
e.lt = 0;
|
|
1993
1993
|
} else ;
|
|
1994
1994
|
}
|
|
1995
|
-
let r = !!(e.
|
|
1995
|
+
let r = !!(e.Le & REACTIVE_OPTIMISTIC_DIRTY);
|
|
1996
1996
|
const i = e.A !== undefined && e.A !== NOT_PENDING;
|
|
1997
|
-
const o = !!(e.
|
|
1997
|
+
const o = !!(e.xe & STATUS_UNINITIALIZED);
|
|
1998
1998
|
// Re-ask classification lives in the verdict module; capture the flag before
|
|
1999
1999
|
// the recompute wipes _flags below.
|
|
2000
|
-
const s = (e.
|
|
2000
|
+
const s = (e.Le & REACTIVE_REASK) !== 0;
|
|
2001
2001
|
const u = context;
|
|
2002
2002
|
context = e;
|
|
2003
2003
|
e.st = null;
|
|
2004
2004
|
e.Rt++;
|
|
2005
|
-
e.
|
|
2006
|
-
e.
|
|
2007
|
-
let l = e.
|
|
2008
|
-
let
|
|
2009
|
-
let
|
|
2005
|
+
e.Le = REACTIVE_RECOMPUTING_DEPS;
|
|
2006
|
+
e.F = clock;
|
|
2007
|
+
let l = e.U === NOT_PENDING ? e.ke : e.U;
|
|
2008
|
+
let a = e.Xe;
|
|
2009
|
+
let c = tracking;
|
|
2010
2010
|
let f = currentOptimisticLane;
|
|
2011
2011
|
tracking = true;
|
|
2012
2012
|
// A computed's fn establishes its OWN dependencies, so it must never run
|
|
@@ -2037,8 +2037,8 @@ function recompute(e, t = false) {
|
|
|
2037
2037
|
const S = stale;
|
|
2038
2038
|
if (d) stale = true;
|
|
2039
2039
|
try {
|
|
2040
|
-
if (!false && e.
|
|
2041
|
-
l = e.
|
|
2040
|
+
if (!false && e.Ge & CONFIG_SYNC) {
|
|
2041
|
+
l = e.Ue(l);
|
|
2042
2042
|
e.ut = null;
|
|
2043
2043
|
} else {
|
|
2044
2044
|
// Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
|
|
@@ -2047,13 +2047,16 @@ function recompute(e, t = false) {
|
|
|
2047
2047
|
// clobber the fresh subscription, so we skip it and let the internally-registered
|
|
2048
2048
|
// iteration drive updates.
|
|
2049
2049
|
const t = e.ut;
|
|
2050
|
-
const n = e.
|
|
2050
|
+
const n = e.Ue(l);
|
|
2051
2051
|
const r = typeof n === "object" && n !== null;
|
|
2052
2052
|
const i = e.ut !== t;
|
|
2053
2053
|
l = i || !r ? n : handleAsync(e, n);
|
|
2054
2054
|
if (!i && !r) e.ut = null;
|
|
2055
2055
|
}
|
|
2056
|
-
clearStatus
|
|
2056
|
+
// On a status-free node clearStatus is a guaranteed no-op: every branch
|
|
2057
|
+
// in its body is gated on one of these fields, and with _statusFlags === 0
|
|
2058
|
+
// the flags write (create or not) stores the 0 already there.
|
|
2059
|
+
if (e.xe !== 0 || e.Nt !== undefined || e.De || e.ht || e.It || e.$e !== undefined || e._ !== undefined || e.p !== undefined || e.nt !== null) clearStatus(e, t);
|
|
2057
2060
|
// _optimisticLane is only ever assigned by engine paths.
|
|
2058
2061
|
if (e.i) GlobalQueue.ge(e);
|
|
2059
2062
|
} catch (t) {
|
|
@@ -2068,15 +2071,15 @@ function recompute(e, t = false) {
|
|
|
2068
2071
|
notifyStatus(e, t instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, t, undefined, t instanceof NotReadyError ? e.i : undefined);
|
|
2069
2072
|
if (n) GlobalQueue.Te(e);
|
|
2070
2073
|
} finally {
|
|
2071
|
-
tracking =
|
|
2074
|
+
tracking = c;
|
|
2072
2075
|
latestReadActive = E;
|
|
2073
2076
|
if (d) stale = S;
|
|
2074
|
-
e.
|
|
2077
|
+
e.Le = REACTIVE_NONE | (t ? e.Le & REACTIVE_SNAPSHOT_STALE : 0);
|
|
2075
2078
|
context = u;
|
|
2076
2079
|
}
|
|
2077
2080
|
if (!e.De) {
|
|
2078
2081
|
trimStaleDeps(e);
|
|
2079
|
-
const s = i ? unwrapOverride(e.A) : e.
|
|
2082
|
+
const s = i ? unwrapOverride(e.A) : e.U === NOT_PENDING ? e.ke : e.U;
|
|
2080
2083
|
let u = false;
|
|
2081
2084
|
try {
|
|
2082
2085
|
u = !n && o || !e.At || !e.At(s, l);
|
|
@@ -2093,14 +2096,19 @@ function recompute(e, t = false) {
|
|
|
2093
2096
|
// gate: the explicit recompute(node, true) inside effect() does not enqueue, so
|
|
2094
2097
|
// effect() can call its runner synchronously for the first run.
|
|
2095
2098
|
if (n && u) {
|
|
2096
|
-
e.
|
|
2099
|
+
e.Fe = !e.De;
|
|
2097
2100
|
// Reuse one bound runner per effect — runEffect no-ops on a stale
|
|
2098
2101
|
// `_modified`, so re-enqueueing the same function is harmless.
|
|
2099
2102
|
if (!t) e.Be.enqueue(n, e.Pt ??= GlobalQueue.J.bind(null, e));
|
|
2100
2103
|
}
|
|
2101
2104
|
if (e.De) ; else if (u) {
|
|
2102
2105
|
const o = i ? e.A : undefined;
|
|
2103
|
-
if (t ||
|
|
2106
|
+
if (t ||
|
|
2107
|
+
// Plain sync flush (no transition on either side) commits effect
|
|
2108
|
+
// values directly — the pending round-trip (queuePendingNode +
|
|
2109
|
+
// commitPendingNodes) exists to sequence transition reveals, and
|
|
2110
|
+
// paying it per effect on the plain path is pure overhead.
|
|
2111
|
+
n && (activeTransition !== e.T || activeTransition === null) || r) {
|
|
2104
2112
|
e.ke = l;
|
|
2105
2113
|
// Lane-propagated correction: upstream data is fresh, correct the
|
|
2106
2114
|
// override unconditionally. The direct _value commit is the lane's
|
|
@@ -2108,10 +2116,10 @@ function recompute(e, t = false) {
|
|
|
2108
2116
|
// commit can't clobber the fresh value.
|
|
2109
2117
|
if (i && r) {
|
|
2110
2118
|
e.A = l === undefined ? OVERRIDE_UNDEFINED : l;
|
|
2111
|
-
e.
|
|
2119
|
+
e.U = NOT_PENDING;
|
|
2112
2120
|
}
|
|
2113
2121
|
} else {
|
|
2114
|
-
e.
|
|
2122
|
+
e.U = l;
|
|
2115
2123
|
// Transition-held sync recompute is a write path like setSignal/asyncWrite,
|
|
2116
2124
|
// so sync derivations of held sources stay visible to isPending()/latest()
|
|
2117
2125
|
// (#2831). Both companion writes are transition-scoped (optimistic) and
|
|
@@ -2119,61 +2127,63 @@ function recompute(e, t = false) {
|
|
|
2119
2127
|
// pending value commits before effects run.
|
|
2120
2128
|
if ((activeTransition || e.T) && GlobalQueue.ue !== null) GlobalQueue.ue(e, l);
|
|
2121
2129
|
}
|
|
2122
|
-
|
|
2130
|
+
// insertSubs only walks _subs (no scheduling of its own), so a
|
|
2131
|
+
// subscriber-less node has nothing to notify.
|
|
2132
|
+
if (e.G !== null && (!i || r || e.A !== o)) insertSubs(e, r || i);
|
|
2123
2133
|
} else if (i) {
|
|
2124
2134
|
// Unchanged value (equals the override) recomputed while the override
|
|
2125
2135
|
// is active: _value may still be stale, so hold the authoritative value
|
|
2126
2136
|
// for commit on its own transition's schedule — invisibly (A17/A18).
|
|
2127
|
-
if (e.
|
|
2128
|
-
e.
|
|
2129
|
-
} else if (e.Xe !=
|
|
2130
|
-
for (let t = e.
|
|
2131
|
-
insertIntoHeapHeight(t.
|
|
2137
|
+
if (e.U === NOT_PENDING) queuePendingNode(e);
|
|
2138
|
+
e.U = l;
|
|
2139
|
+
} else if (e.Xe != a) {
|
|
2140
|
+
for (let t = e.G; t !== null; t = t.ve) {
|
|
2141
|
+
insertIntoHeapHeight(t.Ve, queueFor(t.Ve));
|
|
2132
2142
|
}
|
|
2133
2143
|
}
|
|
2134
2144
|
}
|
|
2135
2145
|
currentOptimisticLane = f;
|
|
2136
|
-
const T = e.
|
|
2146
|
+
const T = e.U !== NOT_PENDING || e.Qe !== null || e.He !== null || (e.xe & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
|
|
2137
2147
|
// Override-covered holds (hasOverride) always queue: their commit belongs
|
|
2138
2148
|
// to their own transition's schedule (A18 re-rule) and is unobservable
|
|
2139
2149
|
// under the override (A17). Revert no longer commits anything, so an
|
|
2140
2150
|
// unqueued covered hold would leak (INV-7) once the revert clears
|
|
2141
2151
|
// _transition.
|
|
2142
|
-
T && (!t || e.
|
|
2152
|
+
T && (!t || e.xe & STATUS_PENDING) && (!e.T || i) && queuePendingNode(e);
|
|
2143
2153
|
e.T && n && activeTransition !== e.T && runInTransition(e.T, () => recompute(e));
|
|
2144
2154
|
}
|
|
2145
2155
|
|
|
2146
2156
|
function updateIfNecessary(e) {
|
|
2147
|
-
if (e.
|
|
2157
|
+
if (e.Le & REACTIVE_CHECK) {
|
|
2148
2158
|
for (let t = e.je; t; t = t.Ke) {
|
|
2149
2159
|
const n = t.Ye;
|
|
2150
2160
|
const r = n.qe || n;
|
|
2151
|
-
if (r.
|
|
2161
|
+
if (r.Ue) {
|
|
2152
2162
|
updateIfNecessary(r);
|
|
2153
2163
|
}
|
|
2154
|
-
if (e.
|
|
2164
|
+
if (e.Le & REACTIVE_DIRTY) {
|
|
2155
2165
|
break;
|
|
2156
2166
|
}
|
|
2157
2167
|
}
|
|
2158
2168
|
}
|
|
2159
|
-
if (e.
|
|
2169
|
+
if (e.Le & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.De && e.F < clock && !e.ut) {
|
|
2160
2170
|
recompute(e);
|
|
2161
2171
|
}
|
|
2162
|
-
e.
|
|
2172
|
+
e.Le = e.Le & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
2163
2173
|
}
|
|
2164
2174
|
|
|
2165
2175
|
function computed(e, t) {
|
|
2166
2176
|
const n = t?.transparent ?? false;
|
|
2167
2177
|
const r = {
|
|
2168
2178
|
id: inheritId(t, n, context),
|
|
2169
|
-
|
|
2179
|
+
Ge: (n ? CONFIG_TRANSPARENT : 0) | (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (!context || t?.lazy ? CONFIG_AUTO_DISPOSE : 0) | (t?.sync ? CONFIG_SYNC : 0) | (t?.Ct ? CONFIG_NO_SNAPSHOT : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
2170
2180
|
At: t?.equals != null ? t.equals : isEqual,
|
|
2171
|
-
|
|
2181
|
+
W: t?.unobserved,
|
|
2172
2182
|
Et: null,
|
|
2173
2183
|
Be: context?.Be ?? globalQueue,
|
|
2174
2184
|
dt: context?.dt ?? defaultContext,
|
|
2175
2185
|
lt: 0,
|
|
2176
|
-
|
|
2186
|
+
Ue: e,
|
|
2177
2187
|
ke: undefined,
|
|
2178
2188
|
Xe: 0,
|
|
2179
2189
|
nt: null,
|
|
@@ -2182,18 +2192,18 @@ function computed(e, t) {
|
|
|
2182
2192
|
je: null,
|
|
2183
2193
|
st: null,
|
|
2184
2194
|
Rt: 0,
|
|
2185
|
-
|
|
2195
|
+
G: null,
|
|
2186
2196
|
Tt: null,
|
|
2187
2197
|
B: context,
|
|
2188
2198
|
ot: null,
|
|
2189
2199
|
ct: null,
|
|
2190
2200
|
it: null,
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2201
|
+
Le: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
2202
|
+
xe: STATUS_UNINITIALIZED,
|
|
2203
|
+
F: clock,
|
|
2204
|
+
U: NOT_PENDING,
|
|
2205
|
+
He: null,
|
|
2206
|
+
Qe: null,
|
|
2197
2207
|
ut: null,
|
|
2198
2208
|
T: null,
|
|
2199
2209
|
ht: false
|
|
@@ -2211,14 +2221,14 @@ function computed(e, t) {
|
|
|
2211
2221
|
const s = o?.transparent ?? false;
|
|
2212
2222
|
const u = {
|
|
2213
2223
|
id: inheritId(o, s, context),
|
|
2214
|
-
|
|
2224
|
+
Ge: (s ? CONFIG_TRANSPARENT : 0) | (o?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (o?.sync ? CONFIG_SYNC : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
2215
2225
|
At: false,
|
|
2216
|
-
|
|
2226
|
+
W: o?.unobserved,
|
|
2217
2227
|
Et: null,
|
|
2218
2228
|
Be: context?.Be ?? globalQueue,
|
|
2219
2229
|
dt: context?.dt ?? defaultContext,
|
|
2220
2230
|
lt: 0,
|
|
2221
|
-
|
|
2231
|
+
Ue: e,
|
|
2222
2232
|
ke: undefined,
|
|
2223
2233
|
Xe: 0,
|
|
2224
2234
|
nt: null,
|
|
@@ -2227,27 +2237,27 @@ function computed(e, t) {
|
|
|
2227
2237
|
je: null,
|
|
2228
2238
|
st: null,
|
|
2229
2239
|
Rt: 0,
|
|
2230
|
-
|
|
2240
|
+
G: null,
|
|
2231
2241
|
Tt: null,
|
|
2232
2242
|
B: context,
|
|
2233
2243
|
ot: null,
|
|
2234
2244
|
ct: null,
|
|
2235
2245
|
it: null,
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2246
|
+
Le: REACTIVE_LAZY,
|
|
2247
|
+
xe: STATUS_UNINITIALIZED,
|
|
2248
|
+
F: clock,
|
|
2249
|
+
U: NOT_PENDING,
|
|
2250
|
+
He: null,
|
|
2251
|
+
Qe: null,
|
|
2242
2252
|
ut: null,
|
|
2243
2253
|
T: null,
|
|
2244
2254
|
ht: false,
|
|
2245
|
-
|
|
2255
|
+
Fe: false,
|
|
2246
2256
|
gt: undefined,
|
|
2247
2257
|
bt: t,
|
|
2248
2258
|
Dt: n,
|
|
2249
2259
|
ft: undefined,
|
|
2250
|
-
|
|
2260
|
+
We: r,
|
|
2251
2261
|
Nt: i
|
|
2252
2262
|
};
|
|
2253
2263
|
setupComputedNode(u, lazyOptions);
|
|
@@ -2275,8 +2285,8 @@ function setupComputedNode(e, t) {
|
|
|
2275
2285
|
if (GlobalQueue.oe !== null) GlobalQueue.oe(e);
|
|
2276
2286
|
!t?.lazy && recompute(e, true);
|
|
2277
2287
|
if (snapshotCaptureActive && !t?.lazy) {
|
|
2278
|
-
if (!(e.
|
|
2279
|
-
e.
|
|
2288
|
+
if (!(e.xe & STATUS_PENDING) && !(e.Ge & CONFIG_NO_SNAPSHOT)) {
|
|
2289
|
+
e.me = e.ke === undefined ? NO_SNAPSHOT : e.ke;
|
|
2280
2290
|
snapshotSources.add(e);
|
|
2281
2291
|
}
|
|
2282
2292
|
}
|
|
@@ -2285,19 +2295,19 @@ function setupComputedNode(e, t) {
|
|
|
2285
2295
|
function signal(e, t, n = null) {
|
|
2286
2296
|
const r = {
|
|
2287
2297
|
At: t?.equals != null ? t.equals : isEqual,
|
|
2288
|
-
|
|
2289
|
-
|
|
2298
|
+
Ge: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.Ct ? CONFIG_NO_SNAPSHOT : 0),
|
|
2299
|
+
W: t?.unobserved,
|
|
2290
2300
|
ke: e,
|
|
2291
|
-
|
|
2301
|
+
G: null,
|
|
2292
2302
|
Tt: null,
|
|
2293
|
-
|
|
2303
|
+
F: clock,
|
|
2294
2304
|
qe: n,
|
|
2295
2305
|
rt: n?.nt || null,
|
|
2296
|
-
|
|
2306
|
+
U: NOT_PENDING
|
|
2297
2307
|
};
|
|
2298
2308
|
n && (n.nt = r);
|
|
2299
|
-
if (snapshotCaptureActive && !(r.
|
|
2300
|
-
r.
|
|
2309
|
+
if (snapshotCaptureActive && !(r.Ge & CONFIG_NO_SNAPSHOT) && !((n?.xe ?? 0) & STATUS_PENDING)) {
|
|
2310
|
+
r.me = e === undefined ? NO_SNAPSHOT : e;
|
|
2301
2311
|
snapshotSources.add(r);
|
|
2302
2312
|
}
|
|
2303
2313
|
return r;
|
|
@@ -2357,16 +2367,37 @@ function isEqual(e, t) {
|
|
|
2357
2367
|
* an isPending() probe (`refresh`) additionally pulls the node fully up to
|
|
2358
2368
|
* date so its status flags reflect the current graph.
|
|
2359
2369
|
*/ function prepareComputed(e, t) {
|
|
2360
|
-
if (e.
|
|
2361
|
-
e.
|
|
2370
|
+
if (e.Le & REACTIVE_LAZY) {
|
|
2371
|
+
e.Le &= ~REACTIVE_LAZY;
|
|
2362
2372
|
recompute(e, true);
|
|
2363
|
-
} else if (e.
|
|
2373
|
+
} else if (e.Le & REACTIVE_DISPOSED) {
|
|
2364
2374
|
recompute(e, true);
|
|
2365
2375
|
} else if (t) {
|
|
2366
2376
|
updateIfNecessary(e);
|
|
2367
2377
|
}
|
|
2368
2378
|
}
|
|
2369
2379
|
|
|
2380
|
+
/**
|
|
2381
|
+
* Sentinel returned by readNodeFast when the plain-signal fast path does not
|
|
2382
|
+
* apply and the caller must fall back to the full read().
|
|
2383
|
+
*/ const READ_SLOW = Symbol("read-slow");
|
|
2384
|
+
|
|
2385
|
+
/**
|
|
2386
|
+
* read()'s plain-signal fast path as a standalone entry for hot callers
|
|
2387
|
+
* (store traps). Safe to substitute for read() only because the bail
|
|
2388
|
+
* conditions mirror read()'s prelude and fast-path guard exactly: the
|
|
2389
|
+
* latestRead and pendingCheck windows run side-effectful hooks before the
|
|
2390
|
+
* fast path, `_fn` nodes need prepareComputed, and firewall / override /
|
|
2391
|
+
* snapshot / transition / lane / dev-strictRead state all take the full
|
|
2392
|
+
* resolution. Anything slow returns READ_SLOW; the caller then calls read().
|
|
2393
|
+
*/ function readNodeFast(e) {
|
|
2394
|
+
if (latestReadActive || pendingCheckActive || e.Ue || e.qe || e.A !== undefined || e.me !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
|
|
2395
|
+
let t = context;
|
|
2396
|
+
if (t?.ze) t = t.Je;
|
|
2397
|
+
if (t && tracking) link(e, t);
|
|
2398
|
+
return !t || e.U === NOT_PENDING ? e.ke : e.U;
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2370
2401
|
function read(e) {
|
|
2371
2402
|
// Handle latest() mode: read from _latestValueComputed
|
|
2372
2403
|
// Checked before isPending so that isPending(() => latest(x)) checks
|
|
@@ -2383,16 +2414,16 @@ function read(e) {
|
|
|
2383
2414
|
// recompute don't collect into the probe.
|
|
2384
2415
|
if (pendingCheckActive) {
|
|
2385
2416
|
GlobalQueue.Ee(e, t, i, r);
|
|
2386
|
-
} else if (typeof n.
|
|
2417
|
+
} else if (typeof n.Ue === "function") {
|
|
2387
2418
|
prepareComputed(e, false);
|
|
2388
2419
|
}
|
|
2389
|
-
if (!n.
|
|
2420
|
+
if (!n.Ue && i === e && e.A === undefined && e.me === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
|
|
2390
2421
|
if (t && tracking) link(e, t);
|
|
2391
|
-
return !t || e.
|
|
2422
|
+
return !t || e.U === NOT_PENDING ? e.ke : e.U;
|
|
2392
2423
|
}
|
|
2393
2424
|
if (t && tracking) {
|
|
2394
2425
|
link(e, t, pendingCheckActive);
|
|
2395
|
-
if (i.
|
|
2426
|
+
if (i.Ue) {
|
|
2396
2427
|
const n = queueFor(e);
|
|
2397
2428
|
if (i.Xe >= n.P) {
|
|
2398
2429
|
markNode(t);
|
|
@@ -2406,7 +2437,7 @@ function read(e) {
|
|
|
2406
2437
|
}
|
|
2407
2438
|
}
|
|
2408
2439
|
}
|
|
2409
|
-
if (i.
|
|
2440
|
+
if (i.xe & STATUS_PENDING) {
|
|
2410
2441
|
if (t && !(stale && i.T && activeTransition !== i.T)) {
|
|
2411
2442
|
// Per-lane suspension lives with the engine (a non-null lane implies it
|
|
2412
2443
|
// is installed): under a lane, only same-lane pending async without an
|
|
@@ -2415,29 +2446,29 @@ function read(e) {
|
|
|
2415
2446
|
if (!tracking && e !== t) link(e, t);
|
|
2416
2447
|
throw i.De;
|
|
2417
2448
|
}
|
|
2418
|
-
} else if (t && i !== e && i.
|
|
2449
|
+
} else if (t && i !== e && i.xe & STATUS_UNINITIALIZED) {
|
|
2419
2450
|
if (!tracking && e !== t) link(e, t);
|
|
2420
2451
|
throw i.De;
|
|
2421
|
-
} else if (!t && i.
|
|
2452
|
+
} else if (!t && i.xe & STATUS_UNINITIALIZED) {
|
|
2422
2453
|
throw i.De;
|
|
2423
2454
|
}
|
|
2424
2455
|
}
|
|
2425
|
-
if (e.
|
|
2456
|
+
if (e.Ue && e.xe & STATUS_ERROR) {
|
|
2426
2457
|
// Only a genuine reactive re-read may retry an errored async source:
|
|
2427
2458
|
// - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
|
|
2428
2459
|
// - !pendingCheckActive: an `isPending` probe observes the error, never refetches
|
|
2429
2460
|
// - el._time < clock: only on a later cycle than the one the error was found
|
|
2430
|
-
if (tracking && !pendingCheckActive && e.
|
|
2461
|
+
if (tracking && !pendingCheckActive && e.F < clock) {
|
|
2431
2462
|
recompute(e);
|
|
2432
2463
|
return read(e);
|
|
2433
2464
|
} else throw e.De;
|
|
2434
2465
|
}
|
|
2435
|
-
if (snapshotCaptureActive && t && t.
|
|
2436
|
-
const n = e.
|
|
2466
|
+
if (snapshotCaptureActive && t && t.Ge & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
2467
|
+
const n = e.me;
|
|
2437
2468
|
if (n !== undefined) {
|
|
2438
2469
|
const r = n === NO_SNAPSHOT ? undefined : n;
|
|
2439
|
-
const i = e.
|
|
2440
|
-
if (i !== r) t.
|
|
2470
|
+
const i = e.U !== NOT_PENDING ? e.U : e.ke;
|
|
2471
|
+
if (i !== r) t.Le |= REACTIVE_SNAPSHOT_STALE;
|
|
2441
2472
|
return r;
|
|
2442
2473
|
}
|
|
2443
2474
|
}
|
|
@@ -2459,11 +2490,11 @@ function read(e) {
|
|
|
2459
2490
|
// and for regular signals in stale mode (render effects). Non-stale readers (user
|
|
2460
2491
|
// effects) see _pendingValue so that latest() and direct reads stay consistent.
|
|
2461
2492
|
// (The lane-context clause lives with the engine.)
|
|
2462
|
-
const o = !t || currentOptimisticLane !== null && GlobalQueue.ye(e, i, t) || e.
|
|
2493
|
+
const o = !t || currentOptimisticLane !== null && GlobalQueue.ye(e, i, t) || e.U === NOT_PENDING || stale && e.T && activeTransition !== e.T ? e.ke : e.U;
|
|
2463
2494
|
// Record that this isPending() probe observed the fresh pending value, so
|
|
2464
2495
|
// the probe doesn't pair "pending" with the new value (#2831).
|
|
2465
2496
|
if (pendingCheckActive) GlobalQueue.de(e, o);
|
|
2466
|
-
if (!t && i === e && typeof n.
|
|
2497
|
+
if (!t && i === e && typeof n.Ue === "function" && e.Ge & CONFIG_AUTO_DISPOSE && !(i.xe & STATUS_PENDING) && !e.G) {
|
|
2467
2498
|
unobserved(e);
|
|
2468
2499
|
}
|
|
2469
2500
|
return o;
|
|
@@ -2475,17 +2506,20 @@ function setSignal(e, t) {
|
|
|
2475
2506
|
// optimisticComputed callers and optimistic store nodes carry an
|
|
2476
2507
|
// _overrideValue slot, and every module that creates one installs the
|
|
2477
2508
|
// engine first.
|
|
2478
|
-
if (e.A !== undefined && !projectionWriteActive) return GlobalQueue.
|
|
2479
|
-
const n = e.
|
|
2509
|
+
if (e.A !== undefined && !projectionWriteActive) return GlobalQueue._e(e, t);
|
|
2510
|
+
const n = e.U === NOT_PENDING ? e.ke : e.U;
|
|
2480
2511
|
if (typeof t === "function") t = t(n);
|
|
2481
2512
|
// Uninitialized check first: the first commit has no previous value, so the
|
|
2482
2513
|
// user comparator must not run against `undefined` (matches recompute).
|
|
2483
|
-
const r = !!(e.
|
|
2514
|
+
const r = !!(e.xe & STATUS_UNINITIALIZED) || !e.At || !e.At(n, t);
|
|
2484
2515
|
if (!r) return t;
|
|
2485
|
-
if (e.
|
|
2486
|
-
e.
|
|
2487
|
-
|
|
2488
|
-
|
|
2516
|
+
if (e.U === NOT_PENDING) queuePendingNode(e);
|
|
2517
|
+
e.U = t;
|
|
2518
|
+
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
2519
|
+
// neither companion present the call is a guaranteed no-op (companions are
|
|
2520
|
+
// only ever created, never removed, and creating one installs the hook).
|
|
2521
|
+
(e._ !== undefined || e.p !== undefined) && GlobalQueue.ue !== null && GlobalQueue.ue(e, t);
|
|
2522
|
+
e.F = clock;
|
|
2489
2523
|
insertSubs(e);
|
|
2490
2524
|
schedule();
|
|
2491
2525
|
return t;
|
|
@@ -2499,11 +2533,11 @@ function setSignal(e, t) {
|
|
|
2499
2533
|
* cleanup point.
|
|
2500
2534
|
*/ function suppressComputedRecompute(e) {
|
|
2501
2535
|
deleteFromHeap(e, queueFor(e));
|
|
2502
|
-
if (!(e.
|
|
2536
|
+
if (!(e.Le & REACTIVE_MANUAL_WRITE) && e.U === NOT_PENDING) {
|
|
2503
2537
|
queuePendingNode(e);
|
|
2504
2538
|
schedule();
|
|
2505
2539
|
}
|
|
2506
|
-
e.
|
|
2540
|
+
e.Le = e.Le & -4 | REACTIVE_MANUAL_WRITE;
|
|
2507
2541
|
}
|
|
2508
2542
|
|
|
2509
2543
|
/**
|
|
@@ -2582,7 +2616,7 @@ function staleValues(e, t = true) {
|
|
|
2582
2616
|
if (!t) {
|
|
2583
2617
|
return;
|
|
2584
2618
|
}
|
|
2585
|
-
if (typeof t.
|
|
2619
|
+
if (typeof t.Ue === "function" && !(t.Le & (REACTIVE_DISPOSED | REACTIVE_MANUAL_WRITE))) {
|
|
2586
2620
|
// A refresh with no value-change dirt already queued is a re-ask of the
|
|
2587
2621
|
// same question: mark it so the recompute classifies any resulting
|
|
2588
2622
|
// pending window as quiet (not pending). If the node is already dirty
|
|
@@ -2590,11 +2624,11 @@ function staleValues(e, t = true) {
|
|
|
2590
2624
|
// REACTIVE_IN_HEAP counts as dirt: insertSubs schedules subscribers by
|
|
2591
2625
|
// heap insertion alone (no DIRTY/CHECK flag), so a same-batch value
|
|
2592
2626
|
// change followed by refresh() must not be laundered into a quiet re-ask.
|
|
2593
|
-
if (!(t.
|
|
2594
|
-
t.
|
|
2627
|
+
if (!(t.Le & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP))) {
|
|
2628
|
+
t.Le |= REACTIVE_REASK;
|
|
2595
2629
|
armReaskClear();
|
|
2596
2630
|
}
|
|
2597
|
-
t.
|
|
2631
|
+
t.Le = t.Le & ~REACTIVE_CHECK | REACTIVE_DIRTY;
|
|
2598
2632
|
insertIntoHeap(t, queueFor(t));
|
|
2599
2633
|
schedule();
|
|
2600
2634
|
}
|
|
@@ -2642,11 +2676,11 @@ function wireExternalSource(e) {
|
|
|
2642
2676
|
equals: false,
|
|
2643
2677
|
ownedWrite: true
|
|
2644
2678
|
});
|
|
2645
|
-
const n = externalSourceConfig.factory(e.
|
|
2679
|
+
const n = externalSourceConfig.factory(e.Ue, () => {
|
|
2646
2680
|
setSignal(t, undefined);
|
|
2647
2681
|
});
|
|
2648
2682
|
cleanup(() => n.dispose());
|
|
2649
|
-
e.
|
|
2683
|
+
e.Ue = e => {
|
|
2650
2684
|
read(t);
|
|
2651
2685
|
return n.track(e);
|
|
2652
2686
|
};
|
|
@@ -2770,7 +2804,7 @@ function isUndefined(e) {
|
|
|
2770
2804
|
const n = e.A !== NOT_PENDING;
|
|
2771
2805
|
const r = n ? unwrapOverride(e.A) : e.ke;
|
|
2772
2806
|
if (typeof t === "function") t = t(r);
|
|
2773
|
-
const i = !!(e.
|
|
2807
|
+
const i = !!(e.xe & STATUS_UNINITIALIZED) || !e.At || !e.At(r, t);
|
|
2774
2808
|
if (!i) {
|
|
2775
2809
|
// Same-value write with an active override still entangles the current
|
|
2776
2810
|
// action's transition — the hold must outlast all overlapping actions.
|
|
@@ -2795,8 +2829,10 @@ function isUndefined(e) {
|
|
|
2795
2829
|
// brand, and erasing it makes the write invisible and routes follow-up
|
|
2796
2830
|
// writes off the optimistic path into permanent commits (#2898).
|
|
2797
2831
|
e.A = t === undefined ? OVERRIDE_UNDEFINED : t;
|
|
2798
|
-
|
|
2799
|
-
|
|
2832
|
+
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
2833
|
+
// neither companion present the call is a guaranteed no-op.
|
|
2834
|
+
(e._ !== undefined || e.p !== undefined) && GlobalQueue.ue !== null && GlobalQueue.ue(e, t);
|
|
2835
|
+
e.F = clock;
|
|
2800
2836
|
insertSubs(e, true);
|
|
2801
2837
|
schedule();
|
|
2802
2838
|
return t;
|
|
@@ -2809,7 +2845,7 @@ function isUndefined(e) {
|
|
|
2809
2845
|
*/ function transitionBlocked(e) {
|
|
2810
2846
|
for (let t = 0; t < e.v.length; t++) {
|
|
2811
2847
|
const n = e.v[t];
|
|
2812
|
-
if (hasActiveOverride(n) && "
|
|
2848
|
+
if (hasActiveOverride(n) && "xe" in n && n.xe & STATUS_PENDING && n.De instanceof NotReadyError) {
|
|
2813
2849
|
return true;
|
|
2814
2850
|
}
|
|
2815
2851
|
}
|
|
@@ -2827,7 +2863,7 @@ function resolveOptimisticNodes(e) {
|
|
|
2827
2863
|
// Revert is a pure drop: there is no revert target to commit —
|
|
2828
2864
|
// override-covered authoritative values hold in _pendingValue and
|
|
2829
2865
|
// elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
|
|
2830
|
-
if (!(t.
|
|
2866
|
+
if (!(t.xe & STATUS_PENDING)) t.xe &= ~STATUS_UNINITIALIZED;
|
|
2831
2867
|
const r = t.A;
|
|
2832
2868
|
t.A = NOT_PENDING;
|
|
2833
2869
|
if (r !== NOT_PENDING && t.ke !== unwrapOverride(r)) insertSubs(t, true);
|
|
@@ -2839,9 +2875,9 @@ function resolveOptimisticNodes(e) {
|
|
|
2839
2875
|
// transition that produced them (A19 — pending is a property of the data).
|
|
2840
2876
|
for (let n = 0; n < t; n++) {
|
|
2841
2877
|
const t = e[n];
|
|
2842
|
-
if (t.
|
|
2878
|
+
if (t._ || t.p) GlobalQueue.ce(t);
|
|
2843
2879
|
const r = t.t;
|
|
2844
|
-
if (r && (r.
|
|
2880
|
+
if (r && (r._ === t || r.p === t)) GlobalQueue.ce(r);
|
|
2845
2881
|
}
|
|
2846
2882
|
e.splice(0, t);
|
|
2847
2883
|
}
|
|
@@ -2894,7 +2930,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2894
2930
|
* that reads a pending mid-transition write sees the committed value; the sub
|
|
2895
2931
|
* is recorded for replay at commit.
|
|
2896
2932
|
*/ function gatedRead(e, t, n) {
|
|
2897
|
-
if (latestReadActive || e.
|
|
2933
|
+
if (latestReadActive || e.U === NOT_PENDING || e.Ue || t !== e && !(t.Le & REACTIVE_MANUAL_WRITE)) {
|
|
2898
2934
|
return false;
|
|
2899
2935
|
}
|
|
2900
2936
|
activeTransition.Y.add(n);
|
|
@@ -2905,7 +2941,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2905
2941
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
2906
2942
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
2907
2943
|
*/ function laneReadsCommitted(e, t, n) {
|
|
2908
|
-
return e.A !== undefined || !!e.i || t === e && stale && n.t !== e || !!(t.
|
|
2944
|
+
return e.A !== undefined || !!e.i || t === e && stale && n.t !== e || !!(t.xe & STATUS_PENDING);
|
|
2909
2945
|
}
|
|
2910
2946
|
|
|
2911
2947
|
/**
|
|
@@ -2916,10 +2952,10 @@ function cleanupCompletedLanes(e) {
|
|
|
2916
2952
|
if (t) return resolveLane(e) ?? null;
|
|
2917
2953
|
for (let t = e.je; t; t = t.Ke) {
|
|
2918
2954
|
const n = t.Ye;
|
|
2919
|
-
if (n.
|
|
2955
|
+
if (n.Le & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
2920
2956
|
const t = resolveLane(n);
|
|
2921
2957
|
if (t) {
|
|
2922
|
-
e.
|
|
2958
|
+
e.Le |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
2923
2959
|
assignOrMergeLane(e, t);
|
|
2924
2960
|
return t;
|
|
2925
2961
|
}
|
|
@@ -2947,7 +2983,7 @@ function cleanupCompletedLanes(e) {
|
|
|
2947
2983
|
|
|
2948
2984
|
function trackOptimisticStore(e) {
|
|
2949
2985
|
// After initTransition, globalQueue._batch IS activeTransition (same reference)
|
|
2950
|
-
globalQueue.D.
|
|
2986
|
+
globalQueue.D.V.add(e);
|
|
2951
2987
|
schedule();
|
|
2952
2988
|
}
|
|
2953
2989
|
|
|
@@ -2956,8 +2992,8 @@ function trackOptimisticStore(e) {
|
|
|
2956
2992
|
* create optimistic state (verdict.ts at module top level, createOptimistic
|
|
2957
2993
|
* and createOptimisticStore at first call) BEFORE any optimistic node exists.
|
|
2958
2994
|
*/ function installOptimisticEngine() {
|
|
2959
|
-
if (GlobalQueue.
|
|
2960
|
-
GlobalQueue.
|
|
2995
|
+
if (GlobalQueue._e !== null) return;
|
|
2996
|
+
GlobalQueue._e = optimisticWrite;
|
|
2961
2997
|
GlobalQueue.pe = resolveOptimisticNodes;
|
|
2962
2998
|
GlobalQueue.Re = transitionBlocked;
|
|
2963
2999
|
GlobalQueue.Ie = cleanupCompletedLanes;
|
|
@@ -2987,15 +3023,15 @@ let pendingProbe = null;
|
|
|
2987
3023
|
* Get or create the pending signal for a node (lazy).
|
|
2988
3024
|
* Used by isPending() to track pending state reactively.
|
|
2989
3025
|
*/ function getPendingSignal(e) {
|
|
2990
|
-
if (!e.
|
|
3026
|
+
if (!e._) {
|
|
2991
3027
|
// Start false, write true if pending - ensures reversion returns to false
|
|
2992
|
-
e.
|
|
3028
|
+
e._ = optimisticSignal(false, {
|
|
2993
3029
|
ownedWrite: true
|
|
2994
3030
|
});
|
|
2995
|
-
e.
|
|
2996
|
-
if (computePendingState(e)) setSignal(e.
|
|
3031
|
+
e._.t = e;
|
|
3032
|
+
if (computePendingState(e)) setSignal(e._, true);
|
|
2997
3033
|
}
|
|
2998
|
-
return e.
|
|
3034
|
+
return e._;
|
|
2999
3035
|
}
|
|
3000
3036
|
|
|
3001
3037
|
function collectPendingSources(e) {
|
|
@@ -3031,7 +3067,7 @@ function collectPendingSources(e) {
|
|
|
3031
3067
|
// not flow through it — matching the rails' behavior, where propagation
|
|
3032
3068
|
// stopped at errored nodes. A DIRECT mark on an errored node still reads
|
|
3033
3069
|
// pending (the count check above), also matching.
|
|
3034
|
-
if (e.
|
|
3070
|
+
if (e.xe & STATUS_ERROR) return false;
|
|
3035
3071
|
if (t.has(e)) return false;
|
|
3036
3072
|
t.add(e);
|
|
3037
3073
|
const n = e.qe;
|
|
@@ -3041,10 +3077,10 @@ function collectPendingSources(e) {
|
|
|
3041
3077
|
// pass's dependency set — walking past it would read dropped deps and
|
|
3042
3078
|
// latch a stale verdict on the companion.
|
|
3043
3079
|
const r = e;
|
|
3044
|
-
const i = r.
|
|
3080
|
+
const i = r.Le & REACTIVE_RECOMPUTING_DEPS ? r.st : undefined;
|
|
3045
3081
|
if (i !== null) {
|
|
3046
3082
|
for (let e = r.je ?? null; e !== null; e = e.Ke) {
|
|
3047
|
-
if (!e.
|
|
3083
|
+
if (!e.Ot && markWalk(e.Ye, t)) return true;
|
|
3048
3084
|
if (e === i) break;
|
|
3049
3085
|
}
|
|
3050
3086
|
}
|
|
@@ -3064,12 +3100,12 @@ function quietPending(e) {
|
|
|
3064
3100
|
}
|
|
3065
3101
|
|
|
3066
3102
|
function newQuestionInFlight(e) {
|
|
3067
|
-
return !!(e.
|
|
3103
|
+
return !!(e.xe & STATUS_PENDING) && !(e.xe & STATUS_UNINITIALIZED) && !quietPending(e);
|
|
3068
3104
|
}
|
|
3069
3105
|
|
|
3070
3106
|
function computePendingState(e) {
|
|
3071
3107
|
const t = e;
|
|
3072
|
-
if (t.
|
|
3108
|
+
if (t.Le & REACTIVE_DISPOSED) return false;
|
|
3073
3109
|
// Mark coverage is transitive by dep-graph reachability: a latest() shadow
|
|
3074
3110
|
// reaches its owner (and a store leaf its firewall) through its own deps,
|
|
3075
3111
|
// so the one walk covers direct marks, derivation, and companion chains.
|
|
@@ -3080,31 +3116,31 @@ function computePendingState(e) {
|
|
|
3080
3116
|
const n = t.qe || t;
|
|
3081
3117
|
return newQuestionInFlight(n);
|
|
3082
3118
|
}
|
|
3083
|
-
if (n && e.
|
|
3084
|
-
return !!(n.
|
|
3119
|
+
if (n && e.U !== NOT_PENDING && !hasActiveOverride(e)) {
|
|
3120
|
+
return !!(n.Le & REACTIVE_MANUAL_WRITE) || !n.ut && !(n.xe & STATUS_PENDING) || !!(n.xe & STATUS_PENDING) && quietPending(n);
|
|
3085
3121
|
}
|
|
3086
|
-
if (e.
|
|
3087
|
-
if (hasActiveOverride(e)) return !e.At || !e.At(e.
|
|
3122
|
+
if (e.U !== NOT_PENDING && !(t.xe & STATUS_UNINITIALIZED)) {
|
|
3123
|
+
if (hasActiveOverride(e)) return !e.At || !e.At(e.U, unwrapOverride(e.A));
|
|
3088
3124
|
return true;
|
|
3089
3125
|
}
|
|
3090
3126
|
return newQuestionInFlight(t);
|
|
3091
3127
|
}
|
|
3092
3128
|
|
|
3093
3129
|
function syncCompanions(e, t) {
|
|
3094
|
-
if (e.
|
|
3130
|
+
if (e._) updatePendingSignal(e);
|
|
3095
3131
|
if (e.p) setSignal(e.p, t);
|
|
3096
3132
|
}
|
|
3097
3133
|
|
|
3098
3134
|
function updatePendingSignal(e) {
|
|
3099
|
-
if (e.
|
|
3100
|
-
setSignal(e.
|
|
3135
|
+
if (e._) {
|
|
3136
|
+
setSignal(e._, computePendingState(e));
|
|
3101
3137
|
}
|
|
3102
3138
|
if (e.p) updatePendingSignal(e.p);
|
|
3103
3139
|
}
|
|
3104
3140
|
|
|
3105
3141
|
function updateChildCompanions(e) {
|
|
3106
3142
|
for (let t = e.nt; t !== null; t = t.rt) {
|
|
3107
|
-
if (t.
|
|
3143
|
+
if (t._ || t.p) updatePendingSignal(t);
|
|
3108
3144
|
}
|
|
3109
3145
|
}
|
|
3110
3146
|
|
|
@@ -3122,8 +3158,8 @@ function updateChildCompanions(e) {
|
|
|
3122
3158
|
const visit = e => {
|
|
3123
3159
|
if (r.has(e)) return;
|
|
3124
3160
|
r.add(e);
|
|
3125
|
-
if (e.
|
|
3126
|
-
for (let t = e.
|
|
3161
|
+
if (e._ || e.p) n(e);
|
|
3162
|
+
for (let t = e.G; t !== null; t = t.ve) visit(t.Ve);
|
|
3127
3163
|
for (let t = e.nt ?? null; t !== null; t = t.rt) {
|
|
3128
3164
|
visit(t);
|
|
3129
3165
|
}
|
|
@@ -3132,21 +3168,21 @@ function updateChildCompanions(e) {
|
|
|
3132
3168
|
}
|
|
3133
3169
|
|
|
3134
3170
|
function snapCompanionsToState(e) {
|
|
3135
|
-
const t = e.
|
|
3171
|
+
const t = e._;
|
|
3136
3172
|
if (t && (t.A === undefined || t.A === NOT_PENDING)) {
|
|
3137
3173
|
const n = computePendingState(e);
|
|
3138
|
-
if (t.ke !== n || t.
|
|
3174
|
+
if (t.ke !== n || t.U !== NOT_PENDING) {
|
|
3139
3175
|
t.ke = n;
|
|
3140
|
-
t.
|
|
3141
|
-
t.
|
|
3176
|
+
t.U = NOT_PENDING;
|
|
3177
|
+
t.F = clock;
|
|
3142
3178
|
insertSubs(t);
|
|
3143
3179
|
schedule();
|
|
3144
3180
|
}
|
|
3145
3181
|
}
|
|
3146
3182
|
const n = e.p;
|
|
3147
|
-
if (n && !(n.
|
|
3148
|
-
if ((n.A === undefined || n.A === NOT_PENDING) && n.
|
|
3149
|
-
n.
|
|
3183
|
+
if (n && !(n.Le & REACTIVE_DISPOSED)) {
|
|
3184
|
+
if ((n.A === undefined || n.A === NOT_PENDING) && n.U === NOT_PENDING && !Object.is(n.ke, e.ke) && !(n.Le & (REACTIVE_DIRTY | REACTIVE_CHECK))) {
|
|
3185
|
+
n.Le |= REACTIVE_DIRTY;
|
|
3150
3186
|
insertIntoHeap(n, queueFor(n));
|
|
3151
3187
|
insertSubs(n);
|
|
3152
3188
|
schedule();
|
|
@@ -3187,18 +3223,18 @@ function getLatestValueComputed(e) {
|
|
|
3187
3223
|
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
3188
3224
|
// queued staleness through the graph, then bring the shadow up to date.
|
|
3189
3225
|
const e = queueFor(t);
|
|
3190
|
-
if (t.Xe >= e.P && !(t.
|
|
3226
|
+
if (t.Xe >= e.P && !(t.Le & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
3191
3227
|
markHeap(e);
|
|
3192
3228
|
prepareComputed(t, true);
|
|
3193
3229
|
}
|
|
3194
3230
|
i = read(t);
|
|
3195
3231
|
} catch (t) {
|
|
3196
|
-
if (t instanceof NotReadyError && (!context || !(e.
|
|
3232
|
+
if (t instanceof NotReadyError && (!context || !(e.xe & STATUS_UNINITIALIZED))) return r;
|
|
3197
3233
|
throw t;
|
|
3198
3234
|
} finally {
|
|
3199
3235
|
setLatestReadActive(n);
|
|
3200
3236
|
}
|
|
3201
|
-
if (t.
|
|
3237
|
+
if (t.xe & STATUS_PENDING) return r;
|
|
3202
3238
|
if (stale && currentOptimisticLane && t.i) {
|
|
3203
3239
|
const e = findLane(t.i);
|
|
3204
3240
|
const n = findLane(currentOptimisticLane);
|
|
@@ -3210,14 +3246,14 @@ function getLatestValueComputed(e) {
|
|
|
3210
3246
|
// speculative value in _pendingValue; a contextless read() only surfaces
|
|
3211
3247
|
// _value. Overrides stay authoritative (A17), and stale readers keep the
|
|
3212
3248
|
// other transition's committed view, matching read()'s own selection.
|
|
3213
|
-
if (t.
|
|
3249
|
+
if (t.U !== NOT_PENDING && !hasActiveOverride(t) && !(stale && t.T && activeTransition !== t.T)) return t.U;
|
|
3214
3250
|
return i;
|
|
3215
3251
|
}
|
|
3216
3252
|
|
|
3217
3253
|
/** The isPending()-probe read path, installed as GlobalQueue._pendingCheck. */ function pendingCheckRead(e, t, n, r) {
|
|
3218
3254
|
setPendingCheckActive(false);
|
|
3219
|
-
if (typeof e.
|
|
3220
|
-
const i = n.
|
|
3255
|
+
if (typeof e.Ue === "function") prepareComputed(e, true);
|
|
3256
|
+
const i = n.xe;
|
|
3221
3257
|
if (t && i & STATUS_PENDING && i & STATUS_UNINITIALIZED) {
|
|
3222
3258
|
if (tracking && e !== t) link(e, t);
|
|
3223
3259
|
setPendingCheckActive(true);
|
|
@@ -3229,11 +3265,11 @@ function getLatestValueComputed(e) {
|
|
|
3229
3265
|
}
|
|
3230
3266
|
|
|
3231
3267
|
function recordFreshRead(e, t) {
|
|
3232
|
-
if (pendingProbe !== null && e.
|
|
3268
|
+
if (pendingProbe !== null && e.U !== NOT_PENDING && t === e.U) pendingProbe.freshReads.add(e);
|
|
3233
3269
|
}
|
|
3234
3270
|
|
|
3235
3271
|
function applyReask(e, t) {
|
|
3236
|
-
const n = !!(e.
|
|
3272
|
+
const n = !!(e.xe & STATUS_PENDING);
|
|
3237
3273
|
const r = t && !(n && !e.ht);
|
|
3238
3274
|
const i = n && e.ht !== r;
|
|
3239
3275
|
e.ht = r;
|
|
@@ -3276,7 +3312,7 @@ function isPending(e) {
|
|
|
3276
3312
|
} catch (e) {
|
|
3277
3313
|
collectPending();
|
|
3278
3314
|
if (e instanceof NotReadyError) {
|
|
3279
|
-
const t = !!(e.source?.
|
|
3315
|
+
const t = !!(e.source?.xe & STATUS_UNINITIALIZED);
|
|
3280
3316
|
if (r.found && !t) return true;
|
|
3281
3317
|
if (context && t) throw e;
|
|
3282
3318
|
}
|
|
@@ -3294,9 +3330,9 @@ GlobalQueue.ue = syncCompanions;
|
|
|
3294
3330
|
|
|
3295
3331
|
GlobalQueue.le = updatePendingSignal;
|
|
3296
3332
|
|
|
3297
|
-
GlobalQueue.
|
|
3333
|
+
GlobalQueue.ae = updateChildCompanions;
|
|
3298
3334
|
|
|
3299
|
-
GlobalQueue.
|
|
3335
|
+
GlobalQueue.ce = snapCompanionsToState;
|
|
3300
3336
|
|
|
3301
3337
|
GlobalQueue.fe = latestRead;
|
|
3302
3338
|
|
|
@@ -3308,7 +3344,7 @@ GlobalQueue.Se = applyReask;
|
|
|
3308
3344
|
|
|
3309
3345
|
GlobalQueue.Te = repollDownstreamVerdicts;
|
|
3310
3346
|
|
|
3311
|
-
GlobalQueue.
|
|
3347
|
+
GlobalQueue.Oe = witnessAffects;
|
|
3312
3348
|
|
|
3313
3349
|
/**
|
|
3314
3350
|
* Effects are the leaf nodes of our reactive graph. When their sources change, they are
|
|
@@ -3318,16 +3354,16 @@ GlobalQueue._e = witnessAffects;
|
|
|
3318
3354
|
const i = !!r?.user;
|
|
3319
3355
|
const o = createEffectNode(e, t, n, i ? EFFECT_USER : EFFECT_RENDER, notifyEffectStatus, r);
|
|
3320
3356
|
recompute(o, true);
|
|
3321
|
-
!r?.defer && (o.
|
|
3357
|
+
!r?.defer && (o.We === EFFECT_USER || r?.schedule ? o.Be.enqueue(o.We, runEffect.bind(null, o)) : runEffect(o));
|
|
3322
3358
|
}
|
|
3323
3359
|
|
|
3324
3360
|
function notifyEffectStatus(e, t) {
|
|
3325
3361
|
// Use passed values if provided, otherwise read from node
|
|
3326
|
-
const n = e !== undefined ? e : this.
|
|
3362
|
+
const n = e !== undefined ? e : this.xe;
|
|
3327
3363
|
const r = t !== undefined ? t : this.De;
|
|
3328
3364
|
if (n & STATUS_ERROR) {
|
|
3329
3365
|
this.Be.notify(this, STATUS_PENDING, 0);
|
|
3330
|
-
if (this.
|
|
3366
|
+
if (this.We === EFFECT_USER) {
|
|
3331
3367
|
// The error handler is the error arm of the effect phase (#2840 ruling):
|
|
3332
3368
|
// queue it like the effect function. It runs in the same imperative,
|
|
3333
3369
|
// writable scope, throws escalate the same way, and a held transition
|
|
@@ -3337,9 +3373,9 @@ function notifyEffectStatus(e, t) {
|
|
|
3337
3373
|
// phase takes the success arm instead. Blocked forwards (explicit
|
|
3338
3374
|
// `status` arg without node-state writes) don't queue: the status
|
|
3339
3375
|
// re-propagates unblocked at commit.
|
|
3340
|
-
if (this.
|
|
3341
|
-
this.
|
|
3342
|
-
this.Be.enqueue(this.
|
|
3376
|
+
if (this.xe & STATUS_ERROR) {
|
|
3377
|
+
this.Fe = true;
|
|
3378
|
+
this.Be.enqueue(this.We, this.Pt ??= runEffect.bind(null, this));
|
|
3343
3379
|
}
|
|
3344
3380
|
return;
|
|
3345
3381
|
}
|
|
@@ -3347,13 +3383,13 @@ function notifyEffectStatus(e, t) {
|
|
|
3347
3383
|
haltReactivity(unwrapStatusError(r));
|
|
3348
3384
|
throw r;
|
|
3349
3385
|
}
|
|
3350
|
-
} else if (this.
|
|
3386
|
+
} else if (this.We === EFFECT_RENDER) {
|
|
3351
3387
|
this.Be.notify(this, STATUS_PENDING | STATUS_ERROR, n, r);
|
|
3352
3388
|
}
|
|
3353
3389
|
}
|
|
3354
3390
|
|
|
3355
3391
|
function runEffect(e) {
|
|
3356
|
-
if (!e.
|
|
3392
|
+
if (!e.Fe || e.Le & REACTIVE_DISPOSED) return;
|
|
3357
3393
|
// Error arm (#2840), user effects only: a compute-phase error that is still
|
|
3358
3394
|
// the node's settled state at effect time runs the bundle's error handler in
|
|
3359
3395
|
// this same imperative, writable scope. Unwrap the StatusError used for
|
|
@@ -3364,10 +3400,10 @@ function runEffect(e) {
|
|
|
3364
3400
|
// Render effects bypass: their errors route to boundaries synchronously in
|
|
3365
3401
|
// notifyEffectStatus, and a runner queued by an earlier valueChanged in the
|
|
3366
3402
|
// same flush must not be hijacked by a later-arriving error status.
|
|
3367
|
-
if (e.
|
|
3403
|
+
if (e.xe & STATUS_ERROR && e.We === EFFECT_USER) {
|
|
3368
3404
|
const t = unwrapStatusError(e.De);
|
|
3369
3405
|
e.gt = e.ke;
|
|
3370
|
-
e.
|
|
3406
|
+
e.Fe = false;
|
|
3371
3407
|
try {
|
|
3372
3408
|
e.Dt ? e.Dt(t, () => {
|
|
3373
3409
|
const t = e.ft;
|
|
@@ -3392,14 +3428,14 @@ function runEffect(e) {
|
|
|
3392
3428
|
e.ft = n;
|
|
3393
3429
|
} catch (t) {
|
|
3394
3430
|
e.De = new StatusError(e, t);
|
|
3395
|
-
e.
|
|
3431
|
+
e.xe |= STATUS_ERROR;
|
|
3396
3432
|
if (!e.Be.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3397
3433
|
haltReactivity(t);
|
|
3398
3434
|
throw t;
|
|
3399
3435
|
}
|
|
3400
3436
|
} finally {
|
|
3401
3437
|
e.gt = e.ke;
|
|
3402
|
-
e.
|
|
3438
|
+
e.Fe = false;
|
|
3403
3439
|
}
|
|
3404
3440
|
}
|
|
3405
3441
|
|
|
@@ -3411,9 +3447,9 @@ GlobalQueue.J = runEffect;
|
|
|
3411
3447
|
* Uses stale reads.
|
|
3412
3448
|
*/ function trackedEffect(e, t) {
|
|
3413
3449
|
const run = () => {
|
|
3414
|
-
if (!n.
|
|
3450
|
+
if (!n.Fe || n.Le & REACTIVE_DISPOSED) return;
|
|
3415
3451
|
try {
|
|
3416
|
-
n.
|
|
3452
|
+
n.Fe = false;
|
|
3417
3453
|
recompute(n);
|
|
3418
3454
|
} finally {}
|
|
3419
3455
|
};
|
|
@@ -3428,11 +3464,11 @@ GlobalQueue.J = runEffect;
|
|
|
3428
3464
|
lazy: true
|
|
3429
3465
|
});
|
|
3430
3466
|
n.ft = undefined;
|
|
3431
|
-
n.
|
|
3432
|
-
n.
|
|
3433
|
-
n.
|
|
3467
|
+
n.Ge = n.Ge & ~CONFIG_AUTO_DISPOSE | CONFIG_CHILDREN_FORBIDDEN;
|
|
3468
|
+
n.Fe = true;
|
|
3469
|
+
n.We = EFFECT_TRACKED;
|
|
3434
3470
|
n.Nt = (e, t) => {
|
|
3435
|
-
const r = e !== undefined ? e : n.
|
|
3471
|
+
const r = e !== undefined ? e : n.xe;
|
|
3436
3472
|
if (r & STATUS_ERROR) {
|
|
3437
3473
|
n.Be.notify(n, STATUS_PENDING, 0);
|
|
3438
3474
|
const e = t !== undefined ? t : n.De;
|
|
@@ -3624,7 +3660,7 @@ function accessor(e) {
|
|
|
3624
3660
|
function createSignal(e, t) {
|
|
3625
3661
|
if (typeof e === "function") {
|
|
3626
3662
|
const n = computed(e, t);
|
|
3627
|
-
n.
|
|
3663
|
+
n.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
3628
3664
|
return [ accessor(n), setMemo.bind(null, n) ];
|
|
3629
3665
|
}
|
|
3630
3666
|
const n = signal(e, t);
|
|
@@ -3865,7 +3901,7 @@ function createOptimistic(e, t) {
|
|
|
3865
3901
|
installOptimisticEngine();
|
|
3866
3902
|
if (typeof e === "function") {
|
|
3867
3903
|
const n = optimisticComputed(e, t);
|
|
3868
|
-
n.
|
|
3904
|
+
n.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
3869
3905
|
return [ accessor(n), setSignal.bind(null, n) ];
|
|
3870
3906
|
}
|
|
3871
3907
|
const n = optimisticSignal(e, t);
|
|
@@ -3954,7 +3990,7 @@ function createOptimistic(e, t) {
|
|
|
3954
3990
|
* on owner disposal
|
|
3955
3991
|
*/ function onSettled(e) {
|
|
3956
3992
|
const t = getOwner();
|
|
3957
|
-
t && !(t.
|
|
3993
|
+
t && !(t.Ge & CONFIG_CHILDREN_FORBIDDEN) ? createTrackedEffect(() => untrack(e), undefined) : globalQueue.enqueue(EFFECT_USER, () => {
|
|
3958
3994
|
// Unowned, out-of-band fire (no owner, or a children-forbidden one this
|
|
3959
3995
|
// one-shot must not bind to): a returned cleanup has no lifecycle to
|
|
3960
3996
|
// attach to. Reject it in dev; in production the return is simply
|
|
@@ -4058,28 +4094,68 @@ function keyedMatch(e, t, n) {
|
|
|
4058
4094
|
// and `in` dependencies should follow the new value's membership. Use
|
|
4059
4095
|
// membership rather than length arithmetic so sparse arrays and named array
|
|
4060
4096
|
// props behave like normal property reads.
|
|
4097
|
+
// Inline key iteration on purpose: these loops run per array target per
|
|
4098
|
+
// reconcile pass, and a shared helper means a closure + per-key call in
|
|
4099
|
+
// instruction counts. String-only records (the common case) iterate in
|
|
4100
|
+
// place; symbol-bearing records take the nodeKeys array path.
|
|
4061
4101
|
function syncArrayNodeMembership(e, t) {
|
|
4062
4102
|
let n = e[STORE_NODE];
|
|
4063
4103
|
if (n) {
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4104
|
+
if (symbolKeyedRecords.has(n)) {
|
|
4105
|
+
const e = nodeKeys(n);
|
|
4106
|
+
for (let r = 0, i = e.length; r < i; r++) {
|
|
4107
|
+
e[r] in t || setSignal(n[e[r]], undefined);
|
|
4108
|
+
}
|
|
4109
|
+
} else {
|
|
4110
|
+
for (const e in n) {
|
|
4111
|
+
e in t || setSignal(n[e], undefined);
|
|
4112
|
+
}
|
|
4068
4113
|
}
|
|
4069
4114
|
}
|
|
4070
4115
|
if (n = e[STORE_HAS]) {
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4116
|
+
if (symbolKeyedRecords.has(n)) {
|
|
4117
|
+
const e = nodeKeys(n);
|
|
4118
|
+
for (let r = 0, i = e.length; r < i; r++) {
|
|
4119
|
+
setSignal(n[e[r]], e[r] in t);
|
|
4120
|
+
}
|
|
4121
|
+
} else {
|
|
4122
|
+
for (const e in n) {
|
|
4123
|
+
setSignal(n[e], e in t);
|
|
4124
|
+
}
|
|
4075
4125
|
}
|
|
4076
4126
|
}
|
|
4077
4127
|
}
|
|
4078
4128
|
|
|
4129
|
+
// Recurse into a matched wrappable child pair without manufacturing a proxy:
|
|
4130
|
+
// resolve the child's target through the lookup and dispatch directly. A
|
|
4131
|
+
// lookup miss means the child was never observed — no proxy, no nodes, no
|
|
4132
|
+
// subscribers anywhere below — so the parent's swap making `next`
|
|
4133
|
+
// authoritative IS the whole update; a later read wraps next's child on
|
|
4134
|
+
// demand. This turns the diff from O(previous graph) into O(observed graph)
|
|
4135
|
+
// and drops the wrap()/$PROXY/$TARGET round-trip per visited child.
|
|
4136
|
+
// Wrap-family stores (projections/optimistic) own child proxy creation and
|
|
4137
|
+
// keep the proxy-based recursion.
|
|
4138
|
+
function applyStateChild(e, t, n, r) {
|
|
4139
|
+
if (n[STORE_WRAP] !== undefined) {
|
|
4140
|
+
applyState(e, wrap(t, n), r);
|
|
4141
|
+
return;
|
|
4142
|
+
}
|
|
4143
|
+
const i = t[$TARGET] ?? storeLookup.get(t);
|
|
4144
|
+
if (i === undefined) return;
|
|
4145
|
+
e = unwrap(e);
|
|
4146
|
+
if (i[STORE_SHALLOW]) {
|
|
4147
|
+
applyStateShallow(e, i);
|
|
4148
|
+
} else if (i[STORE_OVERRIDE] || i[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
4149
|
+
applyStateSlow(e, i, r);
|
|
4150
|
+
} else {
|
|
4151
|
+
applyStateFast(e, i, r);
|
|
4152
|
+
}
|
|
4153
|
+
}
|
|
4154
|
+
|
|
4079
4155
|
// Reconcile a single array slot: recurse into a wrappable pair, otherwise replace
|
|
4080
4156
|
// the node's value outright (covers object→primitive and primitive→object).
|
|
4081
4157
|
function applyArrayItem(e, t, n, r, i) {
|
|
4082
|
-
if (isWrappable(e) && isWrappable(t)) {
|
|
4158
|
+
if (isWrappable(e) && isWrappable(t) && !(rawValuesUsed && (isRawValue(t) || isRawValue(e)))) {
|
|
4083
4159
|
const o = wrap(t, n);
|
|
4084
4160
|
r && setSignal(r, o);
|
|
4085
4161
|
applyState(e, o, i);
|
|
@@ -4099,18 +4175,51 @@ function applyArrayItem(e, t, n, r, i) {
|
|
|
4099
4175
|
* `$TRACK` absence (an enumeration-tracked record already diffs every key).
|
|
4100
4176
|
*/ function applyDescendants(e, t, n, r, i, o, s) {
|
|
4101
4177
|
const u = n[STORE_LOOKUP] || storeLookup;
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4178
|
+
if (o) {
|
|
4179
|
+
const n = getKeys(e, o).concat(getStoreSymbols(e, o));
|
|
4180
|
+
for (let l = 0, a = n.length; l < a; l++) {
|
|
4181
|
+
const a = n[l];
|
|
4182
|
+
if (r?.[a]) continue;
|
|
4106
4183
|
// main loop already diffed this slot
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4184
|
+
const c = unwrap(getOverrideValue(e, o, a, s));
|
|
4185
|
+
if (!isWrappable(c)) continue;
|
|
4186
|
+
descendInto(c, t[a], u, i);
|
|
4187
|
+
}
|
|
4188
|
+
return;
|
|
4189
|
+
}
|
|
4190
|
+
// No-override path (every applyStateFast call): iterate in place instead of
|
|
4191
|
+
// building keys + symbols + concat arrays per object per pass. The cheap
|
|
4192
|
+
// bails (noded key, primitive value) stay inline — only genuine descent
|
|
4193
|
+
// candidates pay a call.
|
|
4194
|
+
for (const n in e) {
|
|
4195
|
+
if (r?.[n]) continue;
|
|
4196
|
+
// main loop already diffed this slot
|
|
4197
|
+
const o = unwrap(e[n]);
|
|
4198
|
+
if (!isWrappable(o)) continue;
|
|
4199
|
+
descendInto(o, t[n], u, i);
|
|
4200
|
+
}
|
|
4201
|
+
const l = Object.getOwnPropertySymbols(e);
|
|
4202
|
+
for (let n = 0, o = l.length; n < o; n++) {
|
|
4203
|
+
if (Object.prototype.propertyIsEnumerable.call(e, l[n])) {
|
|
4204
|
+
if (r?.[l[n]]) continue;
|
|
4205
|
+
const o = unwrap(e[l[n]]);
|
|
4206
|
+
if (!isWrappable(o)) continue;
|
|
4207
|
+
descendInto(o, t[l[n]], u, i);
|
|
4208
|
+
}
|
|
4209
|
+
}
|
|
4210
|
+
}
|
|
4211
|
+
|
|
4212
|
+
function descendInto(e, t, n, r) {
|
|
4213
|
+
const i = lookupTarget(e, n);
|
|
4214
|
+
if (!i?.[STORE_DESC]) return;
|
|
4215
|
+
const o = unwrap(t);
|
|
4216
|
+
if (e === o || !isWrappable(o) || Array.isArray(e) !== Array.isArray(o) || r(e) != null && r(e) !== r(o)) return;
|
|
4217
|
+
if (i[STORE_SHALLOW]) {
|
|
4218
|
+
applyStateShallow(o, i);
|
|
4219
|
+
} else if (i[STORE_OVERRIDE] || i[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
4220
|
+
applyStateSlow(o, i, r);
|
|
4221
|
+
} else {
|
|
4222
|
+
applyStateFast(o, i, r);
|
|
4114
4223
|
}
|
|
4115
4224
|
}
|
|
4116
4225
|
|
|
@@ -4125,36 +4234,134 @@ function applyState(e, t, n) {
|
|
|
4125
4234
|
e = unwrap(e);
|
|
4126
4235
|
const r = t?.[$TARGET];
|
|
4127
4236
|
if (!r) return;
|
|
4128
|
-
if (r[
|
|
4237
|
+
if (r[STORE_SHALLOW]) {
|
|
4238
|
+
applyStateShallow(e, r);
|
|
4239
|
+
} else if (r[STORE_OVERRIDE] || r[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
4129
4240
|
applyStateSlow(e, r, n);
|
|
4130
4241
|
} else {
|
|
4131
4242
|
applyStateFast(e, r, n);
|
|
4132
4243
|
}
|
|
4133
4244
|
}
|
|
4134
4245
|
|
|
4246
|
+
// Shallow boundary diff: the target's own keys are reactive, its values are
|
|
4247
|
+
// raw records replaced by reference — no recursion, no wrapping. Arrays merge
|
|
4248
|
+
// positionally (below a shallow boundary the VALUE is the identity; keyed
|
|
4249
|
+
// row identity belongs to the consumer, e.g. <For keyed>). Incoming
|
|
4250
|
+
// wrappables are sticky-marked raw so they present raw through every store.
|
|
4251
|
+
// One pass over a shallow target's node record: replace changed slots with
|
|
4252
|
+
// raw next values, null out slots absent from next. Returns whether anything
|
|
4253
|
+
// differed.
|
|
4254
|
+
function shallowDiffNodes(e, t, n, r) {
|
|
4255
|
+
let i = false;
|
|
4256
|
+
for (const o in e) {
|
|
4257
|
+
if (r && o === "length") continue;
|
|
4258
|
+
if (o in t) {
|
|
4259
|
+
const r = t[o];
|
|
4260
|
+
if (r !== n(o)) {
|
|
4261
|
+
i = true;
|
|
4262
|
+
setSignal(e[o], r);
|
|
4263
|
+
}
|
|
4264
|
+
} else {
|
|
4265
|
+
i = true;
|
|
4266
|
+
setSignal(e[o], undefined);
|
|
4267
|
+
}
|
|
4268
|
+
}
|
|
4269
|
+
return i;
|
|
4270
|
+
}
|
|
4271
|
+
|
|
4272
|
+
function applyStateShallow(e, t, n) {
|
|
4273
|
+
const r = t[STORE_VALUE];
|
|
4274
|
+
const i = t[STORE_OVERRIDE];
|
|
4275
|
+
const o = t[STORE_OPTIMISTIC_OVERRIDE];
|
|
4276
|
+
if (e === r && !i && !o) return;
|
|
4277
|
+
// Setter-staged writes fold into the diff: previous values resolve through
|
|
4278
|
+
// the override layers (so a replaced slot compares against what readers
|
|
4279
|
+
// saw), and the regular override clears with the swap — reconcile makes
|
|
4280
|
+
// `next` the authoritative base, same as the deep slow path.
|
|
4281
|
+
const prevAt = e => {
|
|
4282
|
+
const t = getOverrideValue(r, i, e, o);
|
|
4283
|
+
return t === $DELETED ? undefined : t;
|
|
4284
|
+
};
|
|
4285
|
+
t[STORE_OVERRIDE] = undefined;
|
|
4286
|
+
const s = t[STORE_LOOKUP];
|
|
4287
|
+
s !== undefined ? s.set(e, t[$PROXY]) : storeLookup.set(e, t);
|
|
4288
|
+
t[STORE_VALUE] = e;
|
|
4289
|
+
markRawIngest(e);
|
|
4290
|
+
const u = t[STORE_NODE];
|
|
4291
|
+
const l = u && u[$TRACK];
|
|
4292
|
+
let a = false;
|
|
4293
|
+
if (Array.isArray(r)) {
|
|
4294
|
+
const n = i?.length ?? o?.length ?? r.length;
|
|
4295
|
+
if (u) {
|
|
4296
|
+
a = shallowDiffNodes(u, e, prevAt, true);
|
|
4297
|
+
if (u.length && n !== e.length) setSignal(u.length, e.length);
|
|
4298
|
+
}
|
|
4299
|
+
if (!a && (l || t[STORE_HAS])) {
|
|
4300
|
+
// Slots without nodes still feed $TRACK enumerators / `in` probes.
|
|
4301
|
+
if (n !== e.length) a = true; else {
|
|
4302
|
+
for (let t = 0, n = e.length; t < n; t++) {
|
|
4303
|
+
if (prevAt(t) !== e[t]) {
|
|
4304
|
+
a = true;
|
|
4305
|
+
break;
|
|
4306
|
+
}
|
|
4307
|
+
}
|
|
4308
|
+
}
|
|
4309
|
+
}
|
|
4310
|
+
} else {
|
|
4311
|
+
if (u) {
|
|
4312
|
+
a = shallowDiffNodes(u, e, prevAt, false);
|
|
4313
|
+
}
|
|
4314
|
+
if (!a && (l || t[STORE_HAS])) a = true;
|
|
4315
|
+
}
|
|
4316
|
+
let c = t[STORE_HAS];
|
|
4317
|
+
if (c) {
|
|
4318
|
+
for (const t in c) {
|
|
4319
|
+
setSignal(c[t], t in e);
|
|
4320
|
+
}
|
|
4321
|
+
}
|
|
4322
|
+
a && notifySelf(t);
|
|
4323
|
+
}
|
|
4324
|
+
|
|
4135
4325
|
function applyStateFast(e, t, n) {
|
|
4136
4326
|
const r = t[STORE_VALUE];
|
|
4137
4327
|
if (e === r) return;
|
|
4138
4328
|
const i = t[STORE_NODE];
|
|
4139
4329
|
// swap
|
|
4140
|
-
|
|
4330
|
+
{
|
|
4331
|
+
const n = t[STORE_LOOKUP];
|
|
4332
|
+
n !== undefined ? n.set(e, t[$PROXY]) : storeLookup.set(e, t);
|
|
4333
|
+
}
|
|
4141
4334
|
t[STORE_VALUE] = e;
|
|
4142
4335
|
// merge
|
|
4143
4336
|
if (Array.isArray(r)) {
|
|
4144
4337
|
let o = false;
|
|
4145
4338
|
const s = r.length;
|
|
4146
4339
|
if (e.length && s && isWrappable(e[0]) && n(e[0]) != null) {
|
|
4147
|
-
let u, l,
|
|
4148
|
-
for (
|
|
4149
|
-
|
|
4340
|
+
let u, l, a, c, f, E, d, S;
|
|
4341
|
+
for (a = 0, c = Math.min(s, e.length); a < c && keyedMatch(E = r[a], e[a], n); a++) {
|
|
4342
|
+
// keyedMatch established both sides wrappable unless they're the
|
|
4343
|
+
// SAME reference — and an identical slot is a guaranteed no-op
|
|
4344
|
+
// (the child's STORE_VALUE tracks the previous graph), so skip
|
|
4345
|
+
// the recursion dispatch entirely. Raw-marked values are leaves:
|
|
4346
|
+
// replace the slot node instead of recursing.
|
|
4347
|
+
if (E !== e[a]) {
|
|
4348
|
+
if (rawValuesUsed && (isRawValue(E) || isRawValue(e[a]))) {
|
|
4349
|
+
i?.[a] && setSignal(i[a], wrapValue(e[a], t));
|
|
4350
|
+
} else applyStateChild(e[a], E, t, n);
|
|
4351
|
+
}
|
|
4150
4352
|
}
|
|
4151
|
-
|
|
4152
|
-
|
|
4353
|
+
// Every position key-matched at equal length (the steady-state shape
|
|
4354
|
+
// of a polling tick): membership, length, and order are unchanged —
|
|
4355
|
+
// nothing below could do observable work, so skip the staging
|
|
4356
|
+
// allocations and membership sync outright.
|
|
4357
|
+
if (a === e.length && a === s) return;
|
|
4358
|
+
const T = new Array(e.length), O = new Map;
|
|
4359
|
+
for (c = s - 1, f = e.length - 1; c >= a && f >= a && keyedMatch(E = r[c], e[f], n); c--,
|
|
4153
4360
|
f--) {
|
|
4154
4361
|
T[f] = E;
|
|
4155
4362
|
}
|
|
4156
|
-
if (
|
|
4157
|
-
for (l =
|
|
4363
|
+
if (a > f || a > c) {
|
|
4364
|
+
for (l = a; l <= f; l++) {
|
|
4158
4365
|
o = true;
|
|
4159
4366
|
i?.[l] && setSignal(i[l], wrapValue(e[l], t));
|
|
4160
4367
|
}
|
|
@@ -4168,33 +4375,35 @@ function applyStateFast(e, t, n) {
|
|
|
4168
4375
|
return;
|
|
4169
4376
|
}
|
|
4170
4377
|
d = new Array(f + 1);
|
|
4171
|
-
for (l = f; l >=
|
|
4378
|
+
for (l = f; l >= a; l--) {
|
|
4172
4379
|
E = e[l];
|
|
4173
4380
|
S = itemKey(E, n);
|
|
4174
|
-
u =
|
|
4381
|
+
u = O.get(S);
|
|
4175
4382
|
d[l] = u === undefined ? -1 : u;
|
|
4176
|
-
|
|
4383
|
+
O.set(S, l);
|
|
4177
4384
|
}
|
|
4178
|
-
for (u =
|
|
4385
|
+
for (u = a; u <= c; u++) {
|
|
4179
4386
|
E = r[u];
|
|
4180
4387
|
S = itemKey(E, n);
|
|
4181
|
-
l =
|
|
4388
|
+
l = O.get(S);
|
|
4182
4389
|
if (l !== undefined && l !== -1) {
|
|
4183
4390
|
T[l] = E;
|
|
4184
4391
|
l = d[l];
|
|
4185
|
-
|
|
4392
|
+
O.set(S, l);
|
|
4186
4393
|
}
|
|
4187
4394
|
}
|
|
4188
|
-
for (l =
|
|
4395
|
+
for (l = a; l < e.length; l++) {
|
|
4189
4396
|
if (l in T) {
|
|
4190
4397
|
applyArrayItem(e[l], T[l], t, i?.[l], n);
|
|
4191
4398
|
} else i?.[l] && setSignal(i[l], wrapValue(e[l], t));
|
|
4192
4399
|
}
|
|
4193
|
-
if (
|
|
4400
|
+
if (a < e.length) o = true;
|
|
4194
4401
|
} else if (e.length) {
|
|
4195
4402
|
for (let s = 0, u = e.length; s < u; s++) {
|
|
4196
4403
|
const u = r[s];
|
|
4197
|
-
if (isWrappable(u) && isWrappable(e[s]))
|
|
4404
|
+
if (isWrappable(u) && isWrappable(e[s]) && !(rawValuesUsed && (isRawValue(u) || isRawValue(e[s])))) {
|
|
4405
|
+
if (u !== e[s]) applyStateChild(e[s], u, t, n);
|
|
4406
|
+
} else {
|
|
4198
4407
|
if (u !== e[s]) o = true;
|
|
4199
4408
|
i?.[s] && setSignal(i[s], wrapValue(e[s], t));
|
|
4200
4409
|
}
|
|
@@ -4213,17 +4422,42 @@ function applyStateFast(e, t, n) {
|
|
|
4213
4422
|
let s;
|
|
4214
4423
|
if (o) {
|
|
4215
4424
|
s = o[$TRACK];
|
|
4216
|
-
|
|
4425
|
+
// The per-key body is duplicated across both loops on purpose: this is
|
|
4426
|
+
// the hottest object-diff site and a shared helper costs a per-key call
|
|
4427
|
+
// in instruction counts (CodSpeed regressed ~7% on deep-tree reconciles
|
|
4428
|
+
// with the extracted form).
|
|
4429
|
+
if (s || symbolKeyedRecords.has(o)) {
|
|
4217
4430
|
const i = s ? getAllKeys(r, undefined, e) : nodeKeys(o);
|
|
4218
4431
|
for (let u = 0, l = i.length; u < l; u++) {
|
|
4219
|
-
|
|
4432
|
+
const l = i[u];
|
|
4433
|
+
const a = o[l];
|
|
4434
|
+
const c = unwrap(r[l]);
|
|
4435
|
+
const f = unwrap(e[l]);
|
|
4436
|
+
if (c === f) continue;
|
|
4437
|
+
if (!c || !isWrappable(c) || !isWrappable(f) ||
|
|
4438
|
+
// Raw-marked values are leaves replaced by reference — a "wrappable
|
|
4439
|
+
// pair" is only recursable when both sides are actual store children.
|
|
4440
|
+
rawValuesUsed && (isRawValue(c) || isRawValue(f)) || Array.isArray(c) !== Array.isArray(f) || n(c) != null && n(c) !== n(f)) {
|
|
4441
|
+
s && setSignal(s, void 0);
|
|
4442
|
+
a && setSignal(a, isWrappable(f) ? wrap(f, t) : f);
|
|
4443
|
+
} else applyStateChild(f, c, t, n);
|
|
4220
4444
|
}
|
|
4221
4445
|
} else {
|
|
4222
4446
|
// Untracked, string-only node records (the overwhelmingly common case)
|
|
4223
4447
|
// iterate in place — nodeKeys() allocated a fresh key array per object
|
|
4224
4448
|
// per pass, which dominates allocation on large-graph reconciles.
|
|
4225
4449
|
for (const i in o) {
|
|
4226
|
-
|
|
4450
|
+
const u = o[i];
|
|
4451
|
+
const l = unwrap(r[i]);
|
|
4452
|
+
const a = unwrap(e[i]);
|
|
4453
|
+
if (l === a) continue;
|
|
4454
|
+
if (!l || !isWrappable(l) || !isWrappable(a) ||
|
|
4455
|
+
// Raw-marked values are leaves replaced by reference — a "wrappable
|
|
4456
|
+
// pair" is only recursable when both sides are actual store children.
|
|
4457
|
+
rawValuesUsed && (isRawValue(l) || isRawValue(a)) || Array.isArray(l) !== Array.isArray(a) || n(l) != null && n(l) !== n(a)) {
|
|
4458
|
+
s && setSignal(s, void 0);
|
|
4459
|
+
u && setSignal(u, isWrappable(a) ? wrap(a, t) : a);
|
|
4460
|
+
} else applyStateChild(a, l, t, n);
|
|
4227
4461
|
}
|
|
4228
4462
|
}
|
|
4229
4463
|
}
|
|
@@ -4238,26 +4472,16 @@ function applyStateFast(e, t, n) {
|
|
|
4238
4472
|
}
|
|
4239
4473
|
}
|
|
4240
4474
|
|
|
4241
|
-
// One node-key step of the fast object diff — shared by the array-iterating
|
|
4242
|
-
// (tracked / symbol-keyed) and for-in (plain) loops in applyStateFast.
|
|
4243
|
-
function diffNodeKey(e, t, n, r, i, o, s) {
|
|
4244
|
-
const u = t[e];
|
|
4245
|
-
const l = unwrap(n[e]);
|
|
4246
|
-
let c = unwrap(r[e]);
|
|
4247
|
-
if (l === c) return;
|
|
4248
|
-
if (!l || !isWrappable(l) || !isWrappable(c) || Array.isArray(l) !== Array.isArray(c) || s(l) != null && s(l) !== s(c)) {
|
|
4249
|
-
o && setSignal(o, void 0);
|
|
4250
|
-
u && setSignal(u, isWrappable(c) ? wrap(c, i) : c);
|
|
4251
|
-
} else applyState(c, wrap(l, i), s);
|
|
4252
|
-
}
|
|
4253
|
-
|
|
4254
4475
|
function applyStateSlow(e, t, n) {
|
|
4255
4476
|
const r = t[STORE_VALUE];
|
|
4256
4477
|
const i = t[STORE_OVERRIDE];
|
|
4257
4478
|
const o = t[STORE_OPTIMISTIC_OVERRIDE];
|
|
4258
4479
|
let s = t[STORE_NODE];
|
|
4259
4480
|
// swap
|
|
4260
|
-
|
|
4481
|
+
{
|
|
4482
|
+
const n = t[STORE_LOOKUP];
|
|
4483
|
+
n !== undefined ? n.set(e, t[$PROXY]) : storeLookup.set(e, t);
|
|
4484
|
+
}
|
|
4261
4485
|
t[STORE_VALUE] = e;
|
|
4262
4486
|
t[STORE_OVERRIDE] = undefined;
|
|
4263
4487
|
// merge
|
|
@@ -4265,23 +4489,27 @@ function applyStateSlow(e, t, n) {
|
|
|
4265
4489
|
let u = false;
|
|
4266
4490
|
const l = getOverrideValue(r, i, "length", o);
|
|
4267
4491
|
if (e.length && l && isWrappable(e[0]) && n(e[0]) != null) {
|
|
4268
|
-
let
|
|
4492
|
+
let a, c, f, E, d, S, T, O;
|
|
4269
4493
|
for (f = 0, E = Math.min(l, e.length); f < E && keyedMatch(S = getOverrideValue(r, i, f, o), e[f], n); f++) {
|
|
4270
|
-
isWrappable(S) && isWrappable(e[f]) &&
|
|
4494
|
+
if (isWrappable(S) && isWrappable(e[f]) && S !== e[f]) {
|
|
4495
|
+
if (rawValuesUsed && (isRawValue(S) || isRawValue(e[f]))) {
|
|
4496
|
+
s?.[f] && setSignal(s[f], wrapValue(e[f], t));
|
|
4497
|
+
} else applyState(e[f], wrap(S, t), n);
|
|
4498
|
+
}
|
|
4271
4499
|
}
|
|
4272
|
-
const
|
|
4500
|
+
const _ = new Array(e.length), p = new Map;
|
|
4273
4501
|
for (E = l - 1, d = e.length - 1; E >= f && d >= f && keyedMatch(S = getOverrideValue(r, i, E, o), e[d], n); E--,
|
|
4274
4502
|
d--) {
|
|
4275
|
-
|
|
4503
|
+
_[d] = S;
|
|
4276
4504
|
}
|
|
4277
4505
|
if (f > d || f > E) {
|
|
4278
|
-
for (
|
|
4506
|
+
for (c = f; c <= d; c++) {
|
|
4279
4507
|
u = true;
|
|
4280
|
-
s?.[
|
|
4508
|
+
s?.[c] && setSignal(s[c], wrapValue(e[c], t));
|
|
4281
4509
|
}
|
|
4282
|
-
for (;
|
|
4510
|
+
for (;c < e.length; c++) {
|
|
4283
4511
|
u = true;
|
|
4284
|
-
applyArrayItem(e[
|
|
4512
|
+
applyArrayItem(e[c], _[c], t, s?.[c], n);
|
|
4285
4513
|
}
|
|
4286
4514
|
const r = e.length;
|
|
4287
4515
|
syncArrayNodeMembership(t, e);
|
|
@@ -4290,43 +4518,45 @@ function applyStateSlow(e, t, n) {
|
|
|
4290
4518
|
return;
|
|
4291
4519
|
}
|
|
4292
4520
|
T = new Array(d + 1);
|
|
4293
|
-
for (
|
|
4294
|
-
S = e[
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
T[
|
|
4298
|
-
p.set(
|
|
4521
|
+
for (c = d; c >= f; c--) {
|
|
4522
|
+
S = e[c];
|
|
4523
|
+
O = itemKey(S, n);
|
|
4524
|
+
a = p.get(O);
|
|
4525
|
+
T[c] = a === undefined ? -1 : a;
|
|
4526
|
+
p.set(O, c);
|
|
4299
4527
|
}
|
|
4300
|
-
for (
|
|
4301
|
-
S = getOverrideValue(r, i,
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
if (
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
p.set(
|
|
4528
|
+
for (a = f; a <= E; a++) {
|
|
4529
|
+
S = getOverrideValue(r, i, a, o);
|
|
4530
|
+
O = itemKey(S, n);
|
|
4531
|
+
c = p.get(O);
|
|
4532
|
+
if (c !== undefined && c !== -1) {
|
|
4533
|
+
_[c] = S;
|
|
4534
|
+
c = T[c];
|
|
4535
|
+
p.set(O, c);
|
|
4308
4536
|
}
|
|
4309
4537
|
}
|
|
4310
|
-
for (
|
|
4311
|
-
if (
|
|
4312
|
-
applyArrayItem(e[
|
|
4313
|
-
} else s?.[
|
|
4538
|
+
for (c = f; c < e.length; c++) {
|
|
4539
|
+
if (c in _) {
|
|
4540
|
+
applyArrayItem(e[c], _[c], t, s?.[c], n);
|
|
4541
|
+
} else s?.[c] && setSignal(s[c], wrapValue(e[c], t));
|
|
4314
4542
|
}
|
|
4315
4543
|
if (f < e.length) u = true;
|
|
4316
4544
|
} else if (e.length) {
|
|
4317
|
-
for (let l = 0,
|
|
4318
|
-
const
|
|
4319
|
-
if (isWrappable(
|
|
4320
|
-
if (
|
|
4545
|
+
for (let l = 0, a = e.length; l < a; l++) {
|
|
4546
|
+
const a = getOverrideValue(r, i, l, o);
|
|
4547
|
+
if (isWrappable(a) && isWrappable(e[l]) && !(rawValuesUsed && (isRawValue(a) || isRawValue(e[l])))) {
|
|
4548
|
+
if (a !== e[l]) applyState(e[l], wrap(a, t), n);
|
|
4549
|
+
} else {
|
|
4550
|
+
if (a !== e[l]) u = true;
|
|
4321
4551
|
s?.[l] && setSignal(s[l], wrapValue(e[l], t));
|
|
4322
4552
|
}
|
|
4323
4553
|
}
|
|
4324
4554
|
}
|
|
4325
|
-
const
|
|
4555
|
+
const a = e.length;
|
|
4326
4556
|
syncArrayNodeMembership(t, e);
|
|
4327
|
-
if (l !==
|
|
4557
|
+
if (l !== a) {
|
|
4328
4558
|
u = true;
|
|
4329
|
-
s?.length && setSignal(s.length,
|
|
4559
|
+
s?.length && setSignal(s.length, a);
|
|
4330
4560
|
}
|
|
4331
4561
|
u && notifySelf(t);
|
|
4332
4562
|
return;
|
|
@@ -4336,13 +4566,13 @@ function applyStateSlow(e, t, n) {
|
|
|
4336
4566
|
if (s) {
|
|
4337
4567
|
u = s[$TRACK];
|
|
4338
4568
|
const l = u ? getAllKeys(r, i, e) : nodeKeys(s);
|
|
4339
|
-
for (let
|
|
4340
|
-
const
|
|
4341
|
-
const f = s[
|
|
4342
|
-
const E = unwrap(getOverrideValue(r, i,
|
|
4343
|
-
let d = unwrap(e[
|
|
4569
|
+
for (let a = 0, c = l.length; a < c; a++) {
|
|
4570
|
+
const c = l[a];
|
|
4571
|
+
const f = s[c];
|
|
4572
|
+
const E = unwrap(getOverrideValue(r, i, c, o));
|
|
4573
|
+
let d = unwrap(e[c]);
|
|
4344
4574
|
if (E === d) continue;
|
|
4345
|
-
if (!E || !isWrappable(E) || !isWrappable(d) || Array.isArray(E) !== Array.isArray(d) || n(E) != null && n(E) !== n(d)) {
|
|
4575
|
+
if (!E || !isWrappable(E) || !isWrappable(d) || rawValuesUsed && (isRawValue(E) || isRawValue(d)) || Array.isArray(E) !== Array.isArray(d) || n(E) != null && n(E) !== n(d)) {
|
|
4346
4576
|
u && setSignal(u, void 0);
|
|
4347
4577
|
f && setSignal(f, isWrappable(d) ? wrap(d, t) : d);
|
|
4348
4578
|
} else applyState(d, wrap(E, t), n);
|
|
@@ -4410,9 +4640,16 @@ const NOKEY = () => null;
|
|
|
4410
4640
|
function createProjectionInternal(e, t, n) {
|
|
4411
4641
|
let r;
|
|
4412
4642
|
const i = new WeakMap;
|
|
4643
|
+
// A shallow projection's children are raw and never wrapped, so the
|
|
4644
|
+
// wrapper only ever runs for the root — flagging unconditionally is safe.
|
|
4645
|
+
const o = !!n?.shallow;
|
|
4413
4646
|
const wrapper = e => {
|
|
4414
4647
|
e[STORE_WRAP] = wrapProjection;
|
|
4415
4648
|
e[STORE_LOOKUP] = i;
|
|
4649
|
+
if (o) {
|
|
4650
|
+
e[STORE_SHALLOW] = true;
|
|
4651
|
+
markRawIngest(e[STORE_VALUE]);
|
|
4652
|
+
}
|
|
4416
4653
|
Object.defineProperty(e, STORE_FIREWALL, {
|
|
4417
4654
|
get() {
|
|
4418
4655
|
return r;
|
|
@@ -4427,14 +4664,14 @@ function createProjectionInternal(e, t, n) {
|
|
|
4427
4664
|
i.set(e, t);
|
|
4428
4665
|
return t;
|
|
4429
4666
|
};
|
|
4430
|
-
const
|
|
4667
|
+
const s = wrapProjection(t);
|
|
4431
4668
|
r = computed(() => {
|
|
4432
4669
|
if (!r) r = getOwner();
|
|
4433
|
-
runProjectionComputed(
|
|
4670
|
+
runProjectionComputed(s, e, n?.key || "id");
|
|
4434
4671
|
}, undefined);
|
|
4435
|
-
r.
|
|
4672
|
+
r.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
4436
4673
|
return {
|
|
4437
|
-
store:
|
|
4674
|
+
store: s,
|
|
4438
4675
|
node: r
|
|
4439
4676
|
};
|
|
4440
4677
|
}
|
|
@@ -4582,7 +4819,7 @@ function createWriteTraps(e, t) {
|
|
|
4582
4819
|
// the record witnesses it into the active isPending() probe.
|
|
4583
4820
|
$AFFECTS = Symbol(0);
|
|
4584
4821
|
|
|
4585
|
-
const STORE_VALUE = "v", STORE_OVERRIDE = "o", STORE_OPTIMISTIC_OVERRIDE = "x", STORE_NODE = "n", STORE_HAS = "h", STORE_CUSTOM_PROTO = "c", STORE_WRAP = "w", STORE_LOOKUP = "l", STORE_FIREWALL = "f", STORE_OPTIMISTIC = "p", STORE_OPTIMISTIC_OWNERS = "t", STORE_PARENT = "u", STORE_DESC = "d";
|
|
4822
|
+
const STORE_VALUE = "v", STORE_OVERRIDE = "o", STORE_OPTIMISTIC_OVERRIDE = "x", STORE_NODE = "n", STORE_HAS = "h", STORE_CUSTOM_PROTO = "c", STORE_WRAP = "w", STORE_LOOKUP = "l", STORE_FIREWALL = "f", STORE_OPTIMISTIC = "p", STORE_OPTIMISTIC_OWNERS = "t", STORE_PARENT = "u", STORE_DESC = "d", STORE_SHALLOW = "s";
|
|
4586
4823
|
|
|
4587
4824
|
const STORE_SELF_PENDING = Symbol(0);
|
|
4588
4825
|
|
|
@@ -4606,6 +4843,7 @@ function initStoreFields(e) {
|
|
|
4606
4843
|
e[STORE_SNAPSHOT_PROPS] = undefined;
|
|
4607
4844
|
e[STORE_PARENT] = undefined;
|
|
4608
4845
|
e[STORE_DESC] = undefined;
|
|
4846
|
+
e[STORE_SHALLOW] = undefined;
|
|
4609
4847
|
e[$PROXY] = null;
|
|
4610
4848
|
}
|
|
4611
4849
|
|
|
@@ -4630,24 +4868,99 @@ function createStoreProxy(e, t = storeTraps, n) {
|
|
|
4630
4868
|
return r[$PROXY] = new Proxy(r, t);
|
|
4631
4869
|
}
|
|
4632
4870
|
|
|
4871
|
+
// The global lookup maps raw value -> StoreNode TARGET (not proxy): reconcile
|
|
4872
|
+
// and the unwrap/snapshot walks resolve targets through it constantly, and a
|
|
4873
|
+
// target hit is a plain field read away from its proxy while a proxy hit
|
|
4874
|
+
// costs a trap to get back to the target. Per-family STORE_LOOKUP maps
|
|
4875
|
+
// (projections/optimistic) still map raw -> proxy — their wrap functions own
|
|
4876
|
+
// that contract — so mixed-lookup consumers resolve through lookupTarget().
|
|
4633
4877
|
const storeLookup = new WeakMap;
|
|
4634
4878
|
|
|
4635
4879
|
// Node records that hold at least one user (non-`$TRACK`) symbol-keyed node.
|
|
4636
4880
|
// Lets reconcile enumerate symbols only for records that need it (#2851).
|
|
4637
4881
|
const symbolKeyedRecords = new WeakSet;
|
|
4638
4882
|
|
|
4883
|
+
function lookupTarget(e, t) {
|
|
4884
|
+
if (t !== undefined && t !== storeLookup) {
|
|
4885
|
+
const n = t.get(e);
|
|
4886
|
+
if (n !== undefined) return n[$TARGET];
|
|
4887
|
+
}
|
|
4888
|
+
return storeLookup.get(e);
|
|
4889
|
+
}
|
|
4890
|
+
|
|
4891
|
+
// Values marked raw never acquire a proxy identity: wrap() serves them as-is
|
|
4892
|
+
// everywhere — deep stores hold them as leaf values replaced by reference.
|
|
4893
|
+
// Once raw, always raw (identity stays single, just unwrapped). Consulted
|
|
4894
|
+
// only on wrap-creation and ingest paths; reads never touch it.
|
|
4895
|
+
const rawValues = new WeakSet;
|
|
4896
|
+
|
|
4897
|
+
/**
|
|
4898
|
+
* Marks a value as raw: no store will ever wrap it — every store presents it
|
|
4899
|
+
* as-is, tracked by reference at whatever slot holds it and updated by
|
|
4900
|
+
* replacement. Useful for class instances and external objects (editors,
|
|
4901
|
+
* scene graphs, Maps) and for record-shaped data updated wholesale. Sticky
|
|
4902
|
+
* for the value's lifetime.
|
|
4903
|
+
*/
|
|
4904
|
+
// Flipped on the first mark and exported as a LIVE binding: reconcile
|
|
4905
|
+
// consults it on every recursable pair, and importing the boolean directly
|
|
4906
|
+
// lets those sites skip even the function call when no shallow store or raw
|
|
4907
|
+
// mark exists anywhere in the app.
|
|
4908
|
+
let rawValuesUsed = false;
|
|
4909
|
+
|
|
4910
|
+
function isRawValue(e) {
|
|
4911
|
+
return rawValuesUsed && rawValues.has(e);
|
|
4912
|
+
}
|
|
4913
|
+
|
|
4914
|
+
function markRawOne(e) {
|
|
4915
|
+
if (isWrappable(e)) {
|
|
4916
|
+
rawValuesUsed = true;
|
|
4917
|
+
rawValues.add(e);
|
|
4918
|
+
}
|
|
4919
|
+
}
|
|
4920
|
+
|
|
4921
|
+
function markRawIngest(e) {
|
|
4922
|
+
if (Array.isArray(e)) {
|
|
4923
|
+
for (let t = 0, n = e.length; t < n; t++) markRawOne(e[t]);
|
|
4924
|
+
} else {
|
|
4925
|
+
for (const t in e) markRawOne(e[t]);
|
|
4926
|
+
}
|
|
4927
|
+
}
|
|
4928
|
+
|
|
4639
4929
|
function wrap(e, t) {
|
|
4930
|
+
// Raw is raw in every family: the mark must preempt family wrapping too,
|
|
4931
|
+
// or a shallow projection/optimistic store would proxy its raw records.
|
|
4932
|
+
if (rawValuesUsed && rawValues.has(e)) return e;
|
|
4640
4933
|
if (t?.[STORE_WRAP]) {
|
|
4641
4934
|
const n = t[STORE_WRAP](e, t);
|
|
4642
4935
|
const r = n[$TARGET];
|
|
4643
4936
|
if (r && !r[STORE_PARENT] && r !== t) r[STORE_PARENT] = t;
|
|
4644
4937
|
return n;
|
|
4645
4938
|
}
|
|
4646
|
-
|
|
4647
|
-
if (
|
|
4648
|
-
|
|
4649
|
-
|
|
4939
|
+
const n = storeLookup.get(e);
|
|
4940
|
+
if (n !== undefined) return n[$PROXY];
|
|
4941
|
+
let r = e[$PROXY];
|
|
4942
|
+
if (!r) {
|
|
4943
|
+
r = createStoreProxy(e);
|
|
4944
|
+
const n = r[$TARGET];
|
|
4945
|
+
storeLookup.set(e, n);
|
|
4946
|
+
if (t) n[STORE_PARENT] = t;
|
|
4650
4947
|
}
|
|
4948
|
+
return r;
|
|
4949
|
+
}
|
|
4950
|
+
|
|
4951
|
+
// Shallow store root: the target itself is fully reactive (per-key nodes,
|
|
4952
|
+
// membership, $TRACK); its values are served raw. Seed values are marked at
|
|
4953
|
+
// creation; reconcile and the set trap mark on ingest.
|
|
4954
|
+
function wrapShallow(e) {
|
|
4955
|
+
const t = storeLookup.get(e);
|
|
4956
|
+
if (t !== undefined) {
|
|
4957
|
+
if (t[STORE_SHALLOW]) return t[$PROXY];
|
|
4958
|
+
}
|
|
4959
|
+
const n = createStoreProxy(e);
|
|
4960
|
+
const r = n[$TARGET];
|
|
4961
|
+
r[STORE_SHALLOW] = true;
|
|
4962
|
+
storeLookup.set(e, r);
|
|
4963
|
+
markRawIngest(e);
|
|
4651
4964
|
return n;
|
|
4652
4965
|
}
|
|
4653
4966
|
|
|
@@ -4669,7 +4982,7 @@ function writeOnly(e) {
|
|
|
4669
4982
|
}
|
|
4670
4983
|
|
|
4671
4984
|
function unwrapStoreValue(e, t, n) {
|
|
4672
|
-
const r = e?.[$TARGET] ||
|
|
4985
|
+
const r = e?.[$TARGET] || lookupTarget(e, n);
|
|
4673
4986
|
if (!r) return e;
|
|
4674
4987
|
const i = r[STORE_OVERRIDE];
|
|
4675
4988
|
if (!i) return r[STORE_VALUE];
|
|
@@ -4733,7 +5046,7 @@ function ownEnumerableKeysPlain(e) {
|
|
|
4733
5046
|
* The value a store leaf's backing signal currently shows to readers: active
|
|
4734
5047
|
* override, else held pending value, else committed value.
|
|
4735
5048
|
*/ function visibleNodeValue(e) {
|
|
4736
|
-
return e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.
|
|
5049
|
+
return e.A !== undefined && e.A !== NOT_PENDING ? unwrapOverride(e.A) : e.U !== NOT_PENDING ? e.U : e.ke;
|
|
4737
5050
|
}
|
|
4738
5051
|
|
|
4739
5052
|
function hasOwnStoreProperty(e, t) {
|
|
@@ -4788,7 +5101,7 @@ function getNode(e, t, n, r, i = isEqual, o) {
|
|
|
4788
5101
|
}
|
|
4789
5102
|
if (o && n in o) {
|
|
4790
5103
|
const e = o[n];
|
|
4791
|
-
s.
|
|
5104
|
+
s.me = e === undefined ? NO_SNAPSHOT : e;
|
|
4792
5105
|
snapshotSources?.add(s);
|
|
4793
5106
|
}
|
|
4794
5107
|
if (typeof n === "symbol" && n !== $TRACK && n !== $AFFECTS) symbolKeyedRecords.add(t);
|
|
@@ -4841,7 +5154,7 @@ const affectsScopes = new Map;
|
|
|
4841
5154
|
// holds the root, and must still descend to pick up records added since.
|
|
4842
5155
|
i) {
|
|
4843
5156
|
if (!isWrappable(e)) return;
|
|
4844
|
-
const o = e[$TARGET] || (r
|
|
5157
|
+
const o = e[$TARGET] || lookupTarget(e, r);
|
|
4845
5158
|
const s = o ? o[STORE_VALUE] : e;
|
|
4846
5159
|
if (i.has(s)) return;
|
|
4847
5160
|
i.add(s);
|
|
@@ -4868,9 +5181,9 @@ i) {
|
|
|
4868
5181
|
const l = o || r ? getStoreSymbols(s, u) : [];
|
|
4869
5182
|
for (let e = 0, o = l.length; e < o; e++) {
|
|
4870
5183
|
const o = l[e];
|
|
4871
|
-
const
|
|
4872
|
-
if (!
|
|
4873
|
-
walkAffectsScope(
|
|
5184
|
+
const a = getPropertyDescriptor(s, u, o);
|
|
5185
|
+
if (!a || a.get) continue;
|
|
5186
|
+
walkAffectsScope(a.value, t, n, r, i);
|
|
4874
5187
|
}
|
|
4875
5188
|
} else {
|
|
4876
5189
|
const e = o || r ? getStoreKeys(s, u) : getKeys(s, u);
|
|
@@ -4906,11 +5219,11 @@ i) {
|
|
|
4906
5219
|
// Callers guard on `pendingCheckActive`, which only flips inside
|
|
4907
5220
|
// isPending() — the verdict layer is loaded and its hook installed.
|
|
4908
5221
|
const n = e[STORE_NODE]?.[$AFFECTS];
|
|
4909
|
-
if (n?.k) GlobalQueue.
|
|
5222
|
+
if (n?.k) GlobalQueue.Oe(n);
|
|
4910
5223
|
if (affectsScopes.size) {
|
|
4911
5224
|
const r = e[STORE_VALUE];
|
|
4912
5225
|
for (const [e, i] of affectsScopes) {
|
|
4913
|
-
if (e !== n && e.k && i.scope.has(r) && (i.key === undefined || i.key === t)) GlobalQueue.
|
|
5226
|
+
if (e !== n && e.k && i.scope.has(r) && (i.key === undefined || i.key === t)) GlobalQueue.Oe(e);
|
|
4914
5227
|
}
|
|
4915
5228
|
}
|
|
4916
5229
|
}
|
|
@@ -5058,7 +5371,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
5058
5371
|
}
|
|
5059
5372
|
const r = e[STORE_VALUE];
|
|
5060
5373
|
const i = r[n];
|
|
5061
|
-
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.
|
|
5374
|
+
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.xe ?? 0) & STATUS_PENDING)) {
|
|
5062
5375
|
if (!e[STORE_SNAPSHOT_PROPS]) {
|
|
5063
5376
|
e[STORE_SNAPSHOT_PROPS] = Object.create(null);
|
|
5064
5377
|
snapshotSources?.add(e);
|
|
@@ -5123,24 +5436,24 @@ function notifyStoreProperty(e, t, n, r, i, o) {
|
|
|
5123
5436
|
const n = upsertStoreNode(e, getNodes(e, STORE_HAS), t, o);
|
|
5124
5437
|
setSignal(n, u);
|
|
5125
5438
|
}
|
|
5126
|
-
const
|
|
5439
|
+
const a = getNodes(e, STORE_NODE);
|
|
5127
5440
|
if (n === "set") {
|
|
5128
|
-
if (
|
|
5129
|
-
setSignal(
|
|
5441
|
+
if (a[t]) {
|
|
5442
|
+
setSignal(a[t], () => isWrappable(r) ? wrap(r, e) : r);
|
|
5130
5443
|
} else if (!s) {
|
|
5131
|
-
const n = upsertStoreNode(e,
|
|
5444
|
+
const n = upsertStoreNode(e, a, t, i, e[STORE_SNAPSHOT_PROPS]);
|
|
5132
5445
|
setSignal(n, () => isWrappable(r) ? wrap(r, e) : r);
|
|
5133
5446
|
}
|
|
5134
5447
|
} else if (n === "invalidate") {
|
|
5135
|
-
if (
|
|
5136
|
-
setSignal(
|
|
5137
|
-
delete
|
|
5448
|
+
if (a[t]) {
|
|
5449
|
+
setSignal(a[t], {});
|
|
5450
|
+
delete a[t];
|
|
5138
5451
|
}
|
|
5139
5452
|
} else {
|
|
5140
|
-
if (
|
|
5141
|
-
setSignal(
|
|
5453
|
+
if (a[t]) {
|
|
5454
|
+
setSignal(a[t], undefined);
|
|
5142
5455
|
} else if (!s) {
|
|
5143
|
-
const n = upsertStoreNode(e,
|
|
5456
|
+
const n = upsertStoreNode(e, a, t, i, e[STORE_SNAPSHOT_PROPS]);
|
|
5144
5457
|
setSignal(n, undefined);
|
|
5145
5458
|
}
|
|
5146
5459
|
}
|
|
@@ -5159,7 +5472,7 @@ let Writing = null;
|
|
|
5159
5472
|
* itself (the derive function works its own draft while uninitialized).
|
|
5160
5473
|
*/ function throwIfUninitialized(e) {
|
|
5161
5474
|
const t = e[STORE_FIREWALL];
|
|
5162
|
-
if (t && t.
|
|
5475
|
+
if (t && t.xe & STATUS_UNINITIALIZED) throw t.De ?? new NotReadyError(t);
|
|
5163
5476
|
}
|
|
5164
5477
|
|
|
5165
5478
|
const storeTraps = {
|
|
@@ -5182,8 +5495,20 @@ const storeTraps = {
|
|
|
5182
5495
|
const n = e[STORE_NODE];
|
|
5183
5496
|
const r = n && n[t];
|
|
5184
5497
|
if (r !== undefined && e[STORE_VALUE][$TARGET] === undefined) {
|
|
5185
|
-
|
|
5498
|
+
// readNodeFast is read()'s plain-signal fast path hoisted over the
|
|
5499
|
+
// call; READ_SLOW means a global read window (latest/pending-check/
|
|
5500
|
+
// transition/lane/snapshot capture) or a node layer is active, and
|
|
5501
|
+
// only then does the full read() resolution have anything to do.
|
|
5502
|
+
let t = readNodeFast(r);
|
|
5503
|
+
if (t === READ_SLOW) t = read(r);
|
|
5186
5504
|
if (t === $DELETED) t = undefined;
|
|
5505
|
+
// Every node-writing site wraps wrappables before setSignal (see the
|
|
5506
|
+
// dev assertion below), so re-wrapping on read is redundant — except
|
|
5507
|
+
// during snapshot capture, where read() can surface a raw captured
|
|
5508
|
+
// value seeded from snapshot props.
|
|
5509
|
+
if (!snapshotCaptureActive) {
|
|
5510
|
+
return t;
|
|
5511
|
+
}
|
|
5187
5512
|
return isWrappable(t) ? wrap(t, e) : t;
|
|
5188
5513
|
}
|
|
5189
5514
|
}
|
|
@@ -5196,33 +5521,38 @@ const storeTraps = {
|
|
|
5196
5521
|
}
|
|
5197
5522
|
const u = getOverlayLayer(e, t);
|
|
5198
5523
|
const l = !!u;
|
|
5199
|
-
const
|
|
5200
|
-
const
|
|
5524
|
+
const a = !!e[STORE_VALUE][$TARGET];
|
|
5525
|
+
const c = u ?? e[STORE_VALUE];
|
|
5201
5526
|
if (!o) {
|
|
5202
|
-
const r = Object.getOwnPropertyDescriptor(
|
|
5527
|
+
const r = Object.getOwnPropertyDescriptor(c, t);
|
|
5203
5528
|
if (r && r.get) return r.get.call(n);
|
|
5204
5529
|
if (!r && !l && e[STORE_CUSTOM_PROTO]) {
|
|
5205
|
-
const e = unwrapStoreValue(
|
|
5530
|
+
const e = unwrapStoreValue(c);
|
|
5206
5531
|
if (hasInheritedAccessor(e, t)) {
|
|
5207
|
-
return Reflect.get(
|
|
5532
|
+
return Reflect.get(c, t, n);
|
|
5208
5533
|
}
|
|
5209
5534
|
}
|
|
5210
5535
|
}
|
|
5211
5536
|
if (writeOnly(n)) {
|
|
5212
5537
|
if (isPrototypePollutionKey$1(t) && !hasOwnStoreProperty(e, t)) return undefined;
|
|
5213
|
-
let n = o && (l || !
|
|
5538
|
+
let n = o && (l || !a) ? visibleNodeValue(o) : c[t];
|
|
5214
5539
|
n === $DELETED && (n = undefined);
|
|
5215
5540
|
if (!isWrappable(n)) return n;
|
|
5541
|
+
// Shallow boundary: records are replaced, never edited in place. Reads
|
|
5542
|
+
// inside a setter serve the raw so read-then-replace, filter/pop and
|
|
5543
|
+
// projection derives all work; in-place mutation of a raw is inert by
|
|
5544
|
+
// construction — the same contract as a markRaw child in a deep store.
|
|
5545
|
+
if (e[STORE_SHALLOW]) return n;
|
|
5216
5546
|
const r = wrap(n, e);
|
|
5217
5547
|
Writing?.add(r);
|
|
5218
5548
|
return r;
|
|
5219
5549
|
}
|
|
5220
|
-
let f = o ? l || !
|
|
5550
|
+
let f = o ? l || !a ? read(i[t]) : (read(i[t]), c[t]) : c[t];
|
|
5221
5551
|
f === $DELETED && (f = undefined);
|
|
5222
5552
|
if (!o) {
|
|
5223
|
-
if (!l && typeof f === "function" && !Object.prototype.hasOwnProperty.call(
|
|
5553
|
+
if (!l && typeof f === "function" && !Object.prototype.hasOwnProperty.call(c, t)) {
|
|
5224
5554
|
let t;
|
|
5225
|
-
return !Array.isArray(e[STORE_VALUE]) && (t = Object.getPrototypeOf(e[STORE_VALUE])) && t !== Object.prototype ? f.bind(
|
|
5555
|
+
return !Array.isArray(e[STORE_VALUE]) && (t = Object.getPrototypeOf(e[STORE_VALUE])) && t !== Object.prototype ? f.bind(c) : f;
|
|
5226
5556
|
} else if (getObserver() && !r) {
|
|
5227
5557
|
return read(getNode(e, i, t, isWrappable(f) ? wrap(f, e) : f, isEqual, e[STORE_SNAPSHOT_PROPS]));
|
|
5228
5558
|
}
|
|
@@ -5260,8 +5590,9 @@ const storeTraps = {
|
|
|
5260
5590
|
const {base: i, overrideKey: o, state: s} = prepareStoreWrite(e, r, t);
|
|
5261
5591
|
const u = getOverlayLayer(e, t);
|
|
5262
5592
|
const l = u ? u[t] : i;
|
|
5263
|
-
const
|
|
5264
|
-
const
|
|
5593
|
+
const a = u ? u[t] !== $DELETED : t in e[STORE_VALUE];
|
|
5594
|
+
const c = unwrapStoreValue(n);
|
|
5595
|
+
if (e[STORE_SHALLOW] && isWrappable(c)) rawValues.add(c);
|
|
5265
5596
|
// Symbol-keyed writes on arrays are metadata, not index writes — never run
|
|
5266
5597
|
// them through the numeric index/length machinery (`parseInt` on a symbol
|
|
5267
5598
|
// throws). #2769
|
|
@@ -5270,27 +5601,27 @@ const storeTraps = {
|
|
|
5270
5601
|
const d = E ? f + 1 : 0;
|
|
5271
5602
|
const S = E && (getOverlayLayer(e, "length") ?? s).length;
|
|
5272
5603
|
const T = E && d > S ? d : undefined;
|
|
5273
|
-
if (l ===
|
|
5604
|
+
if (l === c && T === undefined) return true;
|
|
5274
5605
|
armOptimisticStoreWrite(e, r);
|
|
5275
|
-
if (
|
|
5606
|
+
if (c !== undefined && c === i && T === undefined) {
|
|
5276
5607
|
delete e[o]?.[t];
|
|
5277
5608
|
if (o === STORE_OPTIMISTIC_OVERRIDE) delete e[STORE_OPTIMISTIC_OWNERS]?.[t];
|
|
5278
5609
|
} else {
|
|
5279
5610
|
const n = e[o] || (e[o] = Object.create(null));
|
|
5280
|
-
n[t] =
|
|
5611
|
+
n[t] = c;
|
|
5281
5612
|
stampOptimisticOwner(e, o, t);
|
|
5282
5613
|
if (T !== undefined) {
|
|
5283
5614
|
n.length = T;
|
|
5284
5615
|
stampOptimisticOwner(e, o, "length");
|
|
5285
5616
|
}
|
|
5286
5617
|
}
|
|
5287
|
-
notifyStoreProperty(e, t, "set",
|
|
5618
|
+
notifyStoreProperty(e, t, "set", c, l, a);
|
|
5288
5619
|
// Shrinking an array's length must remove the truncated indices, otherwise
|
|
5289
5620
|
// they leak through `has`, `ownKeys`, and (tracked) index reads from the
|
|
5290
5621
|
// underlying value. Mark each as deleted and notify so reactive reads update. #2768
|
|
5291
|
-
if (Array.isArray(s) && t === "length" && typeof
|
|
5622
|
+
if (Array.isArray(s) && t === "length" && typeof c === "number" && typeof l === "number" && c < l) {
|
|
5292
5623
|
const t = e[o] || (e[o] = Object.create(null));
|
|
5293
|
-
for (let n =
|
|
5624
|
+
for (let n = c; n < l; n++) {
|
|
5294
5625
|
if (t[n] === $DELETED) continue;
|
|
5295
5626
|
const r = n in t ? t[n] : s[n];
|
|
5296
5627
|
if (!(n in t) && !(n in s)) continue;
|
|
@@ -5453,7 +5784,7 @@ function storeSetter(e, t) {
|
|
|
5453
5784
|
}
|
|
5454
5785
|
|
|
5455
5786
|
function createStore(e, t, n) {
|
|
5456
|
-
const r = typeof e === "function", i = r ? createProjectionInternal(e, t, n).store : wrap(e);
|
|
5787
|
+
const r = typeof e === "function", i = r ? createProjectionInternal(e, t, n).store : t?.shallow ? wrapShallow(e) : wrap(e);
|
|
5457
5788
|
return [ i, r ? e => {
|
|
5458
5789
|
// Mark the projection as manually written before notifying property nodes.
|
|
5459
5790
|
suppressComputedRecompute(i[$REFRESH]);
|
|
@@ -5485,9 +5816,9 @@ function createStore(e, t, n) {
|
|
|
5485
5816
|
* flush that would surface them, before effects run — verdict-only, netting
|
|
5486
5817
|
* no visual change.
|
|
5487
5818
|
*/ function notifyMarkBoundaries(e) {
|
|
5488
|
-
if (!e.
|
|
5819
|
+
if (!e.G && !e.nt) return;
|
|
5489
5820
|
const t = new NotReadyError(e);
|
|
5490
|
-
t.
|
|
5821
|
+
t.we = true;
|
|
5491
5822
|
const n = new Set;
|
|
5492
5823
|
const visit = e => {
|
|
5493
5824
|
if (n.has(e)) return;
|
|
@@ -5513,7 +5844,7 @@ function createStore(e, t, n) {
|
|
|
5513
5844
|
* earlier overlapping registration get covered, and dedup stops re-descent.
|
|
5514
5845
|
*/ function registerAffectsMark(e) {
|
|
5515
5846
|
markAffects(e);
|
|
5516
|
-
globalQueue.D.
|
|
5847
|
+
globalQueue.D.L.push(e);
|
|
5517
5848
|
// Companions only exist once the verdict layer (isPending/latest) loaded;
|
|
5518
5849
|
// without them there is no materialized verdict to poke.
|
|
5519
5850
|
GlobalQueue.Te !== null && GlobalQueue.Te(e);
|
|
@@ -5575,6 +5906,8 @@ function createOptimisticStore(e, t, n) {
|
|
|
5575
5906
|
installOptimisticEngine();
|
|
5576
5907
|
GlobalQueue.ee ||= clearOptimisticStores;
|
|
5577
5908
|
const r = typeof e === "function";
|
|
5909
|
+
// Plain form: the second slot carries options.
|
|
5910
|
+
if (!r && n === undefined) n = t;
|
|
5578
5911
|
const i = r ? t : e;
|
|
5579
5912
|
const o = r ? e : undefined;
|
|
5580
5913
|
// Create optimistic projection store
|
|
@@ -5638,23 +5971,23 @@ function clearOptimisticStores(e, t) {
|
|
|
5638
5971
|
delete n[l];
|
|
5639
5972
|
if (i) delete i[l];
|
|
5640
5973
|
s = true;
|
|
5641
|
-
const
|
|
5642
|
-
if (
|
|
5974
|
+
const a = r?.[l];
|
|
5975
|
+
if (a) {
|
|
5643
5976
|
// Clear lane association so effects go to regular queue
|
|
5644
|
-
|
|
5977
|
+
a.i = undefined;
|
|
5645
5978
|
// Re-read from base — this key left the optimistic layer above, so the
|
|
5646
5979
|
// overlay resolves to STORE_OVERRIDE or STORE_VALUE.
|
|
5647
5980
|
const t = getOverlayLayer(e, l);
|
|
5648
5981
|
const n = t ? t[l] : e[STORE_VALUE][l];
|
|
5649
5982
|
const r = n === $DELETED ? undefined : n;
|
|
5650
5983
|
const i = isWrappable(r) ? wrap(r, e) : r;
|
|
5651
|
-
const o = visibleNodeValue(
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
if (!
|
|
5657
|
-
insertSubs(
|
|
5984
|
+
const o = visibleNodeValue(a);
|
|
5985
|
+
a.A = NOT_PENDING;
|
|
5986
|
+
a.R = null;
|
|
5987
|
+
a.U = NOT_PENDING;
|
|
5988
|
+
a.ke = i;
|
|
5989
|
+
if (!a.At || !a.At(o, i)) {
|
|
5990
|
+
insertSubs(a, true);
|
|
5658
5991
|
schedule();
|
|
5659
5992
|
}
|
|
5660
5993
|
}
|
|
@@ -5678,9 +6011,14 @@ function clearOptimisticStores(e, t) {
|
|
|
5678
6011
|
function createOptimisticProjectionInternal(e, t, n) {
|
|
5679
6012
|
let r;
|
|
5680
6013
|
const i = new WeakMap;
|
|
6014
|
+
const o = !!n?.shallow;
|
|
5681
6015
|
const wrapper = e => {
|
|
5682
6016
|
e[STORE_WRAP] = wrapProjection;
|
|
5683
6017
|
e[STORE_LOOKUP] = i;
|
|
6018
|
+
if (o) {
|
|
6019
|
+
e[STORE_SHALLOW] = true;
|
|
6020
|
+
markRawIngest(e[STORE_VALUE]);
|
|
6021
|
+
}
|
|
5684
6022
|
e[STORE_OPTIMISTIC] = true;
|
|
5685
6023
|
// Mark as optimistic store
|
|
5686
6024
|
Object.defineProperty(e, STORE_FIREWALL, {
|
|
@@ -5697,7 +6035,7 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
5697
6035
|
i.set(e, t);
|
|
5698
6036
|
return t;
|
|
5699
6037
|
};
|
|
5700
|
-
const
|
|
6038
|
+
const s = wrapProjection(t);
|
|
5701
6039
|
// If there's a projection function, create a computed to drive it
|
|
5702
6040
|
if (e) {
|
|
5703
6041
|
// All writes inside firewall recompute must go to STORE_OVERRIDE (base), not
|
|
@@ -5706,7 +6044,7 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
5706
6044
|
// async yields because they fire outside any enclosing try/finally. It also
|
|
5707
6045
|
// consumes stale optimistic overlays once fresh projected data lands.
|
|
5708
6046
|
const clearProjectionOverride = () => {
|
|
5709
|
-
const e =
|
|
6047
|
+
const e = s[$TARGET];
|
|
5710
6048
|
if (e?.[STORE_OPTIMISTIC_OVERRIDE]) clearOptimisticOverride(e);
|
|
5711
6049
|
};
|
|
5712
6050
|
const wrapCommit = e => {
|
|
@@ -5722,15 +6060,15 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
5722
6060
|
r = computed(() => {
|
|
5723
6061
|
setProjectionWriteActive(true);
|
|
5724
6062
|
try {
|
|
5725
|
-
runProjectionComputed(
|
|
6063
|
+
runProjectionComputed(s, e, n?.key || "id", wrapCommit, clearProjectionOverride);
|
|
5726
6064
|
} finally {
|
|
5727
6065
|
setProjectionWriteActive(false);
|
|
5728
6066
|
}
|
|
5729
6067
|
}, undefined);
|
|
5730
|
-
r.
|
|
6068
|
+
r.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
5731
6069
|
}
|
|
5732
6070
|
return {
|
|
5733
|
-
store:
|
|
6071
|
+
store: s,
|
|
5734
6072
|
node: r
|
|
5735
6073
|
};
|
|
5736
6074
|
}
|
|
@@ -5836,11 +6174,11 @@ function updatePath(e, t, n = 0) {
|
|
|
5836
6174
|
});
|
|
5837
6175
|
|
|
5838
6176
|
function snapshotImpl(e, t, n, r) {
|
|
5839
|
-
let i, o, s, u, l,
|
|
6177
|
+
let i, o, s, u, l, a;
|
|
5840
6178
|
if (!isWrappable(e)) return e;
|
|
5841
6179
|
if (n && n.has(e)) return n.get(e);
|
|
5842
6180
|
if (!n) n = new Map;
|
|
5843
|
-
if (i = e[$TARGET] ||
|
|
6181
|
+
if (i = e[$TARGET] || lookupTarget(e, r)) {
|
|
5844
6182
|
if (t) {
|
|
5845
6183
|
trackSelf(i, $TRACK);
|
|
5846
6184
|
// A tracked walk reads THROUGH the record without touching the proxy
|
|
@@ -5870,26 +6208,26 @@ function snapshotImpl(e, t, n, r) {
|
|
|
5870
6208
|
}
|
|
5871
6209
|
if (o) {
|
|
5872
6210
|
const o = s?.length ?? e.length;
|
|
5873
|
-
for (let
|
|
5874
|
-
|
|
5875
|
-
if (
|
|
5876
|
-
if (t && isWrappable(
|
|
5877
|
-
if ((l = snapshotImpl(
|
|
6211
|
+
for (let c = 0; c < o; c++) {
|
|
6212
|
+
a = s && c in s ? s[c] : e[c];
|
|
6213
|
+
if (a === $DELETED) continue;
|
|
6214
|
+
if (t && isWrappable(a) && !(rawValuesUsed && isRawValue(a))) wrap(a, i);
|
|
6215
|
+
if ((l = snapshotImpl(a, t, n, r)) !== a || u) {
|
|
5878
6216
|
if (!u) n.set(e, u = [ ...e ]);
|
|
5879
|
-
u[
|
|
6217
|
+
u[c] = l;
|
|
5880
6218
|
}
|
|
5881
6219
|
}
|
|
5882
6220
|
// Enumerate array symbols separately to avoid scanning indices twice.
|
|
5883
6221
|
// Spread copies omit symbols, so assign them after the numeric walk.
|
|
5884
|
-
const
|
|
5885
|
-
for (let o = 0, f =
|
|
5886
|
-
const f =
|
|
6222
|
+
const c = r ? getStoreSymbols(e, s) : [];
|
|
6223
|
+
for (let o = 0, f = c.length; o < f; o++) {
|
|
6224
|
+
const f = c[o];
|
|
5887
6225
|
const E = getPropertyDescriptor(e, s, f);
|
|
5888
6226
|
if (!E || E.get) continue;
|
|
5889
|
-
|
|
5890
|
-
if (t && isWrappable(
|
|
5891
|
-
l = snapshotImpl(
|
|
5892
|
-
if (l !==
|
|
6227
|
+
a = s && f in s ? s[f] : e[f];
|
|
6228
|
+
if (t && isWrappable(a) && !(rawValuesUsed && isRawValue(a))) wrap(a, i);
|
|
6229
|
+
l = snapshotImpl(a, t, n, r);
|
|
6230
|
+
if (l !== a || u) {
|
|
5893
6231
|
if (!u) n.set(e, u = Object.assign([ ...e ], e));
|
|
5894
6232
|
u[f] = l;
|
|
5895
6233
|
}
|
|
@@ -5904,31 +6242,31 @@ function snapshotImpl(e, t, n, r) {
|
|
|
5904
6242
|
// A lookup means this object belongs to an immutable store backing tree,
|
|
5905
6243
|
// even if that nested value has not needed its own proxy yet.
|
|
5906
6244
|
const o = r ? getStoreKeys(e, undefined) : getKeys(e, undefined);
|
|
5907
|
-
for (let s = 0,
|
|
5908
|
-
const
|
|
5909
|
-
const f = Object.getOwnPropertyDescriptor(e,
|
|
6245
|
+
for (let s = 0, c = o.length; s < c; s++) {
|
|
6246
|
+
const c = o[s];
|
|
6247
|
+
const f = Object.getOwnPropertyDescriptor(e, c);
|
|
5910
6248
|
if (f.get) continue;
|
|
5911
|
-
|
|
5912
|
-
if (t && isWrappable(
|
|
5913
|
-
if ((l = snapshotImpl(
|
|
6249
|
+
a = f.value;
|
|
6250
|
+
if (t && isWrappable(a) && !(rawValuesUsed && isRawValue(a))) wrap(a, i);
|
|
6251
|
+
if ((l = snapshotImpl(a, t, n, r)) !== a || u) {
|
|
5914
6252
|
if (!u) {
|
|
5915
6253
|
u = Object.create(Object.getPrototypeOf(e));
|
|
5916
6254
|
Object.assign(u, e);
|
|
5917
6255
|
}
|
|
5918
|
-
u[
|
|
6256
|
+
u[c] = l;
|
|
5919
6257
|
}
|
|
5920
6258
|
}
|
|
5921
6259
|
} else {
|
|
5922
6260
|
// An override only exists on a store record, and the target branch above
|
|
5923
6261
|
// always set `lookup` alongside it — so this branch is always store-keyed.
|
|
5924
6262
|
const o = getStoreKeys(e, s);
|
|
5925
|
-
for (let
|
|
5926
|
-
let f = o[
|
|
6263
|
+
for (let c = 0, f = o.length; c < f; c++) {
|
|
6264
|
+
let f = o[c];
|
|
5927
6265
|
const E = getPropertyDescriptor(e, s, f);
|
|
5928
6266
|
if (E.get) continue;
|
|
5929
|
-
|
|
5930
|
-
if (t && isWrappable(
|
|
5931
|
-
if ((l = snapshotImpl(
|
|
6267
|
+
a = f in s ? s[f] : e[f];
|
|
6268
|
+
if (t && isWrappable(a) && !(rawValuesUsed && isRawValue(a))) wrap(a, i);
|
|
6269
|
+
if ((l = snapshotImpl(a, t, n, r)) !== e[f] || u) {
|
|
5932
6270
|
if (!u) {
|
|
5933
6271
|
u = Object.create(Object.getPrototypeOf(e));
|
|
5934
6272
|
Object.assign(u, e);
|
|
@@ -6151,24 +6489,24 @@ function mapArray(e, t, n) {
|
|
|
6151
6489
|
const i = t.length > 1;
|
|
6152
6490
|
const o = t;
|
|
6153
6491
|
const s = {
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
Lt: [],
|
|
6158
|
-
Ut: o,
|
|
6492
|
+
wt: createOwner(),
|
|
6493
|
+
vt: 0,
|
|
6494
|
+
Lt: e,
|
|
6159
6495
|
Vt: [],
|
|
6496
|
+
Gt: o,
|
|
6497
|
+
Ut: [],
|
|
6160
6498
|
kt: [],
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6499
|
+
Wt: r,
|
|
6500
|
+
Ft: r || n?.keyed === false ? [] : undefined,
|
|
6501
|
+
xt: i && n?.keyed !== false ? [] : undefined,
|
|
6502
|
+
Qt: n?.keyed === false,
|
|
6503
|
+
Ht: n?.fallback
|
|
6166
6504
|
};
|
|
6167
6505
|
const u = computed(updateKeyedMap.bind(s));
|
|
6168
6506
|
// Untracked reads inside the internal owner resolve via _parentComputed; routing
|
|
6169
6507
|
// them through node lets store-proxy lookups see pending writes (not stale _value).
|
|
6170
|
-
s.
|
|
6171
|
-
u.
|
|
6508
|
+
s.wt.Je = u;
|
|
6509
|
+
u.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
6172
6510
|
return accessor(u);
|
|
6173
6511
|
}
|
|
6174
6512
|
|
|
@@ -6186,52 +6524,52 @@ const pureOptions = {
|
|
|
6186
6524
|
// strong-abort ordering: removed rows now dispose AFTER the pass's new rows
|
|
6187
6525
|
// are created (you cannot destroy state before knowing the pass will land).
|
|
6188
6526
|
function updateKeyedMap() {
|
|
6189
|
-
const e = this.
|
|
6527
|
+
const e = this.Lt() || [], t = e.length;
|
|
6190
6528
|
e[$TRACK];
|
|
6191
6529
|
// top level tracking
|
|
6192
|
-
runWithOwner(this.
|
|
6530
|
+
runWithOwner(this.wt, () => {
|
|
6193
6531
|
let n, r, i, o,
|
|
6194
6532
|
// Mappers write freshly-created row/index signals into the STAGE
|
|
6195
6533
|
// arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
|
|
6196
|
-
s = this.
|
|
6534
|
+
s = this.Ft ? this.Qt ? () => {
|
|
6197
6535
|
i[r] = signal(e[r], pureOptions);
|
|
6198
|
-
return this.
|
|
6536
|
+
return this.Gt(accessor(i[r]), r);
|
|
6199
6537
|
} : () => {
|
|
6200
6538
|
i[r] = signal(e[r], pureOptions);
|
|
6201
6539
|
o && (o[r] = signal(r, pureOptions));
|
|
6202
|
-
return this.
|
|
6203
|
-
} : this.
|
|
6540
|
+
return this.Gt(accessor(i[r]), o ? accessor(o[r]) : undefined);
|
|
6541
|
+
} : this.xt ? () => {
|
|
6204
6542
|
const t = e[r];
|
|
6205
6543
|
o[r] = signal(r, pureOptions);
|
|
6206
|
-
return this.
|
|
6544
|
+
return this.Gt(t, accessor(o[r]));
|
|
6207
6545
|
} : () => {
|
|
6208
6546
|
const t = e[r];
|
|
6209
|
-
return this.
|
|
6547
|
+
return this.Gt(t);
|
|
6210
6548
|
};
|
|
6211
6549
|
// fast path for empty arrays
|
|
6212
6550
|
if (t === 0) {
|
|
6213
|
-
if (this.
|
|
6214
|
-
this.
|
|
6551
|
+
if (this.vt !== 0) {
|
|
6552
|
+
this.wt.dispose(false);
|
|
6215
6553
|
this.kt = [];
|
|
6216
|
-
this.Lt = [];
|
|
6217
6554
|
this.Vt = [];
|
|
6218
|
-
this.
|
|
6555
|
+
this.Ut = [];
|
|
6556
|
+
this.vt = 0;
|
|
6557
|
+
this.Ft && (this.Ft = []);
|
|
6219
6558
|
this.xt && (this.xt = []);
|
|
6220
|
-
this.Qt && (this.Qt = []);
|
|
6221
6559
|
}
|
|
6222
|
-
if (this.
|
|
6560
|
+
if (this.Ht && !this.Ut[0]) {
|
|
6223
6561
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
6224
6562
|
// dispose it before re-creating
|
|
6225
6563
|
this.kt[0]?.dispose();
|
|
6226
|
-
this.
|
|
6564
|
+
this.Ut[0] = runWithOwner(this.kt[0] = createOwner(), this.Ht);
|
|
6227
6565
|
}
|
|
6228
6566
|
}
|
|
6229
6567
|
// fast path for new create
|
|
6230
|
-
else if (this.
|
|
6568
|
+
else if (this.vt === 0) {
|
|
6231
6569
|
const u = new Array(t);
|
|
6232
6570
|
const l = new Array(t);
|
|
6233
|
-
i = this.
|
|
6234
|
-
o = this.
|
|
6571
|
+
i = this.Ft && new Array(t);
|
|
6572
|
+
o = this.xt && new Array(t);
|
|
6235
6573
|
try {
|
|
6236
6574
|
for (r = 0; r < t; r++) u[r] = runWithOwner(l[r] = createOwner(), s);
|
|
6237
6575
|
} catch (e) {
|
|
@@ -6241,41 +6579,41 @@ function updateKeyedMap() {
|
|
|
6241
6579
|
// commit
|
|
6242
6580
|
if (this.kt[0]) this.kt[0].dispose();
|
|
6243
6581
|
// previous fallback
|
|
6244
|
-
this.
|
|
6582
|
+
this.Ut = u;
|
|
6245
6583
|
this.kt = l;
|
|
6246
|
-
i && (this.
|
|
6247
|
-
o && (this.
|
|
6248
|
-
this.
|
|
6249
|
-
this.
|
|
6584
|
+
i && (this.Ft = i);
|
|
6585
|
+
o && (this.xt = o);
|
|
6586
|
+
this.Vt = e.slice(0);
|
|
6587
|
+
this.vt = t;
|
|
6250
6588
|
} else {
|
|
6251
|
-
let u, l,
|
|
6589
|
+
let u, l, a, c, f, E, d, S, T;
|
|
6252
6590
|
// skip common prefix
|
|
6253
|
-
for (u = 0, l = Math.min(this.
|
|
6254
|
-
if (this.
|
|
6591
|
+
for (u = 0, l = Math.min(this.vt, t); u < l && (this.Vt[u] === e[u] || this.Ft && compare(this.Wt, this.Vt[u], e[u])); u++) {
|
|
6592
|
+
if (this.Ft) setSignal(this.Ft[u], e[u]);
|
|
6255
6593
|
}
|
|
6256
6594
|
// skip common suffix — counted only; retained entries land in one pass
|
|
6257
6595
|
// at commit instead of being staged and copied twice
|
|
6258
|
-
for (l = this.
|
|
6259
|
-
|
|
6596
|
+
for (l = this.vt - 1, a = t - 1; l >= u && a >= u && (this.Vt[l] === e[a] || this.Ft && compare(this.Wt, this.Vt[l], e[a])); l--,
|
|
6597
|
+
a--) ;
|
|
6260
6598
|
// no structural change (every position matched in place at equal
|
|
6261
6599
|
// length — the common post-reconcile shape): keep the same mapped
|
|
6262
6600
|
// array identity so downstream consumers don't re-run at all
|
|
6263
|
-
if (u === t && this.
|
|
6264
|
-
this.
|
|
6601
|
+
if (u === t && this.vt === t) {
|
|
6602
|
+
this.Vt = e.slice(0);
|
|
6265
6603
|
return;
|
|
6266
6604
|
}
|
|
6267
|
-
const
|
|
6268
|
-
const
|
|
6605
|
+
const O = t - this.vt;
|
|
6606
|
+
const _ = new Array(t);
|
|
6269
6607
|
const p = new Array(t);
|
|
6270
|
-
i = this.
|
|
6271
|
-
o = this.
|
|
6608
|
+
i = this.Ft ? new Array(t) : undefined;
|
|
6609
|
+
o = this.xt ? new Array(t) : undefined;
|
|
6272
6610
|
// 0) prepare a map of all indices in the changed window of newItems,
|
|
6273
6611
|
// scanning backwards so we encounter them in natural order
|
|
6274
6612
|
E = new Map;
|
|
6275
|
-
d = new Array(
|
|
6276
|
-
for (r =
|
|
6277
|
-
|
|
6278
|
-
f = this.
|
|
6613
|
+
d = new Array(a + 1);
|
|
6614
|
+
for (r = a; r >= u; r--) {
|
|
6615
|
+
c = e[r];
|
|
6616
|
+
f = this.Wt ? this.Wt(c) : c;
|
|
6279
6617
|
n = E.get(f);
|
|
6280
6618
|
d[r] = n === undefined ? -1 : n;
|
|
6281
6619
|
E.set(f, r);
|
|
@@ -6284,24 +6622,24 @@ function updateKeyedMap() {
|
|
|
6284
6622
|
// in the new set; if so, stage them at their new positions; if not,
|
|
6285
6623
|
// queue them for disposal at commit
|
|
6286
6624
|
for (n = u; n <= l; n++) {
|
|
6287
|
-
|
|
6288
|
-
f = this.
|
|
6625
|
+
c = this.Vt[n];
|
|
6626
|
+
f = this.Wt ? this.Wt(c) : c;
|
|
6289
6627
|
r = E.get(f);
|
|
6290
6628
|
if (r !== undefined && r !== -1) {
|
|
6291
|
-
|
|
6629
|
+
_[r] = this.Ut[n];
|
|
6292
6630
|
p[r] = this.kt[n];
|
|
6293
|
-
i && (i[r] = this.
|
|
6294
|
-
o && (o[r] = this.
|
|
6631
|
+
i && (i[r] = this.Ft[n]);
|
|
6632
|
+
o && (o[r] = this.xt[n]);
|
|
6295
6633
|
r = d[r];
|
|
6296
6634
|
E.set(f, r);
|
|
6297
6635
|
} else (S ??= []).push(this.kt[n]);
|
|
6298
6636
|
}
|
|
6299
6637
|
// 2) create new rows into the temp arrays; an abort disposes only these
|
|
6300
6638
|
try {
|
|
6301
|
-
for (r = u; r <=
|
|
6639
|
+
for (r = u; r <= a; r++) {
|
|
6302
6640
|
if (p[r] !== undefined) continue;
|
|
6303
6641
|
(T ??= []).push(p[r] = createOwner());
|
|
6304
|
-
|
|
6642
|
+
_[r] = runWithOwner(p[r], s);
|
|
6305
6643
|
}
|
|
6306
6644
|
} catch (e) {
|
|
6307
6645
|
if (T) for (n = 0; n < T.length; n++) T[n].dispose();
|
|
@@ -6311,38 +6649,38 @@ function updateKeyedMap() {
|
|
|
6311
6649
|
// into the fresh arrays, swap them in (new identity for downstream
|
|
6312
6650
|
// change propagation), then dispose exited rows
|
|
6313
6651
|
for (n = 0; n < u; n++) {
|
|
6314
|
-
|
|
6652
|
+
_[n] = this.Ut[n];
|
|
6315
6653
|
p[n] = this.kt[n];
|
|
6316
|
-
i && (i[n] = this.
|
|
6317
|
-
o && (o[n] = this.
|
|
6654
|
+
i && (i[n] = this.Ft[n]);
|
|
6655
|
+
o && (o[n] = this.xt[n]);
|
|
6318
6656
|
}
|
|
6319
|
-
for (r = u; r <=
|
|
6657
|
+
for (r = u; r <= a; r++) {
|
|
6320
6658
|
if (i) setSignal(i[r], e[r]);
|
|
6321
6659
|
if (o) setSignal(o[r], r);
|
|
6322
6660
|
}
|
|
6323
|
-
for (r =
|
|
6324
|
-
|
|
6325
|
-
p[r] = this.kt[r -
|
|
6661
|
+
for (r = a + 1; r < t; r++) {
|
|
6662
|
+
_[r] = this.Ut[r - O];
|
|
6663
|
+
p[r] = this.kt[r - O];
|
|
6326
6664
|
if (i) {
|
|
6327
|
-
i[r] = this.
|
|
6665
|
+
i[r] = this.Ft[r - O];
|
|
6328
6666
|
setSignal(i[r], e[r]);
|
|
6329
6667
|
}
|
|
6330
6668
|
if (o) {
|
|
6331
|
-
o[r] = this.
|
|
6332
|
-
if (
|
|
6669
|
+
o[r] = this.xt[r - O];
|
|
6670
|
+
if (O !== 0) setSignal(o[r], r);
|
|
6333
6671
|
}
|
|
6334
6672
|
}
|
|
6335
|
-
this.
|
|
6673
|
+
this.Ut = _;
|
|
6336
6674
|
this.kt = p;
|
|
6337
|
-
i && (this.
|
|
6338
|
-
o && (this.
|
|
6339
|
-
this.
|
|
6675
|
+
i && (this.Ft = i);
|
|
6676
|
+
o && (this.xt = o);
|
|
6677
|
+
this.vt = t;
|
|
6340
6678
|
// save a copy of the mapped items for the next update
|
|
6341
|
-
this.
|
|
6679
|
+
this.Vt = e.slice(0);
|
|
6342
6680
|
if (S) for (n = 0; n < S.length; n++) S[n].dispose();
|
|
6343
6681
|
}
|
|
6344
6682
|
});
|
|
6345
|
-
return this.
|
|
6683
|
+
return this.Ut;
|
|
6346
6684
|
}
|
|
6347
6685
|
|
|
6348
6686
|
/**
|
|
@@ -6362,22 +6700,22 @@ function updateKeyedMap() {
|
|
|
6362
6700
|
*/ function repeat(e, t, n) {
|
|
6363
6701
|
const r = t;
|
|
6364
6702
|
const i = {
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6703
|
+
wt: createOwner(),
|
|
6704
|
+
vt: 0,
|
|
6705
|
+
Mt: 0,
|
|
6368
6706
|
$t: e,
|
|
6369
|
-
|
|
6707
|
+
Gt: r,
|
|
6370
6708
|
kt: [],
|
|
6371
|
-
|
|
6709
|
+
Ut: [],
|
|
6372
6710
|
jt: n?.from,
|
|
6373
|
-
|
|
6711
|
+
Ht: n?.fallback
|
|
6374
6712
|
};
|
|
6375
6713
|
const o = computed(updateRepeat.bind(i));
|
|
6376
6714
|
// Same as mapArray: untracked reads inside the internal owner resolve via
|
|
6377
6715
|
// _parentComputed, so async reads in row callbacks register with the node
|
|
6378
6716
|
// (pending tracking + post-settle retry) instead of vanishing.
|
|
6379
|
-
i.
|
|
6380
|
-
o.
|
|
6717
|
+
i.wt.Je = o;
|
|
6718
|
+
o.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
6381
6719
|
return accessor(o);
|
|
6382
6720
|
}
|
|
6383
6721
|
|
|
@@ -6391,53 +6729,53 @@ function updateKeyedMap() {
|
|
|
6391
6729
|
function updateRepeat() {
|
|
6392
6730
|
const e = this.$t();
|
|
6393
6731
|
const t = this.jt?.() || 0;
|
|
6394
|
-
runWithOwner(this.
|
|
6732
|
+
runWithOwner(this.wt, () => {
|
|
6395
6733
|
if (e === 0) {
|
|
6396
|
-
if (this.
|
|
6397
|
-
this.
|
|
6734
|
+
if (this.vt !== 0) {
|
|
6735
|
+
this.wt.dispose(false);
|
|
6398
6736
|
this.kt = [];
|
|
6399
|
-
this.
|
|
6400
|
-
this.
|
|
6737
|
+
this.Ut = [];
|
|
6738
|
+
this.vt = 0;
|
|
6401
6739
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
6402
|
-
this.
|
|
6740
|
+
this.Mt = 0;
|
|
6403
6741
|
}
|
|
6404
|
-
if (this.
|
|
6742
|
+
if (this.Ht && !this.Ut[0]) {
|
|
6405
6743
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
6406
6744
|
// dispose it before re-creating
|
|
6407
6745
|
this.kt[0]?.dispose();
|
|
6408
|
-
this.
|
|
6746
|
+
this.Ut[0] = runWithOwner(this.kt[0] = createOwner(), this.Ht);
|
|
6409
6747
|
}
|
|
6410
6748
|
return;
|
|
6411
6749
|
}
|
|
6412
6750
|
const n = t + e;
|
|
6413
|
-
const r = this.
|
|
6751
|
+
const r = this.Mt + this.vt;
|
|
6414
6752
|
// Retained overlap [keepStart, keepEnd) in global indexes; empty when the
|
|
6415
6753
|
// windows are disjoint or when coming from empty/fallback.
|
|
6416
|
-
const i = Math.max(t, this.
|
|
6754
|
+
const i = Math.max(t, this.Mt);
|
|
6417
6755
|
const o = Math.min(n, r);
|
|
6418
6756
|
const s = new Array(e);
|
|
6419
6757
|
const u = new Array(e);
|
|
6420
6758
|
for (let e = i; e < o; e++) {
|
|
6421
|
-
u[e - t] = this.kt[e - this.
|
|
6422
|
-
s[e - t] = this.
|
|
6759
|
+
u[e - t] = this.kt[e - this.Mt];
|
|
6760
|
+
s[e - t] = this.Ut[e - this.Mt];
|
|
6423
6761
|
}
|
|
6424
6762
|
try {
|
|
6425
6763
|
for (let e = t; e < n; e++) {
|
|
6426
6764
|
if (e >= i && e < o) continue;
|
|
6427
|
-
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.
|
|
6765
|
+
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.Gt(e));
|
|
6428
6766
|
}
|
|
6429
6767
|
} catch (e) {
|
|
6430
6768
|
for (let e = t; e < n; e++) if ((e < i || e >= o) && u[e - t]) u[e - t].dispose();
|
|
6431
6769
|
throw e;
|
|
6432
6770
|
}
|
|
6433
6771
|
// commit: dispose the previous fallback or the rows leaving the window
|
|
6434
|
-
if (this.
|
|
6435
|
-
this.
|
|
6772
|
+
if (this.vt === 0) this.kt[0]?.dispose(); else for (let e = this.Mt; e < r; e++) if (e < t || e >= n) this.kt[e - this.Mt].dispose();
|
|
6773
|
+
this.Ut = s;
|
|
6436
6774
|
this.kt = u;
|
|
6437
|
-
this.
|
|
6438
|
-
this.
|
|
6775
|
+
this.Mt = t;
|
|
6776
|
+
this.vt = e;
|
|
6439
6777
|
});
|
|
6440
|
-
return this.
|
|
6778
|
+
return this.Ut;
|
|
6441
6779
|
}
|
|
6442
6780
|
|
|
6443
6781
|
function compare(e, t, n) {
|
|
@@ -6450,12 +6788,12 @@ function boundaryComputed(e, t) {
|
|
|
6450
6788
|
});
|
|
6451
6789
|
n.Nt = (e, t) => {
|
|
6452
6790
|
// Use passed values if provided, otherwise read from node
|
|
6453
|
-
const r = e !== undefined ? e : n.
|
|
6791
|
+
const r = e !== undefined ? e : n.xe;
|
|
6454
6792
|
const i = t !== undefined ? t : n.De;
|
|
6455
6793
|
// Notify both status dimensions like a render effect does; the queue chain
|
|
6456
6794
|
// consumes this boundary's own type and forwards the remainder upward until
|
|
6457
6795
|
// a boundary that handles it is found.
|
|
6458
|
-
n.
|
|
6796
|
+
n.xe &= ~n.Kt;
|
|
6459
6797
|
const o = n.Be.notify(n, STATUS_PENDING | STATUS_ERROR, r, i);
|
|
6460
6798
|
// The queue is the only propagation channel: a foreign status must not stay
|
|
6461
6799
|
// reader-visible on the tree, or reads re-throw it across the boundary and
|
|
@@ -6463,8 +6801,8 @@ function boundaryComputed(e, t) {
|
|
|
6463
6801
|
// untouched, so the tree still recomputes when the foreign source settles.
|
|
6464
6802
|
const s = r & ~n.Kt & (STATUS_PENDING | STATUS_ERROR);
|
|
6465
6803
|
if (s) {
|
|
6466
|
-
n.
|
|
6467
|
-
if (n.De === i && !(n.
|
|
6804
|
+
n.xe &= ~s;
|
|
6805
|
+
if (n.De === i && !(n.xe & (STATUS_PENDING | STATUS_ERROR))) n.De = undefined;
|
|
6468
6806
|
}
|
|
6469
6807
|
// An ERROR the chain could not deliver to any boundary is uncaught. The
|
|
6470
6808
|
// scrub above already removed it from reader-visible state, so without
|
|
@@ -6476,7 +6814,7 @@ function boundaryComputed(e, t) {
|
|
|
6476
6814
|
}
|
|
6477
6815
|
};
|
|
6478
6816
|
n.Kt = t;
|
|
6479
|
-
n.
|
|
6817
|
+
n.Ge &= ~CONFIG_AUTO_DISPOSE;
|
|
6480
6818
|
recompute(n, true);
|
|
6481
6819
|
return n;
|
|
6482
6820
|
}
|
|
@@ -6537,8 +6875,8 @@ class RevealController {
|
|
|
6537
6875
|
Ct: true
|
|
6538
6876
|
});
|
|
6539
6877
|
ln=true;
|
|
6540
|
-
|
|
6541
|
-
|
|
6878
|
+
an=true;
|
|
6879
|
+
cn=false;
|
|
6542
6880
|
constructor(e, t) {
|
|
6543
6881
|
this.rn = e;
|
|
6544
6882
|
this.sn = t;
|
|
@@ -6596,10 +6934,10 @@ class RevealController {
|
|
|
6596
6934
|
untrack(() => this.en());
|
|
6597
6935
|
}
|
|
6598
6936
|
en(e, t) {
|
|
6599
|
-
if (this.
|
|
6600
|
-
this.
|
|
6937
|
+
if (this.cn) return;
|
|
6938
|
+
this.cn = true;
|
|
6601
6939
|
const n = this.ln;
|
|
6602
|
-
const r = this.
|
|
6940
|
+
const r = this.an;
|
|
6603
6941
|
try {
|
|
6604
6942
|
const n = e ?? read(this.Xt), r = untrack(this.rn), i = r === "sequential" && !!untrack(this.sn), o = t ?? i;
|
|
6605
6943
|
if (n) {
|
|
@@ -6651,10 +6989,10 @@ class RevealController {
|
|
|
6651
6989
|
}
|
|
6652
6990
|
} finally {
|
|
6653
6991
|
this.ln = this.Yt();
|
|
6654
|
-
this.
|
|
6655
|
-
this.
|
|
6992
|
+
this.an = this.Zt();
|
|
6993
|
+
this.cn = false;
|
|
6656
6994
|
}
|
|
6657
|
-
if (this.Jt && (n !== this.ln || r !== this.
|
|
6995
|
+
if (this.Jt && (n !== this.ln || r !== this.an)) this.Jt.en();
|
|
6658
6996
|
}
|
|
6659
6997
|
}
|
|
6660
6998
|
|
|
@@ -6674,8 +7012,8 @@ class CollectionQueue extends Queue {
|
|
|
6674
7012
|
});
|
|
6675
7013
|
tn;
|
|
6676
7014
|
nn=false;
|
|
6677
|
-
|
|
6678
|
-
|
|
7015
|
+
On;
|
|
7016
|
+
_n=ON_INIT;
|
|
6679
7017
|
constructor(e) {
|
|
6680
7018
|
super();
|
|
6681
7019
|
this.Sn = e;
|
|
@@ -6686,16 +7024,16 @@ class CollectionQueue extends Queue {
|
|
|
6686
7024
|
}
|
|
6687
7025
|
notify(e, t, n, r) {
|
|
6688
7026
|
if (!(t & this.Sn)) return super.notify(e, t, n, r);
|
|
6689
|
-
if (this.nn && this.
|
|
7027
|
+
if (this.nn && this.On) {
|
|
6690
7028
|
const e = untrack(() => {
|
|
6691
7029
|
try {
|
|
6692
|
-
return this.
|
|
7030
|
+
return this.On();
|
|
6693
7031
|
} catch {
|
|
6694
7032
|
return ON_INIT;
|
|
6695
7033
|
}
|
|
6696
7034
|
});
|
|
6697
|
-
if (e !== this.
|
|
6698
|
-
this.
|
|
7035
|
+
if (e !== this._n) {
|
|
7036
|
+
this._n = e;
|
|
6699
7037
|
this.nn = false;
|
|
6700
7038
|
this.qt.clear();
|
|
6701
7039
|
}
|
|
@@ -6726,25 +7064,25 @@ class CollectionQueue extends Queue {
|
|
|
6726
7064
|
t &= ~this.Sn;
|
|
6727
7065
|
return t ? super.notify(e, t, n, r) : true;
|
|
6728
7066
|
}
|
|
6729
|
-
|
|
7067
|
+
Me() {
|
|
6730
7068
|
for (const e of this.qt) {
|
|
6731
7069
|
// A source with a live affects() mark holds display state for the
|
|
6732
7070
|
// mark's lifetime (the visual channel): the marked node carries no
|
|
6733
7071
|
// status of its own, so the count is the liveness test. The release
|
|
6734
7072
|
// sweep (finalizePureQueue after mark release) re-runs this check.
|
|
6735
|
-
if (e.
|
|
7073
|
+
if (e.Le & REACTIVE_DISPOSED || !e.k && !(e.xe & this.Sn) && !(this.Sn & STATUS_ERROR && e.xe & STATUS_PENDING)) this.qt.delete(e);
|
|
6736
7074
|
}
|
|
6737
7075
|
if (!this.qt.size) {
|
|
6738
7076
|
if (this.Sn & STATUS_PENDING && this.Bt && !this.nn && this.Tn) {
|
|
6739
|
-
this.Bt = !!(this.Tn.
|
|
7077
|
+
this.Bt = !!(this.Tn.xe & this.Sn);
|
|
6740
7078
|
} else {
|
|
6741
7079
|
this.Bt = false;
|
|
6742
7080
|
}
|
|
6743
7081
|
if (!this.Bt) {
|
|
6744
7082
|
setSignal(this.Xt, false);
|
|
6745
|
-
if (this.
|
|
7083
|
+
if (this.On) {
|
|
6746
7084
|
try {
|
|
6747
|
-
this.
|
|
7085
|
+
this._n = untrack(() => this.On());
|
|
6748
7086
|
} catch {
|
|
6749
7087
|
/* value not yet committed — _prevOn stays stale, next notify will reset */}
|
|
6750
7088
|
}
|
|
@@ -6762,7 +7100,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6762
7100
|
ownedWrite: true,
|
|
6763
7101
|
Ct: true
|
|
6764
7102
|
});
|
|
6765
|
-
if (r) o.
|
|
7103
|
+
if (r) o.On = r;
|
|
6766
7104
|
const s = o.Tn = createBoundChildren(i, t, o, e);
|
|
6767
7105
|
// Prime source tracking so reveal registration sees pending sources.
|
|
6768
7106
|
untrack(() => {
|
|
@@ -6772,7 +7110,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
6772
7110
|
} catch (e) {
|
|
6773
7111
|
if (e instanceof NotReadyError) t = true; else throw e;
|
|
6774
7112
|
}
|
|
6775
|
-
o.Bt = t || !!(s.
|
|
7113
|
+
o.Bt = t || !!(s.xe & e) || s.De instanceof NotReadyError;
|
|
6776
7114
|
});
|
|
6777
7115
|
const u = _revealUsed && e === STATUS_PENDING ? getContext(RevealControllerContext) : null;
|
|
6778
7116
|
if (u) {
|