@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/affects.js
CHANGED
|
@@ -4,7 +4,9 @@ import { ext } from "./core/core.js";
|
|
|
4
4
|
|
|
5
5
|
import { enqueueSub } from "./core/heap.js";
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { schedule, resolveTx, flushTransaction, GlobalQueue } from "./core/scheduler.js";
|
|
8
|
+
|
|
9
|
+
import { storeMarks, installStoreAffects, releaseMarkScope } from "./store/affects.js";
|
|
8
10
|
|
|
9
11
|
import { $TARGET } from "./store/types.js";
|
|
10
12
|
|
|
@@ -36,12 +38,12 @@ let active = 0;
|
|
|
36
38
|
/** The verdict readers downstream of `node` — through derivations, stopping
|
|
37
39
|
* at effects — re-derive: the mark's one notification (a probe's answer
|
|
38
40
|
* changed with no value notifying anyone). */ function repoll(e, t = new Set) {
|
|
39
|
-
for (let
|
|
40
|
-
const e =
|
|
41
|
+
for (let r = e.t; r !== null; r = r.o) {
|
|
42
|
+
const e = r.l;
|
|
41
43
|
if (t.has(e)) continue;
|
|
42
44
|
t.add(e);
|
|
43
|
-
if (e.
|
|
44
|
-
if (!e.
|
|
45
|
+
if (e.i & CONFIG_VERDICT) enqueueSub(e);
|
|
46
|
+
if (!e.u) repoll(e, t);
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
|
|
@@ -51,13 +53,13 @@ let active = 0;
|
|
|
51
53
|
* (a direct mark on one still reads pending). Mid-recompute, only the
|
|
52
54
|
* validated prefix of the dependency list is this pass's. */ function marked(e, t) {
|
|
53
55
|
if (e.m !== null && e.m.T !== 0) return true;
|
|
54
|
-
const
|
|
55
|
-
if (
|
|
56
|
+
const r = e;
|
|
57
|
+
if (r.S & STATUS_ERROR || t.has(e)) return false;
|
|
56
58
|
t.add(e);
|
|
57
|
-
const
|
|
58
|
-
if (
|
|
59
|
+
const n = r.R & REACTIVE_RECOMPUTING_DEPS ? r.G : undefined;
|
|
60
|
+
if (n !== null) for (let e = r.p ?? null; e !== null; e = e._) {
|
|
59
61
|
if (marked(e.I, t)) return true;
|
|
60
|
-
if (e ===
|
|
62
|
+
if (e === n) break;
|
|
61
63
|
}
|
|
62
64
|
return false;
|
|
63
65
|
}
|
|
@@ -65,13 +67,13 @@ let active = 0;
|
|
|
65
67
|
/** Releases one scope's marks (a landed transaction's, the ambient list at
|
|
66
68
|
* the seam): a node whose last mark drops re-derives its verdict readers. */ function release(e) {
|
|
67
69
|
for (let t = 0; t < e.length; t++) {
|
|
68
|
-
const
|
|
70
|
+
const r = e[t];
|
|
69
71
|
active--;
|
|
70
|
-
if (--
|
|
71
|
-
repoll(
|
|
72
|
+
if (--r.m.T === 0) {
|
|
73
|
+
repoll(r);
|
|
72
74
|
// A store mark's carrier: its scope (and the marks the nodes born in
|
|
73
75
|
// its window inherited) goes with it.
|
|
74
|
-
|
|
76
|
+
releaseMarkScope(r);
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
79
|
e.length = 0;
|
|
@@ -82,8 +84,8 @@ let active = 0;
|
|
|
82
84
|
mark(e);
|
|
83
85
|
const t = flushTransaction;
|
|
84
86
|
if (t === null) ambient.push(e); else {
|
|
85
|
-
const
|
|
86
|
-
(
|
|
87
|
+
const r = resolveTx(t);
|
|
88
|
+
(r.T ??= []).push(e);
|
|
87
89
|
}
|
|
88
90
|
repoll(e);
|
|
89
91
|
}
|
|
@@ -96,28 +98,29 @@ function mark(e) {
|
|
|
96
98
|
function affects(e, t) {
|
|
97
99
|
// A store (the store half, store/affects.ts): the slot's leaf, or the
|
|
98
100
|
// record's carrier and every live node under it.
|
|
99
|
-
const
|
|
100
|
-
if (
|
|
101
|
-
|
|
101
|
+
const r = e?.[$TARGET];
|
|
102
|
+
if (r !== undefined) {
|
|
103
|
+
installStoreAffects();
|
|
104
|
+
const e = storeMarks(r, t);
|
|
102
105
|
for (let t = 0; t < e.length; t++) register(e[t]);
|
|
103
106
|
schedule();
|
|
104
107
|
return;
|
|
105
108
|
}
|
|
106
|
-
const
|
|
107
|
-
if (!
|
|
109
|
+
const n = e?.[$REFRESH];
|
|
110
|
+
if (!n) {
|
|
108
111
|
return;
|
|
109
112
|
}
|
|
110
|
-
register(
|
|
113
|
+
register(n);
|
|
111
114
|
schedule();
|
|
112
115
|
}
|
|
113
116
|
|
|
114
|
-
GlobalQueue.
|
|
117
|
+
GlobalQueue.N = e => active !== 0 && marked(e, new Set);
|
|
115
118
|
|
|
116
|
-
GlobalQueue.
|
|
119
|
+
GlobalQueue.O = mark;
|
|
117
120
|
|
|
118
|
-
GlobalQueue.
|
|
121
|
+
GlobalQueue.k = release;
|
|
119
122
|
|
|
120
|
-
GlobalQueue.
|
|
123
|
+
GlobalQueue.A = e => {
|
|
121
124
|
if (ambient.length === 0) return;
|
|
122
125
|
// The flush parked: the declaration's window is the frame's — the marks
|
|
123
126
|
// are its transaction's ("nothing async below ⇒ no window").
|
|
@@ -132,17 +135,17 @@ GlobalQueue.D = e => {
|
|
|
132
135
|
// the window is the flight's; the mark stays to the seam after the
|
|
133
136
|
// landing. The rest release: verdict-only, nothing to show.
|
|
134
137
|
let t = 0;
|
|
135
|
-
const
|
|
138
|
+
const r = [];
|
|
136
139
|
for (let e = 0; e < ambient.length; e++) {
|
|
137
|
-
const
|
|
138
|
-
if (inFlight(
|
|
140
|
+
const n = ambient[e];
|
|
141
|
+
if (inFlight(n)) ambient[t++] = n; else r.push(n);
|
|
139
142
|
}
|
|
140
143
|
ambient.length = t;
|
|
141
|
-
if (
|
|
144
|
+
if (r.length !== 0) release(r);
|
|
142
145
|
};
|
|
143
146
|
|
|
144
147
|
function inFlight(e) {
|
|
145
|
-
return (e.
|
|
148
|
+
return (e.S & STATUS_PENDING) !== 0 || (e.i & CONFIG_SLOT_NODE) !== 0 && GlobalQueue.C?.(e) === true;
|
|
146
149
|
}
|
|
147
150
|
|
|
148
151
|
export { affects };
|
package/dist/prod/boundaries.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { STATUS_PENDING, STATUS_ERROR, CONFIG_REDERIVE, REACTIVE_DISPOSED, STATUS_UNINITIALIZED, CONFIG_HELD, REACTIVE_ZOMBIE, CONFIG_VERDICT, REACTIVE_LANE_READ, CONFIG_OVERRIDE, EFFECT_USER, EFFECT_TRACKED } from "./core/constants.js";
|
|
1
|
+
import { STATUS_PENDING, STATUS_ERROR, CONFIG_REDERIVE, REACTIVE_DISPOSED, STATUS_UNINITIALIZED, CONFIG_HELD, EFFECT_RENDER, REACTIVE_ZOMBIE, CONFIG_VERDICT, REACTIVE_LANE_READ, CONFIG_OVERRIDE, EFFECT_USER, EFFECT_TRACKED } from "./core/constants.js";
|
|
2
2
|
|
|
3
3
|
import { signal, runWithOwner, computed, read, setSignal, recompute } from "./core/core.js";
|
|
4
4
|
|
|
@@ -10,7 +10,7 @@ import { link } from "./core/graph.js";
|
|
|
10
10
|
|
|
11
11
|
import { enqueueSub } from "./core/heap.js";
|
|
12
12
|
|
|
13
|
-
import { createOwner, getOwner, cleanup } from "./core/owner.js";
|
|
13
|
+
import { createOwner, getOwner, cleanup, dispose } from "./core/owner.js";
|
|
14
14
|
|
|
15
15
|
import { globalQueue, haltReactivity, passLane, joinFuture, GlobalQueue, flushTransaction, schedule, setPassLane, txOf } from "./core/scheduler.js";
|
|
16
16
|
|
|
@@ -73,34 +73,34 @@ function setRevealHooks(e) {
|
|
|
73
73
|
|
|
74
74
|
/** Boundaries with readers to sweep (or an arm to resolve) at the seam. */ const collecting = new Set;
|
|
75
75
|
|
|
76
|
-
const boundaryOf = e => e.
|
|
76
|
+
const boundaryOf = e => e.D[BOUNDARY];
|
|
77
77
|
|
|
78
78
|
/** Catches what reaches it: an error boundary always; a loading one until it
|
|
79
|
-
* has shown content, or while re-armed. */ const isCollecting = e => e.
|
|
79
|
+
* has shown content, or while re-armed. */ const isCollecting = e => e.u === STATUS_ERROR || !e.h || e.U;
|
|
80
80
|
|
|
81
81
|
/** The reader goes to the fallback: recorded, and the output re-derives
|
|
82
82
|
* (a no-op while the output's own pass is running — its post-check
|
|
83
83
|
* decides). */ function caught(e, n, r) {
|
|
84
|
-
if (e.
|
|
84
|
+
if (e.u === STATUS_ERROR) {
|
|
85
85
|
// An error boundary waits on what THREW (`StatusError.source`), not on
|
|
86
86
|
// the reader that saw it: the reader recovers the moment a refetch
|
|
87
87
|
// starts (its boundary catches the pending), while the error is settled
|
|
88
88
|
// only when its source is neither errored nor in flight. `reset` re-runs
|
|
89
89
|
// the same node.
|
|
90
|
-
r ??= n.m?.
|
|
90
|
+
r ??= n.m?.F;
|
|
91
91
|
n = r?.source ?? n;
|
|
92
92
|
const t = unwrapStatusError(r);
|
|
93
|
-
setSignal(e.
|
|
94
|
-
reportClientError(t, e.
|
|
93
|
+
setSignal(e.F, t);
|
|
94
|
+
reportClientError(t, e.L, n);
|
|
95
95
|
}
|
|
96
|
-
e.
|
|
96
|
+
e.V.add(n);
|
|
97
97
|
collecting.add(e);
|
|
98
|
-
if (e.
|
|
98
|
+
if (e.U) flip(e);
|
|
99
99
|
// Already showing the fallback: one more reader to wait on changes
|
|
100
100
|
// nothing on screen. The fallback is instantiated once per show — a later
|
|
101
101
|
// error reaches it through the `error` accessor, which is why it is one.
|
|
102
|
-
if (!e.
|
|
103
|
-
if (e.
|
|
102
|
+
if (!e.v) redraw(e);
|
|
103
|
+
if (e.H !== null) revealHooks.P(e.H);
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
/** A re-armed boundary found something pending: fresh again, and the swap
|
|
@@ -108,14 +108,14 @@ const boundaryOf = e => e.U[BOUNDARY];
|
|
|
108
108
|
* the lane's work from its next pass's head — not a re-pass of the
|
|
109
109
|
* transaction holding its pending content, which would entangle that
|
|
110
110
|
* transaction with the arming frame's (#3540 `on: () => latest(dep)`). */ function flip(e) {
|
|
111
|
-
e.
|
|
112
|
-
e.
|
|
113
|
-
if (e.
|
|
111
|
+
e.h = false;
|
|
112
|
+
e.B = e.j;
|
|
113
|
+
if (e.B !== null && e.Z !== null) GlobalQueue.W(e.Z, e.B, true, false);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
function redraw(e) {
|
|
117
|
-
if (e.
|
|
118
|
-
enqueueSub(e.
|
|
117
|
+
if (e.Z !== null && !(e.Z.R & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
118
|
+
enqueueSub(e.Z);
|
|
119
119
|
schedule();
|
|
120
120
|
}
|
|
121
121
|
}
|
|
@@ -131,26 +131,26 @@ function redraw(e) {
|
|
|
131
131
|
// held reader's landing has joined its transaction, so the content
|
|
132
132
|
// lands with its run, not a round after). Others still waiting: nothing
|
|
133
133
|
// on screen changes, the fallback stays as it is.
|
|
134
|
-
if (collecting.size !== 0) for (let n = boundaryOf(e); n !== undefined; n = n._parent ?? undefined) if (!(e.
|
|
135
|
-
if (n.
|
|
136
|
-
if (n.
|
|
134
|
+
if (collecting.size !== 0) for (let n = boundaryOf(e); n !== undefined; n = n._parent ?? undefined) if (!(e.S & unsettled(n)) && n.V.delete(e) && n.V.size === 0) {
|
|
135
|
+
if (n.v) redraw(n);
|
|
136
|
+
if (n.H !== null) revealHooks.P(n.H);
|
|
137
137
|
}
|
|
138
138
|
return false;
|
|
139
139
|
}
|
|
140
140
|
for (let t = boundaryOf(e); t !== undefined; t = t._parent ?? undefined) {
|
|
141
|
-
if (!(t.
|
|
141
|
+
if (!(t.u & n)) continue;
|
|
142
142
|
if (isCollecting(t)) {
|
|
143
143
|
caught(t, e, r);
|
|
144
144
|
return true;
|
|
145
145
|
}
|
|
146
|
-
t.
|
|
146
|
+
t.V.add(e);
|
|
147
147
|
collecting.add(t);
|
|
148
148
|
}
|
|
149
149
|
return false;
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
/** The nearest boundary on `r`'s chain showing its fallback, if any. */ function hiddenBy(e) {
|
|
153
|
-
for (let n = boundaryOf(e); n !== undefined; n = n._parent ?? undefined) if (n.
|
|
153
|
+
for (let n = boundaryOf(e); n !== undefined; n = n._parent ?? undefined) if (n.v) return n;
|
|
154
154
|
return undefined;
|
|
155
155
|
}
|
|
156
156
|
|
|
@@ -171,19 +171,19 @@ function redraw(e) {
|
|
|
171
171
|
* still showing its fallback holds it again then. */ function heldRun(e) {
|
|
172
172
|
const n = hiddenBy(e);
|
|
173
173
|
if (n === undefined) return false;
|
|
174
|
-
(n.
|
|
174
|
+
(n.K ??= new Set).add(e);
|
|
175
175
|
return true;
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
/** The reveal: the runs held behind the fallback are this flush's, each in
|
|
179
179
|
* its own phase — render updates with the frame that attaches the content,
|
|
180
180
|
* user effects after it. */ function release(e) {
|
|
181
|
-
if (e.
|
|
182
|
-
for (const n of e.
|
|
183
|
-
const e = n.
|
|
184
|
-
globalQueue.enqueue(e === EFFECT_TRACKED ? EFFECT_USER : e, e === EFFECT_TRACKED ? n.
|
|
181
|
+
if (e.K === null) return;
|
|
182
|
+
for (const n of e.K) {
|
|
183
|
+
const e = n.u;
|
|
184
|
+
globalQueue.enqueue(e === EFFECT_TRACKED ? EFFECT_USER : e, e === EFFECT_TRACKED ? n.M : n.Y ??= GlobalQueue.q.bind(null, n));
|
|
185
185
|
}
|
|
186
|
-
e.
|
|
186
|
+
e.K = null;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
/** Drop the readers that settled or died. Settled: a loading reader no
|
|
@@ -191,37 +191,40 @@ function redraw(e) {
|
|
|
191
191
|
* that landed but is held (its value staged in a transaction) is not: the
|
|
192
192
|
* content reveals at the commit, with its run. The tree is: the output reads
|
|
193
193
|
* it and enters the transaction itself (its committed value shows until the
|
|
194
|
-
* landing). */ const unsettled = e => e.
|
|
194
|
+
* landing). */ const unsettled = e => e.u === STATUS_ERROR ? STATUS_ERROR | STATUS_PENDING : STATUS_PENDING;
|
|
195
195
|
|
|
196
196
|
function prune(e, n) {
|
|
197
197
|
const r = unsettled(e);
|
|
198
|
-
for (const t of e.
|
|
199
|
-
if (t.R & REACTIVE_DISPOSED) e.
|
|
200
|
-
if (t !== e
|
|
198
|
+
for (const t of e.V) {
|
|
199
|
+
if (t.R & REACTIVE_DISPOSED) e.V.delete(t); else if (!(t.S & r)) {
|
|
200
|
+
if (t !== e.J && (t.i & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD) {
|
|
201
201
|
// Landed, held: the content is that transaction's — the output's
|
|
202
202
|
// pass enters it and the reveal lands with the reader's run. The
|
|
203
203
|
// seam, past its park decision, waits for the commit instead. (A
|
|
204
|
-
// lane's reader reveals with the lane, this round.)
|
|
205
|
-
|
|
204
|
+
// lane's reader reveals with the lane, this round.) A boundary that
|
|
205
|
+
// has not shown content catches it instead: the fallback stays until
|
|
206
|
+
// the reader is committed (#3540: what a fresh boundary catches holds
|
|
207
|
+
// nothing outside it).
|
|
208
|
+
if (!n || !e.h) continue;
|
|
206
209
|
joinFuture(txOf(t));
|
|
207
210
|
}
|
|
208
|
-
e.
|
|
211
|
+
e.V.delete(t);
|
|
209
212
|
}
|
|
210
213
|
}
|
|
211
|
-
return e.
|
|
214
|
+
return e.V.size;
|
|
212
215
|
}
|
|
213
216
|
|
|
214
217
|
/** Reveal order: a slot is ready when its content can show — it has shown
|
|
215
218
|
* content, or nothing under it is unready (the tree neither pending nor
|
|
216
219
|
* born held, no reader waited on). */ function ready(e) {
|
|
217
|
-
return e.
|
|
220
|
+
return e.h || !(e.J.S & STATUS_PENDING) && !(e.J.i & CONFIG_HELD && (e.Z === null || e.Z.S & STATUS_UNINITIALIZED)) && prune(e, false) === 0;
|
|
218
221
|
}
|
|
219
222
|
|
|
220
223
|
/** GlobalQueue._boundarySeam, end of the seam: readers that settled, died,
|
|
221
224
|
* or landed and committed are dropped; a fallback with none left reveals
|
|
222
225
|
* next round. An arm resolves: nothing collected, nothing happened. */ function boundarySeam() {
|
|
223
226
|
for (const e of collecting) {
|
|
224
|
-
const n = e.
|
|
227
|
+
const n = e.Z.R;
|
|
225
228
|
if (n & REACTIVE_DISPOSED) {
|
|
226
229
|
collecting.delete(e);
|
|
227
230
|
continue;
|
|
@@ -229,11 +232,11 @@ function prune(e, n) {
|
|
|
229
232
|
// A parked frame's boundary (zombie) keeps its state for its revival.
|
|
230
233
|
if (n & REACTIVE_ZOMBIE) continue;
|
|
231
234
|
prune(e, false);
|
|
232
|
-
e.
|
|
233
|
-
if (e.
|
|
235
|
+
e.U = false;
|
|
236
|
+
if (e.V.size === 0) {
|
|
234
237
|
collecting.delete(e);
|
|
235
|
-
if (e.
|
|
236
|
-
if (e.
|
|
238
|
+
if (e.v) redraw(e);
|
|
239
|
+
if (e.H !== null) revealHooks.P(e.H);
|
|
237
240
|
}
|
|
238
241
|
}
|
|
239
242
|
}
|
|
@@ -241,22 +244,22 @@ function prune(e, n) {
|
|
|
241
244
|
/** The `on` pass is a verdict's: it probed itself (CONFIG_VERDICT), or it
|
|
242
245
|
* read a memo that did (#3528's `createMemo(() => isPending(m2))`) — its
|
|
243
246
|
* swap is display-ahead either way. */ function verdictDerived(e) {
|
|
244
|
-
if (e.
|
|
245
|
-
for (let n = e.
|
|
247
|
+
if (e.i & CONFIG_VERDICT) return true;
|
|
248
|
+
for (let n = e.p; n !== null; n = n._) if (n.I.i & CONFIG_VERDICT) return true;
|
|
246
249
|
return false;
|
|
247
250
|
}
|
|
248
251
|
|
|
249
252
|
/** `on` changed after the mount: fresh again if anything under it is
|
|
250
253
|
* pending now; collecting for the rest of the flush either way. */ function arm(e) {
|
|
251
|
-
if (!e.
|
|
254
|
+
if (!e.h) {
|
|
252
255
|
// Already re-armed and on its fallback, as the frame's work — and the
|
|
253
256
|
// `on` pass arms again as lane work: its verdict was provisional (a
|
|
254
257
|
// memo of `isPending(m2)` is a watcher until the flush parks, then the
|
|
255
258
|
// holder's verdict lane's — verdict.ts), and the swap it asked for is
|
|
256
259
|
// display-ahead after all (#3528). Re-home the swap: the output re-runs
|
|
257
260
|
// as the lane's, shown now beside the held frame.
|
|
258
|
-
if (e.
|
|
259
|
-
e.
|
|
261
|
+
if (e.v && e.B === null && e.j === null && passLane !== null) {
|
|
262
|
+
e.j = passLane;
|
|
260
263
|
// The swap the frame's pass staged (held with the frame) is void: the
|
|
261
264
|
// lane's pass stages it anew (`flip` lists the output in the lane,
|
|
262
265
|
// which voids its staging), as a watcher's provisional value is
|
|
@@ -266,20 +269,20 @@ function prune(e, n) {
|
|
|
266
269
|
}
|
|
267
270
|
return;
|
|
268
271
|
}
|
|
269
|
-
e.
|
|
272
|
+
e.U = true;
|
|
270
273
|
// A verdict read in `on` (`isPending`) whose frame has no transaction
|
|
271
274
|
// yet: the swap is still display-ahead — the frame gets one now (it lands
|
|
272
275
|
// at this very seam if nothing holds it), and the swap is its verdict
|
|
273
276
|
// lane's work, shown ahead of the frame's own runs (#3528).
|
|
274
277
|
let n = passLane;
|
|
275
|
-
if (n === null && globalQueue.
|
|
278
|
+
if (n === null && globalQueue.X && verdictDerived(getOwner())) {
|
|
276
279
|
joinFuture(null);
|
|
277
|
-
n = GlobalQueue
|
|
280
|
+
n = GlobalQueue.$(flushTransaction);
|
|
278
281
|
}
|
|
279
|
-
e.
|
|
282
|
+
e.j = n;
|
|
280
283
|
collecting.add(e);
|
|
281
|
-
for (const n of e.
|
|
282
|
-
if (n.
|
|
284
|
+
for (const n of e.V) {
|
|
285
|
+
if (n.S & STATUS_PENDING && !(n.R & REACTIVE_DISPOSED)) {
|
|
283
286
|
flip(e);
|
|
284
287
|
redraw(e);
|
|
285
288
|
return;
|
|
@@ -290,35 +293,36 @@ function prune(e, n) {
|
|
|
290
293
|
/** The error boundary's `reset`: re-run what threw (a comparator throw
|
|
291
294
|
* names a signal — nothing to re-run). */ function reset(e) {
|
|
292
295
|
// A snapshot: a source failing again is caught — and re-added — mid-walk.
|
|
293
|
-
for (const n of [ ...e.
|
|
296
|
+
for (const n of [ ...e.V ]) if (n.ee !== undefined && !(n.R & REACTIVE_DISPOSED)) recompute(n);
|
|
294
297
|
schedule();
|
|
295
298
|
}
|
|
296
299
|
|
|
297
300
|
function createBoundary(e, n, r, t) {
|
|
298
301
|
const l = createOwner();
|
|
299
302
|
const o = {
|
|
300
|
-
|
|
303
|
+
u: e,
|
|
301
304
|
_parent: boundaryOf(l) ?? null,
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
K: null,
|
|
305
|
-
H: new Set,
|
|
306
|
-
L: false,
|
|
307
|
-
k: false,
|
|
308
|
-
W: null,
|
|
305
|
+
L: l,
|
|
306
|
+
J: null,
|
|
309
307
|
Z: null,
|
|
310
|
-
|
|
311
|
-
|
|
308
|
+
V: new Set,
|
|
309
|
+
h: false,
|
|
310
|
+
U: false,
|
|
311
|
+
j: null,
|
|
312
312
|
B: null,
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
313
|
+
v: false,
|
|
314
|
+
K: null,
|
|
315
|
+
H: null,
|
|
316
|
+
ne: false,
|
|
317
|
+
re: false,
|
|
318
|
+
F: e === STATUS_ERROR ? signal(undefined, ERROR_SIGNAL) : null,
|
|
319
|
+
te: r,
|
|
320
|
+
le: null
|
|
317
321
|
};
|
|
318
|
-
const u = e === STATUS_PENDING ? l.
|
|
322
|
+
const u = e === STATUS_PENDING ? l.D[REVEAL] : null;
|
|
319
323
|
if (getOwner()) cleanup(() => {
|
|
320
324
|
collecting.delete(o);
|
|
321
|
-
if (u) revealHooks.
|
|
325
|
+
if (u) revealHooks.oe(u, o);
|
|
322
326
|
});
|
|
323
327
|
// The `on` dependencies live OUTSIDE the boundary, as the condition of a
|
|
324
328
|
// `<Show>` wrapping it would: created before the owner's context names it.
|
|
@@ -340,14 +344,14 @@ function createBoundary(e, n, r, t) {
|
|
|
340
344
|
}
|
|
341
345
|
}
|
|
342
346
|
if (e) arm(o); else e = true;
|
|
343
|
-
})).
|
|
347
|
+
})).i |= CONFIG_REDERIVE;
|
|
344
348
|
}
|
|
345
349
|
const a = {
|
|
346
|
-
...l.
|
|
350
|
+
...l.D,
|
|
347
351
|
[BOUNDARY]: o
|
|
348
352
|
};
|
|
349
353
|
if (revealHooks !== null) a[REVEAL] = null;
|
|
350
|
-
l.
|
|
354
|
+
l.D = a;
|
|
351
355
|
const i = runWithOwner(l, () => {
|
|
352
356
|
const e = false ? computed(n, {
|
|
353
357
|
name: "children"
|
|
@@ -356,26 +360,26 @@ function createBoundary(e, n, r, t) {
|
|
|
356
360
|
name: "boundary"
|
|
357
361
|
}) : computed(() => flatten(read(e)));
|
|
358
362
|
});
|
|
359
|
-
o
|
|
363
|
+
o.J = i;
|
|
360
364
|
// A slot of the reveal order in its context (reveal.ts): gated until the
|
|
361
365
|
// controller releases it — before the output's first pass.
|
|
362
|
-
if (u) revealHooks.
|
|
366
|
+
if (u) revealHooks.ue(u, o);
|
|
363
367
|
const f = computed(() => {
|
|
364
368
|
// Reveal order (reveal.ts): a gated slot shows its fallback — or, in a
|
|
365
369
|
// collapsed tail, nothing — whatever its content's state; the
|
|
366
370
|
// controller is told the pass ran (its readiness may have changed) and
|
|
367
371
|
// releases it in turn.
|
|
368
|
-
if (o.
|
|
372
|
+
if (o.ne) {
|
|
369
373
|
// Linked without being read: the tree settling (or changing)
|
|
370
374
|
// re-derives this pass, which is how the controller hears of it.
|
|
371
375
|
// It may release this very slot (the frontier whose content just
|
|
372
376
|
// settled): the pass goes on to show it — the redraw it asks for is
|
|
373
377
|
// refused mid-pass and not needed.
|
|
374
378
|
link(i, getOwner());
|
|
375
|
-
if (o.
|
|
376
|
-
if (o.
|
|
377
|
-
if (o.
|
|
378
|
-
o.
|
|
379
|
+
if (o.H !== null) revealHooks.P(o.H);
|
|
380
|
+
if (o.ne) {
|
|
381
|
+
if (o.re) {
|
|
382
|
+
o.v = true;
|
|
379
383
|
return undefined;
|
|
380
384
|
}
|
|
381
385
|
return fallback(o);
|
|
@@ -388,7 +392,7 @@ function createBoundary(e, n, r, t) {
|
|
|
388
392
|
// display-ahead `on` causes is the lane's, and must still be the
|
|
389
393
|
// fallback. Linked, so its recovery re-derives this pass; read again
|
|
390
394
|
// once clean.
|
|
391
|
-
const n = i.
|
|
395
|
+
const n = i.S & (STATUS_PENDING | STATUS_ERROR);
|
|
392
396
|
if (n !== 0) {
|
|
393
397
|
link(i, getOwner());
|
|
394
398
|
if (n & e) {
|
|
@@ -398,12 +402,12 @@ function createBoundary(e, n, r, t) {
|
|
|
398
402
|
}
|
|
399
403
|
// Forwarded: a loading boundary showing content keeps it and
|
|
400
404
|
// holds the frame like any reader (recorded for its `on`).
|
|
401
|
-
o.
|
|
405
|
+
o.V.add(i);
|
|
402
406
|
collecting.add(o);
|
|
403
407
|
}
|
|
404
408
|
// A pending passes an error boundary by (A6); an error, a loading
|
|
405
409
|
// one; a loading boundary showing content forwards its pending.
|
|
406
|
-
throw i.m.
|
|
410
|
+
throw i.m.F;
|
|
407
411
|
}
|
|
408
412
|
if (isCollecting(o)) {
|
|
409
413
|
// A29's boundary exemption (#3540): a boundary MOUNTED over a held
|
|
@@ -418,7 +422,7 @@ function createBoundary(e, n, r, t) {
|
|
|
418
422
|
// which reveals the content — a fallback staged earlier is replaced
|
|
419
423
|
// ahead of the commit and never shown.
|
|
420
424
|
const e = getOwner();
|
|
421
|
-
if (o.
|
|
425
|
+
if (o.V.size !== 0 && e.S & STATUS_UNINITIALIZED && !(e.i & CONFIG_HELD)) return fallback(o);
|
|
422
426
|
// Readers under it still unready: the fallback, the tree untouched.
|
|
423
427
|
// The seam re-derives this pass when they settle.
|
|
424
428
|
if (prune(o, true) !== 0) return fallback(o);
|
|
@@ -434,7 +438,7 @@ function createBoundary(e, n, r, t) {
|
|
|
434
438
|
}
|
|
435
439
|
// Forwarded: a loading boundary showing content keeps it and
|
|
436
440
|
// holds the frame like any reader (recorded for its `on`).
|
|
437
|
-
o.
|
|
441
|
+
o.V.add(i);
|
|
438
442
|
collecting.add(o);
|
|
439
443
|
}
|
|
440
444
|
// A pending passes an error boundary by (A6).
|
|
@@ -442,16 +446,29 @@ function createBoundary(e, n, r, t) {
|
|
|
442
446
|
}
|
|
443
447
|
// Readers under it still unready (caught before, or while the read
|
|
444
448
|
// ran the content at a mount): the fallback.
|
|
445
|
-
if (isCollecting(o) && o.
|
|
446
|
-
o.
|
|
447
|
-
o.
|
|
449
|
+
if (isCollecting(o) && o.V.size !== 0) return fallback(o);
|
|
450
|
+
o.h = true;
|
|
451
|
+
o.v = false;
|
|
452
|
+
// The fallback dies when the content that replaces it is on screen —
|
|
453
|
+
// with this flush's commits when the pass is the frame's, at the
|
|
454
|
+
// landing when the frame parks (the run is held with it, as the old
|
|
455
|
+
// children of a held pass are) — not now: a held swap keeps the
|
|
456
|
+
// fallback on screen, live, until it commits. A pass back to the
|
|
457
|
+
// fallback before then finds it still built and keeps it.
|
|
458
|
+
const t = o.le;
|
|
459
|
+
if (t !== null) globalQueue.enqueue(EFFECT_RENDER, () => {
|
|
460
|
+
if (!o.v && o.le === t) {
|
|
461
|
+
dispose(t);
|
|
462
|
+
o.le = null;
|
|
463
|
+
}
|
|
464
|
+
});
|
|
448
465
|
release(o);
|
|
449
466
|
// Shown: the slot leaves its reveal order (a later re-arm gates nobody
|
|
450
467
|
// else; the frontier moves on).
|
|
451
|
-
if (o.
|
|
452
|
-
const e = o.
|
|
453
|
-
o.
|
|
454
|
-
revealHooks.
|
|
468
|
+
if (o.H !== null) {
|
|
469
|
+
const e = o.H;
|
|
470
|
+
o.H = null;
|
|
471
|
+
revealHooks.P(e);
|
|
455
472
|
}
|
|
456
473
|
return r;
|
|
457
474
|
},
|
|
@@ -459,10 +476,10 @@ function createBoundary(e, n, r, t) {
|
|
|
459
476
|
// and legitimately swaps mid-hydration (resume), so it must never be
|
|
460
477
|
// frozen by snapshot capture.
|
|
461
478
|
{
|
|
462
|
-
|
|
479
|
+
ae: true
|
|
463
480
|
});
|
|
464
|
-
f.
|
|
465
|
-
o.
|
|
481
|
+
f.i |= CONFIG_REDERIVE;
|
|
482
|
+
o.Z = f;
|
|
466
483
|
return accessor(f);
|
|
467
484
|
}
|
|
468
485
|
|
|
@@ -470,18 +487,35 @@ function fallback(e) {
|
|
|
470
487
|
// The swap a display-ahead re-arm asked for: this pass is the lane's — a
|
|
471
488
|
// lane read by construction (REACTIVE_LANE_READ: `recompute`'s tail keeps
|
|
472
489
|
// the pass in the lane).
|
|
473
|
-
if (e.
|
|
474
|
-
setPassLane(e.
|
|
475
|
-
e.
|
|
476
|
-
e.
|
|
490
|
+
if (e.B !== null) {
|
|
491
|
+
setPassLane(e.B);
|
|
492
|
+
e.Z.R |= REACTIVE_LANE_READ;
|
|
493
|
+
e.B = null;
|
|
494
|
+
}
|
|
495
|
+
e.v = true;
|
|
496
|
+
// Built in its own scope, like `Show`'s function child, once per show
|
|
497
|
+
// (D-39: the fallback is the display until a new answer replaces the
|
|
498
|
+
// error): a re-derive of the output while it shows — a second reader
|
|
499
|
+
// caught, the same error propagated again through a sibling's re-run, a
|
|
500
|
+
// retry pending after `reset()`, a later error — keeps the built
|
|
501
|
+
// fallback, its DOM and focus with it (#3991). A later error reaches it
|
|
502
|
+
// through the error accessor; only a fallback reading the accessor at its
|
|
503
|
+
// top level is rebuilt by it. Created beside the output — in its owner,
|
|
504
|
+
// outside the boundary, as the output is: its errors and runs are the
|
|
505
|
+
// enclosing boundary's — with the output's id, so what it builds gets the
|
|
506
|
+
// ids a build under the output would; disposed once content is on screen.
|
|
507
|
+
if (e.le === null) {
|
|
508
|
+
const n = getOwner();
|
|
509
|
+
e.le = runWithOwner(n._parent, () => computed(() => e.te(e), {
|
|
510
|
+
id: n.id
|
|
511
|
+
}));
|
|
477
512
|
}
|
|
478
|
-
e.
|
|
479
|
-
return e.oe(e);
|
|
513
|
+
return read(e.le);
|
|
480
514
|
}
|
|
481
515
|
|
|
482
516
|
const ERROR_SIGNAL = {
|
|
483
517
|
ownedWrite: true,
|
|
484
|
-
|
|
518
|
+
ae: true
|
|
485
519
|
};
|
|
486
520
|
|
|
487
521
|
/**
|
|
@@ -552,19 +586,19 @@ const ERROR_SIGNAL = {
|
|
|
552
586
|
* }
|
|
553
587
|
* ```
|
|
554
588
|
*/ function createErrorBoundary(e, n) {
|
|
555
|
-
return createBoundary(STATUS_ERROR, e, e => n(accessor(e.
|
|
589
|
+
return createBoundary(STATUS_ERROR, e, e => n(accessor(e.F), () => reset(e)));
|
|
556
590
|
}
|
|
557
591
|
|
|
558
592
|
// Installed at module evaluation — present exactly when something imports a
|
|
559
593
|
// boundary. An app without one pays the three null checks and nothing else.
|
|
560
|
-
GlobalQueue.
|
|
594
|
+
GlobalQueue.ie = catchStatus;
|
|
561
595
|
|
|
562
|
-
GlobalQueue.
|
|
596
|
+
GlobalQueue.fe = e => e.S & STATUS_UNINITIALIZED && catchStatus(e, STATUS_PENDING);
|
|
563
597
|
|
|
564
|
-
GlobalQueue.
|
|
598
|
+
GlobalQueue.ce = hidden;
|
|
565
599
|
|
|
566
|
-
GlobalQueue.
|
|
600
|
+
GlobalQueue.se = boundarySeam;
|
|
567
601
|
|
|
568
|
-
GlobalQueue.
|
|
602
|
+
GlobalQueue.Ee = heldRun;
|
|
569
603
|
|
|
570
604
|
export { REVEAL, createErrorBoundary, createLoadingBoundary, prune, ready, redraw, revealHooks, setRevealHooks };
|