@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { STATUS_PENDING, STATUS_ERROR, CONFIG_REDERIVE,
|
|
1
|
+
import { STATUS_PENDING, STATUS_ERROR, CONFIG_REDERIVE, STATUS_UNINITIALIZED, CONFIG_HELD, EFFECT_RENDER, CONFIG_VERDICT, REACTIVE_DISPOSED, REACTIVE_LANE_READ, 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
|
|
|
@@ -14,7 +14,7 @@ import { enqueueSub } from "./core/heap.js";
|
|
|
14
14
|
|
|
15
15
|
import { createOwner, getOwner, cleanup, dispose } from "./core/owner.js";
|
|
16
16
|
|
|
17
|
-
import { globalQueue, haltReactivity, passLane, joinFuture, GlobalQueue, flushTransaction,
|
|
17
|
+
import { globalQueue, haltReactivity, passLane, joinFuture, GlobalQueue, flushTransaction, heldUnder, setPassLane, passTx, resolveTx, schedule, txOf, unhold, laneStageHook, installBoundaryHooks } from "./core/scheduler.js";
|
|
18
18
|
|
|
19
19
|
import { attrHooks } from "./core/attribution-hooks.js";
|
|
20
20
|
|
|
@@ -44,7 +44,7 @@ import { accessor } from "./signals.js";
|
|
|
44
44
|
* the root holds the frame as for any reader. The tree's own status takes
|
|
45
45
|
* the same route from the output's pass (`read(tree)` throws it).
|
|
46
46
|
*
|
|
47
|
-
* The hold (`blocked`, scheduler.ts) asks `
|
|
47
|
+
* The hold (`blocked`, scheduler.ts) asks `hiddenBy`: a reader behind a
|
|
48
48
|
* fallback — any boundary on its chain whose last pass chose the fallback —
|
|
49
49
|
* is not on screen and holds nothing. An error boundary flipping to its
|
|
50
50
|
* fallback is the same as a loading one resetting: every reader under it
|
|
@@ -77,34 +77,38 @@ function setRevealHooks(e) {
|
|
|
77
77
|
|
|
78
78
|
/** Boundaries with readers to sweep (or an arm to resolve) at the seam. */ const collecting = new Set;
|
|
79
79
|
|
|
80
|
-
const boundaryOf = e => e.
|
|
80
|
+
const boundaryOf = e => e.A[BOUNDARY];
|
|
81
81
|
|
|
82
82
|
/** Catches what reaches it: an error boundary always; a loading one until it
|
|
83
|
-
* has shown content, or while re-armed. */ const isCollecting = e => e.
|
|
83
|
+
* has shown content, or while re-armed. */ const isCollecting = e => e.i === STATUS_ERROR || !e.D || e.h;
|
|
84
|
+
|
|
85
|
+
/** A reader `b` waits on: recorded for its `on`, and `b` visited at the seam. */ function record(e, r) {
|
|
86
|
+
e.U.add(r);
|
|
87
|
+
collecting.add(e);
|
|
88
|
+
}
|
|
84
89
|
|
|
85
90
|
/** The reader goes to the fallback: recorded, and the output re-derives
|
|
86
91
|
* (a no-op while the output's own pass is running — its post-check
|
|
87
|
-
* decides). */ function caught(e,
|
|
88
|
-
if (e.
|
|
92
|
+
* decides). */ function caught(e, r, n) {
|
|
93
|
+
if (e.i === STATUS_ERROR) {
|
|
89
94
|
// An error boundary waits on what THREW (`StatusError.source`), not on
|
|
90
95
|
// the reader that saw it: the reader recovers the moment a refetch
|
|
91
96
|
// starts (its boundary catches the pending), while the error is settled
|
|
92
97
|
// only when its source is neither errored nor in flight. `reset` re-runs
|
|
93
98
|
// the same node.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const t = unwrapStatusError(
|
|
99
|
+
n ??= r.T?.F;
|
|
100
|
+
r = n?.source ?? r;
|
|
101
|
+
const t = unwrapStatusError(n);
|
|
97
102
|
setSignal(e.F, t);
|
|
98
|
-
reportClientError(t, e.
|
|
103
|
+
reportClientError(t, e.H, r);
|
|
99
104
|
}
|
|
100
|
-
e
|
|
101
|
-
|
|
102
|
-
if (e.U) flip(e);
|
|
105
|
+
record(e, r);
|
|
106
|
+
if (e.h) flip(e);
|
|
103
107
|
// Already showing the fallback: one more reader to wait on changes
|
|
104
108
|
// nothing on screen. The fallback is instantiated once per show — a later
|
|
105
109
|
// error reaches it through the `error` accessor, which is why it is one.
|
|
106
|
-
if (!e.
|
|
107
|
-
if (e.
|
|
110
|
+
if (!e.L) redraw(e);
|
|
111
|
+
if (e.v !== null) revealHooks.P(e.v);
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
/** A re-armed boundary found something pending: fresh again, and the swap
|
|
@@ -112,22 +116,24 @@ const boundaryOf = e => e.D[BOUNDARY];
|
|
|
112
116
|
* the lane's work from its next pass's head — not a re-pass of the
|
|
113
117
|
* transaction holding its pending content, which would entangle that
|
|
114
118
|
* transaction with the arming frame's (#3540 `on: () => latest(dep)`). */ function flip(e) {
|
|
115
|
-
e.
|
|
116
|
-
e.
|
|
117
|
-
|
|
119
|
+
e.D = false;
|
|
120
|
+
e.V = e.B;
|
|
121
|
+
const r = e.j;
|
|
122
|
+
if (!e.V && r.l & CONFIG_HELD && txOf(r) !== flushTransaction) unhold(r);
|
|
123
|
+
if (e.V !== null && e.j !== null) laneStageHook(e.j, e.V, true, false);
|
|
118
124
|
}
|
|
119
125
|
|
|
120
126
|
function redraw(e) {
|
|
121
|
-
if (e.
|
|
122
|
-
enqueueSub(e.
|
|
127
|
+
if (e.j !== null && !(e.j.R & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
128
|
+
enqueueSub(e.j);
|
|
123
129
|
schedule();
|
|
124
130
|
}
|
|
125
131
|
}
|
|
126
132
|
|
|
127
|
-
/**
|
|
133
|
+
/** `catchHook` (scheduler.ts): status from a frame reader, nearest boundary first.
|
|
128
134
|
* A loading boundary on the way records a pending reader whether or not it
|
|
129
|
-
* catches it (its `on` may collect it later). */ function catchStatus(e,
|
|
130
|
-
if (
|
|
135
|
+
* catches it (its `on` may collect it later). */ function catchStatus(e, r, n) {
|
|
136
|
+
if (r === 0) {
|
|
131
137
|
// A status cleared. Judged by the node's status now, against each
|
|
132
138
|
// boundary's own rule (`unsettled`) — the error path clears pending
|
|
133
139
|
// first and the node is still errored then. The last reader a fallback
|
|
@@ -135,34 +141,35 @@ function redraw(e) {
|
|
|
135
141
|
// held reader's landing has joined its transaction, so the content
|
|
136
142
|
// lands with its run, not a round after). Others still waiting: nothing
|
|
137
143
|
// on screen changes, the fallback stays as it is.
|
|
138
|
-
if (collecting.size !== 0) for (let
|
|
139
|
-
if (
|
|
140
|
-
if (
|
|
144
|
+
if (collecting.size !== 0) for (let r = boundaryOf(e); r; r = r._parent) if (!(e.m & unsettled(r)) && r.U.delete(e) && r.U.size === 0) {
|
|
145
|
+
if (r.L) redraw(r);
|
|
146
|
+
if (r.v !== null) revealHooks.P(r.v);
|
|
141
147
|
}
|
|
142
148
|
return false;
|
|
143
149
|
}
|
|
144
|
-
for (let t = boundaryOf(e); t
|
|
145
|
-
if (!(t.
|
|
150
|
+
for (let t = boundaryOf(e); t; t = t._parent) {
|
|
151
|
+
if (!(t.i & r)) continue;
|
|
146
152
|
if (isCollecting(t)) {
|
|
147
|
-
caught(t, e,
|
|
148
|
-
return true;
|
|
153
|
+
caught(t, e, n);
|
|
154
|
+
return t.h ? CAUGHT_REARMED : true;
|
|
149
155
|
}
|
|
150
|
-
t
|
|
151
|
-
collecting.add(t);
|
|
156
|
+
record(t, e);
|
|
152
157
|
}
|
|
153
158
|
return false;
|
|
154
159
|
}
|
|
155
160
|
|
|
156
|
-
/** The nearest boundary
|
|
157
|
-
|
|
158
|
-
return
|
|
161
|
+
/** The nearest loading boundary that would catch `node` was re-armed this
|
|
162
|
+
* flush. */ function armedOver(e) {
|
|
163
|
+
for (let r = boundaryOf(e); r; r = r._parent) if (r.i & STATUS_PENDING && isCollecting(r)) return r.h;
|
|
159
164
|
}
|
|
160
165
|
|
|
161
|
-
/**
|
|
162
|
-
|
|
166
|
+
/** The nearest boundary on `r`'s chain showing its fallback, if any
|
|
167
|
+
* (`hiddenHook`: `r` is behind a fallback). */ function hiddenBy(e) {
|
|
168
|
+
for (let r = boundaryOf(e); r; r = r._parent) if (r.L) return r;
|
|
169
|
+
return undefined;
|
|
163
170
|
}
|
|
164
171
|
|
|
165
|
-
/**
|
|
172
|
+
/** `heldRunHook` (scheduler.ts): a queued run behind a fallback waits for the reveal
|
|
166
173
|
* (maintainer, 2026-10-02: the queue is held, the synchronous first render
|
|
167
174
|
* goes through). A user effect's, which would read a DOM that is not
|
|
168
175
|
* attached ("many depend on reading the DOM, something that can't happen
|
|
@@ -173,21 +180,21 @@ function redraw(e) {
|
|
|
173
180
|
* synchronous on creation and never comes here. The run's `_modified` stays
|
|
174
181
|
* set; the reveal re-queues it by type (`release`), and a boundary above
|
|
175
182
|
* still showing its fallback holds it again then. */ function heldRun(e) {
|
|
176
|
-
const
|
|
177
|
-
if (
|
|
178
|
-
(
|
|
183
|
+
const r = hiddenBy(e);
|
|
184
|
+
if (r === undefined) return false;
|
|
185
|
+
(r.Z ??= new Set).add(e);
|
|
179
186
|
return true;
|
|
180
187
|
}
|
|
181
188
|
|
|
182
189
|
/** The reveal: the runs held behind the fallback are this flush's, each in
|
|
183
190
|
* its own phase — render updates with the frame that attaches the content,
|
|
184
191
|
* user effects after it. */ function release(e) {
|
|
185
|
-
if (e.
|
|
186
|
-
for (const
|
|
187
|
-
const e =
|
|
188
|
-
globalQueue.enqueue(e === EFFECT_TRACKED ? EFFECT_USER : e, e === EFFECT_TRACKED ?
|
|
192
|
+
if (e.Z === null) return;
|
|
193
|
+
for (const r of e.Z) {
|
|
194
|
+
const e = r.i;
|
|
195
|
+
globalQueue.enqueue(e === EFFECT_TRACKED ? EFFECT_USER : e, e === EFFECT_TRACKED ? r.M : r.W ??= GlobalQueue.K.bind(null, r));
|
|
189
196
|
}
|
|
190
|
-
e.
|
|
197
|
+
e.Z = null;
|
|
191
198
|
}
|
|
192
199
|
|
|
193
200
|
/** Drop the readers that settled or died. Settled: a loading reader no
|
|
@@ -195,13 +202,13 @@ function redraw(e) {
|
|
|
195
202
|
* that landed but is held (its value staged in a transaction) is not: the
|
|
196
203
|
* content reveals at the commit, with its run. The tree is: the output reads
|
|
197
204
|
* it and enters the transaction itself (its committed value shows until the
|
|
198
|
-
* landing). */ const unsettled = e => e.
|
|
205
|
+
* landing). */ const unsettled = e => e.i === STATUS_ERROR ? STATUS_ERROR | STATUS_PENDING : STATUS_PENDING;
|
|
199
206
|
|
|
200
|
-
function prune(e,
|
|
201
|
-
const
|
|
202
|
-
for (const t of e.
|
|
203
|
-
if (t.R & REACTIVE_DISPOSED) e.
|
|
204
|
-
if (t !== e.
|
|
207
|
+
function prune(e, r) {
|
|
208
|
+
const n = unsettled(e);
|
|
209
|
+
for (const t of e.U) {
|
|
210
|
+
if (t.R & REACTIVE_DISPOSED) e.U.delete(t); else if (!(t.m & n)) {
|
|
211
|
+
if ((t !== e.Y || e.h) && (t.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD) {
|
|
205
212
|
// Landed, held: the content is that transaction's — the output's
|
|
206
213
|
// pass enters it and the reveal lands with the reader's run. The
|
|
207
214
|
// seam, past its park decision, waits for the commit instead. (A
|
|
@@ -209,61 +216,58 @@ function prune(e, n) {
|
|
|
209
216
|
// has not shown content catches it instead: the fallback stays until
|
|
210
217
|
// the reader is committed (#3540: what a fresh boundary catches holds
|
|
211
218
|
// nothing outside it).
|
|
212
|
-
if (!
|
|
219
|
+
if (!r || !e.D) continue;
|
|
213
220
|
joinFuture(txOf(t));
|
|
214
221
|
}
|
|
215
|
-
e.
|
|
222
|
+
e.U.delete(t);
|
|
216
223
|
}
|
|
217
224
|
}
|
|
218
|
-
return e.
|
|
225
|
+
return e.U.size;
|
|
219
226
|
}
|
|
220
227
|
|
|
221
228
|
/** Reveal order: a slot is ready when its content can show — it has shown
|
|
222
229
|
* content, or nothing under it is unready (the tree neither pending nor
|
|
223
230
|
* born held, no reader waited on). */ function ready(e) {
|
|
224
|
-
return e.
|
|
231
|
+
return e.D || !(e.Y.m & STATUS_PENDING) && !(e.Y.l & CONFIG_HELD && (e.j === null || e.j.m & STATUS_UNINITIALIZED)) && prune(e, false) === 0;
|
|
225
232
|
}
|
|
226
233
|
|
|
227
|
-
/**
|
|
234
|
+
/** `boundarySeamHook` (scheduler.ts), end of the seam: readers that settled, died,
|
|
228
235
|
* or landed and committed are dropped; a fallback with none left reveals
|
|
229
236
|
* next round. An arm resolves: nothing collected, nothing happened. */ function boundarySeam() {
|
|
230
237
|
for (const e of collecting) {
|
|
231
|
-
const
|
|
232
|
-
if (
|
|
238
|
+
const r = e.j.R;
|
|
239
|
+
if (r & REACTIVE_DISPOSED) {
|
|
233
240
|
collecting.delete(e);
|
|
234
241
|
continue;
|
|
235
242
|
}
|
|
236
243
|
// A parked frame's boundary (zombie) keeps its state for its revival.
|
|
237
|
-
if (
|
|
244
|
+
if (r & REACTIVE_ZOMBIE) continue;
|
|
238
245
|
prune(e, false);
|
|
239
|
-
|
|
240
|
-
if (e.
|
|
246
|
+
const n = e.j;
|
|
247
|
+
if (e.h && !e.D && n.l & CONFIG_HELD && [ ...e.U ].every(e => !(e.m & STATUS_PENDING) && e.l & CONFIG_HELD && txOf(e) === txOf(n))) {
|
|
248
|
+
e.U.clear();
|
|
249
|
+
e.D = true;
|
|
250
|
+
}
|
|
251
|
+
e.h = false;
|
|
252
|
+
if (e.U.size === 0) {
|
|
241
253
|
collecting.delete(e);
|
|
242
|
-
if (e.
|
|
243
|
-
if (e.
|
|
254
|
+
if (e.L) redraw(e);
|
|
255
|
+
if (e.v !== null) revealHooks.P(e.v);
|
|
244
256
|
}
|
|
245
257
|
}
|
|
246
258
|
}
|
|
247
259
|
|
|
248
|
-
/** The `on` pass is a verdict's: it probed itself (CONFIG_VERDICT), or it
|
|
249
|
-
* read a memo that did (#3528's `createMemo(() => isPending(m2))`) — its
|
|
250
|
-
* swap is display-ahead either way. */ function verdictDerived(e) {
|
|
251
|
-
if (e.i & CONFIG_VERDICT) return true;
|
|
252
|
-
for (let n = e.G; n !== null; n = n._) if (n.I.i & CONFIG_VERDICT) return true;
|
|
253
|
-
return false;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
260
|
/** `on` changed after the mount: fresh again if anything under it is
|
|
257
261
|
* pending now; collecting for the rest of the flush either way. */ function arm(e) {
|
|
258
|
-
if (!e.
|
|
262
|
+
if (!e.D) {
|
|
259
263
|
// Already re-armed and on its fallback, as the frame's work — and the
|
|
260
264
|
// `on` pass arms again as lane work: its verdict was provisional (a
|
|
261
265
|
// memo of `isPending(m2)` is a watcher until the flush parks, then the
|
|
262
266
|
// holder's verdict lane's — verdict.ts), and the swap it asked for is
|
|
263
267
|
// display-ahead after all (#3528). Re-home the swap: the output re-runs
|
|
264
268
|
// as the lane's, shown now beside the held frame.
|
|
265
|
-
if (e.
|
|
266
|
-
e.
|
|
269
|
+
if (e.L && e.V === null && e.B === null && passLane !== null) {
|
|
270
|
+
e.B = passLane;
|
|
267
271
|
// The swap the frame's pass staged (held with the frame) is void: the
|
|
268
272
|
// lane's pass stages it anew (`flip` lists the output in the lane,
|
|
269
273
|
// which voids its staging), as a watcher's provisional value is
|
|
@@ -273,20 +277,28 @@ function prune(e, n) {
|
|
|
273
277
|
}
|
|
274
278
|
return;
|
|
275
279
|
}
|
|
276
|
-
e.
|
|
277
|
-
// A verdict read in `on` (`isPending
|
|
278
|
-
//
|
|
280
|
+
e.h = true;
|
|
281
|
+
// A verdict read in `on` (`isPending`, or a memo of one — #3528's
|
|
282
|
+
// `createMemo(() => isPending(m2))`: the mark carries, core.ts `read`)
|
|
283
|
+
// whose frame has no transaction yet: the swap is still display-ahead — the frame gets one now (it lands
|
|
279
284
|
// at this very seam if nothing holds it), and the swap is its verdict
|
|
280
285
|
// lane's work, shown ahead of the frame's own runs (#3528).
|
|
281
|
-
let
|
|
282
|
-
if (
|
|
286
|
+
let r = passLane;
|
|
287
|
+
if (r === null && globalQueue.q && getOwner().l & CONFIG_VERDICT) {
|
|
283
288
|
joinFuture(null);
|
|
284
|
-
|
|
289
|
+
r = GlobalQueue.J(flushTransaction);
|
|
285
290
|
}
|
|
286
|
-
e.
|
|
291
|
+
e.B = r;
|
|
287
292
|
collecting.add(e);
|
|
288
|
-
|
|
289
|
-
|
|
293
|
+
const n = e.U.size;
|
|
294
|
+
heldUnder(e.H, flushTransaction, r => record(e, r));
|
|
295
|
+
for (const r of e.U) {
|
|
296
|
+
if (e.U.size !== n || r.m & STATUS_PENDING && !(r.R & REACTIVE_DISPOSED)) {
|
|
297
|
+
// What it collects was forwarded through it to the boundaries above
|
|
298
|
+
// too (`catchStatus` records a reader in every boundary on the way).
|
|
299
|
+
// It is this boundary's alone now (B5, the nearest catcher): an outer
|
|
300
|
+
// re-armed by the same tick does not wait for it (D-14, U-4).
|
|
301
|
+
for (let r = e._parent; r !== null; r = r._parent) for (const n of e.U) r.U.delete(n);
|
|
290
302
|
flip(e);
|
|
291
303
|
redraw(e);
|
|
292
304
|
return;
|
|
@@ -297,36 +309,36 @@ function prune(e, n) {
|
|
|
297
309
|
/** The error boundary's `reset`: re-run what threw (a comparator throw
|
|
298
310
|
* names a signal — nothing to re-run). */ function reset(e) {
|
|
299
311
|
// A snapshot: a source failing again is caught — and re-added — mid-walk.
|
|
300
|
-
for (const
|
|
312
|
+
for (const r of [ ...e.U ]) if (r.X !== undefined && !(r.R & REACTIVE_DISPOSED)) recompute(r);
|
|
301
313
|
schedule();
|
|
302
314
|
}
|
|
303
315
|
|
|
304
|
-
function createBoundary(e,
|
|
305
|
-
const
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
_parent: boundaryOf(
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
Z: null,
|
|
312
|
-
v: new Set,
|
|
313
|
-
h: false,
|
|
314
|
-
U: false,
|
|
316
|
+
function createBoundary(e, r, n, t) {
|
|
317
|
+
const o = createOwner();
|
|
318
|
+
const l = {
|
|
319
|
+
i: e,
|
|
320
|
+
_parent: boundaryOf(o) ?? null,
|
|
321
|
+
H: o,
|
|
322
|
+
Y: null,
|
|
315
323
|
j: null,
|
|
324
|
+
U: new Set,
|
|
325
|
+
D: false,
|
|
326
|
+
h: false,
|
|
316
327
|
B: null,
|
|
317
|
-
H: false,
|
|
318
|
-
K: null,
|
|
319
328
|
V: null,
|
|
320
|
-
|
|
321
|
-
|
|
329
|
+
L: false,
|
|
330
|
+
Z: null,
|
|
331
|
+
v: null,
|
|
332
|
+
$: false,
|
|
333
|
+
ee: false,
|
|
322
334
|
F: e === STATUS_ERROR ? signal(undefined, ERROR_SIGNAL) : null,
|
|
323
|
-
|
|
324
|
-
|
|
335
|
+
re: n,
|
|
336
|
+
ne: null
|
|
325
337
|
};
|
|
326
|
-
const u = e === STATUS_PENDING ?
|
|
338
|
+
const u = e === STATUS_PENDING ? o.A[REVEAL] : null;
|
|
327
339
|
if (getOwner()) cleanup(() => {
|
|
328
|
-
collecting.delete(
|
|
329
|
-
if (u) revealHooks.
|
|
340
|
+
collecting.delete(l);
|
|
341
|
+
if (u) revealHooks.te(u, l);
|
|
330
342
|
});
|
|
331
343
|
// The `on` dependencies live OUTSIDE the boundary, as the condition of a
|
|
332
344
|
// `<Show>` wrapping it would: created before the owner's context names it.
|
|
@@ -335,7 +347,7 @@ function createBoundary(e, n, r, t) {
|
|
|
335
347
|
// does not suspend the parent — and re-arms.
|
|
336
348
|
if (t) {
|
|
337
349
|
let e = false;
|
|
338
|
-
runWithOwner(
|
|
350
|
+
runWithOwner(o, () => computed(() => {
|
|
339
351
|
try {
|
|
340
352
|
t();
|
|
341
353
|
} catch (e) {
|
|
@@ -347,46 +359,46 @@ function createBoundary(e, n, r, t) {
|
|
|
347
359
|
return;
|
|
348
360
|
}
|
|
349
361
|
}
|
|
350
|
-
if (e) arm(
|
|
351
|
-
})).
|
|
362
|
+
if (e) arm(l); else e = true;
|
|
363
|
+
})).l |= CONFIG_REDERIVE;
|
|
352
364
|
}
|
|
353
365
|
const a = {
|
|
354
|
-
...
|
|
355
|
-
[BOUNDARY]:
|
|
366
|
+
...o.A,
|
|
367
|
+
[BOUNDARY]: l
|
|
356
368
|
};
|
|
357
369
|
if (revealHooks !== null) a[REVEAL] = null;
|
|
358
|
-
|
|
359
|
-
const i = runWithOwner(
|
|
360
|
-
const e = true ? computed(
|
|
370
|
+
o.A = a;
|
|
371
|
+
const i = runWithOwner(o, () => {
|
|
372
|
+
const e = true ? computed(r, {
|
|
361
373
|
name: "children"
|
|
362
|
-
}) : computed(
|
|
374
|
+
}) : computed(r);
|
|
363
375
|
return true ? computed(() => flatten(read(e)), {
|
|
364
376
|
name: "boundary"
|
|
365
377
|
}) : computed(() => flatten(read(e)));
|
|
366
378
|
});
|
|
367
|
-
|
|
379
|
+
l.Y = i;
|
|
368
380
|
// A slot of the reveal order in its context (reveal.ts): gated until the
|
|
369
381
|
// controller releases it — before the output's first pass.
|
|
370
|
-
if (u) revealHooks.
|
|
371
|
-
const
|
|
382
|
+
if (u) revealHooks.oe(u, l);
|
|
383
|
+
const s = computed(() => {
|
|
372
384
|
// Reveal order (reveal.ts): a gated slot shows its fallback — or, in a
|
|
373
385
|
// collapsed tail, nothing — whatever its content's state; the
|
|
374
386
|
// controller is told the pass ran (its readiness may have changed) and
|
|
375
387
|
// releases it in turn.
|
|
376
|
-
if (
|
|
388
|
+
if (l.$) {
|
|
377
389
|
// Linked without being read: the tree settling (or changing)
|
|
378
390
|
// re-derives this pass, which is how the controller hears of it.
|
|
379
391
|
// It may release this very slot (the frontier whose content just
|
|
380
392
|
// settled): the pass goes on to show it — the redraw it asks for is
|
|
381
393
|
// refused mid-pass and not needed.
|
|
382
394
|
link(i, getOwner());
|
|
383
|
-
if (
|
|
384
|
-
if (
|
|
385
|
-
if (
|
|
386
|
-
|
|
395
|
+
if (l.v !== null) revealHooks.P(l.v);
|
|
396
|
+
if (l.$) {
|
|
397
|
+
if (l.ee) {
|
|
398
|
+
l.L = true;
|
|
387
399
|
return undefined;
|
|
388
400
|
}
|
|
389
|
-
return fallback(
|
|
401
|
+
return fallback(l);
|
|
390
402
|
}
|
|
391
403
|
}
|
|
392
404
|
// A tree carrying a status is not read: an errored memo's reactive
|
|
@@ -396,24 +408,23 @@ function createBoundary(e, n, r, t) {
|
|
|
396
408
|
// display-ahead `on` causes is the lane's, and must still be the
|
|
397
409
|
// fallback. Linked, so its recovery re-derives this pass; read again
|
|
398
410
|
// once clean.
|
|
399
|
-
const
|
|
400
|
-
if (
|
|
411
|
+
const r = i.m & (STATUS_PENDING | STATUS_ERROR);
|
|
412
|
+
if (r !== 0) {
|
|
401
413
|
link(i, getOwner());
|
|
402
|
-
if (
|
|
403
|
-
if (isCollecting(
|
|
404
|
-
caught(
|
|
405
|
-
return fallback(
|
|
414
|
+
if (r & e) {
|
|
415
|
+
if (isCollecting(l)) {
|
|
416
|
+
caught(l, i, undefined);
|
|
417
|
+
return fallback(l);
|
|
406
418
|
}
|
|
407
419
|
// Forwarded: a loading boundary showing content keeps it and
|
|
408
420
|
// holds the frame like any reader (recorded for its `on`).
|
|
409
|
-
|
|
410
|
-
collecting.add(o);
|
|
421
|
+
record(l, i);
|
|
411
422
|
}
|
|
412
423
|
// A pending passes an error boundary by (A6); an error, a loading
|
|
413
424
|
// one; a loading boundary showing content forwards its pending.
|
|
414
|
-
throw i.
|
|
425
|
+
throw i.T.F;
|
|
415
426
|
}
|
|
416
|
-
if (isCollecting(
|
|
427
|
+
if (isCollecting(l)) {
|
|
417
428
|
// A29's boundary exemption (#3540): a boundary MOUNTED over a held
|
|
418
429
|
// value (its first pass; a first pass under it that read a hold was
|
|
419
430
|
// collected, `joinPass` — the tree's own, or a render effect's that
|
|
@@ -426,89 +437,88 @@ function createBoundary(e, n, r, t) {
|
|
|
426
437
|
// which reveals the content — a fallback staged earlier is replaced
|
|
427
438
|
// ahead of the commit and never shown.
|
|
428
439
|
const e = getOwner();
|
|
429
|
-
if (
|
|
440
|
+
if (l.U.size !== 0 && e.m & STATUS_UNINITIALIZED && !(e.l & CONFIG_HELD)) return fallback(l);
|
|
430
441
|
// Readers under it still unready: the fallback, the tree untouched.
|
|
431
442
|
// The seam re-derives this pass when they settle.
|
|
432
|
-
if (prune(
|
|
443
|
+
if (prune(l, true) !== 0) return fallback(l);
|
|
433
444
|
}
|
|
434
|
-
let
|
|
445
|
+
let n;
|
|
435
446
|
try {
|
|
436
|
-
|
|
437
|
-
} catch (
|
|
438
|
-
if (
|
|
439
|
-
if (isCollecting(
|
|
440
|
-
caught(
|
|
441
|
-
return fallback(
|
|
447
|
+
n = read(i);
|
|
448
|
+
} catch (r) {
|
|
449
|
+
if (r instanceof NotReadyError ? e === STATUS_PENDING : e === STATUS_ERROR) {
|
|
450
|
+
if (isCollecting(l)) {
|
|
451
|
+
caught(l, i, r);
|
|
452
|
+
return fallback(l);
|
|
442
453
|
}
|
|
443
454
|
// Forwarded: a loading boundary showing content keeps it and
|
|
444
455
|
// holds the frame like any reader (recorded for its `on`).
|
|
445
|
-
|
|
446
|
-
collecting.add(o);
|
|
456
|
+
record(l, i);
|
|
447
457
|
}
|
|
448
458
|
// A pending passes an error boundary by (A6).
|
|
449
|
-
throw
|
|
459
|
+
throw r;
|
|
450
460
|
}
|
|
451
461
|
// Readers under it still unready (caught before, or while the read
|
|
452
462
|
// ran the content at a mount): the fallback.
|
|
453
|
-
if (isCollecting(
|
|
454
|
-
|
|
463
|
+
if (isCollecting(l) && l.U.size !== 0) return fallback(l);
|
|
464
|
+
l.D = true;
|
|
455
465
|
// Observe: the fallback stops showing (a hide before its commit means
|
|
456
466
|
// it never displayed — the engine knows the swap it was staged with).
|
|
457
|
-
if (
|
|
458
|
-
|
|
467
|
+
if (l.L && l.i & STATUS_PENDING && attrHooks !== null) attrHooks.boundaryFallback(l, l.Y, false);
|
|
468
|
+
l.L = false;
|
|
459
469
|
// The fallback dies when the content that replaces it is on screen —
|
|
460
470
|
// with this flush's commits when the pass is the frame's, at the
|
|
461
471
|
// landing when the frame parks (the run is held with it, as the old
|
|
462
472
|
// children of a held pass are) — not now: a held swap keeps the
|
|
463
473
|
// fallback on screen, live, until it commits. A pass back to the
|
|
464
474
|
// fallback before then finds it still built and keeps it.
|
|
465
|
-
const t =
|
|
475
|
+
const t = l.ne;
|
|
466
476
|
if (t !== null) globalQueue.enqueue(EFFECT_RENDER, () => {
|
|
467
|
-
if (!
|
|
477
|
+
if (!l.L && l.ne === t) {
|
|
468
478
|
dispose(t);
|
|
469
|
-
|
|
479
|
+
l.ne = null;
|
|
470
480
|
}
|
|
471
481
|
});
|
|
472
|
-
release(
|
|
482
|
+
release(l);
|
|
473
483
|
// Shown: the slot leaves its reveal order (a later re-arm gates nobody
|
|
474
484
|
// else; the frontier moves on).
|
|
475
|
-
if (
|
|
476
|
-
const e =
|
|
477
|
-
|
|
485
|
+
if (l.v !== null) {
|
|
486
|
+
const e = l.v;
|
|
487
|
+
l.v = null;
|
|
478
488
|
revealHooks.P(e);
|
|
479
489
|
}
|
|
480
|
-
return
|
|
490
|
+
return n;
|
|
481
491
|
},
|
|
482
492
|
// Boundary structure, not a user source: its value is fallback-or-content
|
|
483
493
|
// and legitimately swaps mid-hydration (resume), so it must never be
|
|
484
494
|
// frozen by snapshot capture.
|
|
485
495
|
{
|
|
486
496
|
name: "value",
|
|
487
|
-
|
|
497
|
+
le: true
|
|
488
498
|
});
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
return accessor(
|
|
499
|
+
s.l |= CONFIG_REDERIVE;
|
|
500
|
+
l.j = s;
|
|
501
|
+
return accessor(s);
|
|
492
502
|
}
|
|
493
503
|
|
|
494
504
|
function fallback(e) {
|
|
495
505
|
// The swap a display-ahead re-arm asked for: this pass is the lane's — a
|
|
496
506
|
// lane read by construction (REACTIVE_LANE_READ: `recompute`'s tail keeps
|
|
497
507
|
// the pass in the lane).
|
|
498
|
-
if (e.
|
|
499
|
-
setPassLane(e.
|
|
500
|
-
e.
|
|
501
|
-
e.
|
|
508
|
+
if (e.V !== null) {
|
|
509
|
+
setPassLane(e.V);
|
|
510
|
+
e.j.R |= REACTIVE_LANE_READ;
|
|
511
|
+
e.V = null;
|
|
502
512
|
}
|
|
503
513
|
// Observe: a loading boundary starts showing its fallback — the swap lands
|
|
504
514
|
// with the frame's transaction, or this drain commits it (lane work, or no
|
|
505
515
|
// transaction). A mount's synchronous first show has no drain of its own:
|
|
506
516
|
// one is scheduled so the engine's display instant (`flushEnd`) comes.
|
|
507
|
-
if (!e.
|
|
508
|
-
attrHooks.boundaryFallback(e, e.
|
|
509
|
-
if (!globalQueue.
|
|
517
|
+
if (!e.L && e.i & STATUS_PENDING && attrHooks !== null) {
|
|
518
|
+
attrHooks.boundaryFallback(e, e.Y, true, passLane !== null ? null : flushTransaction !== null ? resolveTx(flushTransaction) : passTx);
|
|
519
|
+
if (!globalQueue.q) schedule();
|
|
510
520
|
}
|
|
511
|
-
e.
|
|
521
|
+
e.L = true;
|
|
512
522
|
// Built in its own scope, like `Show`'s function child, once per show
|
|
513
523
|
// (D-39: the fallback is the display until a new answer replaces the
|
|
514
524
|
// error): a re-derive of the output while it shows — a second reader
|
|
@@ -520,18 +530,18 @@ function fallback(e) {
|
|
|
520
530
|
// outside the boundary, as the output is: its errors and runs are the
|
|
521
531
|
// enclosing boundary's — with the output's id, so what it builds gets the
|
|
522
532
|
// ids a build under the output would; disposed once content is on screen.
|
|
523
|
-
if (e.
|
|
524
|
-
const
|
|
525
|
-
e.
|
|
526
|
-
id:
|
|
533
|
+
if (e.ne === null) {
|
|
534
|
+
const r = getOwner();
|
|
535
|
+
e.ne = runWithOwner(r._parent, () => computed(() => e.re(e), {
|
|
536
|
+
id: r.id
|
|
527
537
|
}));
|
|
528
538
|
}
|
|
529
|
-
return read(e.
|
|
539
|
+
return read(e.ne);
|
|
530
540
|
}
|
|
531
541
|
|
|
532
542
|
const ERROR_SIGNAL = {
|
|
533
543
|
ownedWrite: true,
|
|
534
|
-
|
|
544
|
+
le: true
|
|
535
545
|
};
|
|
536
546
|
|
|
537
547
|
/**
|
|
@@ -575,8 +585,8 @@ const ERROR_SIGNAL = {
|
|
|
575
585
|
* ) as unknown as JSX.Element;
|
|
576
586
|
* }
|
|
577
587
|
* ```
|
|
578
|
-
*/ function createLoadingBoundary(e,
|
|
579
|
-
return createBoundary(STATUS_PENDING, e, () =>
|
|
588
|
+
*/ function createLoadingBoundary(e, r, n) {
|
|
589
|
+
return createBoundary(STATUS_PENDING, e, () => r(), n?.on);
|
|
580
590
|
}
|
|
581
591
|
|
|
582
592
|
/**
|
|
@@ -601,20 +611,12 @@ const ERROR_SIGNAL = {
|
|
|
601
611
|
* ) as unknown as JSX.Element;
|
|
602
612
|
* }
|
|
603
613
|
* ```
|
|
604
|
-
*/ function createErrorBoundary(e,
|
|
605
|
-
return createBoundary(STATUS_ERROR, e, e =>
|
|
614
|
+
*/ function createErrorBoundary(e, r) {
|
|
615
|
+
return createBoundary(STATUS_ERROR, e, e => r(accessor(e.F), () => reset(e)));
|
|
606
616
|
}
|
|
607
617
|
|
|
608
618
|
// Installed at module evaluation — present exactly when something imports a
|
|
609
619
|
// boundary. An app without one pays the three null checks and nothing else.
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
GlobalQueue.fe = e => e.S & STATUS_UNINITIALIZED && catchStatus(e, STATUS_PENDING);
|
|
613
|
-
|
|
614
|
-
GlobalQueue.se = hidden;
|
|
615
|
-
|
|
616
|
-
GlobalQueue.ce = boundarySeam;
|
|
617
|
-
|
|
618
|
-
GlobalQueue.Ee = heldRun;
|
|
620
|
+
installBoundaryHooks(catchStatus, (e, r) => !r && (e.m & STATUS_UNINITIALIZED ? catchStatus(e, STATUS_PENDING) : armedOver(e)), hiddenBy, boundarySeam, heldRun);
|
|
619
621
|
|
|
620
622
|
export { REVEAL, createErrorBoundary, createLoadingBoundary, prune, ready, redraw, revealHooks, setRevealHooks };
|