@solidjs/signals 2.0.0-rc.14 → 2.0.0-rc.15
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 +248 -189
- package/dist/dev.attribution.js +124 -41
- package/dist/dev.js +553 -322
- package/dist/observe/affects.js +34 -31
- package/dist/observe/boundaries.js +166 -132
- package/dist/observe/core/async.js +90 -83
- package/dist/observe/core/attribution-queries.js +1 -1
- package/dist/observe/core/attribution.js +281 -197
- package/dist/observe/core/constants.js +7 -2
- package/dist/observe/core/context.js +3 -3
- package/dist/observe/core/core.js +277 -245
- package/dist/observe/core/dev.js +3 -3
- package/dist/observe/core/effect.js +21 -21
- package/dist/observe/core/external.js +2 -2
- package/dist/observe/core/graph.js +25 -25
- package/dist/observe/core/heap.js +9 -9
- package/dist/observe/core/lanes.js +206 -160
- package/dist/observe/core/owner.js +27 -27
- package/dist/observe/core/scheduler.js +92 -86
- package/dist/observe/core/verdict.js +66 -54
- package/dist/observe/map.js +35 -35
- package/dist/observe/reveal.js +24 -24
- package/dist/observe/signals.js +38 -28
- package/dist/observe/store/affects.js +75 -68
- package/dist/observe/store/hooks.js +13 -0
- package/dist/observe/store/index.js +0 -2
- package/dist/observe/store/optimistic.js +67 -34
- package/dist/observe/store/projection.js +37 -31
- package/dist/observe/store/reconcile.js +32 -30
- package/dist/observe/store/store.js +128 -85
- package/dist/prod/affects.js +34 -31
- package/dist/prod/boundaries.js +143 -109
- package/dist/prod/core/async.js +64 -67
- package/dist/prod/core/constants.js +7 -2
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +302 -270
- package/dist/prod/core/effect.js +38 -38
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +27 -27
- package/dist/prod/core/heap.js +30 -30
- package/dist/prod/core/lanes.js +257 -211
- package/dist/prod/core/owner.js +39 -39
- package/dist/prod/core/scheduler.js +125 -119
- package/dist/prod/core/verdict.js +70 -58
- package/dist/prod/map.js +73 -73
- package/dist/prod/reveal.js +38 -38
- package/dist/prod/signals.js +30 -20
- package/dist/prod/store/affects.js +75 -68
- package/dist/prod/store/hooks.js +13 -0
- package/dist/prod/store/index.js +0 -2
- package/dist/prod/store/optimistic.js +114 -81
- package/dist/prod/store/projection.js +30 -24
- package/dist/prod/store/reconcile.js +32 -30
- package/dist/prod/store/store.js +136 -93
- package/dist/types/boundaries.d.ts +4 -0
- package/dist/types/core/attribution.d.ts +6 -2
- package/dist/types/core/constants.d.ts +5 -0
- package/dist/types/core/core.d.ts +33 -3
- package/dist/types/core/lanes.d.ts +10 -0
- package/dist/types/core/scheduler.d.ts +12 -6
- package/dist/types/core/types.d.ts +0 -6
- package/dist/types/store/affects.d.ts +11 -0
- package/dist/types/store/hooks.d.ts +48 -0
- package/dist/types/store/index.d.ts +0 -1
- package/dist/types/store/store.d.ts +3 -38
- package/package.json +1 -1
package/dist/prod/reveal.js
CHANGED
|
@@ -41,8 +41,8 @@ const slotMinReady = t => isController(t) ? t.Ct() : ready(t);
|
|
|
41
41
|
* (`!gated`), a nested controller leaves its parent's ownership and runs its
|
|
42
42
|
* own order; a boundary leaves when it has shown content (boundaries.ts). */ function setSlotState(t, e, s, r) {
|
|
43
43
|
if (isController(t)) {
|
|
44
|
-
t.
|
|
45
|
-
t.
|
|
44
|
+
t.ne = s;
|
|
45
|
+
t.re = r;
|
|
46
46
|
t.vt();
|
|
47
47
|
// Released and ready — every slot of its own has shown — it graduates,
|
|
48
48
|
// as a boundary does when it shows content. Released at the frontier
|
|
@@ -50,9 +50,9 @@ const slotMinReady = t => isController(t) ? t.Ct() : ready(t);
|
|
|
50
50
|
if (!s && t.Lt && t._parent === e) t._parent = null;
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
|
-
if (t.
|
|
54
|
-
t.
|
|
55
|
-
t.
|
|
53
|
+
if (t.ne !== s || t.re !== r) {
|
|
54
|
+
t.ne = s;
|
|
55
|
+
t.re = r;
|
|
56
56
|
redraw(t);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
@@ -64,32 +64,32 @@ class RevealController {
|
|
|
64
64
|
/** The controller gating this one, until it releases this one. */
|
|
65
65
|
_parent=null;
|
|
66
66
|
/** The state a parent forces on this whole group. */
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
ne=false;
|
|
68
|
+
re=false;
|
|
69
69
|
Lt=true;
|
|
70
70
|
Qt=true;
|
|
71
|
-
|
|
71
|
+
Tt=false;
|
|
72
72
|
constructor(t, e) {
|
|
73
73
|
this.qt = t;
|
|
74
74
|
this.Vt = e;
|
|
75
75
|
}
|
|
76
76
|
/** A slot that has left this controller's ownership: a boundary that has
|
|
77
77
|
* shown content, a nested group that is ready. Shown is shown — it counts
|
|
78
|
-
* as ready whatever happens to it later (a re-arm gates nobody else). */
|
|
79
|
-
return (isController(t) ? t._parent : t.
|
|
78
|
+
* as ready whatever happens to it later (a re-arm gates nobody else). */ Ut(t) {
|
|
79
|
+
return (isController(t) ? t._parent : t.H) !== this;
|
|
80
80
|
}
|
|
81
81
|
/** The slots this controller still owns, in registration order — the
|
|
82
|
-
* ones the order's state is forced on. */
|
|
82
|
+
* ones the order's state is forced on. */ Wt(t) {
|
|
83
83
|
for (let e = 0; e < this.Ft.length; e++) {
|
|
84
84
|
const s = this.Ft[e];
|
|
85
|
-
if (!this.
|
|
85
|
+
if (!this.Ut(s) && t(s) === false) return false;
|
|
86
86
|
}
|
|
87
87
|
return true;
|
|
88
88
|
}
|
|
89
89
|
/** Readiness is judged over every slot, done ones as ready. */ Rt() {
|
|
90
90
|
for (let t = 0; t < this.Ft.length; t++) {
|
|
91
91
|
const e = this.Ft[t];
|
|
92
|
-
if (!this.
|
|
92
|
+
if (!this.Ut(e) && !slotReady(e)) return false;
|
|
93
93
|
}
|
|
94
94
|
return true;
|
|
95
95
|
}
|
|
@@ -99,14 +99,14 @@ class RevealController {
|
|
|
99
99
|
const t = untrack(this.qt);
|
|
100
100
|
const e = this.Ft;
|
|
101
101
|
if (e.length === 0) return true;
|
|
102
|
-
if (t === "sequential") return this.
|
|
102
|
+
if (t === "sequential") return this.Ut(e[0]) || slotMinReady(e[0]);
|
|
103
103
|
for (let s = 0; s < e.length; s++) {
|
|
104
|
-
const r = this.
|
|
104
|
+
const r = this.Ut(e[s]) || slotMinReady(e[s]);
|
|
105
105
|
if (t === "natural" ? r : !r) return t === "natural";
|
|
106
106
|
}
|
|
107
107
|
return t !== "natural";
|
|
108
108
|
}
|
|
109
|
-
|
|
109
|
+
ue(t) {
|
|
110
110
|
if (this.Ft.includes(t)) return;
|
|
111
111
|
this.Ft.push(t);
|
|
112
112
|
// Gated from the start (collapsed in a collapsed sequential tail); the
|
|
@@ -114,42 +114,42 @@ class RevealController {
|
|
|
114
114
|
const e = untrack(this.qt) === "sequential" && !!untrack(this.Vt);
|
|
115
115
|
if (isController(t)) {
|
|
116
116
|
t._parent = this;
|
|
117
|
-
t.
|
|
118
|
-
t.
|
|
117
|
+
t.ne = true;
|
|
118
|
+
t.re = e;
|
|
119
119
|
t.vt();
|
|
120
120
|
} else {
|
|
121
|
-
t.
|
|
122
|
-
t.
|
|
123
|
-
t.
|
|
121
|
+
t.H = this;
|
|
122
|
+
t.ne = true;
|
|
123
|
+
t.re = e;
|
|
124
124
|
}
|
|
125
125
|
untrack(() => this.vt());
|
|
126
126
|
}
|
|
127
|
-
|
|
127
|
+
oe(t) {
|
|
128
128
|
const e = this.Ft.indexOf(t);
|
|
129
129
|
if (e >= 0) this.Ft.splice(e, 1);
|
|
130
130
|
untrack(() => this.vt());
|
|
131
131
|
}
|
|
132
132
|
/** Apply the order to the owned slots — or, gated by a parent, its state
|
|
133
133
|
* to all of them. */ vt() {
|
|
134
|
-
if (this.
|
|
135
|
-
this.
|
|
134
|
+
if (this.Tt) return;
|
|
135
|
+
this.Tt = true;
|
|
136
136
|
const t = this.Lt;
|
|
137
137
|
const e = this.Qt;
|
|
138
138
|
try {
|
|
139
139
|
const t = untrack(this.qt);
|
|
140
140
|
const e = t === "sequential" && !!untrack(this.Vt);
|
|
141
|
-
if (this.
|
|
142
|
-
this.
|
|
141
|
+
if (this.ne) {
|
|
142
|
+
this.Wt(t => setSlotState(t, this, true, this.re));
|
|
143
143
|
} else if (t === "natural") {
|
|
144
|
-
this.
|
|
144
|
+
this.Wt(t => {
|
|
145
145
|
if (isController(t)) setSlotState(t, this, false, false); else setSlotState(t, this, !ready(t), false);
|
|
146
146
|
});
|
|
147
147
|
} else if (t === "together") {
|
|
148
|
-
const t = this.
|
|
149
|
-
this.
|
|
148
|
+
const t = this.Wt(slotMinReady);
|
|
149
|
+
this.Wt(e => setSlotState(e, this, !t, false));
|
|
150
150
|
} else {
|
|
151
151
|
let t = false;
|
|
152
|
-
this.
|
|
152
|
+
this.Wt(s => {
|
|
153
153
|
if (t) return setSlotState(s, this, true, e);
|
|
154
154
|
if (slotReady(s)) return setSlotState(s, this, false, false);
|
|
155
155
|
t = true;
|
|
@@ -161,7 +161,7 @@ class RevealController {
|
|
|
161
161
|
} finally {
|
|
162
162
|
this.Lt = this.Rt();
|
|
163
163
|
this.Qt = this.Ct();
|
|
164
|
-
this.
|
|
164
|
+
this.Tt = false;
|
|
165
165
|
}
|
|
166
166
|
if (this._parent !== null && (t !== this.Lt || e !== this.Qt)) this._parent.vt();
|
|
167
167
|
}
|
|
@@ -179,10 +179,10 @@ class RevealController {
|
|
|
179
179
|
* slots behind the frontier render nothing instead of their fallbacks
|
|
180
180
|
*/ function createRevealOrder(t, e) {
|
|
181
181
|
const s = createOwner();
|
|
182
|
-
const r = s.
|
|
182
|
+
const r = s.D[REVEAL];
|
|
183
183
|
const i = new RevealController(e?.order || SEQUENTIAL_ACCESSOR, e?.collapsed || FALSE_ACCESSOR);
|
|
184
|
-
s.
|
|
185
|
-
...s.
|
|
184
|
+
s.D = {
|
|
185
|
+
...s.D,
|
|
186
186
|
[REVEAL]: i
|
|
187
187
|
};
|
|
188
188
|
return runWithOwner(s, () => {
|
|
@@ -194,8 +194,8 @@ class RevealController {
|
|
|
194
194
|
});
|
|
195
195
|
if (false) ;
|
|
196
196
|
if (r) {
|
|
197
|
-
r.
|
|
198
|
-
cleanup(() => r.
|
|
197
|
+
r.ue(i);
|
|
198
|
+
cleanup(() => r.oe(i));
|
|
199
199
|
}
|
|
200
200
|
return e;
|
|
201
201
|
});
|
|
@@ -204,9 +204,9 @@ class RevealController {
|
|
|
204
204
|
// Installed at module evaluation — present exactly when something imports
|
|
205
205
|
// `createRevealOrder`; a Loading boundary without one pays a null check.
|
|
206
206
|
setRevealHooks({
|
|
207
|
-
ae: (t, e) => t.ae(e),
|
|
208
207
|
ue: (t, e) => t.ue(e),
|
|
209
|
-
|
|
208
|
+
oe: (t, e) => t.oe(e),
|
|
209
|
+
P: t => t.vt()
|
|
210
210
|
});
|
|
211
211
|
|
|
212
212
|
export { createRevealOrder };
|
package/dist/prod/signals.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { NotReadyError, unwrapStatusError
|
|
1
|
+
import { TimeoutError, NotReadyError, unwrapStatusError } from "./core/error.js";
|
|
2
2
|
|
|
3
3
|
import "./core/verdict.js";
|
|
4
4
|
|
|
5
|
-
import { CONFIG_CHILDREN_FORBIDDEN, EFFECT_USER, $REFRESH, CONFIG_REDERIVE, REACTIVE_JOINED,
|
|
5
|
+
import { CONFIG_CHILDREN_FORBIDDEN, EFFECT_USER, $REFRESH, CONFIG_AUTO_DISPOSE, CONFIG_AUTHORITATIVE, CONFIG_REDERIVE, REACTIVE_JOINED, CONFIG_FRESH_READ, CONFIG_GUESS, STATUS_PENDING, STATUS_ERROR } from "./core/constants.js";
|
|
6
6
|
|
|
7
7
|
import { computed, signal, runWithOwner, setMemo, setSignal, markRefresh, read, untrack } from "./core/core.js";
|
|
8
8
|
|
|
9
|
-
import { globalQueue, flushTransaction, resolveTx, passTx, staleReader,
|
|
9
|
+
import { globalQueue, flushTransaction, dirtyQueue, GlobalQueue, resolveTx, passTx, staleReader, joinFuture } from "./core/scheduler.js";
|
|
10
10
|
|
|
11
11
|
import { cleanup, createRoot, getOwner, dispose } from "./core/owner.js";
|
|
12
12
|
|
|
13
13
|
import { effect, trackedEffect } from "./core/effect.js";
|
|
14
14
|
|
|
15
|
-
import { optimisticWrite } from "./core/lanes.js";
|
|
15
|
+
import { optimisticWrite, truthRead, truthConfirmed } from "./core/lanes.js";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Low-level reactive-cleanup primitive. Registers a callback that runs when
|
|
@@ -71,7 +71,7 @@ function accessor(e) {
|
|
|
71
71
|
function createSignal(e, t) {
|
|
72
72
|
if (typeof e === "function") {
|
|
73
73
|
const r = computed(e, t);
|
|
74
|
-
r.
|
|
74
|
+
r.i &= ~CONFIG_AUTO_DISPOSE;
|
|
75
75
|
return [ accessor(r), setMemo.bind(null, r) ];
|
|
76
76
|
}
|
|
77
77
|
const r = signal(e, t);
|
|
@@ -81,7 +81,7 @@ function createSignal(e, t) {
|
|
|
81
81
|
function createOptimistic(e, t) {
|
|
82
82
|
if (typeof e === "function") {
|
|
83
83
|
const r = computed(e, t);
|
|
84
|
-
r.
|
|
84
|
+
r.i &= ~CONFIG_AUTO_DISPOSE;
|
|
85
85
|
return [ accessor(r), optimisticWrite.bind(null, r) ];
|
|
86
86
|
}
|
|
87
87
|
const r = signal(e, t);
|
|
@@ -320,11 +320,15 @@ function createMemo(e, t) {
|
|
|
320
320
|
* - a mainline reader whose pass read a frame another transaction holds
|
|
321
321
|
* joined it (L2, born held — A29) and delivers at that commit: the
|
|
322
322
|
* committed view, never a foreign hold's unrevealed frame. */ function watch(e, t, r, n = 0, o, c = flushTransaction) {
|
|
323
|
+
if (n & CONFIG_AUTHORITATIVE) {
|
|
324
|
+
GlobalQueue.En = truthRead;
|
|
325
|
+
GlobalQueue.un = truthConfirmed;
|
|
326
|
+
}
|
|
323
327
|
// `config` is on the node for its first pass too (the pass runs inside
|
|
324
328
|
// `computed()`): `until`'s predicate is authoritative from its first read,
|
|
325
329
|
// or an already-displayed guess would satisfy it in a later slice. (REDERIVE
|
|
326
330
|
// after: the first pass's own error is the promise's rejection.)
|
|
327
|
-
|
|
331
|
+
computed(() => {
|
|
328
332
|
let n;
|
|
329
333
|
try {
|
|
330
334
|
n = e();
|
|
@@ -343,8 +347,8 @@ function createMemo(e, t) {
|
|
|
343
347
|
o?.(n);
|
|
344
348
|
queueMicrotask(() => t(n));
|
|
345
349
|
}, {
|
|
346
|
-
|
|
347
|
-
}).
|
|
350
|
+
Me: n
|
|
351
|
+
}).i |= CONFIG_REDERIVE;
|
|
348
352
|
}
|
|
349
353
|
|
|
350
354
|
/**
|
|
@@ -430,23 +434,29 @@ function createMemo(e, t) {
|
|
|
430
434
|
const r = flushTransaction;
|
|
431
435
|
const n = new Promise((n, o) => {
|
|
432
436
|
queueMicrotask(() => {
|
|
433
|
-
//
|
|
434
|
-
//
|
|
435
|
-
//
|
|
436
|
-
// capture runs inside the watcher's
|
|
437
|
-
// IS the watcher — exactly what
|
|
437
|
+
// The root is load-bearing: an ownerless computed is auto-disposing,
|
|
438
|
+
// and the settle walk releases an unobserved one instead of re-running
|
|
439
|
+
// it, so the waiter would never see the refetch land (#3888). Settle
|
|
440
|
+
// disposes the waiter directly; the capture runs inside the watcher's
|
|
441
|
+
// own pass, where the ambient owner IS the watcher — exactly what
|
|
442
|
+
// dispose() takes.
|
|
438
443
|
let c = null;
|
|
439
444
|
const make = () => watch(() => {
|
|
440
445
|
if (c === null) c = getOwner();
|
|
441
|
-
|
|
446
|
+
// Authoritative: the truth beneath a guess (`until`'s view). A
|
|
447
|
+
// guessed node's own re-ask is not answered by it (#3895): park
|
|
448
|
+
// on that flight, or reject with its error.
|
|
449
|
+
const e = read(t);
|
|
450
|
+
if (t.i & CONFIG_GUESS && t.S & (STATUS_PENDING | STATUS_ERROR)) throw t.m?.F;
|
|
451
|
+
return e;
|
|
442
452
|
}, t => {
|
|
443
453
|
n(typeof e === "function" ? t : e);
|
|
444
454
|
dispose(c);
|
|
445
455
|
}, e => {
|
|
446
456
|
o(e);
|
|
447
457
|
dispose(c);
|
|
448
|
-
}, CONFIG_FRESH_READ, undefined, r);
|
|
449
|
-
make
|
|
458
|
+
}, CONFIG_FRESH_READ | CONFIG_AUTHORITATIVE, undefined, r);
|
|
459
|
+
createRoot(make);
|
|
450
460
|
});
|
|
451
461
|
});
|
|
452
462
|
// Fire-and-forget refresh must not turn a failed refetch into an unhandled
|
|
@@ -515,7 +525,7 @@ function createMemo(e, t) {
|
|
|
515
525
|
// The flip, inside the pass of the flush carrying it: the flush
|
|
516
526
|
// joins the action's transaction, and what it staged is held and
|
|
517
527
|
// revealed with the action.
|
|
518
|
-
if (e && c !== null && globalQueue.
|
|
528
|
+
if (e && c !== null && globalQueue.X && resolveTx(c).tt !== 0) joinFuture(c);
|
|
519
529
|
});
|
|
520
530
|
if (t?.timeout !== undefined) i = setTimeout(() => settle(() => n(new TimeoutError)), t.timeout);
|
|
521
531
|
if (o !== undefined) {
|
|
@@ -623,7 +633,7 @@ function createMemo(e, t) {
|
|
|
623
633
|
* on owner disposal
|
|
624
634
|
*/ function onSettled(e) {
|
|
625
635
|
const t = getOwner();
|
|
626
|
-
t && !(t.
|
|
636
|
+
t && !(t.i & CONFIG_CHILDREN_FORBIDDEN) ? trackedEffect(() => untrack(e), undefined) : globalQueue.enqueue(EFFECT_USER, function fire() {
|
|
627
637
|
// Settled means derived. A settle that reverts optimism (or replays
|
|
628
638
|
// gated reads) only enqueues the affected subscribers; the pass after
|
|
629
639
|
// the commit re-derives them. Fired in the commit pass, the callback
|
|
@@ -631,7 +641,7 @@ function createMemo(e, t) {
|
|
|
631
641
|
// still holding the optimistic value — reads do not pull (#3411). Fall
|
|
632
642
|
// to the next pass while the heap has work; `run` swapped the queue,
|
|
633
643
|
// so this lands there, and `enqueue` keeps the drain alive.
|
|
634
|
-
if (dirtyQueue.
|
|
644
|
+
if (dirtyQueue.ft >= dirtyQueue.Ue) return globalQueue.enqueue(EFFECT_USER, fire);
|
|
635
645
|
// Unowned, out-of-band fire (no owner, or a children-forbidden one this
|
|
636
646
|
// one-shot must not bind to): a returned cleanup has no lifecycle to
|
|
637
647
|
// attach to. Reject it in dev; in production the return is simply
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { GlobalQueue } from "../core/scheduler.js";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { optHooks, installAffectsHooks } from "./hooks.js";
|
|
4
4
|
|
|
5
5
|
import { lookupTarget, $OWNER } from "./target.js";
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { $TARGET } from "./types.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Store — the store half of `affects()` (plan sec. 29, plan sec. 37; A24 (4), #2882,
|
|
@@ -23,113 +23,120 @@ import { isWrappable, $TARGET } from "./types.js";
|
|
|
23
23
|
* the verdict. A mark declared on a draft (inside a setter) or over an
|
|
24
24
|
* optimistic family walks the view the writer sees.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
26
|
+
* Imported by `affects()`, which installs it on its first store target
|
|
27
|
+
* (#3891, after #3912): a program with stores that never declares a mark
|
|
28
|
+
* carries none of it. It never imports store.ts — the engine's top level —
|
|
29
|
+
* so a program declaring marks without stores carries this module alone:
|
|
30
|
+
* the store's nodes and its wrappability test come through `GlobalQueue`
|
|
31
|
+
* (`_storeNode`, `_storeWrappable`), and node birth and the untracked traps
|
|
32
|
+
* reach back through `affectsHooks` (hooks.ts).
|
|
28
33
|
*/
|
|
29
34
|
/** The keyless mark's carrier key: a leaf of the record no read serves. */ const $AFFECTS = Symbol(0);
|
|
30
35
|
|
|
31
36
|
const scopes = new Map;
|
|
32
37
|
|
|
38
|
+
function scopeOf(e, o) {
|
|
39
|
+
let n = scopes.get(e);
|
|
40
|
+
if (n === undefined) scopes.set(e, n = {
|
|
41
|
+
eo: new Set,
|
|
42
|
+
oo: [],
|
|
43
|
+
ot: o
|
|
44
|
+
});
|
|
45
|
+
return n;
|
|
46
|
+
}
|
|
47
|
+
|
|
33
48
|
/** The nodes an `affects(store[, key])` declaration marks (affects.ts
|
|
34
|
-
* registers each). */ function storeMarks(e,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
});
|
|
42
|
-
const t = [ n ];
|
|
43
|
-
walk(e.px, o, t, e.fam, new Set);
|
|
44
|
-
return t;
|
|
49
|
+
* registers each). */ function storeMarks(e, o) {
|
|
50
|
+
const n = GlobalQueue.no(e, o === undefined ? $AFFECTS : o);
|
|
51
|
+
const t = scopeOf(n, o);
|
|
52
|
+
if (o === undefined) {
|
|
53
|
+
const o = [ n ];
|
|
54
|
+
walk(e.px, t, o, e.fam, new Set);
|
|
55
|
+
return o;
|
|
45
56
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
scope: new Set,
|
|
50
|
-
inherited: [],
|
|
51
|
-
key: n
|
|
52
|
-
});
|
|
53
|
-
t.scope.add(e.v);
|
|
54
|
-
if (e.pb !== null) t.scope.add(e.pb);
|
|
55
|
-
return [ o ];
|
|
57
|
+
t.eo.add(e.v);
|
|
58
|
+
if (e.pb !== null) t.eo.add(e.pb);
|
|
59
|
+
return [ n ];
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
/** The identities reachable from `value` into the scope (the draft's and
|
|
59
63
|
* the committed backing both, when a draft is open; an optimistic family's
|
|
60
64
|
* view), every live node under each record into `found`. Untracked by
|
|
61
|
-
* construction: raws, never traps. */ function walk(e,
|
|
62
|
-
if (!
|
|
65
|
+
* construction: raws, never traps. */ function walk(e, o, n, t, s) {
|
|
66
|
+
if (!GlobalQueue.so(e)) return;
|
|
63
67
|
const f = e[$TARGET] ?? lookupTarget(e, t);
|
|
64
|
-
let
|
|
65
|
-
if (s.has(
|
|
66
|
-
s.add(
|
|
67
|
-
|
|
68
|
+
let r = f !== undefined ? f.pb ?? f.v : e;
|
|
69
|
+
if (s.has(r)) return;
|
|
70
|
+
s.add(r);
|
|
71
|
+
o.eo.add(r);
|
|
68
72
|
if (f !== undefined) {
|
|
69
|
-
if (f.pb !== null)
|
|
73
|
+
if (f.pb !== null) o.eo.add(f.v);
|
|
70
74
|
// The writer's view: the tick's own unflushed guesses are in motion too.
|
|
71
|
-
if (f.fam?.opt === true)
|
|
75
|
+
if (f.fam?.opt === true) r = optHooks.view(f, r, true);
|
|
72
76
|
const e = f.n;
|
|
73
|
-
if (e !== null) for (const
|
|
77
|
+
if (e !== null) for (const o of Reflect.ownKeys(e))
|
|
74
78
|
// Another mark's carrier is its own channel: counting it here would
|
|
75
79
|
// extend that scope's lifetime to this declaration's.
|
|
76
|
-
if (
|
|
80
|
+
if (o !== $AFFECTS) n.push(e[o]);
|
|
77
81
|
const s = f.h;
|
|
78
|
-
if (s !== null) for (const e of Reflect.ownKeys(s))
|
|
79
|
-
if (f.k !== null)
|
|
80
|
-
if (f.dk !== null)
|
|
82
|
+
if (s !== null) for (const e of Reflect.ownKeys(s)) n.push(s[e]);
|
|
83
|
+
if (f.k !== null) n.push(f.k);
|
|
84
|
+
if (f.dk !== null) n.push(f.dk);
|
|
81
85
|
t = f.fam ?? t;
|
|
82
86
|
}
|
|
83
|
-
for (const e of Reflect.ownKeys(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (f === undefined || f.get !== undefined) continue;
|
|
87
|
-
walk(f.value, n, o, t, s);
|
|
87
|
+
for (const e of Reflect.ownKeys(r)) if (e !== $OWNER) {
|
|
88
|
+
const f = Object.getOwnPropertyDescriptor(r, e);
|
|
89
|
+
if (f.get === undefined) walk(f.value, o, n, t, s);
|
|
88
90
|
}
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
/** A live scope covering `t`'s identity (keyed: for `key`). Chained
|
|
92
94
|
* backings (§7b): a view's backing is another store's proxy — marks cover
|
|
93
|
-
* the BASE raw, so every identity along the chain is checked. */ function covering(e,
|
|
95
|
+
* the BASE raw, so every identity along the chain is checked. */ function covering(e, o, n) {
|
|
94
96
|
for (const [t, s] of scopes) {
|
|
95
|
-
if (t ===
|
|
96
|
-
for (let
|
|
97
|
-
if (s.
|
|
98
|
-
const e =
|
|
97
|
+
if (t === n || s.ot !== undefined && s.ot !== o) continue;
|
|
98
|
+
for (let o = e.v; ;) {
|
|
99
|
+
if (s.eo.has(o)) return t;
|
|
100
|
+
const e = o?.[$TARGET];
|
|
99
101
|
if (e === undefined) break;
|
|
100
|
-
const
|
|
101
|
-
if (
|
|
102
|
-
|
|
102
|
+
const n = e.pb ?? e.v;
|
|
103
|
+
if (n === o) break;
|
|
104
|
+
o = n;
|
|
103
105
|
}
|
|
104
106
|
}
|
|
105
107
|
return null;
|
|
106
108
|
}
|
|
107
109
|
|
|
108
|
-
|
|
110
|
+
/** The store's side: node birth and the untracked traps call it (store.ts,
|
|
111
|
+
* through `affectsHooks`) — with no live mark too: an empty scope map is
|
|
112
|
+
* no work. */ const hooks = {
|
|
109
113
|
// A node born on a record a live mark covers inherits it (released with
|
|
110
114
|
// the carrier's last registration).
|
|
111
|
-
|
|
112
|
-
if (
|
|
113
|
-
const t = covering(e,
|
|
114
|
-
if (t
|
|
115
|
-
GlobalQueue.
|
|
116
|
-
scopes.get(t).
|
|
115
|
+
fo(e, o, n) {
|
|
116
|
+
if (scopes.size === 0 || n === $AFFECTS) return;
|
|
117
|
+
const t = covering(e, n, o);
|
|
118
|
+
if (!t) return;
|
|
119
|
+
GlobalQueue.O(o);
|
|
120
|
+
scopes.get(t).oo.push(o);
|
|
117
121
|
},
|
|
118
122
|
// An untracked probe (`isPending(() => s.x)` with no observer) reading a
|
|
119
123
|
// record a live mark covers: no node carries the mark for it — the
|
|
120
124
|
// verdict is told directly.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (o !== undefined && o.m !== null && o.m.T !== 0 || covering(e, n) !== null) GlobalQueue.dt();
|
|
125
|
+
ro(e, o) {
|
|
126
|
+
if (e.n?.[$AFFECTS]?.m?.T || covering(e, o)) GlobalQueue.ct();
|
|
124
127
|
}
|
|
125
|
-
}
|
|
128
|
+
};
|
|
126
129
|
|
|
127
|
-
|
|
130
|
+
/** `affects()` calls it before a store-targeted declaration (idempotent). */ function installStoreAffects() {
|
|
131
|
+
installAffectsHooks(hooks);
|
|
132
|
+
}
|
|
128
133
|
|
|
129
134
|
/** The carrier's last mark released (affects.ts): its scope dies, and the
|
|
130
|
-
* nodes that inherited the mark release theirs. */
|
|
131
|
-
const
|
|
132
|
-
if (
|
|
135
|
+
* nodes that inherited the mark release theirs. */ function releaseMarkScope(e) {
|
|
136
|
+
const o = scopes.get(e);
|
|
137
|
+
if (o === undefined) return;
|
|
133
138
|
scopes.delete(e);
|
|
134
|
-
GlobalQueue.
|
|
135
|
-
}
|
|
139
|
+
GlobalQueue.k(o.oo);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export { installStoreAffects, releaseMarkScope, storeMarks };
|
package/dist/prod/store/index.js
CHANGED
|
@@ -2,8 +2,6 @@ import { createStore as createStore$1, deep as deep$1, snapshot as snapshot$1 }
|
|
|
2
2
|
|
|
3
3
|
export { storeHasFamily, storeHasOptimisticFamily, storeIsShallow } from "./store.js";
|
|
4
4
|
|
|
5
|
-
import "./affects.js";
|
|
6
|
-
|
|
7
5
|
export { createOptimisticStore } from "./optimistic.js";
|
|
8
6
|
|
|
9
7
|
import { createStoreDerived } from "./projection.js";
|