@solidjs/signals 2.0.0-rc.16 → 2.0.0-rc.17
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 +1719 -1603
- package/dist/dev.attribution.js +13 -13
- package/dist/dev.js +182 -45
- package/dist/observe/boundaries.js +2 -2
- package/dist/observe/core/async.js +3 -1
- package/dist/observe/core/context.js +2 -0
- package/dist/observe/core/core.js +26 -10
- package/dist/observe/core/effect.js +2 -0
- package/dist/observe/core/graph.js +10 -8
- package/dist/observe/core/lanes.js +25 -14
- package/dist/observe/core/owner.js +73 -47
- package/dist/observe/core/scheduler.js +189 -173
- package/dist/observe/core/verdict.js +3 -0
- package/dist/observe/map.js +2 -2
- package/dist/observe/signals.js +6 -1
- package/dist/observe/store/affects.js +13 -13
- package/dist/observe/store/optimistic.js +112 -71
- package/dist/observe/store/store.js +25 -16
- package/dist/prod/boundaries.js +2 -2
- package/dist/prod/core/async.js +3 -1
- package/dist/prod/core/context.js +2 -0
- package/dist/prod/core/core.js +31 -15
- package/dist/prod/core/effect.js +2 -0
- package/dist/prod/core/graph.js +10 -8
- package/dist/prod/core/heap.js +1 -1
- package/dist/prod/core/lanes.js +25 -14
- package/dist/prod/core/owner.js +70 -44
- package/dist/prod/core/scheduler.js +43 -27
- package/dist/prod/core/verdict.js +4 -1
- package/dist/prod/map.js +2 -2
- package/dist/prod/signals.js +18 -13
- package/dist/prod/store/optimistic.js +112 -71
- package/dist/prod/store/store.js +18 -7
- package/dist/types/core/core.d.ts +10 -3
- package/dist/types/core/dev.d.ts +9 -1
- package/dist/types/core/error.d.ts +9 -1
- package/dist/types/core/owner.d.ts +4 -0
- package/dist/types/core/scheduler.d.ts +23 -4
- package/package.json +1 -1
|
@@ -14,6 +14,8 @@ import { runHeap, enqueueSub, deleteFromHeap } from "./heap.js";
|
|
|
14
14
|
|
|
15
15
|
import { devCheckQuiescent } from "./invariants.js";
|
|
16
16
|
|
|
17
|
+
import { rethrowCleanupError } from "./owner.js";
|
|
18
|
+
|
|
17
19
|
// Optional-module hooks: module bindings, not `GlobalQueue` statics, so a
|
|
18
20
|
// bundle that never imports the installing module never assigns them — its
|
|
19
21
|
// minifier folds every guarded call site (and the branch behind it) away.
|
|
@@ -38,12 +40,12 @@ let endLanesHook = null;
|
|
|
38
40
|
|
|
39
41
|
let lanesBlockedHook = null;
|
|
40
42
|
|
|
41
|
-
function installLaneHooks(e, n, o,
|
|
43
|
+
function installLaneHooks(e, n, o, t, l, s, u, i, r) {
|
|
42
44
|
laneReadHook = e;
|
|
43
45
|
laneStageHook = n;
|
|
44
46
|
laneOutcomeHook = o;
|
|
45
|
-
laneWriteHook =
|
|
46
|
-
applyGuessesHook =
|
|
47
|
+
laneWriteHook = t;
|
|
48
|
+
applyGuessesHook = l;
|
|
47
49
|
laneSeamsHook = s;
|
|
48
50
|
laneCorrectionsHook = u;
|
|
49
51
|
endLanesHook = i;
|
|
@@ -73,12 +75,12 @@ let boundarySeamHook = null;
|
|
|
73
75
|
|
|
74
76
|
let heldRunHook = null;
|
|
75
77
|
|
|
76
|
-
function installBoundaryHooks(e, n, o,
|
|
78
|
+
function installBoundaryHooks(e, n, o, t, l) {
|
|
77
79
|
catchHook = e;
|
|
78
80
|
freshHook = n;
|
|
79
81
|
hiddenHook = o;
|
|
80
|
-
boundarySeamHook =
|
|
81
|
-
heldRunHook =
|
|
82
|
+
boundarySeamHook = t;
|
|
83
|
+
heldRunHook = l;
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
/** Store (store/store.ts): `park` — the flush parked into `t`: the store
|
|
@@ -287,16 +289,16 @@ let judge = null;
|
|
|
287
289
|
}
|
|
288
290
|
|
|
289
291
|
function blockedBy(e, n, o = false) {
|
|
290
|
-
for (let
|
|
291
|
-
const
|
|
292
|
-
if (!(
|
|
292
|
+
for (let t = 0; t < e.length; t++) {
|
|
293
|
+
const l = e[t];
|
|
294
|
+
if (!(l.m & STATUS_PENDING) || l.R & REACTIVE_DISPOSED || l.l & CONFIG_GUESS || l.T.Re !== null && txOf(l) !== n || o && !ownSource(l, n)) continue;
|
|
293
295
|
// The frame's own pending observer (off screen: this one holds nothing;
|
|
294
296
|
// the next listed node may).
|
|
295
|
-
if (
|
|
296
|
-
if (onScreen(
|
|
297
|
+
if (l.i === EFFECT_RENDER) {
|
|
298
|
+
if (onScreen(l, judge ?? n)) return true;
|
|
297
299
|
continue;
|
|
298
300
|
}
|
|
299
|
-
for (let e =
|
|
301
|
+
for (let e = l.o; e !== null; e = e.t) {
|
|
300
302
|
const o = e.u;
|
|
301
303
|
// A frame reader: a render effect, or a stale reader of the flight
|
|
302
304
|
// (REACTIVE_FRAME_READ — a verdict reader, `observeFlight`; lane work,
|
|
@@ -399,9 +401,9 @@ function deferZombie(e) {
|
|
|
399
401
|
|
|
400
402
|
/** The nodes under `owner` a transaction other than `t` holds (boundaries.ts:
|
|
401
403
|
* what an earlier hold staged under a re-armed boundary). */ function heldUnder(e, n, o) {
|
|
402
|
-
for (let
|
|
403
|
-
if ((
|
|
404
|
-
heldUnder(
|
|
404
|
+
for (let t = e.De; t !== null; t = t.pe) {
|
|
405
|
+
if ((t.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && txOf(t) !== n) o(t);
|
|
406
|
+
heldUnder(t, n, o);
|
|
405
407
|
}
|
|
406
408
|
}
|
|
407
409
|
|
|
@@ -498,6 +500,8 @@ function schedule() {
|
|
|
498
500
|
function haltReactivity(e) {
|
|
499
501
|
if (halted) return;
|
|
500
502
|
halted = true;
|
|
503
|
+
// A cleanup error collected before the halt is dropped (owner.ts).
|
|
504
|
+
rethrowCleanupError(true);
|
|
501
505
|
let n = "[REACTIVITY_HALTED]";
|
|
502
506
|
// Surface the cause here too: callers rethrow it, but a creation-time throw
|
|
503
507
|
// unwinds through ancestor recomputes that convert it to status instead of
|
|
@@ -513,6 +517,15 @@ function haltReactivity(e) {
|
|
|
513
517
|
o && o(e);
|
|
514
518
|
}
|
|
515
519
|
|
|
520
|
+
/**
|
|
521
|
+
* Dev: `haltReactivity`, located at `subject` — the computation the uncaught
|
|
522
|
+
* error escaped from — for the REACTIVITY_HALTED message's owner path. Call
|
|
523
|
+
* sites pick it in dev builds only (`haltReactivity(e)` in production), so
|
|
524
|
+
* production keeps the one-argument halt and its bytes unchanged.
|
|
525
|
+
*/ function haltReactivityAt(e, n) {
|
|
526
|
+
haltReactivity(e);
|
|
527
|
+
}
|
|
528
|
+
|
|
516
529
|
// Logs on the first write after a halt so a frozen interaction is traceable.
|
|
517
530
|
function notifyHalted() {
|
|
518
531
|
if (haltNotified) return;
|
|
@@ -664,7 +677,7 @@ class GlobalQueue {
|
|
|
664
677
|
// This flush's own runs, the lanes' reveals, and the landings' held runs
|
|
665
678
|
// are collected apart and ordered below.
|
|
666
679
|
const o = this.un;
|
|
667
|
-
const
|
|
680
|
+
const t = this.un = [ [], [] ];
|
|
668
681
|
// The passes that read this frame's stagings as the screen read held
|
|
669
682
|
// writes if it parked: the lane seam re-derives them on the committed
|
|
670
683
|
// world (a lane's runs wait this round).
|
|
@@ -691,8 +704,8 @@ class GlobalQueue {
|
|
|
691
704
|
// parked (something async below) — the window is the frame's, the marks
|
|
692
705
|
// are its transaction's; else they release at the seam, verdict-only,
|
|
693
706
|
// nothing to show (affects.ts).
|
|
694
|
-
const
|
|
695
|
-
releaseAmbientMarksHook?.(
|
|
707
|
+
const l = n && liveTx(n);
|
|
708
|
+
releaseAmbientMarksHook?.(l);
|
|
696
709
|
// The effect phase: lane work first (displayed ahead of the frame), then
|
|
697
710
|
// this flush's runs, then the runs the landings held from earlier
|
|
698
711
|
// flushes — as one pass would have queued them (#3540: a shell
|
|
@@ -700,14 +713,14 @@ class GlobalQueue {
|
|
|
700
713
|
// write; #3528: a display-ahead swap before the count it is shown
|
|
701
714
|
// beside). A parked frame's runs wait with its transaction instead: the
|
|
702
715
|
// effect phase applies a committed frame.
|
|
703
|
-
const s =
|
|
716
|
+
const s = l !== null;
|
|
704
717
|
for (let e = 0; e < 2; e++) {
|
|
705
|
-
if (s) append(
|
|
718
|
+
if (s) append(l.un[e], o[e]);
|
|
706
719
|
// The plain flush — no reveal, no landing, not parked — has nothing to
|
|
707
720
|
// order around its own runs: they are the queue as they stand (the
|
|
708
721
|
// same array, not a copy; `run` takes it whole). Every other seam
|
|
709
722
|
// builds the ordered queue above.
|
|
710
|
-
this.un[e] = s ||
|
|
723
|
+
this.un[e] = s || t[e].length || this.un[e].length ? t[e].concat(s ? [] : o[e], this.un[e]) : o[e];
|
|
711
724
|
}
|
|
712
725
|
if (deferredZombies.length !== 0) {
|
|
713
726
|
// Survivors are the displayed frame of a held pass: they rerun for the
|
|
@@ -749,8 +762,8 @@ class GlobalQueue {
|
|
|
749
762
|
*
|
|
750
763
|
* A boundary between the observer and the root (boundaries.ts) is asked
|
|
751
764
|
* first: a fallback catches what is not ready under it, and the root
|
|
752
|
-
* never hears of it. */ notify(e, n, o,
|
|
753
|
-
if (catchHook?.(e, o & n,
|
|
765
|
+
* never hears of it. */ notify(e, n, o, t) {
|
|
766
|
+
if (catchHook?.(e, o & n, t)) return true;
|
|
754
767
|
if (n & STATUS_PENDING) {
|
|
755
768
|
if (o & STATUS_PENDING) {
|
|
756
769
|
// A pass that went pending holds its frame: the async's own
|
|
@@ -932,7 +945,7 @@ function commitPendingNode(e) {
|
|
|
932
945
|
// commit beneath a flight publishes its inputs (A15 reveal corollary,
|
|
933
946
|
// #3305): a reveal of it must observe, not show the pre-flight value.
|
|
934
947
|
const o = e.se === NOT_PENDING && (n.m & STATUS_PENDING) !== 0;
|
|
935
|
-
const
|
|
948
|
+
const t = e.l & CONFIG_STAGED_ERROR;
|
|
936
949
|
// An answer commits: the error it replaces leaves the display (D-41).
|
|
937
950
|
if (!o && n.T) n.T.de = undefined;
|
|
938
951
|
e.l = o ? e.l & -1048833 | CONFIG_INPUTS_PUBLISHED : e.l & -3147137;
|
|
@@ -940,7 +953,7 @@ function commitPendingNode(e) {
|
|
|
940
953
|
// show, through the ordinary error path (`stageError`). Its readers first
|
|
941
954
|
// see it in the cycle after this seam: a tracked re-read there is not a
|
|
942
955
|
// retry (`read`), or a boundary re-derived by it would retry it forever.
|
|
943
|
-
if (
|
|
956
|
+
if (t) {
|
|
944
957
|
const o = e.se;
|
|
945
958
|
e.se = NOT_PENDING;
|
|
946
959
|
e.ie = clock + 1;
|
|
@@ -954,7 +967,7 @@ function commitPendingNode(e) {
|
|
|
954
967
|
// the landed value's commit (A19 exc. 2, #3178): verdict-quiet through
|
|
955
968
|
// the reveal. (The sweep of a node still in flight is not a landing.)
|
|
956
969
|
// The A28 stash goes with it.
|
|
957
|
-
if (n.T != null) n.T.Ve = false, n.T.
|
|
970
|
+
if (n.T != null) n.T.Ve = false, n.T.je = NOT_PENDING;
|
|
958
971
|
// An effect with a staged value was born held (L2): its first run is
|
|
959
972
|
// this commit's, not its creation's (A29) — queue it now.
|
|
960
973
|
if (e.i && e.i !== EFFECT_TRACKED) {
|
|
@@ -1018,10 +1031,13 @@ function flush(e) {
|
|
|
1018
1031
|
while (scheduled) {
|
|
1019
1032
|
globalQueue.flush();
|
|
1020
1033
|
}
|
|
1034
|
+
// A cleanup that threw during the drain, now that the drain is complete
|
|
1035
|
+
// (owner.ts).
|
|
1036
|
+
rethrowCleanupError();
|
|
1021
1037
|
}
|
|
1022
1038
|
|
|
1023
1039
|
function runQueue(e, n) {
|
|
1024
1040
|
for (let o = 0; o < e.length; o++) e[o](n);
|
|
1025
1041
|
}
|
|
1026
1042
|
|
|
1027
|
-
export { GlobalQueue, MAINLINE_QUESTION, ROOT_ERROR_HOOK, actionDepth, applyGuessesHook, blocked, boundarySeamHook, bumpNotifyEpoch, catchHook, clock, commitPendingNode, deferZombie, dirtyQueue, endLanesHook, enforceLoadingBoundary, enterAction, exitAction, externalUntrackHook, flush, flushTransaction, freshHook, globalQueue, haltReactivity, heldRunHook, heldTrim, heldUnder, hiddenHook, holdNode, insertSubs, installBoundaryHooks, installLaneHooks, installMarkHooks, installStoreHooks, installVerdictHooks, joinFuture, joinPassTx, laneCorrectionsHook, laneDirty, laneOutcomeHook, laneReadHook, laneSeamsHook, laneStageHook, laneWriteHook, lanesBlockedHook, list, liveTx, merge, newTransaction, nextQuestion, notifyEpoch, observeFlightHook, ownFlights, passLane, passTx, question, queuePendingNode, releaseAmbientMarksHook, releaseMarksHook, releaseQueues, reruns, resetErrorHalt, resolveTx, sameLane, schedule, setExternalHooks, setPassLane, setQuestion, stagedReaders, staleReader, storeCommitHook, storeParkHook, txOf, unhold, wireExternalSourceHook };
|
|
1043
|
+
export { GlobalQueue, MAINLINE_QUESTION, ROOT_ERROR_HOOK, actionDepth, applyGuessesHook, blocked, boundarySeamHook, bumpNotifyEpoch, catchHook, clock, commitPendingNode, deferZombie, dirtyQueue, endLanesHook, enforceLoadingBoundary, enterAction, exitAction, externalUntrackHook, flush, flushTransaction, freshHook, globalQueue, haltReactivity, haltReactivityAt, heldRunHook, heldTrim, heldUnder, hiddenHook, holdNode, insertSubs, installBoundaryHooks, installLaneHooks, installMarkHooks, installStoreHooks, installVerdictHooks, joinFuture, joinPassTx, laneCorrectionsHook, laneDirty, laneOutcomeHook, laneReadHook, laneSeamsHook, laneStageHook, laneWriteHook, lanesBlockedHook, list, liveTx, merge, newTransaction, nextQuestion, notifyEpoch, observeFlightHook, ownFlights, passLane, passTx, question, queuePendingNode, releaseAmbientMarksHook, releaseMarksHook, releaseQueues, reruns, resetErrorHalt, resolveTx, sameLane, schedule, setExternalHooks, setPassLane, setQuestion, stagedReaders, staleReader, storeCommitHook, storeParkHook, txOf, unhold, wireExternalSourceHook };
|
|
@@ -175,7 +175,7 @@ let probeFound = false;
|
|
|
175
175
|
* a router's link claim probing inside the computation that creates the
|
|
176
176
|
* anchor). A throw still reaches the pass through `untrack`. */ function markVerdictReader(e) {
|
|
177
177
|
let t = context;
|
|
178
|
-
if (t?.
|
|
178
|
+
if (t?.Qe) t = t.Ye;
|
|
179
179
|
if (t !== null && tracking) {
|
|
180
180
|
t.l |= CONFIG_VERDICT;
|
|
181
181
|
t.R |= REACTIVE_PROBED;
|
|
@@ -318,6 +318,9 @@ let probeFound = false;
|
|
|
318
318
|
const u = (n.m & STATUS_PENDING) !== 0 && !quietPending(n);
|
|
319
319
|
if (e.l & CONFIG_GUESS) {
|
|
320
320
|
if (probing && (u || e.se !== NOT_PENDING && (!e.xe || !e.xe(e.T.v, e.se)))) probeFound = true;
|
|
321
|
+
// A lane a correction folded under (D-34): `latest()` shows the hold's
|
|
322
|
+
// world whole — the truth beneath each guess, else what it covered.
|
|
323
|
+
if (latestActive && r.folded) return r.folded(null, e);
|
|
321
324
|
return e.T.v;
|
|
322
325
|
}
|
|
323
326
|
if (probing && u) probeFound = true;
|
package/dist/prod/map.js
CHANGED
|
@@ -301,7 +301,7 @@ function updateKeyedMap() {
|
|
|
301
301
|
this.ct && (this.ct = []);
|
|
302
302
|
this.lt && (this.lt = []);
|
|
303
303
|
}
|
|
304
|
-
if (this.H && !this.ht
|
|
304
|
+
if (this.H && !this.ht.length) {
|
|
305
305
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
306
306
|
// dispose it before re-creating
|
|
307
307
|
this.tn[0]?.dispose();
|
|
@@ -539,7 +539,7 @@ function updateRepeat() {
|
|
|
539
539
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
540
540
|
this.dt = 0;
|
|
541
541
|
}
|
|
542
|
-
if (this.H && !this.ht
|
|
542
|
+
if (this.H && !this.ht.length) {
|
|
543
543
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
544
544
|
// dispose it before re-creating
|
|
545
545
|
this.tn[0]?.dispose();
|
package/dist/prod/signals.js
CHANGED
|
@@ -292,7 +292,12 @@ function createMemo(e, t) {
|
|
|
292
292
|
o = undefined;
|
|
293
293
|
}
|
|
294
294
|
runWithOwner(n, () => {
|
|
295
|
-
effect(() =>
|
|
295
|
+
effect(() => {
|
|
296
|
+
const e = getOwner();
|
|
297
|
+
o = e;
|
|
298
|
+
c();
|
|
299
|
+
return e;
|
|
300
|
+
}, t => {
|
|
296
301
|
o = undefined;
|
|
297
302
|
r?.();
|
|
298
303
|
const n = (e.effect || e)?.();
|
|
@@ -334,14 +339,14 @@ function createMemo(e, t) {
|
|
|
334
339
|
// or an already-displayed guess would satisfy it in a later slice. (REDERIVE
|
|
335
340
|
// after: the first pass's own error is the promise's rejection.)
|
|
336
341
|
computed(() => {
|
|
337
|
-
let
|
|
342
|
+
let u, i = false;
|
|
338
343
|
try {
|
|
339
|
-
|
|
344
|
+
u = e();
|
|
340
345
|
} catch (e) {
|
|
341
346
|
if (e instanceof NotReadyError) throw e;
|
|
342
347
|
// An error is an answer (D-41): delivered by the same frame rule.
|
|
343
|
-
|
|
344
|
-
|
|
348
|
+
u = unwrapStatusError(e);
|
|
349
|
+
i = true;
|
|
345
350
|
}
|
|
346
351
|
const s = getOwner();
|
|
347
352
|
// A truth reader waits out a `createDeferred` flight its value derives
|
|
@@ -354,9 +359,9 @@ function createMemo(e, t) {
|
|
|
354
359
|
staleReader(s, resolveTx(a));
|
|
355
360
|
return;
|
|
356
361
|
}
|
|
357
|
-
if (
|
|
358
|
-
o?.(
|
|
359
|
-
queueMicrotask(() => t(
|
|
362
|
+
if (i) return void queueMicrotask(() => r(u));
|
|
363
|
+
o?.(u);
|
|
364
|
+
queueMicrotask(() => t(u));
|
|
360
365
|
}, {
|
|
361
366
|
Le: n
|
|
362
367
|
}).l |= CONFIG_REDERIVE;
|
|
@@ -516,14 +521,14 @@ function createMemo(e, t) {
|
|
|
516
521
|
// (`saving=true` beside the confirmed `version=1` is a tear no timeline
|
|
517
522
|
// contains). Updates that do not flip the predicate reveal freely.
|
|
518
523
|
const c = flushTransaction;
|
|
519
|
-
createRoot(
|
|
520
|
-
let
|
|
524
|
+
createRoot(u => {
|
|
525
|
+
let i;
|
|
521
526
|
let s;
|
|
522
527
|
const settle = e => {
|
|
523
|
-
if (
|
|
528
|
+
if (i !== undefined) clearTimeout(i);
|
|
524
529
|
if (s !== undefined) o.removeEventListener("abort", s);
|
|
525
530
|
e();
|
|
526
|
-
|
|
531
|
+
u();
|
|
527
532
|
};
|
|
528
533
|
// Authoritative: the predicate sees the truth, never the action's own
|
|
529
534
|
// optimistic guess — a guess cannot satisfy the wait for its own
|
|
@@ -538,7 +543,7 @@ function createMemo(e, t) {
|
|
|
538
543
|
// revealed with the action.
|
|
539
544
|
if (e && c !== null && globalQueue.q && resolveTx(c).tt !== 0) joinFuture(c);
|
|
540
545
|
});
|
|
541
|
-
if (t?.timeout !== undefined)
|
|
546
|
+
if (t?.timeout !== undefined) i = setTimeout(() => settle(() => n(new TimeoutError)), t.timeout);
|
|
542
547
|
if (o !== undefined) {
|
|
543
548
|
s = () => settle(() => n(o.reason));
|
|
544
549
|
o.addEventListener("abort", s, {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { CONFIG_OVERRIDE,
|
|
1
|
+
import { CONFIG_OVERRIDE, CONFIG_GUESS, EFFECT_RENDER, CONFIG_CHILDREN_FORBIDDEN, NOT_PENDING, CONFIG_SLOT_NODE, CONFIG_AUTO_DISPOSE } from "../core/constants.js";
|
|
2
2
|
|
|
3
|
-
import { computed, ext, untrack, read, isEqual } from "../core/core.js";
|
|
3
|
+
import { computed, joinPassAt, ext, untrack, read, isEqual } from "../core/core.js";
|
|
4
4
|
|
|
5
5
|
import { pendingGuessOf, optimisticWrite } from "../core/lanes.js";
|
|
6
6
|
|
|
7
7
|
import { getOwner } from "../core/owner.js";
|
|
8
8
|
|
|
9
|
-
import { GlobalQueue, txOf,
|
|
9
|
+
import { GlobalQueue, txOf, insertSubs, joinFuture, resolveTx, passLane, list, laneDirty, notifyEpoch, schedule } from "../core/scheduler.js";
|
|
10
10
|
|
|
11
11
|
import { runProjectionComputed } from "./projection.js";
|
|
12
12
|
|
|
@@ -93,16 +93,16 @@ function notifyOptimisticWrites(e, n) {
|
|
|
93
93
|
// A chained draft holds the inner store's raws; a raw is the inner slot it
|
|
94
94
|
// resolves to (as a read of it serves) — the row a held write staged is
|
|
95
95
|
// the same row, not a guess over the slot (#3796).
|
|
96
|
-
const
|
|
97
|
-
const f = unwrapValue(o &&
|
|
96
|
+
const u = n[t];
|
|
97
|
+
const f = unwrapValue(o && u ? resolveChainedRaw(e, t, u) : u);
|
|
98
98
|
if (!(t in i)) {
|
|
99
99
|
guess(getNode(e, t), t, false, f);
|
|
100
100
|
guess(getHasNode(e, t), t, true, true);
|
|
101
101
|
s = true;
|
|
102
102
|
} else {
|
|
103
103
|
const n = i[t];
|
|
104
|
-
const
|
|
105
|
-
if (!isEqual(
|
|
104
|
+
const u = unwrapValue(o && n ? resolveChainedRaw(e, t, n) : n);
|
|
105
|
+
if (!isEqual(u, f) && !targetsEqual(u, f)) {
|
|
106
106
|
guess(getNode(e, t), t, false, f);
|
|
107
107
|
if (r) s = true;
|
|
108
108
|
}
|
|
@@ -122,29 +122,31 @@ function notifyOptimisticWrites(e, n) {
|
|
|
122
122
|
if (s) {
|
|
123
123
|
const o = r ? n.map(unwrapValue) : shallowKeys(n);
|
|
124
124
|
// The rows the setter removed from the view it saw, by key: a later
|
|
125
|
-
// re-base over another action's truth must not bring them back.
|
|
125
|
+
// re-base over another action's truth must not bring them back. A set
|
|
126
|
+
// (empty or not) marks a keyed arrangement guess (`fold`).
|
|
126
127
|
let s = null;
|
|
127
|
-
const
|
|
128
|
-
if (r &&
|
|
128
|
+
const u = e.fam.key;
|
|
129
|
+
if (r && u !== null && u !== undefined) {
|
|
130
|
+
s = new Set;
|
|
129
131
|
const e = new Set;
|
|
130
132
|
for (let n = 0; n < o.length; n++) {
|
|
131
|
-
const t = isWrappable(o[n]) ?
|
|
133
|
+
const t = isWrappable(o[n]) ? u(o[n]) : undefined;
|
|
132
134
|
if (t !== undefined) e.add(t);
|
|
133
135
|
}
|
|
134
136
|
for (let n = 0; n < i.length; n++) {
|
|
135
137
|
const t = unwrapValue(i[n]);
|
|
136
|
-
const r = isWrappable(t) ?
|
|
137
|
-
if (r !== undefined && !e.has(r))
|
|
138
|
+
const r = isWrappable(t) ? u(t) : undefined;
|
|
139
|
+
if (r !== undefined && !e.has(r)) s.add(r);
|
|
138
140
|
}
|
|
139
141
|
}
|
|
140
142
|
optimisticWrite(getContainerNode(e), new LaneView(o, t, s));
|
|
141
143
|
}
|
|
142
144
|
if (e.dk !== null) optimisticWrite(e.dk, {});
|
|
143
145
|
markOverlaid(e);
|
|
144
|
-
const
|
|
145
|
-
if (
|
|
146
|
+
const u = optStaged.get(e);
|
|
147
|
+
if (u === undefined) return null;
|
|
146
148
|
optStaged.delete(e);
|
|
147
|
-
return
|
|
149
|
+
return u;
|
|
148
150
|
}
|
|
149
151
|
|
|
150
152
|
/** The container comparator's lane arm (store.ts `containerEquals`): an
|
|
@@ -228,18 +230,18 @@ function arrangementEqual(e, n, t) {
|
|
|
228
230
|
}
|
|
229
231
|
}
|
|
230
232
|
for (let s = 0; s < n.length; s++) {
|
|
231
|
-
const
|
|
233
|
+
const u = n[s];
|
|
232
234
|
let f;
|
|
233
|
-
if (isWrappable(
|
|
235
|
+
if (isWrappable(u)) {
|
|
234
236
|
if (o !== null) {
|
|
235
|
-
const e = t(
|
|
237
|
+
const e = t(u);
|
|
236
238
|
if (e !== undefined) f = o.get(e);
|
|
237
239
|
} else if (s < i && isWrappable(unwrapValue(r[s]))) f = r[s];
|
|
238
240
|
}
|
|
239
241
|
if (f !== undefined) {
|
|
240
|
-
if (unwrapValue(f) !==
|
|
242
|
+
if (unwrapValue(f) !== u) reconcileDraft(f, u, t);
|
|
241
243
|
if (e[s] !== f) e[s] = f;
|
|
242
|
-
} else if (unwrapValue(e[s]) !==
|
|
244
|
+
} else if (unwrapValue(e[s]) !== u) e[s] = u;
|
|
243
245
|
}
|
|
244
246
|
if (e.length !== n.length) e.length = n.length;
|
|
245
247
|
return;
|
|
@@ -268,66 +270,105 @@ function arrangementEqual(e, n, t) {
|
|
|
268
270
|
* node is born for it as the lane's derivation), on `length` only when the
|
|
269
271
|
* committed length differs, and as the `LaneView`'s base for structural
|
|
270
272
|
* reads. Unkeyed families compose
|
|
271
|
-
* positionally — the guess stands as written (the documented residue). */ GlobalQueue.an = (e, n) => {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
if (!
|
|
277
|
-
|
|
273
|
+
* positionally — the guess stands as written (the documented residue). */ GlobalQueue.an = (e, n, t) => {
|
|
274
|
+
if (!t) return fold(e, n);
|
|
275
|
+
const i = e.O;
|
|
276
|
+
if (i === undefined || e.ze !== $TRACK) return;
|
|
277
|
+
const r = e.T.v;
|
|
278
|
+
if (!(r instanceof LaneView)) return;
|
|
279
|
+
if (!Array.isArray(n) || !Array.isArray(r.rows)) {
|
|
280
|
+
r.base = n;
|
|
278
281
|
return;
|
|
279
282
|
}
|
|
280
|
-
const
|
|
281
|
-
if (
|
|
282
|
-
const
|
|
283
|
+
const o = i.fam?.key ?? null;
|
|
284
|
+
if (o === null) return;
|
|
285
|
+
const s = new Map;
|
|
283
286
|
for (let e = 0; e < n.length; e++) {
|
|
284
287
|
const t = n[e];
|
|
285
|
-
const i = isWrappable(t) ?
|
|
286
|
-
if (i !== undefined && !
|
|
288
|
+
const i = isWrappable(t) ? o(t) : undefined;
|
|
289
|
+
if (i !== undefined && !s.has(i)) s.set(i, t);
|
|
287
290
|
}
|
|
288
|
-
const
|
|
289
|
-
const
|
|
290
|
-
const
|
|
291
|
-
for (let e = 0; e <
|
|
292
|
-
const n =
|
|
293
|
-
const t = isWrappable(n) ?
|
|
294
|
-
const i = t !== undefined ?
|
|
291
|
+
const u = new Set;
|
|
292
|
+
const f = [];
|
|
293
|
+
const a = r.rows;
|
|
294
|
+
for (let e = 0; e < a.length; e++) {
|
|
295
|
+
const n = a[e];
|
|
296
|
+
const t = isWrappable(n) ? o(n) : undefined;
|
|
297
|
+
const i = t !== undefined ? s.get(t) : undefined;
|
|
295
298
|
if (i !== undefined) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
} else
|
|
299
|
+
f.push(i);
|
|
300
|
+
u.add(t);
|
|
301
|
+
} else f.push(n);
|
|
299
302
|
}
|
|
300
|
-
const
|
|
303
|
+
const l = r.removed;
|
|
301
304
|
for (let e = 0; e < n.length; e++) {
|
|
302
305
|
const t = n[e];
|
|
303
|
-
const i = isWrappable(t) ?
|
|
304
|
-
if (i !== undefined && !
|
|
306
|
+
const i = isWrappable(t) ? o(t) : undefined;
|
|
307
|
+
if (i !== undefined && !u.has(i) && (l === null || !l.has(i))) f.push(t);
|
|
305
308
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const
|
|
309
|
-
const
|
|
310
|
-
const
|
|
311
|
-
for (let e = 0; e <
|
|
312
|
-
const n =
|
|
309
|
+
r.rows = f;
|
|
310
|
+
r.base = f;
|
|
311
|
+
const c = txOf(e);
|
|
312
|
+
const d = committed(i);
|
|
313
|
+
const p = i.n;
|
|
314
|
+
for (let e = 0; e < f.length; e++) {
|
|
315
|
+
const n = p?.[e];
|
|
313
316
|
// A slot the lane does not own shows the committed row: it becomes the
|
|
314
317
|
// lane's only where the composed row is another row (by key — the same
|
|
315
318
|
// key's new object is the same row, its target adopted it).
|
|
316
319
|
if (n === undefined) {
|
|
317
|
-
if (!sameRow(
|
|
318
|
-
} else if (!sameRow(n.l & CONFIG_OVERRIDE ? n.T.v :
|
|
320
|
+
if (!sameRow(d[e], f[e], o)) laneSet(getNode(i, e), f[e], c);
|
|
321
|
+
} else if (!sameRow(n.l & CONFIG_OVERRIDE ? n.T.v : d[e], f[e], o)) laneSet(n, f[e], c);
|
|
319
322
|
}
|
|
320
|
-
if (
|
|
321
|
-
for (let e =
|
|
322
|
-
const n =
|
|
323
|
+
if (p !== null) {
|
|
324
|
+
for (let e = f.length; ;e++) {
|
|
325
|
+
const n = p[e];
|
|
323
326
|
if (n === undefined) break;
|
|
324
|
-
laneSet(n, undefined,
|
|
327
|
+
laneSet(n, undefined, c);
|
|
325
328
|
}
|
|
326
|
-
const e =
|
|
327
|
-
if (e !== undefined && (e.l & CONFIG_OVERRIDE ||
|
|
329
|
+
const e = p.length;
|
|
330
|
+
if (e !== undefined && (e.l & CONFIG_OVERRIDE || d.length !== f.length)) laneSet(e, f.length, c);
|
|
328
331
|
}
|
|
329
332
|
};
|
|
330
333
|
|
|
334
|
+
/** D-34 for a keyed arrangement guess: rows by key, not positions. A
|
|
335
|
+
* current truth that differs folds into the hold beneath it instead of
|
|
336
|
+
* voiding the lane: the guess stays the lane's value and the screen's until
|
|
337
|
+
* the hold commits, where rows match by key, and the graph outside the lane
|
|
338
|
+
* re-derives from the truth now (`foldedRead`). A confirmation is silent
|
|
339
|
+
* (A17): only truth readers are told. True: the lane stages the truth
|
|
340
|
+
* beneath (`laneWrite`). */ function fold(e, n) {
|
|
341
|
+
const t = e.O?.k;
|
|
342
|
+
const i = txOf(e);
|
|
343
|
+
// A guess the screen never showed is void at the correction (D-34); a
|
|
344
|
+
// keyed arrangement guess's view carries its removed-keys set.
|
|
345
|
+
if (!i.ke || !(t?.l & CONFIG_OVERRIDE) || !t.T.v?.removed) return false;
|
|
346
|
+
const r = e.T.v;
|
|
347
|
+
if ((!e.xe || !e.xe(r, n)) && !GlobalQueue.nn(r, n)) {
|
|
348
|
+
i.folded = foldedRead;
|
|
349
|
+
insertSubs(e);
|
|
350
|
+
} else GlobalQueue.sn?.(i);
|
|
351
|
+
joinFuture(resolveTx(i._parent ?? i));
|
|
352
|
+
return true;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/** A folded lane's guess read by a deriving pass outside the lane, tracked
|
|
356
|
+
* or not (`untrack` is about dependencies, not about which world a pass
|
|
357
|
+
* derives from), or by `latest()` (`c` null): the hold's world — the truth
|
|
358
|
+
* staged beneath the guess, else the value it covered — and the pass joins
|
|
359
|
+
* the hold. Lane passes and the screen keep the guess: held truth is masked
|
|
360
|
+
* from lane passes only (#3164). The store's own derive reconciles its
|
|
361
|
+
* landings against the arrangement the guesses made: it is the author, not
|
|
362
|
+
* a reader. */ function foldedRead(e, n) {
|
|
363
|
+
if (e !== null) {
|
|
364
|
+
if (!(n.l & CONFIG_GUESS) || passLane !== null || e.i === EFFECT_RENDER || e.l & CONFIG_CHILDREN_FORBIDDEN || n.O?.fam?.node === e) return NOT_PENDING;
|
|
365
|
+
const t = txOf(n);
|
|
366
|
+
joinPassAt(e, resolveTx(t._parent ?? t));
|
|
367
|
+
}
|
|
368
|
+
if (n.se !== NOT_PENDING) return n.se;
|
|
369
|
+
return n.l & CONFIG_SLOT_NODE ? GlobalQueue.fn(n) : n.Ie;
|
|
370
|
+
}
|
|
371
|
+
|
|
331
372
|
function sameRow(e, n, t) {
|
|
332
373
|
if (e === n) return true;
|
|
333
374
|
if (!isWrappable(e) || !isWrappable(n)) return false;
|
|
@@ -521,11 +562,11 @@ i = false) {
|
|
|
521
562
|
if (s !== null) {
|
|
522
563
|
for (const e of Reflect.ownKeys(s)) {
|
|
523
564
|
const o = s[e];
|
|
524
|
-
let
|
|
525
|
-
if (o.l & CONFIG_OVERRIDE)
|
|
526
|
-
const f = !!
|
|
527
|
-
const
|
|
528
|
-
if (!f && e in
|
|
565
|
+
let u;
|
|
566
|
+
if (o.l & CONFIG_OVERRIDE) u = t(o); else if (!i || (u = pendingGuessOf(o)) === NOT_PENDING) continue;
|
|
567
|
+
const f = !!u;
|
|
568
|
+
const a = r ?? n;
|
|
569
|
+
if (!f && e in a) delete ensure()[e];
|
|
529
570
|
}
|
|
530
571
|
}
|
|
531
572
|
return r ?? n;
|
|
@@ -538,7 +579,7 @@ function createOptimisticStore(e, n, t) {
|
|
|
538
579
|
// createProjectionInternal).
|
|
539
580
|
const o = i ? n || {} : e;
|
|
540
581
|
const s = r?.key === undefined ? "id" : r.key;
|
|
541
|
-
const
|
|
582
|
+
const u = {
|
|
542
583
|
map: new WeakMap,
|
|
543
584
|
node: null,
|
|
544
585
|
live: new Set,
|
|
@@ -546,8 +587,8 @@ function createOptimisticStore(e, n, t) {
|
|
|
546
587
|
opt: true,
|
|
547
588
|
key: typeof s === "function" ? s : s === null ? null : e => isWrappable(e) ? e[s] : undefined
|
|
548
589
|
};
|
|
549
|
-
const f = wrap(o, null, null,
|
|
550
|
-
if (
|
|
590
|
+
const f = wrap(o, null, null, u);
|
|
591
|
+
if (u.shallow) {
|
|
551
592
|
f[$TARGET].s = true;
|
|
552
593
|
markRawIngest(o);
|
|
553
594
|
}
|
|
@@ -558,11 +599,11 @@ function createOptimisticStore(e, n, t) {
|
|
|
558
599
|
loadingValue: undefined
|
|
559
600
|
};
|
|
560
601
|
const i = computed(() => {
|
|
561
|
-
if (!
|
|
602
|
+
if (!u.node) u.node = getOwner();
|
|
562
603
|
runProjectionComputed(f, n, s);
|
|
563
604
|
}, t);
|
|
564
605
|
i.l &= ~CONFIG_AUTO_DISPOSE;
|
|
565
|
-
|
|
606
|
+
u.node = i;
|
|
566
607
|
}
|
|
567
608
|
return [ f, e => storeSetter(f, e) ];
|
|
568
609
|
}
|