@solidjs/signals 2.0.0-rc.19 → 2.0.0-rc.20
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 +553 -264
- package/dist/dev.attribution.js +18 -18
- package/dist/dev.js +1030 -439
- package/dist/observe/affects.js +12 -2
- package/dist/observe/boundaries.js +168 -115
- package/dist/observe/core/async.js +57 -37
- package/dist/observe/core/attribution.js +6 -6
- package/dist/observe/core/constants.js +9 -1
- package/dist/observe/core/copies.js +10 -0
- package/dist/observe/core/core.js +261 -181
- package/dist/observe/core/effect.js +32 -27
- package/dist/observe/core/graph.js +7 -7
- package/dist/observe/core/heap.js +29 -29
- package/dist/observe/core/lanes.js +301 -101
- package/dist/observe/core/owner.js +13 -13
- package/dist/observe/core/scheduler.js +124 -69
- package/dist/observe/core/truth.js +9 -7
- package/dist/observe/core/verdict.js +160 -98
- package/dist/observe/deferred.js +1 -1
- package/dist/observe/index.js +2 -0
- package/dist/observe/map.js +120 -116
- package/dist/observe/reveal.js +48 -48
- package/dist/observe/signals.js +5 -5
- package/dist/observe/store/affects.js +2 -2
- package/dist/observe/store/optimistic.js +272 -176
- package/dist/observe/store/projection.js +21 -10
- package/dist/observe/store/reconcile.js +8 -2
- package/dist/observe/store/store.js +91 -55
- package/dist/observe/store/types.js +11 -1
- package/dist/observe/store/utils.js +1 -1
- package/dist/prod/affects.js +12 -2
- package/dist/prod/boundaries.js +164 -109
- package/dist/prod/core/async.js +201 -181
- package/dist/prod/core/constants.js +9 -1
- package/dist/prod/core/copies.js +10 -0
- package/dist/prod/core/core.js +244 -164
- package/dist/prod/core/dev.js +108 -3
- package/dist/prod/core/effect.js +28 -23
- package/dist/prod/core/graph.js +9 -9
- package/dist/prod/core/heap.js +16 -16
- package/dist/prod/core/identities.js +1 -1
- package/dist/prod/core/lanes.js +307 -95
- package/dist/prod/core/owner.js +22 -22
- package/dist/prod/core/scheduler.js +266 -211
- package/dist/prod/core/truth.js +9 -7
- package/dist/prod/core/verdict.js +161 -99
- package/dist/prod/deferred.js +1 -1
- package/dist/prod/index.js +2 -0
- package/dist/prod/map.js +78 -74
- package/dist/prod/reveal.js +34 -34
- package/dist/prod/signals.js +3 -3
- package/dist/prod/store/affects.js +15 -15
- package/dist/prod/store/optimistic.js +185 -89
- package/dist/prod/store/projection.js +49 -38
- package/dist/prod/store/reconcile.js +8 -2
- package/dist/prod/store/store.js +99 -63
- package/dist/prod/store/types.js +11 -1
- package/dist/types/affects.d.ts +3 -2
- package/dist/types/boundaries.d.ts +14 -2
- package/dist/types/core/async.d.ts +2 -1
- package/dist/types/core/constants.d.ts +8 -0
- package/dist/types/core/copies.d.ts +54 -0
- package/dist/types/core/core.d.ts +15 -0
- package/dist/types/core/dev.d.ts +1 -1
- package/dist/types/core/lanes.d.ts +8 -1
- package/dist/types/core/scheduler.d.ts +36 -4
- package/dist/types/core/truth.d.ts +3 -1
- package/dist/types/core/types.d.ts +6 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/store/hooks.d.ts +15 -1
- package/dist/types/store/store.d.ts +2 -1
- package/dist/types/store/target.d.ts +5 -0
- package/dist/types/store/types.d.ts +7 -0
- package/package.json +1 -1
package/dist/observe/affects.js
CHANGED
|
@@ -16,7 +16,8 @@ import { $TARGET } from "./store/types.js";
|
|
|
16
16
|
// A mark is a declared in-flight change: the marked node — and everything
|
|
17
17
|
// derived from it — reads pending (`isPending` → true) from the declaration
|
|
18
18
|
// until the surrounding transaction lands (an ambient mark, declared outside
|
|
19
|
-
// one, releases at the next seam
|
|
19
|
+
// one, releases at the next seam; either, on a node whose own flight is
|
|
20
|
+
// still up then, at the seam after that flight lands). The marked values stay readable: no reader
|
|
20
21
|
// suspends on a mark, a mark holds nothing and entangles nothing — it is not
|
|
21
22
|
// a node of its transaction (`blocked` never sees it), and a reader of marked
|
|
22
23
|
// data joins nothing through it. A mark is never a re-ask, so a declared
|
|
@@ -71,7 +72,16 @@ function affects(e, t) {
|
|
|
71
72
|
schedule();
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
installMarkHooks(
|
|
75
|
+
installMarkHooks(e => {
|
|
76
|
+
// A landing's mark on a node whose own flight is up (a declared reload's
|
|
77
|
+
// quiet re-ask the action did not wait for) stays to the seam after
|
|
78
|
+
// that flight lands, as an ambient one does: the reload's window is the
|
|
79
|
+
// flight's (#4349). The rest release with the transaction.
|
|
80
|
+
const t = [];
|
|
81
|
+
for (let r = 0; r < e.length; r++) (inFlight(e[r]) ? ambient : t).push(e[r]);
|
|
82
|
+
e.length = 0;
|
|
83
|
+
release(t);
|
|
84
|
+
}, e => {
|
|
75
85
|
if (ambient.length === 0) return;
|
|
76
86
|
// The flush parked: the declaration's window is the frame's — the marks
|
|
77
87
|
// are its transaction's ("nothing async below ⇒ no window").
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { STATUS_PENDING, STATUS_ERROR, CONFIG_REDERIVE, CONFIG_HELD, CONFIG_FRAME, STATUS_UNINITIALIZED, EFFECT_RENDER, CONFIG_VERDICT, REACTIVE_DISPOSED, REACTIVE_LANE_READ, CONFIG_OVERRIDE, EFFECT_USER, EFFECT_TRACKED, REACTIVE_ZOMBIE, CAUGHT_REARMED } from "./core/constants.js";
|
|
1
|
+
import { STATUS_PENDING, STATUS_ERROR, CONFIG_REDERIVE, CONFIG_HELD, CONFIG_FRAME, STATUS_UNINITIALIZED, EFFECT_RENDER, CONFIG_VERDICT, REACTIVE_DISPOSED, REACTIVE_LANE_READ, REACTIVE_PROBED, CONFIG_STAGED_ERROR, CONFIG_OVERRIDE, EFFECT_USER, EFFECT_TRACKED, REACTIVE_ZOMBIE, CAUGHT_REARMED } from "./core/constants.js";
|
|
2
2
|
|
|
3
3
|
import { signal, runWithOwner, computed, read, setSignal, recompute } from "./core/core.js";
|
|
4
4
|
|
|
5
|
-
import "./core/dev.js";
|
|
5
|
+
import { reportDiagnostic, emitDiagnostic } from "./core/dev.js";
|
|
6
6
|
|
|
7
7
|
import { NotReadyError, unwrapStatusError } from "./core/error.js";
|
|
8
8
|
|
|
@@ -85,27 +85,37 @@ const boundaryOf = e => e.A[BOUNDARY];
|
|
|
85
85
|
/** Catches what reaches it: an error boundary always; a loading one until it
|
|
86
86
|
* has shown content, or while re-armed. */ const isCollecting = e => e.i === STATUS_ERROR || !e.D || e.h;
|
|
87
87
|
|
|
88
|
-
/** A reader `b` waits on: recorded for its `on`, and `b` visited at the seam. */ function record(e, r) {
|
|
89
|
-
e.
|
|
88
|
+
/** A reader `b` waits on: recorded for its `on`, and `b` visited at the seam. */ function record(e, n, r = n) {
|
|
89
|
+
e.F.set(n, r);
|
|
90
90
|
collecting.add(e);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
/** The reader goes to the fallback: recorded, and the output re-derives
|
|
94
94
|
* (a no-op while the output's own pass is running — its post-check
|
|
95
|
-
* decides). */ function caught(e, r, n) {
|
|
95
|
+
* decides). */ function caught(e, n, r, o = n) {
|
|
96
96
|
if (e.i === STATUS_ERROR) {
|
|
97
97
|
// An error boundary waits on what THREW (`StatusError.source`), not on
|
|
98
|
-
// the reader that saw it
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
98
|
+
// the reader that saw it, while the error is settled only when its
|
|
99
|
+
// source is neither errored nor in flight and the reader is not pending
|
|
100
|
+
// on the answer that replaces it (`prune`) — or when the
|
|
101
|
+
// reader is disposed: a source no live reader holds holds nothing
|
|
102
|
+
// (#4373). A source that died (a memo its reader owned, kept past the
|
|
103
|
+
// pass that disposed it) settles nothing: the reader is waited on.
|
|
104
|
+
// `reset` re-runs the source.
|
|
105
|
+
r ??= n.T?.U;
|
|
106
|
+
o = r?.source ?? n;
|
|
107
|
+
if (o.R & REACTIVE_DISPOSED) o = n;
|
|
108
|
+
const t = unwrapStatusError(r);
|
|
109
|
+
setSignal(e.U, t);
|
|
110
|
+
reportClientError(t, e.H, o);
|
|
107
111
|
}
|
|
108
|
-
record(e,
|
|
112
|
+
record(e, n, o);
|
|
113
|
+
// A loading fallback behind an error fallback is hidden: the error stays
|
|
114
|
+
// the display until what the fallback waits on answers (D-39) — the
|
|
115
|
+
// error boundary waits on it too.
|
|
116
|
+
// (`_type`: STATUS_PENDING 1 < STATUS_ERROR 2 — an error boundary above a
|
|
117
|
+
// loading one.)
|
|
118
|
+
for (let r = e; r = r._parent; ) if (r.L && r.i > e.i) record(r, n);
|
|
109
119
|
if (e.h) flip(e);
|
|
110
120
|
// Already showing the fallback: one more reader to wait on changes
|
|
111
121
|
// nothing on screen. The fallback is instantiated once per show — a later
|
|
@@ -121,8 +131,8 @@ const boundaryOf = e => e.A[BOUNDARY];
|
|
|
121
131
|
* transaction with the arming frame's (#3540 `on: () => latest(dep)`). */ function flip(e) {
|
|
122
132
|
e.D = false;
|
|
123
133
|
e.V = e.B;
|
|
124
|
-
const
|
|
125
|
-
if (!e.V &&
|
|
134
|
+
const n = e.j;
|
|
135
|
+
if (!e.V && n.l & CONFIG_HELD && txOf(n) !== flushTransaction) unhold(n);
|
|
126
136
|
if (laneStageHook && e.V !== null && e.j !== null) laneStageHook(e.j, e.V, true, false);
|
|
127
137
|
}
|
|
128
138
|
|
|
@@ -135,25 +145,29 @@ function redraw(e) {
|
|
|
135
145
|
|
|
136
146
|
/** `catchHook` (scheduler.ts): status from a frame reader, nearest boundary first.
|
|
137
147
|
* A loading boundary on the way records a pending reader whether or not it
|
|
138
|
-
* catches it (its `on` may collect it later). */ function catchStatus(e,
|
|
139
|
-
if (
|
|
148
|
+
* catches it (its `on` may collect it later). */ function catchStatus(e, n, r) {
|
|
149
|
+
if (n === 0) {
|
|
140
150
|
// A status cleared. Judged by the node's status now, against each
|
|
141
|
-
// boundary's own rule (`
|
|
151
|
+
// boundary's own rule (`prune`'s mask) — the error path clears pending
|
|
142
152
|
// first and the node is still errored then. The last reader a fallback
|
|
143
153
|
// waited on settling re-derives the output now, in the same heap (a
|
|
144
154
|
// held reader's landing has joined its transaction, so the content
|
|
145
155
|
// lands with its run, not a round after). Others still waiting: nothing
|
|
146
|
-
// on screen changes, the fallback stays as it is.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
156
|
+
// on screen changes, the fallback stays as it is. `node` here is an
|
|
157
|
+
// effect reporting its own status. An error boundary records an effect
|
|
158
|
+
// only while it is errored, and a staged error keeps STATUS_ERROR on a
|
|
159
|
+
// node that had it (`stageError`), so `prune`'s CONFIG_STAGED_ERROR case
|
|
160
|
+
// cannot reach this path (#4364).
|
|
161
|
+
if (collecting.size !== 0) for (let n = boundaryOf(e); n; n = n._parent) if (!(n.F.get(e)?.m & (n.i | STATUS_PENDING)) && n.F.delete(e) && n.F.size === 0) {
|
|
162
|
+
if (n.L) redraw(n);
|
|
163
|
+
if (revealHooks && n.v !== null) revealHooks.P(n.v);
|
|
150
164
|
}
|
|
151
165
|
return false;
|
|
152
166
|
}
|
|
153
167
|
for (let o = boundaryOf(e); o; o = o._parent) {
|
|
154
|
-
if (!(o.i &
|
|
168
|
+
if (!(o.i & n)) continue;
|
|
155
169
|
if (isCollecting(o)) {
|
|
156
|
-
caught(o, e,
|
|
170
|
+
caught(o, e, r);
|
|
157
171
|
return o.h ? CAUGHT_REARMED : true;
|
|
158
172
|
}
|
|
159
173
|
record(o, e);
|
|
@@ -163,12 +177,12 @@ function redraw(e) {
|
|
|
163
177
|
|
|
164
178
|
/** The nearest loading boundary that would catch `node` was re-armed this
|
|
165
179
|
* flush. */ function armedOver(e) {
|
|
166
|
-
for (let
|
|
180
|
+
for (let n = boundaryOf(e); n; n = n._parent) if (n.i & STATUS_PENDING && isCollecting(n)) return n.h;
|
|
167
181
|
}
|
|
168
182
|
|
|
169
183
|
/** The nearest boundary on `r`'s chain showing its fallback, if any
|
|
170
184
|
* (`hiddenHook`: `r` is behind a fallback). */ function hiddenBy(e) {
|
|
171
|
-
for (let
|
|
185
|
+
for (let n = boundaryOf(e); n; n = n._parent) if (n.L) return n;
|
|
172
186
|
return undefined;
|
|
173
187
|
}
|
|
174
188
|
|
|
@@ -183,9 +197,9 @@ function redraw(e) {
|
|
|
183
197
|
* synchronous on creation and never comes here. The run's `_modified` stays
|
|
184
198
|
* set; the reveal re-queues it by type (`release`), and a boundary above
|
|
185
199
|
* still showing its fallback holds it again then. */ function heldRun(e) {
|
|
186
|
-
const
|
|
187
|
-
if (
|
|
188
|
-
(
|
|
200
|
+
const n = hiddenBy(e);
|
|
201
|
+
if (n === undefined) return false;
|
|
202
|
+
(n.M ??= new Set).add(e);
|
|
189
203
|
return true;
|
|
190
204
|
}
|
|
191
205
|
|
|
@@ -193,9 +207,9 @@ function redraw(e) {
|
|
|
193
207
|
* its own phase — render updates with the frame that attaches the content,
|
|
194
208
|
* user effects after it. */ function release(e) {
|
|
195
209
|
if (e.M === null) return;
|
|
196
|
-
for (const
|
|
197
|
-
const e =
|
|
198
|
-
globalQueue.enqueue(e === EFFECT_TRACKED ? EFFECT_USER : e, e === EFFECT_TRACKED ?
|
|
210
|
+
for (const n of e.M) {
|
|
211
|
+
const e = n.i;
|
|
212
|
+
globalQueue.enqueue(e === EFFECT_TRACKED ? EFFECT_USER : e, e === EFFECT_TRACKED ? n.Z : n.W ??= GlobalQueue.q.bind(null, n));
|
|
199
213
|
}
|
|
200
214
|
e.M = null;
|
|
201
215
|
}
|
|
@@ -205,13 +219,21 @@ function redraw(e) {
|
|
|
205
219
|
* that landed but is held (its value staged in a transaction) is not: the
|
|
206
220
|
* content reveals at the commit, with its run. The tree is: the output reads
|
|
207
221
|
* it and enters the transaction itself (its committed value shows until the
|
|
208
|
-
* landing).
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
222
|
+
* landing). The statuses that keep a reader: pending — and its error, for an
|
|
223
|
+
* error boundary (`_type` is the status it catches) — on the reader or its
|
|
224
|
+
* source. A reader pending again after the source that threw answered (it
|
|
225
|
+
* re-asks through a memo that carried the error) has no new answer yet: the
|
|
226
|
+
* error stays the display (D-39: a pending is not a value; async-gen 91501
|
|
227
|
+
* #1831). */ function prune(e, n) {
|
|
228
|
+
const r = e.i | STATUS_PENDING;
|
|
229
|
+
for (const [o, t] of e.F) {
|
|
230
|
+
if (!((o.R | t.R) & REACTIVE_DISPOSED)) {
|
|
231
|
+
// An error staged on its source (D-41, `stageError`) is not settled:
|
|
232
|
+
// it publishes with the commit. A reader that threw it now (a lane
|
|
233
|
+
// pass, a reader of a node born staged) reached the boundary first
|
|
234
|
+
// (#4364).
|
|
235
|
+
if ((o.m | t.m) & r || r & STATUS_ERROR && t.l & CONFIG_STAGED_ERROR) continue;
|
|
236
|
+
if ((t !== e.K || e.h) && (t.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD) {
|
|
215
237
|
// Landed, held: the content is that transaction's — the output's
|
|
216
238
|
// pass enters it and the reveal lands with the reader's run. The
|
|
217
239
|
// seam, past its park decision, waits for the commit instead. (A
|
|
@@ -219,40 +241,45 @@ function prune(e, r) {
|
|
|
219
241
|
// has not shown content catches it instead: the fallback stays until
|
|
220
242
|
// the reader is committed (#3540: what a fresh boundary catches holds
|
|
221
243
|
// nothing outside it).
|
|
222
|
-
if (!
|
|
223
|
-
joinFuture(txOf(
|
|
244
|
+
if (!n || !e.D) continue;
|
|
245
|
+
joinFuture(txOf(t));
|
|
224
246
|
}
|
|
225
|
-
e.U.delete(o);
|
|
226
247
|
}
|
|
248
|
+
e.F.delete(o);
|
|
227
249
|
}
|
|
228
|
-
return e.
|
|
250
|
+
return e.F.size;
|
|
229
251
|
}
|
|
230
252
|
|
|
231
253
|
/** Reveal order: a slot is ready when its content can show — it has shown
|
|
232
254
|
* content, or nothing under it is unready (the tree neither pending nor
|
|
233
255
|
* born held, no reader waited on). */ function ready(e) {
|
|
234
|
-
return e.D || !(e.
|
|
256
|
+
return e.D || !(e.K.m & STATUS_PENDING) && !(e.K.l & CONFIG_HELD && (e.j === null || e.j.m & STATUS_UNINITIALIZED)) && prune(e, false) === 0;
|
|
235
257
|
}
|
|
236
258
|
|
|
237
259
|
/** `boundarySeamHook` (scheduler.ts), end of the seam: readers that settled, died,
|
|
238
260
|
* or landed and committed are dropped; a fallback with none left reveals
|
|
239
261
|
* next round. An arm resolves: nothing collected, nothing happened. */ function boundarySeam() {
|
|
240
262
|
for (const e of collecting) {
|
|
241
|
-
const
|
|
242
|
-
if (
|
|
263
|
+
const n = e.j.R;
|
|
264
|
+
if (n & REACTIVE_DISPOSED) {
|
|
243
265
|
collecting.delete(e);
|
|
244
266
|
continue;
|
|
245
267
|
}
|
|
246
268
|
// A parked frame's boundary (zombie) keeps its state for its revival.
|
|
247
|
-
if (
|
|
269
|
+
if (n & REACTIVE_ZOMBIE) continue;
|
|
248
270
|
prune(e, false);
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
271
|
+
const r = e.j;
|
|
272
|
+
// A fallback staged into the very hold its readers landed in folds back
|
|
273
|
+
// (D-16, U-9): the content is ready when that hold commits (D-15). Not
|
|
274
|
+
// only at the re-arm's own seam: readers pending then land, held, a
|
|
275
|
+
// flush later (#4379 — the staged fallback otherwise commits with the
|
|
276
|
+
// hold, and a quiet refresh then caught keeps it up, F-9).
|
|
277
|
+
if (!e.D && r.l & CONFIG_HELD && [ ...e.F ].every(([, e]) => !(e.m & STATUS_PENDING) && e.l & CONFIG_HELD && txOf(e) === txOf(r))) {
|
|
278
|
+
e.F.clear();
|
|
252
279
|
e.D = true;
|
|
253
280
|
}
|
|
254
281
|
e.h = false;
|
|
255
|
-
if (e.
|
|
282
|
+
if (e.F.size === 0) {
|
|
256
283
|
collecting.delete(e);
|
|
257
284
|
if (e.L) redraw(e);
|
|
258
285
|
if (revealHooks && e.v !== null) revealHooks.P(e.v);
|
|
@@ -288,22 +315,25 @@ function prune(e, r) {
|
|
|
288
315
|
// whose frame has no transaction yet: the swap is still display-ahead — the frame gets one now (it lands
|
|
289
316
|
// at this very seam if nothing holds it), and the swap is its verdict
|
|
290
317
|
// lane's work, shown ahead of the frame's own runs (#3528).
|
|
291
|
-
let
|
|
292
|
-
if (
|
|
318
|
+
let n = passLane;
|
|
319
|
+
if (n === null && globalQueue.Y && getOwner().l & CONFIG_VERDICT) {
|
|
293
320
|
joinFuture(null);
|
|
294
|
-
|
|
321
|
+
n = GlobalQueue.J(flushTransaction);
|
|
295
322
|
}
|
|
296
|
-
e.B =
|
|
323
|
+
e.B = n;
|
|
297
324
|
collecting.add(e);
|
|
298
|
-
const
|
|
299
|
-
heldUnder(e.H, flushTransaction,
|
|
300
|
-
for (const
|
|
301
|
-
if (e.
|
|
325
|
+
const r = e.F.size;
|
|
326
|
+
heldUnder(e.H, flushTransaction, n => record(e, n));
|
|
327
|
+
for (const [n] of e.F) {
|
|
328
|
+
if (e.F.size !== r || n.m & STATUS_PENDING && !(n.R & REACTIVE_DISPOSED)) {
|
|
302
329
|
// What it collects was forwarded through it to the boundaries above
|
|
303
330
|
// too (`catchStatus` records a reader in every boundary on the way).
|
|
304
331
|
// It is this boundary's alone now (B5, the nearest catcher): an outer
|
|
305
332
|
// re-armed by the same tick does not wait for it (D-14, U-4).
|
|
306
|
-
for (let
|
|
333
|
+
for (let n = e._parent; n !== null; n = n._parent)
|
|
334
|
+
// An outer error boundary keys its readers too, but waits on their
|
|
335
|
+
// sources: a re-armed Loading taking the pending does not settle it.
|
|
336
|
+
if (n.i & STATUS_PENDING) for (const [r] of e.F) n.F.delete(r);
|
|
307
337
|
flip(e);
|
|
308
338
|
redraw(e);
|
|
309
339
|
return;
|
|
@@ -314,19 +344,33 @@ function prune(e, r) {
|
|
|
314
344
|
/** The error boundary's `reset`: re-run what threw (a comparator throw
|
|
315
345
|
* names a signal — nothing to re-run). */ function reset(e) {
|
|
316
346
|
// A snapshot: a source failing again is caught — and re-added — mid-walk.
|
|
317
|
-
for (const
|
|
347
|
+
for (const n of new Set(e.F.values())) if (n.X !== undefined && !(n.R & REACTIVE_DISPOSED)) recompute(n);
|
|
318
348
|
schedule();
|
|
319
349
|
}
|
|
320
350
|
|
|
321
|
-
|
|
351
|
+
/**
|
|
352
|
+
* Dev CHECK: the `on` dependencies evaluated to a function — `<Loading
|
|
353
|
+
* on={route}>` or `on={() => route()}` passes the accessor itself, a stable
|
|
354
|
+
* value that is never called, so nothing is read and the boundary never
|
|
355
|
+
* re-arms. Checked on the first run only: the shape is static.
|
|
356
|
+
*/ function reportOnAccessor(e) {
|
|
357
|
+
reportDiagnostic(emitDiagnostic({
|
|
358
|
+
code: "LOADING_ON_ACCESSOR",
|
|
359
|
+
kind: "async",
|
|
360
|
+
severity: "warn",
|
|
361
|
+
message: "[LOADING_ON_ACCESSOR] A Loading boundary's `on` received a function. `on` takes the " + "dependency's value — `on={route()}`, or `on={[query(), page()]}` for several — and an " + "accessor passed instead is never called, so nothing is read and the boundary never re-arms."
|
|
362
|
+
}, e.H));
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function createBoundary(e, n, r, o) {
|
|
322
366
|
const t = createOwner();
|
|
323
367
|
const l = {
|
|
324
368
|
i: e,
|
|
325
369
|
_parent: boundaryOf(t) ?? null,
|
|
326
370
|
H: t,
|
|
327
|
-
|
|
371
|
+
K: null,
|
|
328
372
|
j: null,
|
|
329
|
-
|
|
373
|
+
F: new Map,
|
|
330
374
|
D: false,
|
|
331
375
|
h: false,
|
|
332
376
|
B: null,
|
|
@@ -336,14 +380,14 @@ function createBoundary(e, r, n, o) {
|
|
|
336
380
|
v: null,
|
|
337
381
|
$: false,
|
|
338
382
|
ee: false,
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
383
|
+
U: e === STATUS_ERROR ? signal(undefined, ERROR_SIGNAL) : null,
|
|
384
|
+
ne: r,
|
|
385
|
+
re: null
|
|
342
386
|
};
|
|
343
|
-
const
|
|
387
|
+
const a = e === STATUS_PENDING ? t.A[REVEAL] : null;
|
|
344
388
|
if (getOwner()) cleanup(() => {
|
|
345
389
|
collecting.delete(l);
|
|
346
|
-
if (revealHooks &&
|
|
390
|
+
if (revealHooks && a) revealHooks.oe(a, l);
|
|
347
391
|
});
|
|
348
392
|
// The `on` dependencies live OUTSIDE the boundary, as the condition of a
|
|
349
393
|
// `<Show>` wrapping it would: created before the owner's context names it.
|
|
@@ -354,7 +398,8 @@ function createBoundary(e, r, n, o) {
|
|
|
354
398
|
let e = false;
|
|
355
399
|
runWithOwner(t, () => computed(() => {
|
|
356
400
|
try {
|
|
357
|
-
o();
|
|
401
|
+
const n = o();
|
|
402
|
+
if (false && !e && typeof n === "function") ;
|
|
358
403
|
} catch (e) {
|
|
359
404
|
if (!(e instanceof NotReadyError)) {
|
|
360
405
|
if (!globalQueue.notify(getOwner(), STATUS_ERROR, STATUS_ERROR, e)) {
|
|
@@ -367,32 +412,32 @@ function createBoundary(e, r, n, o) {
|
|
|
367
412
|
if (e) arm(l); else e = true;
|
|
368
413
|
})).l |= CONFIG_REDERIVE;
|
|
369
414
|
}
|
|
370
|
-
const
|
|
415
|
+
const u = {
|
|
371
416
|
...t.A,
|
|
372
417
|
[BOUNDARY]: l
|
|
373
418
|
};
|
|
374
|
-
if (revealHooks !== null)
|
|
375
|
-
t.A =
|
|
419
|
+
if (revealHooks !== null) u[REVEAL] = null;
|
|
420
|
+
t.A = u;
|
|
376
421
|
const s = runWithOwner(t, () => {
|
|
377
|
-
const e = true ? computed(
|
|
422
|
+
const e = true ? computed(n, {
|
|
378
423
|
name: "children"
|
|
379
|
-
}) : computed(
|
|
424
|
+
}) : computed(n);
|
|
380
425
|
return true ? computed(() => flatten(read(e)), {
|
|
381
426
|
name: "boundary"
|
|
382
427
|
}) : computed(() => flatten(read(e)));
|
|
383
428
|
});
|
|
384
|
-
l.
|
|
429
|
+
l.K = s;
|
|
385
430
|
// A slot of the reveal order in its context (reveal.ts): gated until the
|
|
386
431
|
// controller releases it — before the output's first pass.
|
|
387
|
-
if (revealHooks &&
|
|
432
|
+
if (revealHooks && a) revealHooks.te(a, l);
|
|
388
433
|
const i = computed(() => {
|
|
389
434
|
// Structure, not a derivation of its content (CONFIG_FRAME, #4283): it
|
|
390
435
|
// reads a hold it is not part of as the screen, as the render effect
|
|
391
436
|
// flattening the same children without a boundary would. Not while a
|
|
392
437
|
// re-arm's swap is the change's work (`arm`), until that swap commits
|
|
393
438
|
// (D-13, #3540).
|
|
394
|
-
const
|
|
395
|
-
if (!l.h && !(
|
|
439
|
+
const n = getOwner();
|
|
440
|
+
if (!l.h && !(n.l & CONFIG_HELD)) n.l |= CONFIG_FRAME;
|
|
396
441
|
// Reveal order (reveal.ts): a gated slot shows its fallback — or, in a
|
|
397
442
|
// collapsed tail, nothing — whatever its content's state; the
|
|
398
443
|
// controller is told the pass ran (its readiness may have changed) and
|
|
@@ -403,7 +448,7 @@ function createBoundary(e, r, n, o) {
|
|
|
403
448
|
// It may release this very slot (the frontier whose content just
|
|
404
449
|
// settled): the pass goes on to show it — the redraw it asks for is
|
|
405
450
|
// refused mid-pass and not needed.
|
|
406
|
-
link(s,
|
|
451
|
+
link(s, n);
|
|
407
452
|
if (revealHooks && l.v !== null) revealHooks.P(l.v);
|
|
408
453
|
if (l.$) {
|
|
409
454
|
if (l.ee) {
|
|
@@ -420,10 +465,10 @@ function createBoundary(e, r, n, o) {
|
|
|
420
465
|
// display-ahead `on` causes is the lane's, and must still be the
|
|
421
466
|
// fallback. Linked, so its recovery re-derives this pass; read again
|
|
422
467
|
// once clean.
|
|
423
|
-
const
|
|
424
|
-
if (
|
|
425
|
-
link(s,
|
|
426
|
-
if (
|
|
468
|
+
const r = s.m & (STATUS_PENDING | STATUS_ERROR);
|
|
469
|
+
if (r !== 0) {
|
|
470
|
+
link(s, n);
|
|
471
|
+
if (r & e) {
|
|
427
472
|
if (isCollecting(l)) {
|
|
428
473
|
caught(l, s, undefined);
|
|
429
474
|
return fallback(l);
|
|
@@ -434,7 +479,7 @@ function createBoundary(e, r, n, o) {
|
|
|
434
479
|
}
|
|
435
480
|
// A pending passes an error boundary by (A6); an error, a loading
|
|
436
481
|
// one; a loading boundary showing content forwards its pending.
|
|
437
|
-
throw s.T.
|
|
482
|
+
throw s.T.U;
|
|
438
483
|
}
|
|
439
484
|
if (isCollecting(l)) {
|
|
440
485
|
// A29's boundary exemption (#3540): a boundary MOUNTED over a held
|
|
@@ -448,7 +493,7 @@ function createBoundary(e, r, n, o) {
|
|
|
448
493
|
// enters: the outside sees its committed value until the landing,
|
|
449
494
|
// which reveals the content — a fallback staged earlier is replaced
|
|
450
495
|
// ahead of the commit and never shown.
|
|
451
|
-
if (l.
|
|
496
|
+
if (l.F.size !== 0 && n.m & STATUS_UNINITIALIZED && !(n.l & CONFIG_HELD)) return fallback(l);
|
|
452
497
|
// Readers under it still unready: the fallback, the tree untouched.
|
|
453
498
|
// The seam re-derives this pass when they settle.
|
|
454
499
|
if (prune(l, true) !== 0) return fallback(l);
|
|
@@ -456,10 +501,10 @@ function createBoundary(e, r, n, o) {
|
|
|
456
501
|
let o;
|
|
457
502
|
try {
|
|
458
503
|
o = read(s);
|
|
459
|
-
} catch (
|
|
460
|
-
if (
|
|
504
|
+
} catch (n) {
|
|
505
|
+
if (n instanceof NotReadyError ? e === STATUS_PENDING : e === STATUS_ERROR) {
|
|
461
506
|
if (isCollecting(l)) {
|
|
462
|
-
caught(l, s,
|
|
507
|
+
caught(l, s, n);
|
|
463
508
|
return fallback(l);
|
|
464
509
|
}
|
|
465
510
|
// Forwarded: a loading boundary showing content keeps it and
|
|
@@ -467,15 +512,15 @@ function createBoundary(e, r, n, o) {
|
|
|
467
512
|
record(l, s);
|
|
468
513
|
}
|
|
469
514
|
// A pending passes an error boundary by (A6).
|
|
470
|
-
throw
|
|
515
|
+
throw n;
|
|
471
516
|
}
|
|
472
517
|
// Readers under it still unready (caught before, or while the read
|
|
473
518
|
// ran the content at a mount): the fallback.
|
|
474
|
-
if (isCollecting(l) && l.
|
|
519
|
+
if (isCollecting(l) && l.F.size !== 0) return fallback(l);
|
|
475
520
|
l.D = true;
|
|
476
521
|
// Observe: the fallback stops showing (a hide before its commit means
|
|
477
522
|
// it never displayed — the engine knows the swap it was staged with).
|
|
478
|
-
if (l.L && l.i & STATUS_PENDING && attrHooks !== null) attrHooks.boundaryFallback(l, l.
|
|
523
|
+
if (l.L && l.i & STATUS_PENDING && attrHooks !== null) attrHooks.boundaryFallback(l, l.K, false);
|
|
479
524
|
l.L = false;
|
|
480
525
|
// The fallback dies when the content that replaces it is on screen —
|
|
481
526
|
// with this flush's commits when the pass is the frame's, at the
|
|
@@ -486,15 +531,15 @@ function createBoundary(e, r, n, o) {
|
|
|
486
531
|
// the screen does not show (a swap staged with a held frame, replaced
|
|
487
532
|
// before it commits) dies now: what it reads holds nothing (S-22 row
|
|
488
533
|
// 3′, #4268).
|
|
489
|
-
const t = l.
|
|
534
|
+
const t = l.re;
|
|
490
535
|
const drop = () => {
|
|
491
|
-
if (!l.L && l.
|
|
536
|
+
if (!l.L && l.re === t) {
|
|
492
537
|
// A fallback that threw (a rethrow the boundary does not
|
|
493
538
|
// handle) is what an enclosing boundary waits on: it died, and
|
|
494
539
|
// the seam of another round drops it there (#4270).
|
|
495
540
|
if (t.m & STATUS_ERROR) schedule();
|
|
496
541
|
dispose(t);
|
|
497
|
-
l.
|
|
542
|
+
l.re = null;
|
|
498
543
|
}
|
|
499
544
|
};
|
|
500
545
|
if (t !== null) l.j.le !== t.le ? drop() : globalQueue.enqueue(EFFECT_RENDER, drop);
|
|
@@ -513,7 +558,7 @@ function createBoundary(e, r, n, o) {
|
|
|
513
558
|
// frozen by snapshot capture.
|
|
514
559
|
{
|
|
515
560
|
name: "value",
|
|
516
|
-
|
|
561
|
+
ae: true
|
|
517
562
|
});
|
|
518
563
|
i.l |= CONFIG_REDERIVE;
|
|
519
564
|
// The tree is structure too (the output's pass marks the output).
|
|
@@ -523,12 +568,14 @@ function createBoundary(e, r, n, o) {
|
|
|
523
568
|
}
|
|
524
569
|
|
|
525
570
|
function fallback(e) {
|
|
571
|
+
// (The output's pass.)
|
|
572
|
+
const n = getOwner();
|
|
526
573
|
// The swap a display-ahead re-arm asked for: this pass is the lane's — a
|
|
527
574
|
// lane read by construction (REACTIVE_LANE_READ: `recompute`'s tail keeps
|
|
528
575
|
// the pass in the lane).
|
|
529
|
-
|
|
576
|
+
if (e.V !== null) {
|
|
530
577
|
setPassLane(e.V);
|
|
531
|
-
|
|
578
|
+
n.R |= REACTIVE_LANE_READ;
|
|
532
579
|
e.V = null;
|
|
533
580
|
}
|
|
534
581
|
// Observe: a loading boundary starts showing its fallback — the swap lands
|
|
@@ -536,8 +583,8 @@ function fallback(e) {
|
|
|
536
583
|
// transaction). A mount's synchronous first show has no drain of its own:
|
|
537
584
|
// one is scheduled so the engine's display instant (`flushEnd`) comes.
|
|
538
585
|
if (!e.L && e.i & STATUS_PENDING && attrHooks !== null) {
|
|
539
|
-
attrHooks.boundaryFallback(e, e.
|
|
540
|
-
if (!globalQueue.
|
|
586
|
+
attrHooks.boundaryFallback(e, e.K, true, passLane !== null ? null : flushTransaction !== null ? resolveTx(flushTransaction) : passTx);
|
|
587
|
+
if (!globalQueue.Y) schedule();
|
|
541
588
|
}
|
|
542
589
|
e.L = true;
|
|
543
590
|
// Built in its own scope, like `Show`'s function child, once per show
|
|
@@ -551,18 +598,24 @@ function fallback(e) {
|
|
|
551
598
|
// outside the boundary, as the output is: its errors and runs are the
|
|
552
599
|
// enclosing boundary's — with the output's id, so what it builds gets the
|
|
553
600
|
// ids a build under the output would; disposed once content is on screen.
|
|
554
|
-
if (e.
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
601
|
+
if (e.re === null) e.re = runWithOwner(n._parent, () => computed(() => e.ne(e), {
|
|
602
|
+
id: n.id
|
|
603
|
+
}));
|
|
604
|
+
// The swap is structure (#3540): what the fallback reads ahead — a
|
|
605
|
+
// verdict (`latest()`), a lane — is the fallback's display-ahead, not the
|
|
606
|
+
// swap's: the output's pass stays where it was (F-6 stays inside the
|
|
607
|
+
// fallback, #4337).
|
|
608
|
+
const r = passLane;
|
|
609
|
+
const o = n.R;
|
|
610
|
+
const t = read(e.re);
|
|
611
|
+
setPassLane(r);
|
|
612
|
+
n.R ^= (n.R ^ o) & (REACTIVE_PROBED | REACTIVE_LANE_READ);
|
|
613
|
+
return t;
|
|
561
614
|
}
|
|
562
615
|
|
|
563
616
|
const ERROR_SIGNAL = {
|
|
564
617
|
ownedWrite: true,
|
|
565
|
-
|
|
618
|
+
ae: true
|
|
566
619
|
};
|
|
567
620
|
|
|
568
621
|
/**
|
|
@@ -606,8 +659,8 @@ const ERROR_SIGNAL = {
|
|
|
606
659
|
* ) as unknown as JSX.Element;
|
|
607
660
|
* }
|
|
608
661
|
* ```
|
|
609
|
-
*/ function createLoadingBoundary(e,
|
|
610
|
-
return createBoundary(STATUS_PENDING, e, () =>
|
|
662
|
+
*/ function createLoadingBoundary(e, n, r) {
|
|
663
|
+
return createBoundary(STATUS_PENDING, e, () => n(), r?.on);
|
|
611
664
|
}
|
|
612
665
|
|
|
613
666
|
/**
|
|
@@ -632,12 +685,12 @@ const ERROR_SIGNAL = {
|
|
|
632
685
|
* ) as unknown as JSX.Element;
|
|
633
686
|
* }
|
|
634
687
|
* ```
|
|
635
|
-
*/ function createErrorBoundary(e,
|
|
636
|
-
return createBoundary(STATUS_ERROR, e, e =>
|
|
688
|
+
*/ function createErrorBoundary(e, n) {
|
|
689
|
+
return createBoundary(STATUS_ERROR, e, e => n(accessor(e.U), () => reset(e)));
|
|
637
690
|
}
|
|
638
691
|
|
|
639
692
|
// Installed at module evaluation — present exactly when something imports a
|
|
640
693
|
// boundary. An app without one pays the three null checks and nothing else.
|
|
641
|
-
installBoundaryHooks(catchStatus, (e,
|
|
694
|
+
installBoundaryHooks(catchStatus, (e, n) => !n && (e.m & STATUS_UNINITIALIZED ? catchStatus(e, STATUS_PENDING) : armedOver(e)), hiddenBy, boundarySeam, heldRun);
|
|
642
695
|
|
|
643
696
|
export { REVEAL, createErrorBoundary, createLoadingBoundary, prune, ready, redraw, revealHooks, setRevealHooks };
|