@solidjs/signals 2.0.0-rc.15 → 2.0.0-rc.16
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 +785 -367
- package/dist/dev.attribution.js +75 -52
- package/dist/dev.js +1120 -567
- package/dist/observe/affects-marks.js +86 -0
- package/dist/observe/affects.js +22 -73
- package/dist/observe/boundaries.js +191 -189
- package/dist/observe/core/async.js +175 -131
- package/dist/observe/core/attribution-queries.js +1 -1
- package/dist/observe/core/attribution.js +176 -159
- package/dist/observe/core/constants.js +17 -3
- package/dist/observe/core/context.js +3 -3
- package/dist/observe/core/core.js +503 -363
- package/dist/observe/core/dev.js +66 -38
- package/dist/observe/core/effect.js +48 -48
- package/dist/observe/core/error.js +5 -3
- package/dist/observe/core/external.js +5 -6
- package/dist/observe/core/graph.js +57 -43
- package/dist/observe/core/heap.js +33 -33
- package/dist/observe/core/identities.js +62 -0
- package/dist/observe/core/lanes.js +226 -259
- package/dist/observe/core/owner.js +62 -50
- package/dist/observe/core/scheduler.js +319 -171
- package/dist/observe/core/truth.js +45 -0
- package/dist/observe/core/verdict.js +88 -50
- package/dist/observe/deferred.js +184 -0
- package/dist/observe/index.js +7 -1
- package/dist/observe/map.js +345 -260
- package/dist/observe/reveal.js +76 -76
- package/dist/observe/signals.js +41 -30
- package/dist/observe/store/affects.js +6 -6
- package/dist/observe/store/edges.js +39 -0
- package/dist/observe/store/optimistic.js +41 -36
- package/dist/observe/store/projection.js +68 -55
- package/dist/observe/store/store.js +157 -104
- package/dist/prod/affects-marks.js +86 -0
- package/dist/prod/affects.js +23 -72
- package/dist/prod/boundaries.js +155 -153
- package/dist/prod/core/async.js +171 -127
- package/dist/prod/core/constants.js +17 -3
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +478 -342
- package/dist/prod/core/effect.js +68 -68
- package/dist/prod/core/error.js +5 -3
- package/dist/prod/core/external.js +5 -6
- package/dist/prod/core/graph.js +57 -43
- package/dist/prod/core/heap.js +38 -38
- package/dist/prod/core/identities.js +62 -0
- package/dist/prod/core/lanes.js +217 -250
- package/dist/prod/core/owner.js +62 -51
- package/dist/prod/core/scheduler.js +310 -162
- package/dist/prod/core/truth.js +45 -0
- package/dist/prod/core/verdict.js +87 -49
- package/dist/prod/deferred.js +182 -0
- package/dist/prod/index.js +7 -1
- package/dist/prod/map.js +360 -275
- package/dist/prod/reveal.js +76 -76
- package/dist/prod/signals.js +41 -30
- package/dist/prod/store/affects.js +6 -6
- package/dist/prod/store/edges.js +39 -0
- package/dist/prod/store/optimistic.js +37 -33
- package/dist/prod/store/projection.js +25 -19
- package/dist/prod/store/store.js +142 -96
- package/dist/types/affects-marks.d.ts +14 -0
- package/dist/types/boundaries.d.ts +1 -1
- package/dist/types/core/async.d.ts +10 -0
- package/dist/types/core/constants.d.ts +13 -1
- package/dist/types/core/core.d.ts +44 -2
- package/dist/types/core/dev.d.ts +43 -13
- package/dist/types/core/graph.d.ts +11 -0
- package/dist/types/core/identities.d.ts +17 -0
- package/dist/types/core/index.d.ts +2 -1
- package/dist/types/core/lanes.d.ts +2 -14
- package/dist/types/core/owner.d.ts +5 -3
- package/dist/types/core/scheduler.d.ts +47 -28
- package/dist/types/core/truth.d.ts +16 -0
- package/dist/types/core/types.d.ts +21 -0
- package/dist/types/core/verdict.d.ts +32 -0
- package/dist/types/deferred.d.ts +28 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/map.d.ts +2 -2
- package/dist/types/signals.d.ts +28 -7
- package/dist/types/store/edges.d.ts +9 -0
- package/dist/types/store/index.d.ts +10 -3
- package/dist/types/store/optimistic.d.ts +3 -2
- package/dist/types/store/projection.d.ts +4 -3
- package/dist/types/store/store.d.ts +1 -1
- package/dist/types/store/target.d.ts +16 -8
- package/dist/types/store/types.d.ts +14 -0
- package/package.json +1 -1
|
@@ -2,17 +2,19 @@ import { attrHooks } from "../core/attribution-hooks.js";
|
|
|
2
2
|
|
|
3
3
|
import { CONFIG_MANUAL_WRITE, CONFIG_OVERRIDE, CONFIG_HELD, $REFRESH, NOT_PENDING, STATUS_PENDING, STATUS_ERROR, EFFECT_RENDER, REACTIVE_RECOMPUTING_DEPS, REACTIVE_STAGED_READ, CONFIG_VERDICT, CONFIG_CHILDREN_FORBIDDEN, CONFIG_PROMOTED, REACTIVE_DIRTY, REACTIVE_CHECK } from "../core/constants.js";
|
|
4
4
|
|
|
5
|
-
import { setSignal, isEqual, read, verdict, snapshotCaptureActive, captureWriteSnapshot, context, notePromotedWrite, untrack, slotSignal, stagedScreen, stagedRead } from "../core/core.js";
|
|
5
|
+
import { writeHook, setSignal, isEqual, read, verdict, snapshotCaptureActive, captureWriteSnapshot, context, notePromotedWrite, untrack, slotSignal, stagedScreen, stagedRead } from "../core/core.js";
|
|
6
6
|
|
|
7
7
|
import { registerGraph } from "../core/dev.js";
|
|
8
8
|
|
|
9
|
+
import { signalHook } from "../core/identities.js";
|
|
10
|
+
|
|
9
11
|
import { setSlotUnobserved } from "../core/graph.js";
|
|
10
12
|
|
|
11
13
|
import { getOwner, getObserver } from "../core/owner.js";
|
|
12
14
|
|
|
13
15
|
import { insertIntoHeap } from "../core/heap.js";
|
|
14
16
|
|
|
15
|
-
import { txOf, flushTransaction, holdNode, joinFuture, insertSubs, schedule, passLane, globalQueue, queuePendingNode, GlobalQueue, joinPassTx, dirtyQueue } from "../core/scheduler.js";
|
|
17
|
+
import { txOf, flushTransaction, holdNode, joinFuture, insertSubs, schedule, passLane, globalQueue, queuePendingNode, GlobalQueue, installStoreHooks, joinPassTx, dirtyQueue } from "../core/scheduler.js";
|
|
16
18
|
|
|
17
19
|
import { lookupTarget, storeOwners, setLookup, $OWNER, isOwned, markDescendants, devAssertNeverUserMutation } from "./target.js";
|
|
18
20
|
|
|
@@ -170,7 +172,7 @@ function wrap(e, n = null, t = null, r = n?.fam ?? null) {
|
|
|
170
172
|
// adoption swap raw identity without changing the logical value — only
|
|
171
173
|
// changed leaves notify, R9).
|
|
172
174
|
const slotNodeEquals = function(e, n) {
|
|
173
|
-
return isEqual(e, n) || sameLogicalSlot(this.
|
|
175
|
+
return isEqual(e, n) || sameLogicalSlot(this.O, e, n);
|
|
174
176
|
};
|
|
175
177
|
|
|
176
178
|
/** The deep witness: the store decides when it notifies. */ const never = false;
|
|
@@ -208,7 +210,7 @@ function sameKey(e, n) {
|
|
|
208
210
|
/** The container node's comparator: a staging is a backing (identity — a
|
|
209
211
|
* pending backing is never "equal" to the committed one); a lane value is
|
|
210
212
|
* an arrangement (`LaneView`), judged by the optimistic machinery. */ const containerEquals = function(e, n) {
|
|
211
|
-
return e === n || optHooks !== null && optHooks.arrangement(this.
|
|
213
|
+
return e === n || optHooks !== null && optHooks.arrangement(this.O, e, n);
|
|
212
214
|
};
|
|
213
215
|
|
|
214
216
|
function sameLogicalSlot(e, n, t) {
|
|
@@ -221,8 +223,8 @@ function sameLogicalSlot(e, n, t) {
|
|
|
221
223
|
* released at the commit that resolves it (`drainFolds`). */ const deferredReleases = new Set;
|
|
222
224
|
|
|
223
225
|
function releaseSlot(e) {
|
|
224
|
-
const n = e.
|
|
225
|
-
const t = e.
|
|
226
|
+
const n = e.O;
|
|
227
|
+
const t = e.Vt;
|
|
226
228
|
if (t === $TRACK) {
|
|
227
229
|
if (n.k === e) n.k = null;
|
|
228
230
|
} else if (t === $DEEP) {
|
|
@@ -245,10 +247,14 @@ function releaseSlot(e) {
|
|
|
245
247
|
// dispatches CONFIG_SLOT_NODE nodes here (graph.ts) instead of holding a
|
|
246
248
|
// per-node closure in a per-node NodeExtension. A dropped node is
|
|
247
249
|
// unreachable through the store — a fresh read makes a fresh node.
|
|
250
|
+
// A staged write — or a lane's value (a guess, S4) — is state only the node
|
|
251
|
+
// holds: its release waits for the commit that resolves it. So does a leaf of
|
|
252
|
+
// a held container (#4146): a mainline write it carried is in the held
|
|
253
|
+
// staging too, where it would read as the hold's until the landing.
|
|
254
|
+
const slotKept = e => e.ue !== NOT_PENDING || e.l & CONFIG_OVERRIDE || e.O.k?.l & CONFIG_HELD;
|
|
255
|
+
|
|
248
256
|
setSlotUnobserved(e => {
|
|
249
|
-
|
|
250
|
-
// node holds: defer the release to the commit that resolves it.
|
|
251
|
-
if (e.Oe !== NOT_PENDING || e.i & CONFIG_OVERRIDE) deferredReleases.add(e); else releaseSlot(e);
|
|
257
|
+
if (slotKept(e)) deferredReleases.add(e); else releaseSlot(e);
|
|
252
258
|
});
|
|
253
259
|
|
|
254
260
|
/** A node born while its container has a staging is born from the two
|
|
@@ -256,19 +262,19 @@ setSlotUnobserved(e => {
|
|
|
256
262
|
* pending one — and held by the container's transaction when the container
|
|
257
263
|
* is held (#3706: the unit of the hold is the key — a key the batch left
|
|
258
264
|
* unchanged stages nothing and holds no one). */ function bornStaged(e, n, t, r) {
|
|
259
|
-
if (n.
|
|
265
|
+
if (n.Ye && n.Ye(n.Ie, t)) return;
|
|
260
266
|
queuePendingNode(n);
|
|
261
|
-
n.
|
|
267
|
+
n.ue = t;
|
|
262
268
|
const o = e.k;
|
|
263
269
|
if (o === null) return;
|
|
264
270
|
// a node-less staging holds nothing (`stageOn`)
|
|
265
271
|
// Held by the container's transaction only for a key the HELD staging
|
|
266
272
|
// changed — a mainline layer's change above it stages mainline. (A
|
|
267
273
|
// container carrying a guess is a lane's: the flush's park decides.)
|
|
268
|
-
if ((o.
|
|
274
|
+
if ((o.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && heldKeyChanged(e, r)) holdNode(n, txOf(o));
|
|
269
275
|
// A28 (4): a batch written inside a creation-time pass is promoted — its
|
|
270
276
|
// late-materialized leaf with it.
|
|
271
|
-
if (o.
|
|
277
|
+
if (o.l & CONFIG_PROMOTED) notePromotedWrite(n);
|
|
272
278
|
}
|
|
273
279
|
|
|
274
280
|
function getNode(e, n,
|
|
@@ -293,7 +299,9 @@ t = -1) {
|
|
|
293
299
|
// the hottest store path, and the disabled cost must stay one null
|
|
294
300
|
// check (nodes created before enable() stay generically named).
|
|
295
301
|
if (attrHooks !== null) {
|
|
296
|
-
|
|
302
|
+
const t = storeRoot(e);
|
|
303
|
+
l._name = (storeNames.get(t) ?? "store") + "." + String(n);
|
|
304
|
+
l._loc = storeLocs.get(t);
|
|
297
305
|
stampNodeOwner(l, e);
|
|
298
306
|
}
|
|
299
307
|
r[n] = o;
|
|
@@ -330,8 +338,8 @@ function getHasNode(e, n) {
|
|
|
330
338
|
// pending backing staged — so whoever asked for it reads the frame it
|
|
331
339
|
// would have read had the node been there from the write.
|
|
332
340
|
if (e.pb !== null && !directCommit) {
|
|
333
|
-
n.
|
|
334
|
-
n.
|
|
341
|
+
n.Ie = preBatch(e);
|
|
342
|
+
n.ue = e.pb;
|
|
335
343
|
queuePendingNode(n);
|
|
336
344
|
}
|
|
337
345
|
}
|
|
@@ -347,11 +355,11 @@ function getHasNode(e, n) {
|
|
|
347
355
|
* staging: nothing allocates, nothing is swept at the commit (dbmon's tick
|
|
348
356
|
* re-created, queued, swept and dropped ~7000 container nodes). If the
|
|
349
357
|
* flush parks, the seam materializes and holds the node then
|
|
350
|
-
* (`
|
|
351
|
-
if (e.k === null && passLane === null && (context === null || globalQueue.
|
|
358
|
+
* (`storeParkHook`) — the one case the staging home exists for. */ function stageOn(e, n) {
|
|
359
|
+
if (e.k === null && passLane === null && (context === null || globalQueue.q) && !deriveHolds(e)) return;
|
|
352
360
|
const t = getContainerNode(e);
|
|
353
|
-
if (t.
|
|
354
|
-
t.
|
|
361
|
+
if (t.ue === NOT_PENDING) queuePendingNode(t);
|
|
362
|
+
t.ue = n;
|
|
355
363
|
// A28 (4): a write issued inside a pass outside a flush (a creation-time
|
|
356
364
|
// derive) is promoted at the pass's end — the batch with it.
|
|
357
365
|
if (context !== null) notePromotedWrite(t);
|
|
@@ -361,10 +369,10 @@ function getHasNode(e, n) {
|
|
|
361
369
|
/** The projection's derive is held by a transaction and this is its own
|
|
362
370
|
* write (not a user setter's): the staging is the derive's (`holdWithDerive`). */ function deriveHolds(e) {
|
|
363
371
|
const n = e.fam?.node;
|
|
364
|
-
return n != null && !userWrite && (n.
|
|
372
|
+
return n != null && !userWrite && (n.l & CONFIG_HELD) !== 0;
|
|
365
373
|
}
|
|
366
374
|
|
|
367
|
-
|
|
375
|
+
const storePark = e => {
|
|
368
376
|
for (let n = 0; n < foldList.length; n++) {
|
|
369
377
|
const t = foldList[n];
|
|
370
378
|
if (t.k === null && t.pb !== null) holdNode(getContainerNode(t), e);
|
|
@@ -393,9 +401,9 @@ function bumpDeep(e) {
|
|
|
393
401
|
// on the guess (`laneWrite` → `supersede`, judged by `containerEquals`);
|
|
394
402
|
// otherwise the structural readers are walked (the staging is already on
|
|
395
403
|
// the node; the comparator is the store's, done).
|
|
396
|
-
if (e.
|
|
397
|
-
if (e.
|
|
398
|
-
if (snapshotCaptureActive) captureWriteSnapshot(e, e.
|
|
404
|
+
if (e.l & CONFIG_OVERRIDE) setSignal(e, n); else {
|
|
405
|
+
if (e.l & CONFIG_HELD) joinFuture(txOf(e));
|
|
406
|
+
if (snapshotCaptureActive) captureWriteSnapshot(e, e.Ie);
|
|
399
407
|
insertSubs(e);
|
|
400
408
|
schedule();
|
|
401
409
|
}
|
|
@@ -413,17 +421,22 @@ function storeRootOwner(e) {
|
|
|
413
421
|
}
|
|
414
422
|
|
|
415
423
|
function stampNodeOwner(e, n) {
|
|
416
|
-
e.
|
|
424
|
+
e.H = storeRootOwner(n) ?? null;
|
|
417
425
|
}
|
|
418
426
|
|
|
419
427
|
const storeNames = new WeakMap;
|
|
420
428
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
429
|
+
// The store's `loc` option, carried onto every property node beside its
|
|
430
|
+
// label (the same gate: nodes created before the engine is installed carry
|
|
431
|
+
// neither).
|
|
432
|
+
const storeLocs = new WeakMap;
|
|
424
433
|
|
|
425
|
-
function
|
|
426
|
-
|
|
434
|
+
function nameStore(e, n, t) {
|
|
435
|
+
if (attrHooks !== null) {
|
|
436
|
+
const r = e[$TARGET];
|
|
437
|
+
if (n) storeNames.set(r, n);
|
|
438
|
+
if (t) storeLocs.set(r, t);
|
|
439
|
+
}
|
|
427
440
|
}
|
|
428
441
|
|
|
429
442
|
// ---------------------------------------------------------------------------
|
|
@@ -512,7 +525,7 @@ const plainProto = e => {
|
|
|
512
525
|
if (e.kc > OVERLAY_REBUILD_MAX_KEYS) return false;
|
|
513
526
|
if (e.del !== null && e.del.size !== 0) return true;
|
|
514
527
|
const t = e.wk;
|
|
515
|
-
if (t !== null && t !== WK_ALL && t.size <= OVERLAY_REBUILD_MIN_ADDS) return false;
|
|
528
|
+
if (t !== null && t !== WK_ALL && t.u === undefined && t.size <= OVERLAY_REBUILD_MIN_ADDS) return false;
|
|
516
529
|
const r = e.v;
|
|
517
530
|
let o = 0;
|
|
518
531
|
for (const e of Reflect.ownKeys(n)) if (!hasOwn.call(r, e) && ++o > OVERLAY_REBUILD_MIN_ADDS) return true;
|
|
@@ -532,7 +545,7 @@ const plainProto = e => {
|
|
|
532
545
|
e.pb = t;
|
|
533
546
|
e.ovl = false;
|
|
534
547
|
// The staging IS the pending backing: re-point the container node.
|
|
535
|
-
if (e.k !== null && e.k.
|
|
548
|
+
if (e.k !== null && e.k.ue === n) e.k.ue = t;
|
|
536
549
|
return t;
|
|
537
550
|
}
|
|
538
551
|
|
|
@@ -553,7 +566,7 @@ const plainProto = e => {
|
|
|
553
566
|
// mainline setter mid-hold publishes mainline; the held keys stay held).
|
|
554
567
|
n = e.pb = cloneRaw(n, e);
|
|
555
568
|
const t = e.k;
|
|
556
|
-
if (t !== null && !(t.
|
|
569
|
+
if (t !== null && !(t.l & CONFIG_HELD)) t.ue = n;
|
|
557
570
|
} else if (n === null) {
|
|
558
571
|
const t = e.v;
|
|
559
572
|
if (!directCommit) queueFold(e);
|
|
@@ -632,7 +645,7 @@ const plainProto = e => {
|
|
|
632
645
|
} else r = e.v;
|
|
633
646
|
if (directCommit) {
|
|
634
647
|
e.pb = null;
|
|
635
|
-
if (e.k !== null) e.k.
|
|
648
|
+
if (e.k !== null) e.k.Ie = n;
|
|
636
649
|
} else {
|
|
637
650
|
// Eager (INTERNALS §3): the backing swaps now — handlers read the
|
|
638
651
|
// adopted object before the flush — while the container node, when
|
|
@@ -728,7 +741,7 @@ let foldIndex = null;
|
|
|
728
741
|
if (r.pb === null) continue;
|
|
729
742
|
// folded already (a direct commit)
|
|
730
743
|
const o = r.k;
|
|
731
|
-
if (o !== null && o.
|
|
744
|
+
if (o !== null && o.ue !== NOT_PENDING) {
|
|
732
745
|
// held: commits with its hold
|
|
733
746
|
foldList.push(r);
|
|
734
747
|
foldOlds.push(n[t]);
|
|
@@ -739,7 +752,7 @@ let foldIndex = null;
|
|
|
739
752
|
}
|
|
740
753
|
if (deferredReleases.size !== 0) {
|
|
741
754
|
for (const e of deferredReleases) {
|
|
742
|
-
if (e.
|
|
755
|
+
if (e.o === null && !slotKept(e)) {
|
|
743
756
|
deferredReleases.delete(e);
|
|
744
757
|
releaseSlot(e);
|
|
745
758
|
}
|
|
@@ -750,28 +763,28 @@ let foldIndex = null;
|
|
|
750
763
|
/** Core asks: is a slot node's truth in flight? Its family's derive is —
|
|
751
764
|
* lanes (A17, #2864: a guess mid-refetch stands in for the flight) and
|
|
752
765
|
* marks (an ambient `affects()` over a declared reload lives to the
|
|
753
|
-
* landing) read it. */ GlobalQueue.
|
|
754
|
-
const n = e.
|
|
755
|
-
return n != null && n.node !== null && (n.node.
|
|
766
|
+
* landing) read it. */ GlobalQueue.k = e => {
|
|
767
|
+
const n = e.O?.fam;
|
|
768
|
+
return n != null && n.node !== null && (n.node.m & STATUS_PENDING) !== 0;
|
|
756
769
|
};
|
|
757
770
|
|
|
758
771
|
/** Core asks (lanes.ts `covered`): the value a slot node's guess covered.
|
|
759
772
|
* A chained link's committed value is the inner store's at the last
|
|
760
773
|
* read-through — refreshed here, since a guess served the reads since
|
|
761
|
-
* (#3672: the revert compares against the base's live value). */ GlobalQueue.
|
|
762
|
-
const n = e.
|
|
774
|
+
* (#3672: the revert compares against the base's live value). */ GlobalQueue.fn = e => {
|
|
775
|
+
const n = e.O;
|
|
763
776
|
if (n.ch) {
|
|
764
|
-
const t = e.
|
|
777
|
+
const t = e.Vt;
|
|
765
778
|
const r = n.v;
|
|
766
|
-
if (n.h !== null && n.h[t] === e) e.
|
|
779
|
+
if (n.h !== null && n.h[t] === e) e.Ie = untrack(() => t in r); else if (n.n !== null && n.n[t] === e) e.Ie = untrack(() => unwrapValue(r[t]));
|
|
767
780
|
}
|
|
768
|
-
return e.
|
|
781
|
+
return e.Ie;
|
|
769
782
|
};
|
|
770
783
|
|
|
771
|
-
|
|
784
|
+
installStoreHooks(storePark, () => {
|
|
772
785
|
drainFolds();
|
|
773
786
|
optHooks?.sweep();
|
|
774
|
-
};
|
|
787
|
+
});
|
|
775
788
|
|
|
776
789
|
/** The store half of `affects()` (store/affects.ts) makes its marks' nodes
|
|
777
790
|
* and walks records through these: it never imports the engine. */ GlobalQueue.no = getNode;
|
|
@@ -804,7 +817,7 @@ function runDirect(e) {
|
|
|
804
817
|
// the adopted object (shared ownership — never cloned).
|
|
805
818
|
e.pb = null;
|
|
806
819
|
e.wk = null;
|
|
807
|
-
} else if (e.ovl && (e.v !== n || !overlayRebuilds(e, r) && t?.
|
|
820
|
+
} else if (e.ovl && (e.v !== n || !overlayRebuilds(e, r) && t?.T?.lt !== n)) {
|
|
808
821
|
// Overlay flatten (#3044): the backing keeps its identity, so the
|
|
809
822
|
// `t.v === old` gate below skips path copying (the parent slot
|
|
810
823
|
// already points here) and the adopted-notify (setter
|
|
@@ -818,8 +831,8 @@ function runDirect(e) {
|
|
|
818
831
|
const t = e.v;
|
|
819
832
|
const o = e.wk;
|
|
820
833
|
if (o !== null && o !== WK_ALL) {
|
|
821
|
-
for (
|
|
822
|
-
if (hasOwn.call(r,
|
|
834
|
+
for (let e = o; e !== undefined; e = e.u) for (const n of e) {
|
|
835
|
+
if (hasOwn.call(r, n)) copyOwn(t, r, n); else delete t[n];
|
|
823
836
|
}
|
|
824
837
|
} else {
|
|
825
838
|
for (const e of Reflect.ownKeys(r)) {
|
|
@@ -846,7 +859,7 @@ function runDirect(e) {
|
|
|
846
859
|
// subscribes to was a transient staging home (INTERNALS §5: an
|
|
847
860
|
// observer-less write holds a transient record until the fold,
|
|
848
861
|
// discarded with it) — gone with the batch.
|
|
849
|
-
if (t.
|
|
862
|
+
if (t.o === null) e.k = null; else if (t.Ie instanceof LaneView) t.Ie.base = e.v; else t.Ie = e.v;
|
|
850
863
|
}
|
|
851
864
|
if (e.v !== n && e.u) {
|
|
852
865
|
const t = parentSlotKey(e, n);
|
|
@@ -919,9 +932,9 @@ function reportReplacedContainers(e, n, t, r) {
|
|
|
919
932
|
|
|
920
933
|
function heldDerivation(e, n, t) {
|
|
921
934
|
if (e.fam === null || !userWrite) return false;
|
|
922
|
-
if (n !== undefined) return (n.
|
|
935
|
+
if (n !== undefined) return (n.l & (CONFIG_HELD | CONFIG_MANUAL_WRITE)) === CONFIG_HELD && txOf(n) !== flushTransaction;
|
|
923
936
|
const r = e.k;
|
|
924
|
-
return r !== null && (r.
|
|
937
|
+
return r !== null && (r.l & CONFIG_HELD) !== 0 && txOf(r) !== flushTransaction && heldKeyChanged(e, t);
|
|
925
938
|
}
|
|
926
939
|
|
|
927
940
|
/** Setter exit: one node write per changed observed key (the leaves stage
|
|
@@ -951,7 +964,10 @@ function heldDerivation(e, n, t) {
|
|
|
951
964
|
// value can change when ANY key is written), or a non-plain prototype
|
|
952
965
|
// (class instances: prototype getters derive from arbitrary fields).
|
|
953
966
|
// Overlay pbs chain to the COMMITTED object (#3044) — plainness is the
|
|
954
|
-
// committed container's prototype, not the overlay's.
|
|
967
|
+
// committed container's prototype, not the overlay's. THIS setter's keys
|
|
968
|
+
// only (D-8, #3743): a key an earlier setter of the batch wrote and this
|
|
969
|
+
// one did not is no second proposal — its node was told then, and telling
|
|
970
|
+
// a held node its unchanged value again would join this tick to the hold.
|
|
955
971
|
const o = e.wk;
|
|
956
972
|
const i = o === WK_ALL || e.a === true || !plainProto(e.ovl ? e.v : n) ? null : o;
|
|
957
973
|
if (attrHooks !== null) reportReplacedContainers(e, t, n, i);
|
|
@@ -987,9 +1003,9 @@ function heldDerivation(e, n, t) {
|
|
|
987
1003
|
// The derive's write is a derivation; a user setter's is a proposal
|
|
988
1004
|
// (A34 (3)'s discriminator).
|
|
989
1005
|
if (!userWrite) {
|
|
990
|
-
o.
|
|
1006
|
+
o.l &= ~CONFIG_MANUAL_WRITE;
|
|
991
1007
|
holdWithDerive(e, o);
|
|
992
|
-
} else o.
|
|
1008
|
+
} else o.l |= CONFIG_MANUAL_WRITE;
|
|
993
1009
|
}
|
|
994
1010
|
}
|
|
995
1011
|
}
|
|
@@ -1020,7 +1036,7 @@ function heldDerivation(e, n, t) {
|
|
|
1020
1036
|
// container carrying an arrangement guess is told whether or not anyone
|
|
1021
1037
|
// subscribes: the write is a landing on the guess (`notifyContainer`).
|
|
1022
1038
|
const u = e.k;
|
|
1023
|
-
if (u !== null && (u.
|
|
1039
|
+
if (u !== null && (u.o !== null || u.l & CONFIG_OVERRIDE)) {
|
|
1024
1040
|
let r;
|
|
1025
1041
|
if (e.ovl) {
|
|
1026
1042
|
r = e.del !== null && e.del.size !== 0;
|
|
@@ -1122,7 +1138,7 @@ function hasAccessorFlag(e) {
|
|
|
1122
1138
|
for (const o of Reflect.ownKeys(r)) if (e || o in n !== o in t) setSignal(r[o], o in t);
|
|
1123
1139
|
}
|
|
1124
1140
|
const o = e.k;
|
|
1125
|
-
if (o !== null && (o.
|
|
1141
|
+
if (o !== null && (o.o !== null || o.l & CONFIG_OVERRIDE)) {
|
|
1126
1142
|
const e = Array.isArray(t) && Array.isArray(n) ? arrayStructureChanged(n, t) : membershipChanged(n, t);
|
|
1127
1143
|
if (e) notifyContainer(o, t);
|
|
1128
1144
|
}
|
|
@@ -1179,7 +1195,7 @@ function inDraft(e) {
|
|
|
1179
1195
|
* "adoption is eager by contract" — and the node keeps the frame committed
|
|
1180
1196
|
* readers under a hold still see), `t.v` otherwise. */ function committed(e) {
|
|
1181
1197
|
const n = e.k;
|
|
1182
|
-
if (n !== null) return n.
|
|
1198
|
+
if (n !== null) return n.ue !== NOT_PENDING ? asBacking(n.Ie) : e.v;
|
|
1183
1199
|
// A node-less staging (`stageOn`): the fold queue remembers the frame.
|
|
1184
1200
|
return e.pb !== null ? preBatch(e) : e.v;
|
|
1185
1201
|
}
|
|
@@ -1191,8 +1207,8 @@ function inDraft(e) {
|
|
|
1191
1207
|
* committed frame. */ function stagingReader() {
|
|
1192
1208
|
let e = context;
|
|
1193
1209
|
if (e === null) return null;
|
|
1194
|
-
if (e.
|
|
1195
|
-
return e === null || e.
|
|
1210
|
+
if (e.Pt) e = e.Ht ?? null;
|
|
1211
|
+
return e === null || e.l & CONFIG_CHILDREN_FORBIDDEN ? null : e;
|
|
1196
1212
|
}
|
|
1197
1213
|
|
|
1198
1214
|
/** The backing a read serves (RUL-1, signal parity): the draft and the write
|
|
@@ -1230,10 +1246,10 @@ function inDraft(e) {
|
|
|
1230
1246
|
if (writeOverride && !userWrite) {
|
|
1231
1247
|
const t = n !== undefined ? e.n?.[n] : undefined;
|
|
1232
1248
|
if (t !== undefined) {
|
|
1233
|
-
if ((t.
|
|
1249
|
+
if ((t.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD) joinPassTx(txOf(t));
|
|
1234
1250
|
} else {
|
|
1235
1251
|
const t = e.k;
|
|
1236
|
-
if (t !== null && (t.
|
|
1252
|
+
if (t !== null && (t.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && (n === undefined || heldKeyChanged(e, n))) joinPassTx(txOf(t));
|
|
1237
1253
|
}
|
|
1238
1254
|
}
|
|
1239
1255
|
return r;
|
|
@@ -1245,9 +1261,9 @@ function inDraft(e) {
|
|
|
1245
1261
|
// it).
|
|
1246
1262
|
if (n !== undefined) {
|
|
1247
1263
|
const t = e.n?.[n];
|
|
1248
|
-
if (t !== undefined && t.
|
|
1264
|
+
if (t !== undefined && t.l & CONFIG_OVERRIDE) return committed(e);
|
|
1249
1265
|
}
|
|
1250
|
-
const i = o !== null && (o.
|
|
1266
|
+
const i = o !== null && (o.l & CONFIG_HELD) !== 0;
|
|
1251
1267
|
// A held container: the hold's unit is the key (#3706). A key the HELD
|
|
1252
1268
|
// staging left unchanged reads the ambient view — a mainline layer's
|
|
1253
1269
|
// write above the hold publishes mainline (#3688, #3612); a key it
|
|
@@ -1265,7 +1281,7 @@ function inDraft(e) {
|
|
|
1265
1281
|
// probe) judges the container like any node — for a key the batch
|
|
1266
1282
|
// changed; an unchanged key is committed and final (A22: pending is per
|
|
1267
1283
|
// key). A held container's committed frame is the node's.
|
|
1268
|
-
if (verdict === null || !i && n !== undefined && !keyChanged(e, n, t)) return i ? asBacking(o.
|
|
1284
|
+
if (verdict === null || !i && n !== undefined && !keyChanged(e, n, t)) return i ? asBacking(o.Ie) : e.v;
|
|
1269
1285
|
return o === null ? committed(e) : asBacking(read(o));
|
|
1270
1286
|
}
|
|
1271
1287
|
// A pass reading a key the batch left unchanged: the same value in both
|
|
@@ -1282,13 +1298,13 @@ function inDraft(e) {
|
|
|
1282
1298
|
// frames, a changed one is what the mark already stands for. The
|
|
1283
1299
|
// per-key question is asked once per pass, not once per key (a
|
|
1284
1300
|
// `mapArray` over 1k shifted rows asked it 1k times).
|
|
1285
|
-
if (l.R & REACTIVE_STAGED_READ && !(l.
|
|
1301
|
+
if (l.R & REACTIVE_STAGED_READ && !(l.l & (CONFIG_VERDICT | CONFIG_CHILDREN_FORBIDDEN))) return r;
|
|
1286
1302
|
if (n !== undefined && !keyChanged(e, n, t)) return committed(e);
|
|
1287
1303
|
// A node-less staging (`stageOn`): what `read()` of its node would do
|
|
1288
1304
|
// for this pass — a verdict reader sees the screen, any other derives
|
|
1289
1305
|
// from the staging and is marked as having read it.
|
|
1290
1306
|
if (o === null) {
|
|
1291
|
-
if (l.
|
|
1307
|
+
if (l.l & CONFIG_VERDICT && stagedScreen(l)) return committed(e);
|
|
1292
1308
|
stagedRead(l);
|
|
1293
1309
|
return r;
|
|
1294
1310
|
}
|
|
@@ -1298,7 +1314,7 @@ function inDraft(e) {
|
|
|
1298
1314
|
|
|
1299
1315
|
/** Did the HELD staging (the container node's, not a mainline layer above
|
|
1300
1316
|
* it) change `key`? */ function heldKeyChanged(e, n, t = true) {
|
|
1301
|
-
return changedBetween(e, e.k.
|
|
1317
|
+
return changedBetween(e, e.k.Ie, e.k.ue, n, t) && !adoptChild(e, n);
|
|
1302
1318
|
}
|
|
1303
1319
|
|
|
1304
1320
|
/** The values of a held frame, built once per frame: neither the committed
|
|
@@ -1325,14 +1341,14 @@ function rawsOf(e) {
|
|
|
1325
1341
|
* `version` holds. A record's keys pair by name; an array's by the family's
|
|
1326
1342
|
* key — without a family the pairing is not known here and the hold stands. */ function adoptChild(e, n) {
|
|
1327
1343
|
const t = e.k;
|
|
1328
|
-
const r = asBacking(t.
|
|
1344
|
+
const r = asBacking(t.Ie);
|
|
1329
1345
|
const o = r[n];
|
|
1330
|
-
const i = t.
|
|
1346
|
+
const i = t.ue[n];
|
|
1331
1347
|
const l = Array.isArray(r) ? e.fam?.key : null;
|
|
1332
1348
|
if (e.s || l === undefined || !sameRow(o, i, l) || !isWrappable(o) || !isWrappable(i) || Array.isArray(o) !== Array.isArray(i) || lookupTarget(o, e.fam) !== undefined || lookupTarget(i, e.fam) !== undefined ||
|
|
1333
1349
|
// A raw in both frames (the same objects swapped or reordered) is its
|
|
1334
1350
|
// own row: pairing it with another would alias the two after the commit.
|
|
1335
|
-
rawsOf(r).has(i) || rawsOf(t.
|
|
1351
|
+
rawsOf(r).has(i) || rawsOf(t.ue).has(o)) return false;
|
|
1336
1352
|
// A raw-marked value wraps to itself, a proxy to its own target: neither
|
|
1337
1353
|
// is a fresh target around `ov`.
|
|
1338
1354
|
const u = wrap(o, e, n)[$TARGET];
|
|
@@ -1343,7 +1359,7 @@ function rawsOf(e) {
|
|
|
1343
1359
|
}
|
|
1344
1360
|
|
|
1345
1361
|
/** A family target's unheld staging, read with no pass (a handler). */ function familyAhead(e) {
|
|
1346
|
-
return e.fam !== null && context === null && !(e.k !== null && e.k.
|
|
1362
|
+
return e.fam !== null && context === null && !(e.k !== null && e.k.l & CONFIG_HELD);
|
|
1347
1363
|
}
|
|
1348
1364
|
|
|
1349
1365
|
/** Did this batch change `key` — value (slot equality), presence, and (for
|
|
@@ -1377,7 +1393,7 @@ function changedBetween(e, n, t, r, o) {
|
|
|
1377
1393
|
* tracked or not, applies the hold and A28 rules a signal's read does. A
|
|
1378
1394
|
* projection's unheld staging is ahead for a handler (`familyAhead`). */ function nodeValue(e, n, t) {
|
|
1379
1395
|
let r = read(e);
|
|
1380
|
-
if (e.
|
|
1396
|
+
if (e.ue !== NOT_PENDING && !(e.l & CONFIG_HELD) && context === null && t.fam !== null) r = e.ue;
|
|
1381
1397
|
return r === FORCE ? n : r;
|
|
1382
1398
|
}
|
|
1383
1399
|
|
|
@@ -1397,8 +1413,8 @@ function changedBetween(e, n, t, r, o) {
|
|
|
1397
1413
|
if (l) {
|
|
1398
1414
|
// The link's committed value follows the inner store's (what a lane
|
|
1399
1415
|
// over it covers — its reveal and revert compare against it, S4).
|
|
1400
|
-
o.
|
|
1401
|
-
if (o.
|
|
1416
|
+
o.Ie = t;
|
|
1417
|
+
if (o.l & CONFIG_OVERRIDE) u = n;
|
|
1402
1418
|
} else u = n;
|
|
1403
1419
|
}
|
|
1404
1420
|
}
|
|
@@ -1419,7 +1435,7 @@ function changedBetween(e, n, t, r, o) {
|
|
|
1419
1435
|
}
|
|
1420
1436
|
|
|
1421
1437
|
/** Is `n` among `c`'s dependencies (any pass's — a kept tail included)? */ function linkedTo(e, n) {
|
|
1422
|
-
for (let t = e.
|
|
1438
|
+
for (let t = e.C; t !== null; t = t.G) if (t.S === n) return true;
|
|
1423
1439
|
return false;
|
|
1424
1440
|
}
|
|
1425
1441
|
|
|
@@ -1438,7 +1454,7 @@ function changedBetween(e, n, t, r, o) {
|
|
|
1438
1454
|
// reader of a memo would — linked, so it re-runs at the landing (the
|
|
1439
1455
|
// next settled pass pulls without linking and the stale link trims), a
|
|
1440
1456
|
// verdict reader registered, a tracked pass suspended.
|
|
1441
|
-
if (n.
|
|
1457
|
+
if (n.m & (STATUS_PENDING | STATUS_ERROR)) {
|
|
1442
1458
|
// A render effect outside the flight's own flush is the frame, not a
|
|
1443
1459
|
// derivation: it keeps what it shows and learns of the landing from the
|
|
1444
1460
|
// leaves the landing changes (unchanged leaves say nothing — it is not a
|
|
@@ -1449,7 +1465,7 @@ function changedBetween(e, n, t, r, o) {
|
|
|
1449
1465
|
// release the hold with the flight still up. An errored derive has no
|
|
1450
1466
|
// landing to learn of: the error is what the frame shows.
|
|
1451
1467
|
const t = context;
|
|
1452
|
-
if (t !== null && t.
|
|
1468
|
+
if (t !== null && t.i === EFFECT_RENDER && !(n.m & STATUS_ERROR) && n.l & CONFIG_HELD && flushTransaction !== txOf(n) && !linkedTo(t, n)) return;
|
|
1453
1469
|
// An optimistic family carrying guesses that stand in for the flight
|
|
1454
1470
|
// (A17): the guesses are the display — a reader is served the leaves
|
|
1455
1471
|
// (committed plus the guesses) and does not suspend on the derive; a
|
|
@@ -1457,7 +1473,7 @@ function changedBetween(e, n, t, r, o) {
|
|
|
1457
1473
|
// up). The family's, not the target's: the edit stands in for the one
|
|
1458
1474
|
// flight the family has.
|
|
1459
1475
|
const r = e.fam.overlaid;
|
|
1460
|
-
if (verdict === null && n.
|
|
1476
|
+
if (verdict === null && n.m & STATUS_PENDING && r !== undefined && r.size !== 0) return;
|
|
1461
1477
|
read(n);
|
|
1462
1478
|
} else untrack(() => read(n));
|
|
1463
1479
|
}
|
|
@@ -1470,12 +1486,12 @@ function changedBetween(e, n, t, r, o) {
|
|
|
1470
1486
|
* classification, as core reads it — `heldNotFinal`). */ function holdWithDerive(e, n) {
|
|
1471
1487
|
const t = e.fam?.node;
|
|
1472
1488
|
if (t !== undefined && t !== null && !userWrite && // the derive's own write (its draft or landing), not a user setter's
|
|
1473
|
-
t.
|
|
1489
|
+
t.l & CONFIG_HELD && n.ue !== NOT_PENDING &&
|
|
1474
1490
|
// A node carrying a guess is the lane's: its staging is the truth beneath
|
|
1475
1491
|
// the guess (`setSignal` → `laneWrite`), never re-homed by the store.
|
|
1476
|
-
!(n.
|
|
1492
|
+
!(n.l & (CONFIG_HELD | CONFIG_OVERRIDE))) {
|
|
1477
1493
|
holdNode(n, txOf(t));
|
|
1478
|
-
n.
|
|
1494
|
+
n.T.ut = t.T.ut;
|
|
1479
1495
|
}
|
|
1480
1496
|
}
|
|
1481
1497
|
|
|
@@ -1518,6 +1534,22 @@ function changedBetween(e, n, t, r, o) {
|
|
|
1518
1534
|
|
|
1519
1535
|
// ---------------------------------------------------------------------------
|
|
1520
1536
|
// traps
|
|
1537
|
+
/** A trap write: the target is told at the setter's exit, the key recorded
|
|
1538
|
+
* in this setter's `wk`. A setter's first write to a target still staged by
|
|
1539
|
+
* an earlier setter of the batch opens a set of its own (the notify visits
|
|
1540
|
+
* it, D-8) and chains the earlier one behind for the fold's union. */ function touch(e, n) {
|
|
1541
|
+
let t = e.wk;
|
|
1542
|
+
if (!pendingNotify.has(e)) {
|
|
1543
|
+
pendingNotify.add(e);
|
|
1544
|
+
if (t !== null && t !== WK_ALL) {
|
|
1545
|
+
t = new Set;
|
|
1546
|
+
t.u = e.wk;
|
|
1547
|
+
e.wk = t;
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
if (t !== WK_ALL) (e.wk ??= new Set).add(n);
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1521
1553
|
const traps = {
|
|
1522
1554
|
get(e, n, t) {
|
|
1523
1555
|
// One typeof gates every brand-symbol compare off the hot string path.
|
|
@@ -1561,7 +1593,7 @@ const traps = {
|
|
|
1561
1593
|
const r = e.n?.[n];
|
|
1562
1594
|
if (writeScopes === null && !writeOverride) {
|
|
1563
1595
|
const t = r;
|
|
1564
|
-
if (t !== undefined && t.acc !== true && (!e.ch || t.
|
|
1596
|
+
if (t !== undefined && t.acc !== true && (!e.ch || t.l & CONFIG_OVERRIDE)) {
|
|
1565
1597
|
const r = nodeValue(t, undefined, e);
|
|
1566
1598
|
if (r === null || typeof r !== "object") return r;
|
|
1567
1599
|
if (e.s) return serveShallow(e, n, r);
|
|
@@ -1656,9 +1688,9 @@ const traps = {
|
|
|
1656
1688
|
const o = read(r);
|
|
1657
1689
|
if (!e.ch || t !== e.v) return !!o;
|
|
1658
1690
|
const i = n in t;
|
|
1659
|
-
r.
|
|
1691
|
+
r.Ie = i;
|
|
1660
1692
|
// the link follows the inner store (S4)
|
|
1661
|
-
if (r.
|
|
1693
|
+
if (r.l & CONFIG_OVERRIDE) return !!o;
|
|
1662
1694
|
return i;
|
|
1663
1695
|
} else if (optRead(e)) {
|
|
1664
1696
|
const t = optHooks.has(e, n);
|
|
@@ -1693,7 +1725,7 @@ const traps = {
|
|
|
1693
1725
|
const t = getHasNode(e, n);
|
|
1694
1726
|
const r = read(t);
|
|
1695
1727
|
i = readSource(e, n, true);
|
|
1696
|
-
if (!r && (!e.ch || t.
|
|
1728
|
+
if (!r && (!e.ch || t.l & CONFIG_OVERRIDE || !(n in i))) return undefined;
|
|
1697
1729
|
} else i = readSource(e, n, true);
|
|
1698
1730
|
let l;
|
|
1699
1731
|
if (!o && optRead(e)) {
|
|
@@ -1714,15 +1746,22 @@ const traps = {
|
|
|
1714
1746
|
// pollution guard (core R30)
|
|
1715
1747
|
const i = e.s ? t : unwrapValue(t);
|
|
1716
1748
|
const l = ensurePB(e);
|
|
1717
|
-
|
|
1749
|
+
// #4146 (R1: node existence is unobservable; #3706: the hold's unit is
|
|
1750
|
+
// the key): a user setter writing a key a HELD container's staging left
|
|
1751
|
+
// unchanged would write it into the held staging — read as the hold's
|
|
1752
|
+
// until its landing, while the same key with a leaf (a live reader)
|
|
1753
|
+
// publishes at the flush. The key gets its leaf first, born from the two
|
|
1754
|
+
// frames (`bornStaged`: a key the hold left unchanged — or added — is
|
|
1755
|
+
// unstaged and held by no one; a key the hold changed is born held, A34
|
|
1756
|
+
// (1)), and the write stages on it (A28; a write by the holder joins it,
|
|
1757
|
+
// A34) — as it would with a reader's leaf. Kept while the container is
|
|
1758
|
+
// held (`deferredReleases`).
|
|
1759
|
+
if (userWrite && e.k?.l & CONFIG_HELD) deferredReleases.add(getNode(e, n));
|
|
1718
1760
|
if (Array.isArray(l)) {
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
t.add(n);
|
|
1722
|
-
t.add("length");
|
|
1723
|
-
}
|
|
1761
|
+
touch(e, n);
|
|
1762
|
+
if (n === "length") e.wk = WK_ALL; else touch(e, "length");
|
|
1724
1763
|
} else {
|
|
1725
|
-
|
|
1764
|
+
touch(e, n);
|
|
1726
1765
|
if (!(n in l)) e.kc++;
|
|
1727
1766
|
}
|
|
1728
1767
|
if (UNSAFE_KEYS.has(n)) {
|
|
@@ -1760,8 +1799,7 @@ const traps = {
|
|
|
1760
1799
|
};
|
|
1761
1800
|
const i = ensurePB(e);
|
|
1762
1801
|
if (e.a || !(t.enumerable && t.writable && t.configurable)) e.sc = 1;
|
|
1763
|
-
|
|
1764
|
-
if (e.wk !== WK_ALL) (e.wk ??= new Set).add(n);
|
|
1802
|
+
touch(e, n);
|
|
1765
1803
|
Object.defineProperty(i, n, t);
|
|
1766
1804
|
if (e.del !== null) e.del.delete(n);
|
|
1767
1805
|
if (o) notifyWrites(e);
|
|
@@ -1772,10 +1810,22 @@ const traps = {
|
|
|
1772
1810
|
const r = !t && writeOverride;
|
|
1773
1811
|
if (!t && !r) return true;
|
|
1774
1812
|
const o = ensurePB(e);
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
delete
|
|
1778
|
-
|
|
1813
|
+
touch(e, n);
|
|
1814
|
+
// The key count (`kc`, the overlay gate and the rebuild cap) follows a
|
|
1815
|
+
// delete the way it follows an add: an own key of the draft leaving — a
|
|
1816
|
+
// clone's key, or an overlay's own add — is one fewer now. An overlay's
|
|
1817
|
+
// override of a committed key is the exception: the committed key's
|
|
1818
|
+
// deletion is recorded in `del` and counted at the rebuild, as before.
|
|
1819
|
+
// Without the decrement the natural "delete the old key, set the new
|
|
1820
|
+
// one" shape drifted the count up by one per write until a three-key
|
|
1821
|
+
// object crossed the overlay threshold and paid a rebuild on every
|
|
1822
|
+
// commit after.
|
|
1823
|
+
const i = e.ovl && hasOwn.call(e.v, n);
|
|
1824
|
+
if (hasOwn.call(o, n)) {
|
|
1825
|
+
delete o[n];
|
|
1826
|
+
i || e.kc--;
|
|
1827
|
+
}
|
|
1828
|
+
if (i) (e.del ??= new Set).add(n);
|
|
1779
1829
|
if (r) notifyWrites(e);
|
|
1780
1830
|
return true;
|
|
1781
1831
|
}
|
|
@@ -1786,11 +1836,12 @@ const traps = {
|
|
|
1786
1836
|
* to the key's presence node or a later add never re-runs it. */ function observerHoldsContainer(e, n) {
|
|
1787
1837
|
const t = e.k;
|
|
1788
1838
|
if (t === null) return false;
|
|
1789
|
-
const r = t.
|
|
1790
|
-
return r !== null && r.
|
|
1839
|
+
const r = t.dt;
|
|
1840
|
+
return r !== null && r.u === n && (!(n.R & REACTIVE_RECOMPUTING_DEPS) || r.Te === n.Ne);
|
|
1791
1841
|
}
|
|
1792
1842
|
|
|
1793
1843
|
function storeSetter(e, n, t = true) {
|
|
1844
|
+
if (writeHook !== null) writeHook(e);
|
|
1794
1845
|
const r = e[$TARGET];
|
|
1795
1846
|
const o = writeScopes;
|
|
1796
1847
|
writeScopes = new Set;
|
|
@@ -1844,6 +1895,8 @@ function storeSetter(e, n, t = true) {
|
|
|
1844
1895
|
function createStore(e, n) {
|
|
1845
1896
|
const t = n?.shallow === true;
|
|
1846
1897
|
const r = wrap(e);
|
|
1898
|
+
// Dependency edges (store/edges.ts): the root is named like a plain signal.
|
|
1899
|
+
if (signalHook !== null) signalHook(r[$TARGET]);
|
|
1847
1900
|
if (t) {
|
|
1848
1901
|
r[$TARGET].s = true;
|
|
1849
1902
|
markRawIngest(e);
|
|
@@ -1858,7 +1911,7 @@ function createStore(e, n) {
|
|
|
1858
1911
|
// disabled, buys nothing.
|
|
1859
1912
|
if (attrHooks !== null) {
|
|
1860
1913
|
storeOwners.set(r[$TARGET], e);
|
|
1861
|
-
nameStore(r, n?.name);
|
|
1914
|
+
nameStore(r, n?.name, n?.loc);
|
|
1862
1915
|
}
|
|
1863
1916
|
}
|
|
1864
1917
|
const setter = e => storeSetter(r, e);
|
|
@@ -1987,7 +2040,7 @@ function snapshotWalk(e, n, t) {
|
|
|
1987
2040
|
// R27: a snapshot sees the batch's pending backing — a held one (another
|
|
1988
2041
|
// transaction's future) only from its own draft.
|
|
1989
2042
|
let i = o.v;
|
|
1990
|
-
if (o.pb !== null && (inDraft(o) || writeOverride || o.k === null || !(o.k.
|
|
2043
|
+
if (o.pb !== null && (inDraft(o) || writeOverride || o.k === null || !(o.k.l & CONFIG_HELD))) {
|
|
1991
2044
|
if (o.ovl) materializePB(o);
|
|
1992
2045
|
i = o.pb;
|
|
1993
2046
|
}
|