@solidjs/signals 2.0.0-rc.16 → 2.0.0-rc.17
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 +1719 -1603
- package/dist/dev.attribution.js +13 -13
- package/dist/dev.js +182 -45
- package/dist/observe/boundaries.js +2 -2
- package/dist/observe/core/async.js +3 -1
- package/dist/observe/core/context.js +2 -0
- package/dist/observe/core/core.js +26 -10
- package/dist/observe/core/effect.js +2 -0
- package/dist/observe/core/graph.js +10 -8
- package/dist/observe/core/lanes.js +25 -14
- package/dist/observe/core/owner.js +73 -47
- package/dist/observe/core/scheduler.js +189 -173
- package/dist/observe/core/verdict.js +3 -0
- package/dist/observe/map.js +2 -2
- package/dist/observe/signals.js +6 -1
- package/dist/observe/store/affects.js +13 -13
- package/dist/observe/store/optimistic.js +112 -71
- package/dist/observe/store/store.js +25 -16
- package/dist/prod/boundaries.js +2 -2
- package/dist/prod/core/async.js +3 -1
- package/dist/prod/core/context.js +2 -0
- package/dist/prod/core/core.js +31 -15
- package/dist/prod/core/effect.js +2 -0
- package/dist/prod/core/graph.js +10 -8
- package/dist/prod/core/heap.js +1 -1
- package/dist/prod/core/lanes.js +25 -14
- package/dist/prod/core/owner.js +70 -44
- package/dist/prod/core/scheduler.js +43 -27
- package/dist/prod/core/verdict.js +4 -1
- package/dist/prod/map.js +2 -2
- package/dist/prod/signals.js +18 -13
- package/dist/prod/store/optimistic.js +112 -71
- package/dist/prod/store/store.js +18 -7
- package/dist/types/core/core.d.ts +10 -3
- package/dist/types/core/dev.d.ts +9 -1
- package/dist/types/core/error.d.ts +9 -1
- package/dist/types/core/owner.d.ts +4 -0
- package/dist/types/core/scheduler.d.ts +23 -4
- package/package.json +1 -1
|
@@ -461,12 +461,21 @@ function supersede(e, n, s) {
|
|
|
461
461
|
* lane's latest. NOT_PENDING falls through: lane work's read of a pending
|
|
462
462
|
* member throws like any. */ function laneRead(e, n) {
|
|
463
463
|
const s = n.l & CONFIG_GUESS;
|
|
464
|
+
const t = txOf(n);
|
|
465
|
+
// A lane a correction folded under (D-34): store/optimistic.ts reads it.
|
|
466
|
+
// Before the authoritative arm: an `until` outside the lane reads the
|
|
467
|
+
// same truth there, and joins the hold it folded into — its posture over
|
|
468
|
+
// a foreign hold (D-31), which the truth read alone would not take.
|
|
469
|
+
const l = e !== null && t.folded;
|
|
470
|
+
if (l) {
|
|
471
|
+
const s = l(e, n);
|
|
472
|
+
if (s !== NOT_PENDING) return s;
|
|
473
|
+
}
|
|
464
474
|
if (e !== null && e.l & CONFIG_AUTHORITATIVE) return GlobalQueue.rn(n);
|
|
465
|
-
const
|
|
475
|
+
const u = n.m;
|
|
466
476
|
// An errored member's lane value predates its error; the error is the answer (#4106).
|
|
467
|
-
if (!s &&
|
|
477
|
+
if (!s && u & STATUS_ERROR) return NOT_PENDING;
|
|
468
478
|
if (e === null) return laneValueOf(n);
|
|
469
|
-
const l = txOf(n);
|
|
470
479
|
if (!tracking || e.l & CONFIG_CHILDREN_FORBIDDEN) {
|
|
471
480
|
// An untracked read inside lane work derives from the lane like a
|
|
472
481
|
// tracked one, minus the subscription — `untrack` is about
|
|
@@ -475,33 +484,33 @@ function supersede(e, n, s) {
|
|
|
475
484
|
// lanes read by one pass link, as for tracked reads). Outside lane
|
|
476
485
|
// work, the screen.
|
|
477
486
|
if (passLane === null || e.l & CONFIG_CHILDREN_FORBIDDEN) return display(n);
|
|
478
|
-
enterLane(
|
|
479
|
-
if (!s &&
|
|
487
|
+
enterLane(t, e);
|
|
488
|
+
if (!s && u & STATUS_PENDING) return NOT_PENDING;
|
|
480
489
|
return laneValueOf(n);
|
|
481
490
|
}
|
|
482
|
-
if (e.i === EFFECT_RENDER && (passLane === null || !sameLane(passLane,
|
|
491
|
+
if (e.i === EFFECT_RENDER && (passLane === null || !sameLane(passLane, t))) {
|
|
483
492
|
if (!s) {
|
|
484
493
|
// A flight whose value has never shown: nothing to show — the leaf
|
|
485
494
|
// waits on it, and its own frame holds (A15, #3334), not the lane's
|
|
486
495
|
// parent. The landing lands the frame: its own pass (the flush
|
|
487
496
|
// joined its transaction) reads the answer it waited on — the lane's
|
|
488
497
|
// staging, revealed at this seam.
|
|
489
|
-
if (
|
|
498
|
+
if (u & STATUS_PENDING && n.T.V === NOT_PENDING) return NOT_PENDING;
|
|
490
499
|
if (n.ue !== NOT_PENDING && e.l & CONFIG_HELD && flushTransaction !== null && resolveTx(flushTransaction) === txOf(e)) return n.ue;
|
|
491
500
|
}
|
|
492
|
-
if (
|
|
493
|
-
if (!s && !
|
|
501
|
+
if (t.ln || !s && u & STATUS_PENDING) {
|
|
502
|
+
if (!s && !t.It && u & STATUS_UNINITIALIZED) throw new NotReadyError(null);
|
|
494
503
|
// Re-derived at the reveal; once per pass (the pass may also be a stale
|
|
495
504
|
// reader of a transaction, REACTIVE_FRAME_READ — both reruns apply).
|
|
496
505
|
if (!(e.R & REACTIVE_SCREEN_READ)) {
|
|
497
506
|
e.R |= REACTIVE_FRAME_READ | REACTIVE_SCREEN_READ;
|
|
498
|
-
|
|
507
|
+
t.En.push(e);
|
|
499
508
|
}
|
|
500
509
|
return display(n);
|
|
501
510
|
}
|
|
502
511
|
}
|
|
503
|
-
enterLane(
|
|
504
|
-
if (!s &&
|
|
512
|
+
enterLane(t, e);
|
|
513
|
+
if (!s && u & STATUS_PENDING) return NOT_PENDING;
|
|
505
514
|
return laneValueOf(n);
|
|
506
515
|
}
|
|
507
516
|
|
|
@@ -626,10 +635,12 @@ function laneSeam(e, n) {
|
|
|
626
635
|
// question is the one being asked (`question`: a slice's, a derive's
|
|
627
636
|
// continuation's — the flight's); unstamped writes and mainline are
|
|
628
637
|
// current.
|
|
629
|
-
|
|
638
|
+
// A store re-bases a keyed arrangement guess over an older truth, and
|
|
639
|
+
// folds a current one beneath it (D-34): true.
|
|
640
|
+
const s = stale(e, question);
|
|
641
|
+
if (GlobalQueue.an?.(e, n, s) || s) {
|
|
630
642
|
e.ue = n;
|
|
631
643
|
e.l |= CONFIG_HELD;
|
|
632
|
-
GlobalQueue.an?.(e, n);
|
|
633
644
|
schedule();
|
|
634
645
|
return n;
|
|
635
646
|
}
|
|
@@ -8,7 +8,7 @@ import { unobserved, clearDeps } from "./graph.js";
|
|
|
8
8
|
|
|
9
9
|
import { deleteFromHeap } from "./heap.js";
|
|
10
10
|
|
|
11
|
-
import { schedule, dirtyQueue } from "./scheduler.js";
|
|
11
|
+
import { globalQueue, schedule, dirtyQueue } from "./scheduler.js";
|
|
12
12
|
|
|
13
13
|
// L2 (step 2): the parked frame. A pass parks the previous frame's children
|
|
14
14
|
// and `_disposal` list on `_x._pendingFirstChild` / `_x._pendingDisposal`
|
|
@@ -37,17 +37,41 @@ function dispose(e) {
|
|
|
37
37
|
unobserved(e);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
// The first error a cleanup threw, boxed so a thrown `undefined` still
|
|
41
|
+
// counts. A throwing cleanup stops neither its siblings nor the rest of the
|
|
42
|
+
// tree: every cleanup runs. The error is rethrown once the teardown is over:
|
|
43
|
+
// by a root's dispose call outside a flush (`disposeRootSelf`), otherwise when
|
|
44
|
+
// the flush ends (`flush`; `runCleanup` schedules one), so a flush is never
|
|
45
|
+
// left half-applied. A halt drops it: the error that halted is the one
|
|
46
|
+
// reported, and a stale one must not surface from a later, unrelated dispose.
|
|
47
|
+
let cleanupError;
|
|
48
|
+
|
|
49
|
+
/** Runs a cleanup or `unobserved` hook; a throw is collected, not raised. @internal */ function runCleanup(e) {
|
|
50
|
+
try {
|
|
51
|
+
e();
|
|
52
|
+
} catch (e) {
|
|
53
|
+
cleanupError ||= [ e ];
|
|
54
|
+
schedule();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Rethrows the error `runCleanup` collected, once; `drop` discards it. @internal */ function rethrowCleanupError(e) {
|
|
59
|
+
const n = cleanupError;
|
|
60
|
+
cleanupError = undefined;
|
|
61
|
+
if (n && !e) throw n[0];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function disposeChildren(e, n = false, r) {
|
|
65
|
+
const t = e.R;
|
|
66
|
+
if (t & REACTIVE_DISPOSED) return;
|
|
43
67
|
// A parked frame dies with its owner (#3024): the commit that would retire
|
|
44
68
|
// it never comes once the node is DISPOSED, so it drains here or its
|
|
45
69
|
// cleanups never run and it stays subscribed, rerunning in a torn-down
|
|
46
70
|
// tree (#3561). Death only (`self`): a re-pass leaves the frame reacting
|
|
47
71
|
// until the commit.
|
|
48
|
-
if (n && !
|
|
72
|
+
if (n && !r && e.T !== null && (e.T.Nt !== null || e.T.ft !== null)) disposeChildren(e, false, true);
|
|
49
73
|
if (n) {
|
|
50
|
-
e.R =
|
|
74
|
+
e.R = t | REACTIVE_DISPOSED;
|
|
51
75
|
if (e._parent === null && e.Pt) unregisterRoot(e);
|
|
52
76
|
}
|
|
53
77
|
if (n && e.X) {
|
|
@@ -56,12 +80,12 @@ function disposeChildren(e, n = false, t) {
|
|
|
56
80
|
// flight's — a transaction's or a lane's (its `_x._transaction`) — or a
|
|
57
81
|
// stale reader's (REACTIVE_FRAME_READ — a frame that derived from one).
|
|
58
82
|
// Nothing else re-examines a dead node, so make sure a seam comes.
|
|
59
|
-
if (e.m & STATUS_PENDING && e.T?.Je != null ||
|
|
83
|
+
if (e.m & STATUS_PENDING && e.T?.Je != null || t & REACTIVE_FRAME_READ) schedule();
|
|
60
84
|
}
|
|
61
|
-
let
|
|
62
|
-
if (
|
|
63
|
-
while (
|
|
64
|
-
const e =
|
|
85
|
+
let l = r ? e.T.Nt : e.ze;
|
|
86
|
+
if (r) e.T.Nt = null; else e.ze = null;
|
|
87
|
+
while (l) {
|
|
88
|
+
const e = l;
|
|
65
89
|
// Owner teardown is death regardless of the child's own lifecycle
|
|
66
90
|
// (#3024): strip AUTO_DISPOSE so a post-disposal read freezes at the
|
|
67
91
|
// last committed value instead of reawakening in a torn-down tree.
|
|
@@ -83,42 +107,42 @@ function disposeChildren(e, n = false, t) {
|
|
|
83
107
|
// on the fresh head and survives. Pointing each drained child's prev at
|
|
84
108
|
// itself routes its later splice onto the detached chain, never the head,
|
|
85
109
|
// and keeps the dev owner-chain-head invariant honest for those children.
|
|
86
|
-
|
|
87
|
-
disposeChildren(
|
|
110
|
+
l.Ct = l;
|
|
111
|
+
disposeChildren(l, true);
|
|
88
112
|
// Read after, not before: a sibling this disposal made dormant spliced
|
|
89
113
|
// itself out of the detached chain, and a cleanup may then have linked
|
|
90
114
|
// it at the fresh head, which rewrote the `_nextSibling` a pre-read
|
|
91
115
|
// would still be holding.
|
|
92
|
-
|
|
116
|
+
l = l.Xe;
|
|
93
117
|
}
|
|
94
|
-
if (!
|
|
118
|
+
if (!r) e.ct = 0;
|
|
95
119
|
// O(1) splice out of parent's chain on individual dispose. Skipped during
|
|
96
120
|
// batch dispose (parent already disposed) and for a zombie (it sits on the
|
|
97
121
|
// parent's parked frame, drained whole by the commit). We leave
|
|
98
122
|
// node._nextSibling intact so outer walks that already advanced past us
|
|
99
123
|
// still reach later siblings.
|
|
100
|
-
if (n && !
|
|
124
|
+
if (n && !r && !(t & REACTIVE_ZOMBIE) && e._parent !== null && !(e._parent.R & REACTIVE_DISPOSED)) {
|
|
101
125
|
const n = e.Ct;
|
|
102
|
-
const
|
|
103
|
-
if (n !== null) n.Xe =
|
|
104
|
-
if (
|
|
126
|
+
const r = e.Xe;
|
|
127
|
+
if (n !== null) n.Xe = r; else e._parent.ze = r;
|
|
128
|
+
if (r !== null) r.Ct = n;
|
|
105
129
|
e.Ct = null;
|
|
106
130
|
}
|
|
107
|
-
runDisposal(e,
|
|
131
|
+
runDisposal(e, r);
|
|
108
132
|
// Final effect-returned cleanup fires at true disposal, after `_disposal`
|
|
109
133
|
// to mirror rerun ordering (compute-phase teardown first, cleanup last).
|
|
110
134
|
if (n && e.kt) {
|
|
111
135
|
const n = e.kt;
|
|
112
136
|
e.kt = undefined;
|
|
113
|
-
n
|
|
137
|
+
runCleanup(n);
|
|
114
138
|
}
|
|
115
139
|
}
|
|
116
140
|
|
|
117
141
|
function linkChild(e, n) {
|
|
118
|
-
const
|
|
142
|
+
const r = e.ze;
|
|
119
143
|
n.Ct = null;
|
|
120
|
-
n.Xe =
|
|
121
|
-
if (
|
|
144
|
+
n.Xe = r;
|
|
145
|
+
if (r !== null) r.Ct = n;
|
|
122
146
|
e.ze = n;
|
|
123
147
|
}
|
|
124
148
|
|
|
@@ -129,27 +153,26 @@ function runDisposal(e, n) {
|
|
|
129
153
|
// walk ran every entry a second time. Detached, the re-entrant drain finds
|
|
130
154
|
// nothing. The same shape latched a throwing cleanup: the list survived the
|
|
131
155
|
// throw and every later drain re-ran and re-threw it.
|
|
132
|
-
const
|
|
133
|
-
if (!
|
|
156
|
+
const r = n ? e.T.ft : e.rt;
|
|
157
|
+
if (!r) return;
|
|
134
158
|
if (n) e.T.ft = null; else e.rt = null;
|
|
135
|
-
if (Array.isArray(
|
|
159
|
+
if (Array.isArray(r)) {
|
|
136
160
|
// Unwind order (#3572, restores 1.x #1562): later registrations run
|
|
137
161
|
// before earlier ones. Children have already been disposed by the caller,
|
|
138
162
|
// so with LIFO a body that registers cleanup before creating its children
|
|
139
163
|
// tears down after them — the same order a per-component owner gives.
|
|
140
|
-
for (let e =
|
|
141
|
-
|
|
142
|
-
n.call(n);
|
|
164
|
+
for (let e = r.length - 1; e >= 0; e--) {
|
|
165
|
+
runCleanup(r[e]);
|
|
143
166
|
}
|
|
144
167
|
} else {
|
|
145
|
-
|
|
168
|
+
runCleanup(r);
|
|
146
169
|
}
|
|
147
170
|
}
|
|
148
171
|
|
|
149
172
|
function childId(e, n) {
|
|
150
|
-
let
|
|
151
|
-
while (
|
|
152
|
-
if (
|
|
173
|
+
let r = e;
|
|
174
|
+
while (r.l & CONFIG_TRANSPARENT && r._parent) r = r._parent;
|
|
175
|
+
if (r.id != null) return formatId(r.id, n ? r.ct++ : r.ct);
|
|
153
176
|
throw new Error("");
|
|
154
177
|
}
|
|
155
178
|
|
|
@@ -166,8 +189,8 @@ function childId(e, n) {
|
|
|
166
189
|
* The id a freshly-created node inherits: an explicit `options.id` wins;
|
|
167
190
|
* transparent nodes share their parent's id; otherwise the parent's next
|
|
168
191
|
* child id is consumed (or `undefined` outside an id-carrying tree).
|
|
169
|
-
*/ function inheritId(e, n,
|
|
170
|
-
return e?.id ?? (n ?
|
|
192
|
+
*/ function inheritId(e, n, r) {
|
|
193
|
+
return e?.id ?? (n ? r?.id : r?.id != null ? getNextChildId(r) : undefined);
|
|
171
194
|
}
|
|
172
195
|
|
|
173
196
|
/**
|
|
@@ -180,8 +203,8 @@ function childId(e, n) {
|
|
|
180
203
|
}
|
|
181
204
|
|
|
182
205
|
function formatId(e, n) {
|
|
183
|
-
const
|
|
184
|
-
return e + (
|
|
206
|
+
const r = n.toString(36), t = r.length - 1;
|
|
207
|
+
return e + (t ? String.fromCharCode(64 + t) : "") + r;
|
|
185
208
|
}
|
|
186
209
|
|
|
187
210
|
/**
|
|
@@ -256,6 +279,9 @@ function formatId(e, n) {
|
|
|
256
279
|
|
|
257
280
|
function disposeRootSelf(e = true) {
|
|
258
281
|
disposeChildren(this, e);
|
|
282
|
+
// Outside a flush the dispose call rethrows; inside one, the flush does.
|
|
283
|
+
// Kept out of `disposeChildren`, whose hot path it slows.
|
|
284
|
+
if (cleanupError && !globalQueue.q) rethrowCleanupError();
|
|
259
285
|
}
|
|
260
286
|
|
|
261
287
|
/**
|
|
@@ -267,15 +293,15 @@ function disposeRootSelf(e = true) {
|
|
|
267
293
|
* @internal
|
|
268
294
|
*/ function createOwner(e) {
|
|
269
295
|
const n = context;
|
|
270
|
-
const
|
|
296
|
+
const r = e?.transparent ?? false;
|
|
271
297
|
// Prod and observe boilerplates (see core.ts computed()). The observe
|
|
272
298
|
// literal carries the `_name` and `_loc` slots the rendering layer fills
|
|
273
299
|
// with the component label and JSX site (`owner._name = "<App>"`,
|
|
274
300
|
// `owner._loc = "src/App.tsx:3:5"`) — slots, so labelling a root is a
|
|
275
301
|
// plain store rather than a shape fork between labelled and plain roots.
|
|
276
|
-
const
|
|
277
|
-
id: inheritId(e,
|
|
278
|
-
l:
|
|
302
|
+
const t = {
|
|
303
|
+
id: inheritId(e, r, n),
|
|
304
|
+
l: r ? CONFIG_TRANSPARENT : 0,
|
|
279
305
|
// Present from birth: disposeChildren marks death here on roots too, and
|
|
280
306
|
// a first store of a missing property is a shape transition plus a
|
|
281
307
|
// properties-store allocation per root — on a 100×4 table teardown that
|
|
@@ -295,8 +321,8 @@ function disposeRootSelf(e = true) {
|
|
|
295
321
|
_name: undefined,
|
|
296
322
|
_loc: undefined
|
|
297
323
|
};
|
|
298
|
-
if (n) linkChild(n,
|
|
299
|
-
return
|
|
324
|
+
if (n) linkChild(n, t); else registerRoot(t);
|
|
325
|
+
return t;
|
|
300
326
|
}
|
|
301
327
|
|
|
302
328
|
/**
|
|
@@ -334,11 +360,11 @@ function disposeRootSelf(e = true) {
|
|
|
334
360
|
*
|
|
335
361
|
* @description https://v2.solidjs.com/reference/solid-js/advanced/owner-introspection/create-root
|
|
336
362
|
*/ function createRoot(e, n) {
|
|
337
|
-
const
|
|
363
|
+
const r = createOwner(n);
|
|
338
364
|
// A bound function, not an arrow: an arrow would share this scope, which
|
|
339
365
|
// holds `init`, so keeping `dispose` would keep `init` and all it closes
|
|
340
366
|
// over alive (#4095).
|
|
341
|
-
return runWithOwner(
|
|
367
|
+
return runWithOwner(r, () => e(disposeRootSelf.bind(r, true)));
|
|
342
368
|
}
|
|
343
369
|
|
|
344
|
-
export { cleanup, createOwner, createRoot, dispose, disposeChildren, getNextChildId, getObserver, getOwner, inheritId, isDisposed, linkChild, markDisposal, peekNextChildId };
|
|
370
|
+
export { cleanup, createOwner, createRoot, dispose, disposeChildren, getNextChildId, getObserver, getOwner, inheritId, isDisposed, linkChild, markDisposal, peekNextChildId, rethrowCleanupError, runCleanup };
|