@solidjs/signals 2.0.0-rc.17 → 2.0.0-rc.19
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 +426 -241
- package/dist/dev.attribution.js +19 -16
- package/dist/dev.js +768 -409
- package/dist/observe/boundaries.js +88 -67
- package/dist/observe/core/action.js +8 -0
- package/dist/observe/core/async.js +183 -138
- package/dist/observe/core/attribution.js +30 -28
- package/dist/observe/core/constants.js +23 -1
- package/dist/observe/core/core.js +185 -157
- package/dist/observe/core/effect.js +34 -37
- package/dist/observe/core/graph.js +8 -8
- package/dist/observe/core/heap.js +5 -5
- package/dist/observe/core/lanes.js +104 -84
- package/dist/observe/core/owner.js +17 -16
- package/dist/observe/core/scheduler.js +61 -47
- package/dist/observe/core/truth.js +6 -6
- package/dist/observe/core/verdict.js +15 -15
- package/dist/observe/deferred.js +40 -38
- package/dist/observe/from.js +248 -0
- package/dist/observe/index.js +4 -2
- package/dist/observe/map.js +22 -22
- package/dist/observe/reveal.js +5 -5
- package/dist/observe/signals.js +57 -15
- package/dist/observe/store/affects.js +1 -1
- package/dist/observe/store/hooks.js +3 -0
- package/dist/observe/store/optimistic.js +11 -11
- package/dist/observe/store/projection.js +34 -21
- package/dist/observe/store/reconcile.js +138 -122
- package/dist/observe/store/store.js +628 -641
- package/dist/observe/store/target.js +1 -5
- package/dist/observe/store/utils.js +7 -2
- package/dist/prod/boundaries.js +153 -132
- package/dist/prod/core/action.js +8 -0
- package/dist/prod/core/async.js +242 -197
- package/dist/prod/core/constants.js +16 -1
- package/dist/prod/core/core.js +166 -138
- package/dist/prod/core/effect.js +31 -34
- package/dist/prod/core/graph.js +5 -5
- package/dist/prod/core/heap.js +12 -12
- package/dist/prod/core/lanes.js +98 -78
- package/dist/prod/core/owner.js +15 -14
- package/dist/prod/core/scheduler.js +64 -50
- package/dist/prod/core/truth.js +6 -6
- package/dist/prod/core/verdict.js +17 -17
- package/dist/prod/deferred.js +40 -38
- package/dist/prod/from.js +248 -0
- package/dist/prod/index.js +4 -2
- package/dist/prod/map.js +14 -14
- package/dist/prod/reveal.js +8 -8
- package/dist/prod/signals.js +46 -4
- package/dist/prod/store/affects.js +1 -1
- package/dist/prod/store/hooks.js +3 -0
- package/dist/prod/store/optimistic.js +16 -16
- package/dist/prod/store/projection.js +22 -9
- package/dist/prod/store/reconcile.js +138 -122
- package/dist/prod/store/store.js +308 -331
- package/dist/prod/store/target.js +13 -17
- package/dist/prod/store/utils.js +2 -0
- package/dist/types/core/action.d.ts +8 -0
- package/dist/types/core/async.d.ts +12 -2
- package/dist/types/core/constants.d.ts +25 -0
- package/dist/types/core/core.d.ts +33 -4
- package/dist/types/core/dev.d.ts +1 -1
- package/dist/types/core/index.d.ts +1 -1
- package/dist/types/core/lanes.d.ts +5 -1
- package/dist/types/core/scheduler.d.ts +17 -3
- package/dist/types/from.d.ts +47 -0
- package/dist/types/index.d.ts +4 -1
- package/dist/types/signals.d.ts +37 -0
- package/dist/types/store/target.d.ts +2 -0
- package/package.json +1 -1
|
@@ -31,10 +31,6 @@ function isOwned(e) {
|
|
|
31
31
|
return n !== undefined && n.fam === o ? n : (o?.map ?? storeLookup).get(e);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
function devAssertNeverUserMutation(e) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
34
|
/** Sticky descendants flag up the parent chain (§6d): adoption descends
|
|
39
35
|
* into a changed child pair only where a target with nodes exists below. */ function markDescendants(e) {
|
|
40
36
|
let o = e;
|
|
@@ -47,4 +43,4 @@ function devAssertNeverUserMutation(e) {
|
|
|
47
43
|
/** Observe tier: the owner in scope at `createStore` (attribution names and
|
|
48
44
|
* owner paths); the `_owner` write never reaches the proxy. */ const storeOwners = new WeakMap;
|
|
49
45
|
|
|
50
|
-
export { $OWNER,
|
|
46
|
+
export { $OWNER, isOwned, lookupTarget, markDescendants, setLookup, storeLookup, storeOwners };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SUPPORTS_PROXY } from "../core/constants.js";
|
|
1
|
+
import { SUPPORTS_PROXY, CONFIG_KEY_BAG } from "../core/constants.js";
|
|
2
2
|
|
|
3
3
|
import { createMemo } from "../signals.js";
|
|
4
4
|
|
|
@@ -921,7 +921,12 @@ const omitTraps = {
|
|
|
921
921
|
f++;
|
|
922
922
|
i = o;
|
|
923
923
|
if (typeof o === "function") {
|
|
924
|
-
|
|
924
|
+
// Observe tiers name it and exempt it from UNSTABLE_MEMO_OUTPUT (see
|
|
925
|
+
// CONFIG_KEY_BAG); prod passes no options.
|
|
926
|
+
n[r] = createMemo(o, {
|
|
927
|
+
name: "merge",
|
|
928
|
+
St: CONFIG_KEY_BAG
|
|
929
|
+
});
|
|
925
930
|
t[r++] = SOURCE_MEMO;
|
|
926
931
|
continue;
|
|
927
932
|
}
|
package/dist/prod/boundaries.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { STATUS_PENDING, STATUS_ERROR, CONFIG_REDERIVE,
|
|
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";
|
|
2
2
|
|
|
3
3
|
import { signal, runWithOwner, computed, read, setSignal, recompute } from "./core/core.js";
|
|
4
4
|
|
|
@@ -12,7 +12,7 @@ import { enqueueSub } from "./core/heap.js";
|
|
|
12
12
|
|
|
13
13
|
import { createOwner, getOwner, cleanup, dispose } from "./core/owner.js";
|
|
14
14
|
|
|
15
|
-
import { globalQueue, haltReactivityAt, haltReactivity, passLane, joinFuture, GlobalQueue, flushTransaction, heldUnder, setPassLane, txOf, unhold, laneStageHook,
|
|
15
|
+
import { globalQueue, haltReactivityAt, haltReactivity, schedule, passLane, joinFuture, GlobalQueue, flushTransaction, heldUnder, setPassLane, txOf, unhold, laneStageHook, installBoundaryHooks } from "./core/scheduler.js";
|
|
16
16
|
|
|
17
17
|
import { flatten } from "./flatten.js";
|
|
18
18
|
|
|
@@ -65,6 +65,9 @@ import { accessor } from "./signals.js";
|
|
|
65
65
|
* slot of (reveal.ts); a boundary clears it for its content — only direct
|
|
66
66
|
* children are slots. */ const REVEAL = Symbol("");
|
|
67
67
|
|
|
68
|
+
// Every call site checks the hooks themselves first (not only the slot or
|
|
69
|
+
// controller, which are never set without them): a build that does not
|
|
70
|
+
// import `createRevealOrder` folds the reveal-order arms away.
|
|
68
71
|
let revealHooks = null;
|
|
69
72
|
|
|
70
73
|
function setRevealHooks(e) {
|
|
@@ -78,33 +81,33 @@ const boundaryOf = e => e.A[BOUNDARY];
|
|
|
78
81
|
/** Catches what reaches it: an error boundary always; a loading one until it
|
|
79
82
|
* has shown content, or while re-armed. */ const isCollecting = e => e.i === STATUS_ERROR || !e.D || e.h;
|
|
80
83
|
|
|
81
|
-
/** A reader `b` waits on: recorded for its `on`, and `b` visited at the seam. */ function record(e,
|
|
82
|
-
e.
|
|
84
|
+
/** A reader `b` waits on: recorded for its `on`, and `b` visited at the seam. */ function record(e, r) {
|
|
85
|
+
e.F.add(r);
|
|
83
86
|
collecting.add(e);
|
|
84
87
|
}
|
|
85
88
|
|
|
86
89
|
/** The reader goes to the fallback: recorded, and the output re-derives
|
|
87
90
|
* (a no-op while the output's own pass is running — its post-check
|
|
88
|
-
* decides). */ function caught(e,
|
|
91
|
+
* decides). */ function caught(e, r, n) {
|
|
89
92
|
if (e.i === STATUS_ERROR) {
|
|
90
93
|
// An error boundary waits on what THREW (`StatusError.source`), not on
|
|
91
94
|
// the reader that saw it: the reader recovers the moment a refetch
|
|
92
95
|
// starts (its boundary catches the pending), while the error is settled
|
|
93
96
|
// only when its source is neither errored nor in flight. `reset` re-runs
|
|
94
97
|
// the same node.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
setSignal(e.
|
|
99
|
-
reportClientError(
|
|
98
|
+
n ??= r.T?.U;
|
|
99
|
+
r = n?.source ?? r;
|
|
100
|
+
const o = unwrapStatusError(n);
|
|
101
|
+
setSignal(e.U, o);
|
|
102
|
+
reportClientError(o, e.H, r);
|
|
100
103
|
}
|
|
101
|
-
record(e,
|
|
104
|
+
record(e, r);
|
|
102
105
|
if (e.h) flip(e);
|
|
103
106
|
// Already showing the fallback: one more reader to wait on changes
|
|
104
107
|
// nothing on screen. The fallback is instantiated once per show — a later
|
|
105
108
|
// error reaches it through the `error` accessor, which is why it is one.
|
|
106
|
-
if (!e.
|
|
107
|
-
if (e.
|
|
109
|
+
if (!e.L) redraw(e);
|
|
110
|
+
if (revealHooks && e.v !== null) revealHooks.V(e.v);
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
/** A re-armed boundary found something pending: fresh again, and the swap
|
|
@@ -113,10 +116,10 @@ const boundaryOf = e => e.A[BOUNDARY];
|
|
|
113
116
|
* transaction holding its pending content, which would entangle that
|
|
114
117
|
* transaction with the arming frame's (#3540 `on: () => latest(dep)`). */ function flip(e) {
|
|
115
118
|
e.D = false;
|
|
116
|
-
e.
|
|
117
|
-
const
|
|
118
|
-
if (!e.
|
|
119
|
-
if (e.
|
|
119
|
+
e.P = e.B;
|
|
120
|
+
const r = e.j;
|
|
121
|
+
if (!e.P && r.l & CONFIG_HELD && txOf(r) !== flushTransaction) unhold(r);
|
|
122
|
+
if (laneStageHook && e.P !== null && e.j !== null) laneStageHook(e.j, e.P, true, false);
|
|
120
123
|
}
|
|
121
124
|
|
|
122
125
|
function redraw(e) {
|
|
@@ -128,8 +131,8 @@ function redraw(e) {
|
|
|
128
131
|
|
|
129
132
|
/** `catchHook` (scheduler.ts): status from a frame reader, nearest boundary first.
|
|
130
133
|
* A loading boundary on the way records a pending reader whether or not it
|
|
131
|
-
* catches it (its `on` may collect it later). */ function catchStatus(e,
|
|
132
|
-
if (
|
|
134
|
+
* catches it (its `on` may collect it later). */ function catchStatus(e, r, n) {
|
|
135
|
+
if (r === 0) {
|
|
133
136
|
// A status cleared. Judged by the node's status now, against each
|
|
134
137
|
// boundary's own rule (`unsettled`) — the error path clears pending
|
|
135
138
|
// first and the node is still errored then. The last reader a fallback
|
|
@@ -137,31 +140,31 @@ function redraw(e) {
|
|
|
137
140
|
// held reader's landing has joined its transaction, so the content
|
|
138
141
|
// lands with its run, not a round after). Others still waiting: nothing
|
|
139
142
|
// on screen changes, the fallback stays as it is.
|
|
140
|
-
if (collecting.size !== 0) for (let
|
|
141
|
-
if (
|
|
142
|
-
if (
|
|
143
|
+
if (collecting.size !== 0) for (let r = boundaryOf(e); r; r = r._parent) if (!(e.m & unsettled(r)) && r.F.delete(e) && r.F.size === 0) {
|
|
144
|
+
if (r.L) redraw(r);
|
|
145
|
+
if (revealHooks && r.v !== null) revealHooks.V(r.v);
|
|
143
146
|
}
|
|
144
147
|
return false;
|
|
145
148
|
}
|
|
146
|
-
for (let
|
|
147
|
-
if (!(
|
|
148
|
-
if (isCollecting(
|
|
149
|
-
caught(
|
|
150
|
-
return
|
|
149
|
+
for (let o = boundaryOf(e); o; o = o._parent) {
|
|
150
|
+
if (!(o.i & r)) continue;
|
|
151
|
+
if (isCollecting(o)) {
|
|
152
|
+
caught(o, e, n);
|
|
153
|
+
return o.h ? CAUGHT_REARMED : true;
|
|
151
154
|
}
|
|
152
|
-
record(
|
|
155
|
+
record(o, e);
|
|
153
156
|
}
|
|
154
157
|
return false;
|
|
155
158
|
}
|
|
156
159
|
|
|
157
160
|
/** The nearest loading boundary that would catch `node` was re-armed this
|
|
158
161
|
* flush. */ function armedOver(e) {
|
|
159
|
-
for (let
|
|
162
|
+
for (let r = boundaryOf(e); r; r = r._parent) if (r.i & STATUS_PENDING && isCollecting(r)) return r.h;
|
|
160
163
|
}
|
|
161
164
|
|
|
162
165
|
/** The nearest boundary on `r`'s chain showing its fallback, if any
|
|
163
166
|
* (`hiddenHook`: `r` is behind a fallback). */ function hiddenBy(e) {
|
|
164
|
-
for (let
|
|
167
|
+
for (let r = boundaryOf(e); r; r = r._parent) if (r.L) return r;
|
|
165
168
|
return undefined;
|
|
166
169
|
}
|
|
167
170
|
|
|
@@ -176,21 +179,21 @@ function redraw(e) {
|
|
|
176
179
|
* synchronous on creation and never comes here. The run's `_modified` stays
|
|
177
180
|
* set; the reveal re-queues it by type (`release`), and a boundary above
|
|
178
181
|
* still showing its fallback holds it again then. */ function heldRun(e) {
|
|
179
|
-
const
|
|
180
|
-
if (
|
|
181
|
-
(
|
|
182
|
+
const r = hiddenBy(e);
|
|
183
|
+
if (r === undefined) return false;
|
|
184
|
+
(r.M ??= new Set).add(e);
|
|
182
185
|
return true;
|
|
183
186
|
}
|
|
184
187
|
|
|
185
188
|
/** The reveal: the runs held behind the fallback are this flush's, each in
|
|
186
189
|
* its own phase — render updates with the frame that attaches the content,
|
|
187
190
|
* user effects after it. */ function release(e) {
|
|
188
|
-
if (e.
|
|
189
|
-
for (const
|
|
190
|
-
const e =
|
|
191
|
-
globalQueue.enqueue(e === EFFECT_TRACKED ? EFFECT_USER : e, e === EFFECT_TRACKED ?
|
|
191
|
+
if (e.M === null) return;
|
|
192
|
+
for (const r of e.M) {
|
|
193
|
+
const e = r.i;
|
|
194
|
+
globalQueue.enqueue(e === EFFECT_TRACKED ? EFFECT_USER : e, e === EFFECT_TRACKED ? r.Z : r.W ??= GlobalQueue.K.bind(null, r));
|
|
192
195
|
}
|
|
193
|
-
e.
|
|
196
|
+
e.M = null;
|
|
194
197
|
}
|
|
195
198
|
|
|
196
199
|
/** Drop the readers that settled or died. Settled: a loading reader no
|
|
@@ -200,11 +203,11 @@ function redraw(e) {
|
|
|
200
203
|
* it and enters the transaction itself (its committed value shows until the
|
|
201
204
|
* landing). */ const unsettled = e => e.i === STATUS_ERROR ? STATUS_ERROR | STATUS_PENDING : STATUS_PENDING;
|
|
202
205
|
|
|
203
|
-
function prune(e,
|
|
204
|
-
const
|
|
205
|
-
for (const
|
|
206
|
-
if (
|
|
207
|
-
if ((
|
|
206
|
+
function prune(e, r) {
|
|
207
|
+
const n = unsettled(e);
|
|
208
|
+
for (const o of e.F) {
|
|
209
|
+
if (o.R & REACTIVE_DISPOSED) e.F.delete(o); else if (!(o.m & n)) {
|
|
210
|
+
if ((o !== e.Y || e.h) && (o.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD) {
|
|
208
211
|
// Landed, held: the content is that transaction's — the output's
|
|
209
212
|
// pass enters it and the reveal lands with the reader's run. The
|
|
210
213
|
// seam, past its park decision, waits for the commit instead. (A
|
|
@@ -212,13 +215,13 @@ function prune(e, n) {
|
|
|
212
215
|
// has not shown content catches it instead: the fallback stays until
|
|
213
216
|
// the reader is committed (#3540: what a fresh boundary catches holds
|
|
214
217
|
// nothing outside it).
|
|
215
|
-
if (!
|
|
216
|
-
joinFuture(txOf(
|
|
218
|
+
if (!r || !e.D) continue;
|
|
219
|
+
joinFuture(txOf(o));
|
|
217
220
|
}
|
|
218
|
-
e.
|
|
221
|
+
e.F.delete(o);
|
|
219
222
|
}
|
|
220
223
|
}
|
|
221
|
-
return e.
|
|
224
|
+
return e.F.size;
|
|
222
225
|
}
|
|
223
226
|
|
|
224
227
|
/** Reveal order: a slot is ready when its content can show — it has shown
|
|
@@ -231,24 +234,24 @@ function prune(e, n) {
|
|
|
231
234
|
* or landed and committed are dropped; a fallback with none left reveals
|
|
232
235
|
* next round. An arm resolves: nothing collected, nothing happened. */ function boundarySeam() {
|
|
233
236
|
for (const e of collecting) {
|
|
234
|
-
const
|
|
235
|
-
if (
|
|
237
|
+
const r = e.j.R;
|
|
238
|
+
if (r & REACTIVE_DISPOSED) {
|
|
236
239
|
collecting.delete(e);
|
|
237
240
|
continue;
|
|
238
241
|
}
|
|
239
242
|
// A parked frame's boundary (zombie) keeps its state for its revival.
|
|
240
|
-
if (
|
|
243
|
+
if (r & REACTIVE_ZOMBIE) continue;
|
|
241
244
|
prune(e, false);
|
|
242
|
-
const
|
|
243
|
-
if (e.h && !e.D &&
|
|
244
|
-
e.
|
|
245
|
+
const n = e.j;
|
|
246
|
+
if (e.h && !e.D && n.l & CONFIG_HELD && [ ...e.F ].every(e => !(e.m & STATUS_PENDING) && e.l & CONFIG_HELD && txOf(e) === txOf(n))) {
|
|
247
|
+
e.F.clear();
|
|
245
248
|
e.D = true;
|
|
246
249
|
}
|
|
247
250
|
e.h = false;
|
|
248
|
-
if (e.
|
|
251
|
+
if (e.F.size === 0) {
|
|
249
252
|
collecting.delete(e);
|
|
250
|
-
if (e.
|
|
251
|
-
if (e.
|
|
253
|
+
if (e.L) redraw(e);
|
|
254
|
+
if (revealHooks && e.v !== null) revealHooks.V(e.v);
|
|
252
255
|
}
|
|
253
256
|
}
|
|
254
257
|
}
|
|
@@ -262,7 +265,7 @@ function prune(e, n) {
|
|
|
262
265
|
// holder's verdict lane's — verdict.ts), and the swap it asked for is
|
|
263
266
|
// display-ahead after all (#3528). Re-home the swap: the output re-runs
|
|
264
267
|
// as the lane's, shown now beside the held frame.
|
|
265
|
-
if (e.
|
|
268
|
+
if (e.L && e.P === null && e.B === null && passLane !== null) {
|
|
266
269
|
e.B = passLane;
|
|
267
270
|
// The swap the frame's pass staged (held with the frame) is void: the
|
|
268
271
|
// lane's pass stages it anew (`flip` lists the output in the lane,
|
|
@@ -274,27 +277,29 @@ function prune(e, n) {
|
|
|
274
277
|
return;
|
|
275
278
|
}
|
|
276
279
|
e.h = true;
|
|
280
|
+
// The swap is the change's work: the output joins it (D-13, #3540).
|
|
281
|
+
e.j.l &= ~CONFIG_FRAME;
|
|
277
282
|
// A verdict read in `on` (`isPending`, or a memo of one — #3528's
|
|
278
283
|
// `createMemo(() => isPending(m2))`: the mark carries, core.ts `read`)
|
|
279
284
|
// whose frame has no transaction yet: the swap is still display-ahead — the frame gets one now (it lands
|
|
280
285
|
// at this very seam if nothing holds it), and the swap is its verdict
|
|
281
286
|
// lane's work, shown ahead of the frame's own runs (#3528).
|
|
282
|
-
let
|
|
283
|
-
if (
|
|
287
|
+
let r = passLane;
|
|
288
|
+
if (r === null && globalQueue.q && getOwner().l & CONFIG_VERDICT) {
|
|
284
289
|
joinFuture(null);
|
|
285
|
-
|
|
290
|
+
r = GlobalQueue.J(flushTransaction);
|
|
286
291
|
}
|
|
287
|
-
e.B =
|
|
292
|
+
e.B = r;
|
|
288
293
|
collecting.add(e);
|
|
289
|
-
const
|
|
290
|
-
heldUnder(e.
|
|
291
|
-
for (const
|
|
292
|
-
if (e.
|
|
294
|
+
const n = e.F.size;
|
|
295
|
+
heldUnder(e.H, flushTransaction, r => record(e, r));
|
|
296
|
+
for (const r of e.F) {
|
|
297
|
+
if (e.F.size !== n || r.m & STATUS_PENDING && !(r.R & REACTIVE_DISPOSED)) {
|
|
293
298
|
// What it collects was forwarded through it to the boundaries above
|
|
294
299
|
// too (`catchStatus` records a reader in every boundary on the way).
|
|
295
300
|
// It is this boundary's alone now (B5, the nearest catcher): an outer
|
|
296
301
|
// re-armed by the same tick does not wait for it (D-14, U-4).
|
|
297
|
-
for (let
|
|
302
|
+
for (let r = e._parent; r !== null; r = r._parent) for (const n of e.F) r.F.delete(n);
|
|
298
303
|
flip(e);
|
|
299
304
|
redraw(e);
|
|
300
305
|
return;
|
|
@@ -305,47 +310,47 @@ function prune(e, n) {
|
|
|
305
310
|
/** The error boundary's `reset`: re-run what threw (a comparator throw
|
|
306
311
|
* names a signal — nothing to re-run). */ function reset(e) {
|
|
307
312
|
// A snapshot: a source failing again is caught — and re-added — mid-walk.
|
|
308
|
-
for (const
|
|
313
|
+
for (const r of [ ...e.F ]) if (r.X !== undefined && !(r.R & REACTIVE_DISPOSED)) recompute(r);
|
|
309
314
|
schedule();
|
|
310
315
|
}
|
|
311
316
|
|
|
312
|
-
function createBoundary(e,
|
|
313
|
-
const
|
|
317
|
+
function createBoundary(e, r, n, o) {
|
|
318
|
+
const t = createOwner();
|
|
314
319
|
const l = {
|
|
315
320
|
i: e,
|
|
316
|
-
_parent: boundaryOf(
|
|
317
|
-
|
|
321
|
+
_parent: boundaryOf(t) ?? null,
|
|
322
|
+
H: t,
|
|
318
323
|
Y: null,
|
|
319
324
|
j: null,
|
|
320
|
-
|
|
325
|
+
F: new Set,
|
|
321
326
|
D: false,
|
|
322
327
|
h: false,
|
|
323
328
|
B: null,
|
|
329
|
+
P: null,
|
|
330
|
+
L: false,
|
|
331
|
+
M: null,
|
|
324
332
|
v: null,
|
|
325
|
-
H: false,
|
|
326
|
-
Z: null,
|
|
327
|
-
V: null,
|
|
328
333
|
$: false,
|
|
329
334
|
ee: false,
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
335
|
+
U: e === STATUS_ERROR ? signal(undefined, ERROR_SIGNAL) : null,
|
|
336
|
+
re: n,
|
|
337
|
+
ne: null
|
|
333
338
|
};
|
|
334
|
-
const u = e === STATUS_PENDING ?
|
|
339
|
+
const u = e === STATUS_PENDING ? t.A[REVEAL] : null;
|
|
335
340
|
if (getOwner()) cleanup(() => {
|
|
336
341
|
collecting.delete(l);
|
|
337
|
-
if (u) revealHooks.
|
|
342
|
+
if (revealHooks && u) revealHooks.oe(u, l);
|
|
338
343
|
});
|
|
339
344
|
// The `on` dependencies live OUTSIDE the boundary, as the condition of a
|
|
340
345
|
// `<Show>` wrapping it would: created before the owner's context names it.
|
|
341
346
|
// A source of it going pending re-runs it (CONFIG_REDERIVE) rather than
|
|
342
347
|
// marking it: the pass catches the NotReady — it is a notification, it
|
|
343
348
|
// does not suspend the parent — and re-arms.
|
|
344
|
-
if (
|
|
349
|
+
if (o) {
|
|
345
350
|
let e = false;
|
|
346
|
-
runWithOwner(
|
|
351
|
+
runWithOwner(t, () => computed(() => {
|
|
347
352
|
try {
|
|
348
|
-
|
|
353
|
+
o();
|
|
349
354
|
} catch (e) {
|
|
350
355
|
if (!(e instanceof NotReadyError)) {
|
|
351
356
|
if (!globalQueue.notify(getOwner(), STATUS_ERROR, STATUS_ERROR, e)) {
|
|
@@ -359,15 +364,15 @@ function createBoundary(e, n, r, t) {
|
|
|
359
364
|
})).l |= CONFIG_REDERIVE;
|
|
360
365
|
}
|
|
361
366
|
const a = {
|
|
362
|
-
...
|
|
367
|
+
...t.A,
|
|
363
368
|
[BOUNDARY]: l
|
|
364
369
|
};
|
|
365
370
|
if (revealHooks !== null) a[REVEAL] = null;
|
|
366
|
-
|
|
367
|
-
const i = runWithOwner(
|
|
368
|
-
const e = false ? computed(
|
|
371
|
+
t.A = a;
|
|
372
|
+
const i = runWithOwner(t, () => {
|
|
373
|
+
const e = false ? computed(r, {
|
|
369
374
|
name: "children"
|
|
370
|
-
}) : computed(
|
|
375
|
+
}) : computed(r);
|
|
371
376
|
return false ? computed(() => flatten(read(e)), {
|
|
372
377
|
name: "boundary"
|
|
373
378
|
}) : computed(() => flatten(read(e)));
|
|
@@ -375,23 +380,30 @@ function createBoundary(e, n, r, t) {
|
|
|
375
380
|
l.Y = i;
|
|
376
381
|
// A slot of the reveal order in its context (reveal.ts): gated until the
|
|
377
382
|
// controller releases it — before the output's first pass.
|
|
378
|
-
if (u) revealHooks.
|
|
383
|
+
if (revealHooks && u) revealHooks.te(u, l);
|
|
379
384
|
const f = computed(() => {
|
|
385
|
+
// Structure, not a derivation of its content (CONFIG_FRAME, #4283): it
|
|
386
|
+
// reads a hold it is not part of as the screen, as the render effect
|
|
387
|
+
// flattening the same children without a boundary would. Not while a
|
|
388
|
+
// re-arm's swap is the change's work (`arm`), until that swap commits
|
|
389
|
+
// (D-13, #3540).
|
|
390
|
+
const r = getOwner();
|
|
391
|
+
if (!l.h && !(r.l & CONFIG_HELD)) r.l |= CONFIG_FRAME;
|
|
380
392
|
// Reveal order (reveal.ts): a gated slot shows its fallback — or, in a
|
|
381
393
|
// collapsed tail, nothing — whatever its content's state; the
|
|
382
394
|
// controller is told the pass ran (its readiness may have changed) and
|
|
383
395
|
// releases it in turn.
|
|
384
|
-
|
|
396
|
+
if (l.$) {
|
|
385
397
|
// Linked without being read: the tree settling (or changing)
|
|
386
398
|
// re-derives this pass, which is how the controller hears of it.
|
|
387
399
|
// It may release this very slot (the frontier whose content just
|
|
388
400
|
// settled): the pass goes on to show it — the redraw it asks for is
|
|
389
401
|
// refused mid-pass and not needed.
|
|
390
|
-
link(i,
|
|
391
|
-
if (l.
|
|
402
|
+
link(i, r);
|
|
403
|
+
if (revealHooks && l.v !== null) revealHooks.V(l.v);
|
|
392
404
|
if (l.$) {
|
|
393
405
|
if (l.ee) {
|
|
394
|
-
l.
|
|
406
|
+
l.L = true;
|
|
395
407
|
return undefined;
|
|
396
408
|
}
|
|
397
409
|
return fallback(l);
|
|
@@ -406,7 +418,7 @@ function createBoundary(e, n, r, t) {
|
|
|
406
418
|
// once clean.
|
|
407
419
|
const n = i.m & (STATUS_PENDING | STATUS_ERROR);
|
|
408
420
|
if (n !== 0) {
|
|
409
|
-
link(i,
|
|
421
|
+
link(i, r);
|
|
410
422
|
if (n & e) {
|
|
411
423
|
if (isCollecting(l)) {
|
|
412
424
|
caught(l, i, undefined);
|
|
@@ -418,7 +430,7 @@ function createBoundary(e, n, r, t) {
|
|
|
418
430
|
}
|
|
419
431
|
// A pending passes an error boundary by (A6); an error, a loading
|
|
420
432
|
// one; a loading boundary showing content forwards its pending.
|
|
421
|
-
throw i.T.
|
|
433
|
+
throw i.T.U;
|
|
422
434
|
}
|
|
423
435
|
if (isCollecting(l)) {
|
|
424
436
|
// A29's boundary exemption (#3540): a boundary MOUNTED over a held
|
|
@@ -432,19 +444,18 @@ function createBoundary(e, n, r, t) {
|
|
|
432
444
|
// enters: the outside sees its committed value until the landing,
|
|
433
445
|
// which reveals the content — a fallback staged earlier is replaced
|
|
434
446
|
// ahead of the commit and never shown.
|
|
435
|
-
|
|
436
|
-
if (l.U.size !== 0 && e.m & STATUS_UNINITIALIZED && !(e.l & CONFIG_HELD)) return fallback(l);
|
|
447
|
+
if (l.F.size !== 0 && r.m & STATUS_UNINITIALIZED && !(r.l & CONFIG_HELD)) return fallback(l);
|
|
437
448
|
// Readers under it still unready: the fallback, the tree untouched.
|
|
438
449
|
// The seam re-derives this pass when they settle.
|
|
439
450
|
if (prune(l, true) !== 0) return fallback(l);
|
|
440
451
|
}
|
|
441
|
-
let
|
|
452
|
+
let o;
|
|
442
453
|
try {
|
|
443
|
-
|
|
444
|
-
} catch (
|
|
445
|
-
if (
|
|
454
|
+
o = read(i);
|
|
455
|
+
} catch (r) {
|
|
456
|
+
if (r instanceof NotReadyError ? e === STATUS_PENDING : e === STATUS_ERROR) {
|
|
446
457
|
if (isCollecting(l)) {
|
|
447
|
-
caught(l, i,
|
|
458
|
+
caught(l, i, r);
|
|
448
459
|
return fallback(l);
|
|
449
460
|
}
|
|
450
461
|
// Forwarded: a loading boundary showing content keeps it and
|
|
@@ -452,43 +463,53 @@ function createBoundary(e, n, r, t) {
|
|
|
452
463
|
record(l, i);
|
|
453
464
|
}
|
|
454
465
|
// A pending passes an error boundary by (A6).
|
|
455
|
-
throw
|
|
466
|
+
throw r;
|
|
456
467
|
}
|
|
457
468
|
// Readers under it still unready (caught before, or while the read
|
|
458
469
|
// ran the content at a mount): the fallback.
|
|
459
|
-
if (isCollecting(l) && l.
|
|
470
|
+
if (isCollecting(l) && l.F.size !== 0) return fallback(l);
|
|
460
471
|
l.D = true;
|
|
461
|
-
l.
|
|
472
|
+
l.L = false;
|
|
462
473
|
// The fallback dies when the content that replaces it is on screen —
|
|
463
474
|
// with this flush's commits when the pass is the frame's, at the
|
|
464
475
|
// landing when the frame parks (the run is held with it, as the old
|
|
465
476
|
// children of a held pass are) — not now: a held swap keeps the
|
|
466
477
|
// fallback on screen, live, until it commits. A pass back to the
|
|
467
|
-
// fallback before then finds it still built and keeps it.
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
478
|
+
// fallback before then finds it still built and keeps it. A fallback
|
|
479
|
+
// the screen does not show (a swap staged with a held frame, replaced
|
|
480
|
+
// before it commits) dies now: what it reads holds nothing (S-22 row
|
|
481
|
+
// 3′, #4268).
|
|
482
|
+
const t = l.ne;
|
|
483
|
+
const drop = () => {
|
|
484
|
+
if (!l.L && l.ne === t) {
|
|
485
|
+
// A fallback that threw (a rethrow the boundary does not
|
|
486
|
+
// handle) is what an enclosing boundary waits on: it died, and
|
|
487
|
+
// the seam of another round drops it there (#4270).
|
|
488
|
+
if (t.m & STATUS_ERROR) schedule();
|
|
471
489
|
dispose(t);
|
|
472
|
-
l.
|
|
490
|
+
l.ne = null;
|
|
473
491
|
}
|
|
474
|
-
}
|
|
492
|
+
};
|
|
493
|
+
if (t !== null) l.j.le !== t.le ? drop() : globalQueue.enqueue(EFFECT_RENDER, drop);
|
|
475
494
|
release(l);
|
|
476
495
|
// Shown: the slot leaves its reveal order (a later re-arm gates nobody
|
|
477
496
|
// else; the frontier moves on).
|
|
478
|
-
if (l.
|
|
479
|
-
const e = l.
|
|
480
|
-
l.
|
|
481
|
-
revealHooks.
|
|
497
|
+
if (revealHooks && l.v !== null) {
|
|
498
|
+
const e = l.v;
|
|
499
|
+
l.v = null;
|
|
500
|
+
revealHooks.V(e);
|
|
482
501
|
}
|
|
483
|
-
return
|
|
502
|
+
return o;
|
|
484
503
|
},
|
|
485
504
|
// Boundary structure, not a user source: its value is fallback-or-content
|
|
486
505
|
// and legitimately swaps mid-hydration (resume), so it must never be
|
|
487
506
|
// frozen by snapshot capture.
|
|
488
507
|
{
|
|
489
|
-
|
|
508
|
+
ue: true
|
|
490
509
|
});
|
|
491
510
|
f.l |= CONFIG_REDERIVE;
|
|
511
|
+
// The tree is structure too (the output's pass marks the output).
|
|
512
|
+
i.l |= CONFIG_FRAME;
|
|
492
513
|
l.j = f;
|
|
493
514
|
return accessor(f);
|
|
494
515
|
}
|
|
@@ -497,12 +518,12 @@ function fallback(e) {
|
|
|
497
518
|
// The swap a display-ahead re-arm asked for: this pass is the lane's — a
|
|
498
519
|
// lane read by construction (REACTIVE_LANE_READ: `recompute`'s tail keeps
|
|
499
520
|
// the pass in the lane).
|
|
500
|
-
if (e.
|
|
501
|
-
setPassLane(e.
|
|
521
|
+
if (e.P !== null) {
|
|
522
|
+
setPassLane(e.P);
|
|
502
523
|
e.j.R |= REACTIVE_LANE_READ;
|
|
503
|
-
e.
|
|
524
|
+
e.P = null;
|
|
504
525
|
}
|
|
505
|
-
e.
|
|
526
|
+
e.L = true;
|
|
506
527
|
// Built in its own scope, like `Show`'s function child, once per show
|
|
507
528
|
// (D-39: the fallback is the display until a new answer replaces the
|
|
508
529
|
// error): a re-derive of the output while it shows — a second reader
|
|
@@ -514,18 +535,18 @@ function fallback(e) {
|
|
|
514
535
|
// outside the boundary, as the output is: its errors and runs are the
|
|
515
536
|
// enclosing boundary's — with the output's id, so what it builds gets the
|
|
516
537
|
// ids a build under the output would; disposed once content is on screen.
|
|
517
|
-
if (e.
|
|
518
|
-
const
|
|
519
|
-
e.
|
|
520
|
-
id:
|
|
538
|
+
if (e.ne === null) {
|
|
539
|
+
const r = getOwner();
|
|
540
|
+
e.ne = runWithOwner(r._parent, () => computed(() => e.re(e), {
|
|
541
|
+
id: r.id
|
|
521
542
|
}));
|
|
522
543
|
}
|
|
523
|
-
return read(e.
|
|
544
|
+
return read(e.ne);
|
|
524
545
|
}
|
|
525
546
|
|
|
526
547
|
const ERROR_SIGNAL = {
|
|
527
548
|
ownedWrite: true,
|
|
528
|
-
|
|
549
|
+
ue: true
|
|
529
550
|
};
|
|
530
551
|
|
|
531
552
|
/**
|
|
@@ -569,8 +590,8 @@ const ERROR_SIGNAL = {
|
|
|
569
590
|
* ) as unknown as JSX.Element;
|
|
570
591
|
* }
|
|
571
592
|
* ```
|
|
572
|
-
*/ function createLoadingBoundary(e,
|
|
573
|
-
return createBoundary(STATUS_PENDING, e, () =>
|
|
593
|
+
*/ function createLoadingBoundary(e, r, n) {
|
|
594
|
+
return createBoundary(STATUS_PENDING, e, () => r(), n?.on);
|
|
574
595
|
}
|
|
575
596
|
|
|
576
597
|
/**
|
|
@@ -595,12 +616,12 @@ const ERROR_SIGNAL = {
|
|
|
595
616
|
* ) as unknown as JSX.Element;
|
|
596
617
|
* }
|
|
597
618
|
* ```
|
|
598
|
-
*/ function createErrorBoundary(e,
|
|
599
|
-
return createBoundary(STATUS_ERROR, e, e =>
|
|
619
|
+
*/ function createErrorBoundary(e, r) {
|
|
620
|
+
return createBoundary(STATUS_ERROR, e, e => r(accessor(e.U), () => reset(e)));
|
|
600
621
|
}
|
|
601
622
|
|
|
602
623
|
// Installed at module evaluation — present exactly when something imports a
|
|
603
624
|
// boundary. An app without one pays the three null checks and nothing else.
|
|
604
|
-
installBoundaryHooks(catchStatus, (e,
|
|
625
|
+
installBoundaryHooks(catchStatus, (e, r) => !r && (e.m & STATUS_UNINITIALIZED ? catchStatus(e, STATUS_PENDING) : armedOver(e)), hiddenBy, boundarySeam, heldRun);
|
|
605
626
|
|
|
606
627
|
export { REVEAL, createErrorBoundary, createLoadingBoundary, prune, ready, redraw, revealHooks, setRevealHooks };
|
package/dist/prod/core/action.js
CHANGED
|
@@ -66,6 +66,14 @@ import { joinFuture, newTransaction, enterAction, exitAction, resolveTx, schedul
|
|
|
66
66
|
* yield until(() => todos.some(t => t.id === saved.id));
|
|
67
67
|
* ```
|
|
68
68
|
*
|
|
69
|
+
* The same holds inside an async helper the action yields
|
|
70
|
+
* (`yield (async () => { ... })()`): everything after its first `await` runs
|
|
71
|
+
* outside the transaction. An `await refresh(x)` or `await until(...)` there
|
|
72
|
+
* waits for this action's commit, which waits on the helper, so it hangs
|
|
73
|
+
* whenever `x` re-ran during the action (#4263) and works otherwise. Call
|
|
74
|
+
* `refresh(x)` in the generator once the helper returns; `yield` it only when
|
|
75
|
+
* the action needs the fresh value.
|
|
76
|
+
*
|
|
69
77
|
* (For the same reason, don't call `flush()` inside an action body — it
|
|
70
78
|
* cannot reveal the held writes and is refused.)
|
|
71
79
|
*
|