@solidjs/signals 2.0.0-rc.17 → 2.0.0-rc.18
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-shared.js +296 -191
- package/dist/dev.attribution.js +16 -16
- package/dist/dev.js +527 -311
- package/dist/observe/core/async.js +148 -115
- package/dist/observe/core/constants.js +3 -1
- package/dist/observe/core/core.js +27 -27
- package/dist/observe/core/effect.js +29 -32
- package/dist/observe/core/graph.js +5 -5
- package/dist/observe/core/owner.js +7 -7
- package/dist/observe/core/scheduler.js +23 -12
- package/dist/observe/core/verdict.js +2 -2
- package/dist/observe/deferred.js +16 -13
- package/dist/observe/from.js +248 -0
- package/dist/observe/index.js +2 -0
- package/dist/observe/store/reconcile.js +137 -121
- package/dist/observe/store/store.js +595 -618
- package/dist/observe/store/target.js +1 -5
- package/dist/prod/core/async.js +209 -176
- package/dist/prod/core/constants.js +3 -1
- package/dist/prod/core/core.js +33 -33
- package/dist/prod/core/effect.js +24 -27
- package/dist/prod/core/graph.js +2 -2
- package/dist/prod/core/lanes.js +14 -14
- package/dist/prod/core/scheduler.js +35 -24
- package/dist/prod/core/truth.js +4 -4
- package/dist/prod/core/verdict.js +7 -7
- package/dist/prod/deferred.js +17 -14
- package/dist/prod/from.js +248 -0
- package/dist/prod/index.js +2 -0
- package/dist/prod/store/optimistic.js +1 -1
- package/dist/prod/store/reconcile.js +137 -121
- package/dist/prod/store/store.js +94 -117
- package/dist/prod/store/target.js +13 -17
- package/dist/types/core/async.d.ts +12 -2
- package/dist/types/core/constants.d.ts +5 -0
- package/dist/types/core/core.d.ts +19 -3
- package/dist/types/core/scheduler.d.ts +15 -3
- package/dist/types/from.d.ts +47 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/prod/store/store.js
CHANGED
|
@@ -12,7 +12,7 @@ import { insertIntoHeap } from "../core/heap.js";
|
|
|
12
12
|
|
|
13
13
|
import { txOf, flushTransaction, holdNode, joinFuture, insertSubs, schedule, passLane, globalQueue, queuePendingNode, resolveTx, GlobalQueue, installStoreHooks, joinPassTx, dirtyQueue } from "../core/scheduler.js";
|
|
14
14
|
|
|
15
|
-
import { lookupTarget, setLookup, $OWNER, isOwned, markDescendants
|
|
15
|
+
import { lookupTarget, setLookup, $OWNER, isOwned, markDescendants } from "./target.js";
|
|
16
16
|
|
|
17
17
|
import { optHooks, affectsHooks } from "./hooks.js";
|
|
18
18
|
|
|
@@ -134,7 +134,7 @@ function wrap(e, n = null, t = null, r = n?.fam ?? null) {
|
|
|
134
134
|
const i = lookupTarget(e, r);
|
|
135
135
|
if (i !== undefined) return i.px;
|
|
136
136
|
const o = e[$TARGET];
|
|
137
|
-
if (o
|
|
137
|
+
if (o?.px === e) {
|
|
138
138
|
// Foreign-family proxies re-wrap into THIS family (writes stay isolated);
|
|
139
139
|
// same-family and plain-store proxies pass through.
|
|
140
140
|
if (r === null || o.fam === r) return e;
|
|
@@ -206,7 +206,7 @@ function sameKey(e, n) {
|
|
|
206
206
|
/** The container node's comparator: a staging is a backing (identity — a
|
|
207
207
|
* pending backing is never "equal" to the committed one); a lane value is
|
|
208
208
|
* an arrangement (`LaneView`), judged by the optimistic machinery. */ const containerEquals = function(e, n) {
|
|
209
|
-
return e === n || optHooks
|
|
209
|
+
return e === n || !!optHooks?.arrangement(this.O, e, n);
|
|
210
210
|
};
|
|
211
211
|
|
|
212
212
|
function sameLogicalSlot(e, n, t) {
|
|
@@ -225,10 +225,10 @@ function releaseSlot(e) {
|
|
|
225
225
|
if (n.k === e) n.k = null;
|
|
226
226
|
} else if (t === $DEEP) {
|
|
227
227
|
if (n.dk === e) n.dk = null;
|
|
228
|
-
} else if (n.n
|
|
228
|
+
} else if (n.n?.[t] === e) {
|
|
229
229
|
delete n.n[t];
|
|
230
230
|
n.nc--;
|
|
231
|
-
} else if (n.h
|
|
231
|
+
} else if (n.h?.[t] === e) delete n.h[t];
|
|
232
232
|
// The family's index keeps only targets that still carry a node.
|
|
233
233
|
if (n.fam !== null && n.nc === 0 && n.k === null && n.dk === null && (n.h === null || Reflect.ownKeys(n.h).length === 0)) n.fam.live.delete(n);
|
|
234
234
|
}
|
|
@@ -247,7 +247,7 @@ function releaseSlot(e) {
|
|
|
247
247
|
// holds: its release waits for the commit that resolves it. So does a leaf of
|
|
248
248
|
// a held container (#4146): a mainline write it carried is in the held
|
|
249
249
|
// staging too, where it would read as the hold's until the landing.
|
|
250
|
-
const slotKept = e => e.
|
|
250
|
+
const slotKept = e => e.ue !== NOT_PENDING || e.l & CONFIG_OVERRIDE || e.O.k?.l & CONFIG_HELD;
|
|
251
251
|
|
|
252
252
|
setSlotUnobserved(e => {
|
|
253
253
|
if (slotKept(e)) deferredReleases.add(e); else releaseSlot(e);
|
|
@@ -260,7 +260,7 @@ setSlotUnobserved(e => {
|
|
|
260
260
|
* unchanged stages nothing and holds no one). */ function bornStaged(e, n, t, r) {
|
|
261
261
|
if (n.xe && n.xe(n.Ie, t)) return;
|
|
262
262
|
queuePendingNode(n);
|
|
263
|
-
n.
|
|
263
|
+
n.ue = t;
|
|
264
264
|
const i = e.k;
|
|
265
265
|
if (i === null) return;
|
|
266
266
|
// a node-less staging holds nothing (`stageOn`)
|
|
@@ -292,7 +292,7 @@ t = -1) {
|
|
|
292
292
|
// receiver.
|
|
293
293
|
const o = e.pb;
|
|
294
294
|
const l = i = slotSignal(committed(e)[n], slotNodeEquals, e, n, t === -1 ? isOwnAccessor(o ?? e.v, n) : t === 1);
|
|
295
|
-
if (o !== null && !l.acc) bornStaged(e, l, e.del
|
|
295
|
+
if (o !== null && !l.acc) bornStaged(e, l, e.del?.has(n) ? undefined : o[n], n);
|
|
296
296
|
r[n] = i;
|
|
297
297
|
e.nc++;
|
|
298
298
|
noteNode(e, l, n);
|
|
@@ -306,7 +306,7 @@ function getHasNode(e, n) {
|
|
|
306
306
|
if (r === undefined) {
|
|
307
307
|
const i = r = slotSignal(n in committed(e), isEqual, e, n, false);
|
|
308
308
|
const o = e.pb;
|
|
309
|
-
if (o !== null) bornStaged(e, i, n in o && !
|
|
309
|
+
if (o !== null) bornStaged(e, i, n in o && !e.del?.has(n), n);
|
|
310
310
|
t[n] = r;
|
|
311
311
|
noteNode(e, i, n);
|
|
312
312
|
}
|
|
@@ -326,7 +326,7 @@ function getHasNode(e, n) {
|
|
|
326
326
|
// would have read had the node been there from the write.
|
|
327
327
|
if (e.pb !== null && !directCommit) {
|
|
328
328
|
n.Ie = preBatch(e);
|
|
329
|
-
n.
|
|
329
|
+
n.ue = e.pb;
|
|
330
330
|
queuePendingNode(n);
|
|
331
331
|
}
|
|
332
332
|
}
|
|
@@ -345,8 +345,8 @@ function getHasNode(e, n) {
|
|
|
345
345
|
* (`storeParkHook`) — the one case the staging home exists for. */ function stageOn(e, n) {
|
|
346
346
|
if (e.k === null && passLane === null && (context === null || globalQueue.q) && !deriveHolds(e)) return;
|
|
347
347
|
const t = getContainerNode(e);
|
|
348
|
-
if (t.
|
|
349
|
-
t.
|
|
348
|
+
if (t.ue === NOT_PENDING) queuePendingNode(t);
|
|
349
|
+
t.ue = n;
|
|
350
350
|
// A28 (4): a write issued inside a pass outside a flush (a creation-time
|
|
351
351
|
// derive) is promoted at the pass's end — the batch with it.
|
|
352
352
|
if (context !== null) notePromotedWrite(t);
|
|
@@ -449,7 +449,7 @@ function copyOwn(e, n, t) {
|
|
|
449
449
|
const t = Reflect.ownKeys(n);
|
|
450
450
|
let r = Object.getPrototypeOf(n) === Object.prototype;
|
|
451
451
|
for (const i of t) {
|
|
452
|
-
if (
|
|
452
|
+
if (isOwnAccessor(n, i)) {
|
|
453
453
|
e.a = true;
|
|
454
454
|
r = false;
|
|
455
455
|
break;
|
|
@@ -479,7 +479,7 @@ const plainProto = e => {
|
|
|
479
479
|
/** An overlay with many adds (or any delete) rebuilds the committed
|
|
480
480
|
* container at flatten so its shape stays fast (#3689). */ function overlayRebuilds(e, n) {
|
|
481
481
|
if (e.kc > OVERLAY_REBUILD_MAX_KEYS) return false;
|
|
482
|
-
if (e.del
|
|
482
|
+
if (e.del?.size) return true;
|
|
483
483
|
const t = e.wk;
|
|
484
484
|
if (t !== null && t !== WK_ALL && t.u === undefined && t.size <= OVERLAY_REBUILD_MIN_ADDS) return false;
|
|
485
485
|
const r = e.v;
|
|
@@ -491,17 +491,10 @@ const plainProto = e => {
|
|
|
491
491
|
/** Downgrade an overlay to a real clone (a consumer needs a container). */ function materializePB(e) {
|
|
492
492
|
const n = e.pb;
|
|
493
493
|
if (!e.ovl) return n;
|
|
494
|
-
const t = e.sc === 2 ? wideClone(e.v, e) : cloneRaw(e.v, e);
|
|
495
|
-
if (e.del !== null) {
|
|
496
|
-
for (const n of e.del) delete t[n];
|
|
497
|
-
e.kc -= e.del.size;
|
|
498
|
-
e.del = null;
|
|
499
|
-
}
|
|
500
|
-
for (const r of Reflect.ownKeys(n)) e.sc === 2 ? t[r] = n[r] : copyOwn(t, n, r);
|
|
494
|
+
const t = overlayOnto(e, e.sc === 2 ? wideClone(e.v, e) : cloneRaw(e.v, e), n);
|
|
501
495
|
e.pb = t;
|
|
502
|
-
e.ovl = false;
|
|
503
496
|
// The staging IS the pending backing: re-point the container node.
|
|
504
|
-
if (e.k
|
|
497
|
+
if (e.k?.ue === n) e.k.ue = t;
|
|
505
498
|
return t;
|
|
506
499
|
}
|
|
507
500
|
|
|
@@ -522,7 +515,7 @@ const plainProto = e => {
|
|
|
522
515
|
// mainline setter mid-hold publishes mainline; the held keys stay held).
|
|
523
516
|
n = e.pb = cloneRaw(n, e);
|
|
524
517
|
const t = e.k;
|
|
525
|
-
if (t !== null && !(t.l & CONFIG_HELD)) t.
|
|
518
|
+
if (t !== null && !(t.l & CONFIG_HELD)) t.ue = n;
|
|
526
519
|
} else if (n === null) {
|
|
527
520
|
const t = e.v;
|
|
528
521
|
if (!directCommit) queueFold(e);
|
|
@@ -546,7 +539,6 @@ const plainProto = e => {
|
|
|
546
539
|
e.ch = false;
|
|
547
540
|
if (e.u) {
|
|
548
541
|
privatizeCommitted(e.u);
|
|
549
|
-
devAssertNeverUserMutation(e.u.v);
|
|
550
542
|
const t = e.u.v;
|
|
551
543
|
const r = parentSlotKey(e, n);
|
|
552
544
|
if (t[r] === n) t[r] = e.v;
|
|
@@ -570,17 +562,20 @@ const plainProto = e => {
|
|
|
570
562
|
/** Overlay flatten (#3044): own keys onto the owned committed backing in
|
|
571
563
|
* place — the backing keeps its identity. */ function flattenOverlay(e, n) {
|
|
572
564
|
privatizeCommitted(e);
|
|
573
|
-
|
|
574
|
-
|
|
565
|
+
overlayOnto(e, e.v, n);
|
|
566
|
+
// the caller (`foldTarget`) closes the staging
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/** An overlay's own keys and deletions onto `to` (the two are disjoint: a
|
|
570
|
+
* write un-deletes its key); the overlay is closed. */ function overlayOnto(e, n, t) {
|
|
571
|
+
for (const r of Reflect.ownKeys(t)) e.sc === 2 ? n[r] = t[r] : copyOwn(n, t, r);
|
|
575
572
|
if (e.del !== null) {
|
|
576
|
-
for (const
|
|
573
|
+
for (const t of e.del) delete n[t];
|
|
577
574
|
e.kc -= e.del.size;
|
|
578
575
|
e.del = null;
|
|
579
576
|
}
|
|
580
|
-
e.pb = null;
|
|
581
577
|
e.ovl = false;
|
|
582
|
-
|
|
583
|
-
// written-keys window closes with the commit
|
|
578
|
+
return n;
|
|
584
579
|
}
|
|
585
580
|
|
|
586
581
|
/** Adoption (a setter's returned replacement; reconcile and projection
|
|
@@ -620,7 +615,7 @@ const plainProto = e => {
|
|
|
620
615
|
e.wk = null;
|
|
621
616
|
// adoption supersedes staged trap writes
|
|
622
617
|
const i = n[$OWNER];
|
|
623
|
-
if (i
|
|
618
|
+
if (i?.fam === e.fam) n[$OWNER] = e; else setLookup(n, e);
|
|
624
619
|
if (t && r !== n) notifyFold(e, r, n);
|
|
625
620
|
}
|
|
626
621
|
|
|
@@ -697,7 +692,7 @@ let foldIndex = null;
|
|
|
697
692
|
if (r.pb === null) continue;
|
|
698
693
|
// folded already (a direct commit)
|
|
699
694
|
const i = r.k;
|
|
700
|
-
if (i !== null && i.
|
|
695
|
+
if (i !== null && i.ue !== NOT_PENDING) {
|
|
701
696
|
// held: commits with its hold
|
|
702
697
|
foldList.push(r);
|
|
703
698
|
foldOlds.push(n[t]);
|
|
@@ -721,7 +716,7 @@ let foldIndex = null;
|
|
|
721
716
|
* marks (an ambient `affects()` over a declared reload lives to the
|
|
722
717
|
* landing) read it. */ GlobalQueue.k = e => {
|
|
723
718
|
const n = e.O?.fam;
|
|
724
|
-
return
|
|
719
|
+
return (n?.node?.m & STATUS_PENDING) !== 0;
|
|
725
720
|
};
|
|
726
721
|
|
|
727
722
|
/** Core asks (lanes.ts `covered`): the value a slot node's guess covered.
|
|
@@ -732,7 +727,7 @@ let foldIndex = null;
|
|
|
732
727
|
if (n.ch) {
|
|
733
728
|
const t = e.ze;
|
|
734
729
|
const r = n.v;
|
|
735
|
-
if (n.h
|
|
730
|
+
if (n.h?.[t] === e) e.Ie = untrack(() => t in r); else if (n.n?.[t] === e) e.Ie = untrack(() => unwrapValue(r[t]));
|
|
736
731
|
}
|
|
737
732
|
return e.Ie;
|
|
738
733
|
};
|
|
@@ -768,12 +763,7 @@ function runDirect(e) {
|
|
|
768
763
|
const t = e.k;
|
|
769
764
|
const r = e.pb;
|
|
770
765
|
if (r !== null) {
|
|
771
|
-
if (r === e.v) {
|
|
772
|
-
// An eager adoption nothing wrote after: the backing is already
|
|
773
|
-
// the adopted object (shared ownership — never cloned).
|
|
774
|
-
e.pb = null;
|
|
775
|
-
e.wk = null;
|
|
776
|
-
} else if (e.ovl && (e.v !== n || !overlayRebuilds(e, r) && t?.T?.Pe !== n)) {
|
|
766
|
+
if (r === e.v) ; else if (e.ovl && (e.v !== n || !overlayRebuilds(e, r) && t?.T?.Pe !== n)) {
|
|
777
767
|
// Overlay flatten (#3044): the backing keeps its identity, so the
|
|
778
768
|
// `t.v === old` gate below skips path copying (the parent slot
|
|
779
769
|
// already points here) and the adopted-notify (setter
|
|
@@ -791,25 +781,21 @@ function runDirect(e) {
|
|
|
791
781
|
if (hasOwn.call(r, n)) copyOwn(t, r, n); else delete t[n];
|
|
792
782
|
}
|
|
793
783
|
} else {
|
|
794
|
-
for (const e of Reflect.ownKeys(r))
|
|
795
|
-
const i = Object.getOwnPropertyDescriptor(r, e);
|
|
796
|
-
if (i.get || i.set || !i.enumerable || !i.writable || !i.configurable) Object.defineProperty(t, e, i); else if (i.value !== n[e] || !hasOwn.call(n, e)) t[e] = i.value;
|
|
797
|
-
}
|
|
784
|
+
for (const e of Reflect.ownKeys(r)) copyOwn(t, r, e);
|
|
798
785
|
for (const e of Reflect.ownKeys(n)) {
|
|
799
786
|
if (!hasOwn.call(r, e)) delete t[e];
|
|
800
787
|
}
|
|
801
788
|
}
|
|
802
|
-
e.pb = null;
|
|
803
|
-
e.wk = null;
|
|
804
789
|
} else {
|
|
805
790
|
// The clone (or adopted object) becomes the committed backing
|
|
806
791
|
// (path copy below).
|
|
807
792
|
e.v = e.ovl ? materializePB(e) : r;
|
|
808
793
|
e.ch = e.v[$TARGET] !== undefined;
|
|
809
|
-
e.pb = null;
|
|
810
|
-
e.wk = null;
|
|
811
794
|
}
|
|
812
|
-
|
|
795
|
+
e.pb = null;
|
|
796
|
+
e.wk = null;
|
|
797
|
+
// the written-keys window closes with the commit
|
|
798
|
+
}
|
|
813
799
|
if (t !== null) {
|
|
814
800
|
// The node's committed value is the backing. A container nobody
|
|
815
801
|
// subscribes to was a transient staging home (INTERNALS §5: an
|
|
@@ -821,7 +807,6 @@ function runDirect(e) {
|
|
|
821
807
|
const t = parentSlotKey(e, n);
|
|
822
808
|
if (e.u.v[t] === n) {
|
|
823
809
|
privatizeCommitted(e.u);
|
|
824
|
-
devAssertNeverUserMutation(e.u.v);
|
|
825
810
|
e.u.v[t] = e.v;
|
|
826
811
|
}
|
|
827
812
|
}
|
|
@@ -906,7 +891,7 @@ function heldDerivation(e, n, t) {
|
|
|
906
891
|
if (e?.get || e?.set || !isEqual(e?.value, r.value)) setSignal(i, () => r.value);
|
|
907
892
|
continue;
|
|
908
893
|
}
|
|
909
|
-
const l = e.del
|
|
894
|
+
const l = e.del?.has(o) ? undefined : n[o];
|
|
910
895
|
setSignal(i, () => l);
|
|
911
896
|
if (e.fam !== null) {
|
|
912
897
|
// The derive's write is a derivation; a user setter's is a proposal
|
|
@@ -924,13 +909,13 @@ function heldDerivation(e, n, t) {
|
|
|
924
909
|
for (const r of t) {
|
|
925
910
|
const t = l[r];
|
|
926
911
|
if (t !== undefined) {
|
|
927
|
-
setSignal(t, r in n && !
|
|
912
|
+
setSignal(t, r in n && !e.del?.has(r));
|
|
928
913
|
if (e.fam !== null) holdWithDerive(e, t);
|
|
929
914
|
}
|
|
930
915
|
}
|
|
931
916
|
}
|
|
932
917
|
if (e.dk !== null) {
|
|
933
|
-
if (e.del
|
|
918
|
+
if (e.del?.size) bumpDeep(e); else for (const r of o ?? Reflect.ownKeys(n)) {
|
|
934
919
|
if (r === $OWNER) continue;
|
|
935
920
|
const i = n[r];
|
|
936
921
|
const o = t[r];
|
|
@@ -948,7 +933,7 @@ function heldDerivation(e, n, t) {
|
|
|
948
933
|
if (u !== null && (u.o !== null || u.l & CONFIG_OVERRIDE)) {
|
|
949
934
|
let r;
|
|
950
935
|
if (e.ovl) {
|
|
951
|
-
r = e.del
|
|
936
|
+
r = !!e.del?.size;
|
|
952
937
|
if (!r) {
|
|
953
938
|
for (const e of Reflect.ownKeys(n)) {
|
|
954
939
|
if (!hasOwn.call(t, e)) {
|
|
@@ -1094,7 +1079,7 @@ function inDraft(e) {
|
|
|
1094
1079
|
/** A child proxy served to a draft joins the draft's scope. */ function draftServe(e, n) {
|
|
1095
1080
|
if (writeScopes !== null && inDraft(e)) {
|
|
1096
1081
|
const e = n?.[$TARGET];
|
|
1097
|
-
if (e
|
|
1082
|
+
if (e?.v !== undefined) writeScopes.add(scopeKey(e));
|
|
1098
1083
|
}
|
|
1099
1084
|
return n;
|
|
1100
1085
|
}
|
|
@@ -1104,7 +1089,7 @@ function inDraft(e) {
|
|
|
1104
1089
|
* "adoption is eager by contract" — and the node keeps the frame committed
|
|
1105
1090
|
* readers under a hold still see), `t.v` otherwise. */ function committed(e) {
|
|
1106
1091
|
const n = e.k;
|
|
1107
|
-
if (n !== null) return n.
|
|
1092
|
+
if (n !== null) return n.ue !== NOT_PENDING ? asBacking(n.Ie) : e.v;
|
|
1108
1093
|
// A node-less staging (`stageOn`): the fold queue remembers the frame.
|
|
1109
1094
|
return e.pb !== null ? preBatch(e) : e.v;
|
|
1110
1095
|
}
|
|
@@ -1137,7 +1122,7 @@ function inDraft(e) {
|
|
|
1137
1122
|
// sees — the lanes' values and the tick's own guesses over the truth
|
|
1138
1123
|
// (#3665), never a staging awaiting its fold: the draft is born on the
|
|
1139
1124
|
// read (and notified at the setter's exit like any).
|
|
1140
|
-
if (userWrite && e.fam
|
|
1125
|
+
if (userWrite && e.fam?.opt === true && !pendingNotify.has(e) && inDraft(e)) {
|
|
1141
1126
|
const n = ensurePB(e);
|
|
1142
1127
|
pendingNotify.add(e);
|
|
1143
1128
|
return n;
|
|
@@ -1170,7 +1155,7 @@ function inDraft(e) {
|
|
|
1170
1155
|
// it).
|
|
1171
1156
|
if (n !== undefined) {
|
|
1172
1157
|
const t = e.n?.[n];
|
|
1173
|
-
if (t
|
|
1158
|
+
if (t?.l & CONFIG_OVERRIDE) return committed(e);
|
|
1174
1159
|
}
|
|
1175
1160
|
const o = i !== null && (i.l & CONFIG_HELD) !== 0;
|
|
1176
1161
|
// A held container: the hold's unit is the key (#3706). A key the HELD
|
|
@@ -1223,7 +1208,7 @@ function inDraft(e) {
|
|
|
1223
1208
|
|
|
1224
1209
|
/** Did the HELD staging (the container node's, not a mainline layer above
|
|
1225
1210
|
* it) change `key`? */ function heldKeyChanged(e, n, t = true) {
|
|
1226
|
-
return changedBetween(e, e.k.Ie, e.k.
|
|
1211
|
+
return changedBetween(e, e.k.Ie, e.k.ue, n, t) && !adoptChild(e, n);
|
|
1227
1212
|
}
|
|
1228
1213
|
|
|
1229
1214
|
/** The values of a held frame, built once per frame: neither the committed
|
|
@@ -1252,23 +1237,23 @@ function rawsOf(e) {
|
|
|
1252
1237
|
const t = e.k;
|
|
1253
1238
|
const r = asBacking(t.Ie);
|
|
1254
1239
|
const i = r[n];
|
|
1255
|
-
const o = t.
|
|
1240
|
+
const o = t.ue[n];
|
|
1256
1241
|
const l = Array.isArray(r) ? e.fam?.key : null;
|
|
1257
1242
|
if (e.s || l === undefined || !sameRow(i, o, l) || !isWrappable(i) || !isWrappable(o) || Array.isArray(i) !== Array.isArray(o) || lookupTarget(i, e.fam) !== undefined || lookupTarget(o, e.fam) !== undefined ||
|
|
1258
1243
|
// A raw in both frames (the same objects swapped or reordered) is its
|
|
1259
1244
|
// own row: pairing it with another would alias the two after the commit.
|
|
1260
|
-
rawsOf(r).has(o) || rawsOf(t.
|
|
1245
|
+
rawsOf(r).has(o) || rawsOf(t.ue).has(i)) return false;
|
|
1261
1246
|
// A raw-marked value wraps to itself, a proxy to its own target: neither
|
|
1262
1247
|
// is a fresh target around `ov`.
|
|
1263
1248
|
const u = wrap(i, e, n)[$TARGET];
|
|
1264
|
-
if (u
|
|
1249
|
+
if (u?.v !== i) return false;
|
|
1265
1250
|
adoptPB(u, o, false);
|
|
1266
1251
|
holdNode(getContainerNode(u), txOf(t));
|
|
1267
1252
|
return true;
|
|
1268
1253
|
}
|
|
1269
1254
|
|
|
1270
1255
|
/** A family target's unheld staging, read with no pass (a handler). */ function familyAhead(e) {
|
|
1271
|
-
return e.fam !== null && context === null && !(e.k
|
|
1256
|
+
return e.fam !== null && context === null && !(e.k?.l & CONFIG_HELD);
|
|
1272
1257
|
}
|
|
1273
1258
|
|
|
1274
1259
|
/** Did this batch change `key` — value (slot equality), presence, and (for
|
|
@@ -1288,7 +1273,7 @@ function rawsOf(e) {
|
|
|
1288
1273
|
|
|
1289
1274
|
function changedBetween(e, n, t, r, i) {
|
|
1290
1275
|
if (e.ch || t[$TARGET] !== undefined || Object.getPrototypeOf(t) !== Object.getPrototypeOf(n) || !plainProto(n)) return true;
|
|
1291
|
-
if (e.del
|
|
1276
|
+
if (e.del?.has(r)) return r in n;
|
|
1292
1277
|
const o = hasOwn.call(t, r) || e.ovl && hasOwn.call(e.v, r);
|
|
1293
1278
|
if (o !== hasOwn.call(n, r)) return true;
|
|
1294
1279
|
if (!o) return false;
|
|
@@ -1302,7 +1287,7 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1302
1287
|
* tracked or not, applies the hold and A28 rules a signal's read does. A
|
|
1303
1288
|
* projection's unheld staging is ahead for a handler (`familyAhead`). */ function nodeValue(e, n, t) {
|
|
1304
1289
|
let r = read(e);
|
|
1305
|
-
if (e.
|
|
1290
|
+
if (e.ue !== NOT_PENDING && !(e.l & CONFIG_HELD) && context === null && t.fam !== null) r = e.ue;
|
|
1306
1291
|
return r === FORCE ? n : r;
|
|
1307
1292
|
}
|
|
1308
1293
|
|
|
@@ -1395,7 +1380,7 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1395
1380
|
* classification, as core reads it — `heldNotFinal`). */ function holdWithDerive(e, n) {
|
|
1396
1381
|
const t = e.fam?.node;
|
|
1397
1382
|
if (t !== undefined && t !== null && !userWrite && // the derive's own write (its draft or landing), not a user setter's
|
|
1398
|
-
t.l & CONFIG_HELD && n.
|
|
1383
|
+
t.l & CONFIG_HELD && n.ue !== NOT_PENDING &&
|
|
1399
1384
|
// A node carrying a guess is the lane's: its staging is the truth beneath
|
|
1400
1385
|
// the guess (`setSignal` → `laneWrite`), never re-homed by the store.
|
|
1401
1386
|
!(n.l & (CONFIG_HELD | CONFIG_OVERRIDE))) {
|
|
@@ -1436,7 +1421,7 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1436
1421
|
/** A read on an optimistic family that composes the lanes' values: not the
|
|
1437
1422
|
* draft's (it composed already), not a derive's write-override read (the
|
|
1438
1423
|
* derive composes on the truth). */ function optRead(e) {
|
|
1439
|
-
return e.fam
|
|
1424
|
+
return e.fam?.opt === true && !inDraft(e) && !writeOverride;
|
|
1440
1425
|
}
|
|
1441
1426
|
|
|
1442
1427
|
/** Pollution keys are never served from the prototype (core R30). */ const UNSAFE_KEYS = new Set([ "__proto__", "prototype", "constructor" ]);
|
|
@@ -1519,7 +1504,7 @@ const traps = {
|
|
|
1519
1504
|
const i = readSource(e, n);
|
|
1520
1505
|
// Overlay delete (#3044): a prototype overlay cannot shadow a delete, so
|
|
1521
1506
|
// deleted keys are tracked aside and read as absent in the pending view.
|
|
1522
|
-
if (
|
|
1507
|
+
if (i === e.pb && e.del?.has(n)) {
|
|
1523
1508
|
if (!inDraft(e) && getObserver() !== null) read(getNode(e, n));
|
|
1524
1509
|
return undefined;
|
|
1525
1510
|
}
|
|
@@ -1606,7 +1591,7 @@ const traps = {
|
|
|
1606
1591
|
if (t !== undefined) return t;
|
|
1607
1592
|
}
|
|
1608
1593
|
}
|
|
1609
|
-
return n in t && !(
|
|
1594
|
+
return n in t && !(t === e.pb && e.del?.has(n));
|
|
1610
1595
|
},
|
|
1611
1596
|
ownKeys(e) {
|
|
1612
1597
|
if (verdict !== null && affectsHooks !== null && getObserver() === null) affectsHooks.ro(e, undefined);
|
|
@@ -1649,14 +1634,13 @@ const traps = {
|
|
|
1649
1634
|
},
|
|
1650
1635
|
set(e, n, t) {
|
|
1651
1636
|
const r = inDraft(e);
|
|
1652
|
-
|
|
1653
|
-
if (!r && !i) {
|
|
1637
|
+
if (!r && !writeOverride) {
|
|
1654
1638
|
return true;
|
|
1655
1639
|
}
|
|
1656
1640
|
if (n === "__proto__") return true;
|
|
1657
1641
|
// pollution guard (core R30)
|
|
1658
|
-
const
|
|
1659
|
-
const
|
|
1642
|
+
const i = e.s ? t : unwrapValue(t);
|
|
1643
|
+
const o = ensurePB(e);
|
|
1660
1644
|
// #4146 (R1: node existence is unobservable; #3706: the hold's unit is
|
|
1661
1645
|
// the key): a user setter writing a key a HELD container's staging left
|
|
1662
1646
|
// unchanged would write it into the held staging — read as the hold's
|
|
@@ -1668,40 +1652,32 @@ const traps = {
|
|
|
1668
1652
|
// A34) — as it would with a reader's leaf. Kept while the container is
|
|
1669
1653
|
// held (`deferredReleases`).
|
|
1670
1654
|
if (userWrite && e.k?.l & CONFIG_HELD) deferredReleases.add(getNode(e, n));
|
|
1671
|
-
if (Array.isArray(
|
|
1655
|
+
if (Array.isArray(o)) {
|
|
1672
1656
|
touch(e, n);
|
|
1673
1657
|
if (n === "length") e.wk = WK_ALL; else touch(e, "length");
|
|
1674
1658
|
} else {
|
|
1675
1659
|
touch(e, n);
|
|
1676
|
-
if (!(n in
|
|
1660
|
+
if (!(n in o)) e.kc++;
|
|
1677
1661
|
}
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1662
|
+
const l = UNSAFE_KEYS.has(n);
|
|
1663
|
+
if (l || e.ovl && e.sc !== 2 && !hasOwn.call(o, n)) {
|
|
1664
|
+
Object.defineProperty(o, n, {
|
|
1665
|
+
value: i,
|
|
1681
1666
|
writable: true,
|
|
1682
1667
|
enumerable: true,
|
|
1683
1668
|
configurable: true
|
|
1684
1669
|
});
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
if (e.
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
enumerable: true,
|
|
1693
|
-
configurable: true
|
|
1694
|
-
});
|
|
1695
|
-
} else l[n] = o;
|
|
1696
|
-
if (e.del !== null) e.del.delete(n);
|
|
1697
|
-
if (e.s && o !== null && typeof o === "object") markRawOne(o);
|
|
1698
|
-
if (i) notifyWrites(e);
|
|
1699
|
-
return true;
|
|
1670
|
+
} else o[n] = i;
|
|
1671
|
+
e.del?.delete(n);
|
|
1672
|
+
if (l) return true;
|
|
1673
|
+
if (e.s && i !== null && typeof i === "object") markRawOne(i);
|
|
1674
|
+
if (!r) notifyWrites(e);
|
|
1675
|
+
// a write-override write
|
|
1676
|
+
return true;
|
|
1700
1677
|
},
|
|
1701
1678
|
defineProperty(e, n, t) {
|
|
1702
1679
|
const r = inDraft(e);
|
|
1703
|
-
|
|
1704
|
-
if (!r && !i) {
|
|
1680
|
+
if (!r && !writeOverride) {
|
|
1705
1681
|
return true;
|
|
1706
1682
|
}
|
|
1707
1683
|
if (n === "__proto__") return true;
|
|
@@ -1710,21 +1686,21 @@ const traps = {
|
|
|
1710
1686
|
...t,
|
|
1711
1687
|
value: unwrapValue(t.value)
|
|
1712
1688
|
};
|
|
1713
|
-
const
|
|
1689
|
+
const i = ensurePB(e);
|
|
1714
1690
|
if (e.a || !(t.enumerable && t.writable && t.configurable)) e.sc = 1;
|
|
1715
1691
|
touch(e, n);
|
|
1716
|
-
Object.defineProperty(
|
|
1717
|
-
|
|
1718
|
-
if (
|
|
1719
|
-
|
|
1692
|
+
Object.defineProperty(i, n, t);
|
|
1693
|
+
e.del?.delete(n);
|
|
1694
|
+
if (!r) notifyWrites(e);
|
|
1695
|
+
// a write-override write
|
|
1696
|
+
return true;
|
|
1720
1697
|
},
|
|
1721
1698
|
deleteProperty(e, n) {
|
|
1722
1699
|
const t = inDraft(e);
|
|
1723
|
-
|
|
1724
|
-
if (!t && !r) {
|
|
1700
|
+
if (!t && !writeOverride) {
|
|
1725
1701
|
return true;
|
|
1726
1702
|
}
|
|
1727
|
-
const
|
|
1703
|
+
const r = ensurePB(e);
|
|
1728
1704
|
touch(e, n);
|
|
1729
1705
|
// The key count (`kc`, the overlay gate and the rebuild cap) follows a
|
|
1730
1706
|
// delete the way it follows an add: an own key of the draft leaving — a
|
|
@@ -1735,14 +1711,15 @@ const traps = {
|
|
|
1735
1711
|
// one" shape drifted the count up by one per write until a three-key
|
|
1736
1712
|
// object crossed the overlay threshold and paid a rebuild on every
|
|
1737
1713
|
// commit after.
|
|
1738
|
-
const
|
|
1739
|
-
if (hasOwn.call(
|
|
1740
|
-
delete
|
|
1741
|
-
|
|
1714
|
+
const i = e.ovl && hasOwn.call(e.v, n);
|
|
1715
|
+
if (hasOwn.call(r, n)) {
|
|
1716
|
+
delete r[n];
|
|
1717
|
+
i || e.kc--;
|
|
1742
1718
|
}
|
|
1743
|
-
if (
|
|
1744
|
-
if (
|
|
1745
|
-
|
|
1719
|
+
if (i) (e.del ??= new Set).add(n);
|
|
1720
|
+
if (!t) notifyWrites(e);
|
|
1721
|
+
// a write-override write
|
|
1722
|
+
return true;
|
|
1746
1723
|
}
|
|
1747
1724
|
};
|
|
1748
1725
|
|
|
@@ -1824,17 +1801,17 @@ function createStore(e, n) {
|
|
|
1824
1801
|
* replaced by reference — #2932). The list driver uses this to choose the
|
|
1825
1802
|
* slot-patch channel (collected row bodies) over per-record registration. */ function storeIsShallow(e) {
|
|
1826
1803
|
const n = e?.[$TARGET];
|
|
1827
|
-
return n
|
|
1804
|
+
return n?.s === true;
|
|
1828
1805
|
}
|
|
1829
1806
|
|
|
1830
1807
|
/** True when `proxy` belongs to a projection family (S3). */ function storeHasFamily(e) {
|
|
1831
1808
|
const n = e?.[$TARGET];
|
|
1832
|
-
return n
|
|
1809
|
+
return n?.fam != null;
|
|
1833
1810
|
}
|
|
1834
1811
|
|
|
1835
1812
|
/** True when `proxy` belongs to an OPTIMISTIC family (S4). */ function storeHasOptimisticFamily(e) {
|
|
1836
1813
|
const n = e?.[$TARGET];
|
|
1837
|
-
return n
|
|
1814
|
+
return n?.fam?.opt === true;
|
|
1838
1815
|
}
|
|
1839
1816
|
|
|
1840
1817
|
// ---------------------------------------------------------------------------
|
|
@@ -1844,7 +1821,7 @@ function visibleKeys(e, n) {
|
|
|
1844
1821
|
if (e.ovl && n === e.pb) {
|
|
1845
1822
|
t = Reflect.ownKeys(e.v);
|
|
1846
1823
|
const r = e.del;
|
|
1847
|
-
if (r
|
|
1824
|
+
if (r?.size) t = t.filter(e => !r.has(e));
|
|
1848
1825
|
for (const r of Reflect.ownKeys(n)) {
|
|
1849
1826
|
if (!hasOwn.call(e.v, r)) t.push(r);
|
|
1850
1827
|
}
|
|
@@ -1862,7 +1839,7 @@ function visibleKeys(e, n) {
|
|
|
1862
1839
|
function visibleDescriptor(e, n, t) {
|
|
1863
1840
|
let r = Object.getOwnPropertyDescriptor(n, t);
|
|
1864
1841
|
if (e.ovl && n === e.pb) {
|
|
1865
|
-
if (e.del
|
|
1842
|
+
if (e.del?.has(t)) return undefined;
|
|
1866
1843
|
if (r === undefined) r = Object.getOwnPropertyDescriptor(e.v, t);
|
|
1867
1844
|
}
|
|
1868
1845
|
return r;
|
|
@@ -1873,7 +1850,7 @@ function visibleDescriptor(e, n, t) {
|
|
|
1873
1850
|
/** Tracking snapshot: subscribes every reachable record's container and deep
|
|
1874
1851
|
* witness (one node per record, not one per path), then snapshots. */ function deep(e) {
|
|
1875
1852
|
const n = e?.[$TARGET];
|
|
1876
|
-
if (n
|
|
1853
|
+
if (n?.px !== e) return e;
|
|
1877
1854
|
const t = new Set;
|
|
1878
1855
|
const childTarget = (e, n, t) => {
|
|
1879
1856
|
let r = lookupTarget(n, e.fam);
|
|
@@ -17,31 +17,27 @@ const $OWNER = Symbol(0);
|
|
|
17
17
|
/** raw → target for plain (family-less) stores. Family stores use their own
|
|
18
18
|
* map so one raw can wrap once per family (§7b). */ const storeLookup = new WeakMap;
|
|
19
19
|
|
|
20
|
-
function setLookup(
|
|
21
|
-
(
|
|
20
|
+
function setLookup(o, e) {
|
|
21
|
+
(e.fam?.map ?? storeLookup).set(o, e);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
function isOwned(
|
|
25
|
-
return
|
|
24
|
+
function isOwned(o) {
|
|
25
|
+
return o[$OWNER] !== undefined;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/** The target wrapping `raw` in `fam` (or the plain lookup). An owned raw
|
|
29
|
-
* answers from its stamp; a user raw from the map. */ function lookupTarget(
|
|
30
|
-
const
|
|
31
|
-
return
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function devAssertNeverUserMutation(e) {
|
|
35
|
-
return;
|
|
29
|
+
* answers from its stamp; a user raw from the map. */ function lookupTarget(o, e) {
|
|
30
|
+
const n = o[$OWNER];
|
|
31
|
+
return n !== undefined && n.fam === e ? n : (e?.map ?? storeLookup).get(o);
|
|
36
32
|
}
|
|
37
33
|
|
|
38
34
|
/** Sticky descendants flag up the parent chain (§6d): adoption descends
|
|
39
|
-
* into a changed child pair only where a target with nodes exists below. */ function markDescendants(
|
|
40
|
-
let
|
|
41
|
-
while (
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
* into a changed child pair only where a target with nodes exists below. */ function markDescendants(o) {
|
|
36
|
+
let e = o;
|
|
37
|
+
while (e && !e.d) {
|
|
38
|
+
e.d = true;
|
|
39
|
+
e = e.u;
|
|
44
40
|
}
|
|
45
41
|
}
|
|
46
42
|
|
|
47
|
-
export { $OWNER,
|
|
43
|
+
export { $OWNER, isOwned, lookupTarget, markDescendants, setLookup, storeLookup };
|
|
@@ -27,12 +27,22 @@ export declare function settlePendingSource(el: Computed<any>, source?: Computed
|
|
|
27
27
|
export declare function isThenable<T>(value: T | PromiseLike<T>): value is PromiseLike<T>;
|
|
28
28
|
/** Fire and clear a node's iterator-flight cancellation hook (#3122). */
|
|
29
29
|
export declare function releaseFlightTeardown(el: Computed<any>): void;
|
|
30
|
+
/**
|
|
31
|
+
* Internal (not a package export): run `fn` when the current pass's flight
|
|
32
|
+
* is superseded, at the same instant as the iterator close above, instead of
|
|
33
|
+
* when the replacing pass commits (owner cleanups wait for that). Chains onto
|
|
34
|
+
* the node's teardown slot; fires once with it. A no-op unless the ambient
|
|
35
|
+
* owner is a computed in its own pass. `consumeIterator` fills the slot
|
|
36
|
+
* before its first pull, so a source opened in an async generator's body
|
|
37
|
+
* (`for await`) composes after the generator's close.
|
|
38
|
+
*/
|
|
39
|
+
export declare function onSupersede(fn: () => void): void;
|
|
30
40
|
export declare function handleAsync<T>(el: Computed<T>, result: T | PromiseLike<T> | AsyncIterable<T>, setter?: (value: T) => void, onError?: (error: unknown, pending: boolean) => void): T;
|
|
31
41
|
export declare function clearStatus(el: Computed<any>, clearUninitialized?: boolean): void;
|
|
32
|
-
export declare function notifyStatus(el: Computed<any>, status: number, error: any
|
|
42
|
+
export declare function notifyStatus(el: Computed<any>, status: number, error: any): void;
|
|
33
43
|
/** The dependents' half of `notifyStatus`: `el`'s status reaches each
|
|
34
44
|
* subscriber as a propagated mark (or a re-derive). On its own for a store
|
|
35
45
|
* family's leaves, which are not the derive's dependents — the family
|
|
36
46
|
* propagates the derive's status from each leaf to the leaf's readers
|
|
37
47
|
* (store/projection.ts `wakeFamily`), exactly as a memo's would reach its. */
|
|
38
|
-
export declare function propagateStatus(el: Computed<any>, status: number, error: any
|
|
48
|
+
export declare function propagateStatus(el: Computed<any>, status: number, error: any): void;
|