@solidjs/signals 2.0.0-beta.21 → 2.0.0-beta.23
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.js +210 -301
- package/dist/node.cjs +1106 -1196
- package/dist/prod/affects.js +71 -163
- package/dist/prod/boundaries.js +141 -137
- package/dist/prod/core/action.js +3 -3
- package/dist/prod/core/async.js +103 -103
- package/dist/prod/core/core.js +254 -297
- package/dist/prod/core/effect.js +46 -46
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +60 -47
- package/dist/prod/core/heap.js +50 -50
- package/dist/prod/core/lanes.js +34 -34
- package/dist/prod/core/optimistic.js +64 -106
- package/dist/prod/core/owner.js +52 -52
- package/dist/prod/core/scheduler.js +210 -211
- package/dist/prod/core/verdict.js +129 -78
- package/dist/prod/map.js +101 -101
- package/dist/prod/signals.js +23 -5
- package/dist/prod/store/optimistic.js +11 -11
- package/dist/prod/store/projection.js +2 -2
- package/dist/prod/store/store.js +14 -14
- package/dist/types/affects.d.ts +9 -9
- package/dist/types/core/async.d.ts +1 -1
- package/dist/types/core/error.d.ts +7 -0
- package/dist/types/core/scheduler.d.ts +1 -6
- package/dist/types/core/types.d.ts +6 -11
- package/dist/types-cjs/affects.d.cts +9 -9
- package/dist/types-cjs/core/async.d.cts +1 -1
- package/dist/types-cjs/core/error.d.cts +7 -0
- package/dist/types-cjs/core/scheduler.d.cts +1 -6
- package/dist/types-cjs/core/types.d.cts +6 -11
- package/package.json +1 -1
package/dist/prod/core/async.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { STATUS_UNINITIALIZED, STATUS_ERROR, STATUS_PENDING, REACTIVE_DIRTY, REACTIVE_OPTIMISTIC_DIRTY, NOT_PENDING } from "./constants.js";
|
|
1
|
+
import { STATUS_UNINITIALIZED, STATUS_ERROR, STATUS_PENDING, REACTIVE_DIRTY, REACTIVE_OPTIMISTIC_DIRTY, NOT_PENDING, CONFIG_AUTO_DISPOSE } from "./constants.js";
|
|
2
2
|
|
|
3
3
|
import { untrack, context, setSignal } from "./core.js";
|
|
4
4
|
|
|
@@ -6,7 +6,7 @@ import "./invariants.js";
|
|
|
6
6
|
|
|
7
7
|
import { NotReadyError, StatusError } from "./error.js";
|
|
8
8
|
|
|
9
|
-
import { trimStaleDeps } from "./graph.js";
|
|
9
|
+
import { trimStaleDeps, unobserved } from "./graph.js";
|
|
10
10
|
|
|
11
11
|
import { enqueueSub } from "./heap.js";
|
|
12
12
|
|
|
@@ -22,79 +22,75 @@ import { globalQueue, GlobalQueue, clock, schedule, flush, queuePendingNode, ins
|
|
|
22
22
|
// overlapping source landed beside the Set and removePendingSource refused
|
|
23
23
|
// to clear it, stranding the Set members' pending forever (#2893).
|
|
24
24
|
function addPendingSource(e, n) {
|
|
25
|
-
if (e.
|
|
26
|
-
(e.
|
|
25
|
+
if (e.oe?.has(n)) return false;
|
|
26
|
+
(e.oe ??= new Set).add(n);
|
|
27
27
|
return true;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
function removePendingSource(e, n) {
|
|
31
|
-
if (!e.
|
|
32
|
-
if (e.
|
|
31
|
+
if (!e.oe?.delete(n)) return false;
|
|
32
|
+
if (e.oe.size === 0) e.oe = undefined;
|
|
33
33
|
return true;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
function clearPendingSources(e) {
|
|
37
|
-
e.
|
|
38
|
-
e.
|
|
37
|
+
e.oe?.clear();
|
|
38
|
+
e.oe = undefined;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
function setPendingError(e, n, r) {
|
|
42
42
|
if (!n) {
|
|
43
|
-
e.
|
|
43
|
+
e._ = null;
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
46
|
if (r instanceof NotReadyError && r.source === n) {
|
|
47
|
-
e.
|
|
47
|
+
e._ = r;
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
|
-
const t = e.
|
|
50
|
+
const t = e._;
|
|
51
51
|
if (!(t instanceof NotReadyError) || t.source !== n) {
|
|
52
|
-
e.
|
|
52
|
+
e._ = new NotReadyError(n);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
function forEachDependent(e, n) {
|
|
57
|
-
for (let r = e.
|
|
57
|
+
for (let r = e.o; r !== null; r = r.ue) n(r.le, r);
|
|
58
58
|
// `?? null`: affects() marks route plain signals (no `_child` slot) through here.
|
|
59
|
-
for (let r = e.
|
|
60
|
-
for (let e = r.
|
|
59
|
+
for (let r = e.u ?? null; r !== null; r = r.fe) {
|
|
60
|
+
for (let e = r.o; e !== null; e = e.ue) n(e.le, e);
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
// Queue a node to re-run on the next flush (used both when a pending source
|
|
65
65
|
// settles and when an `isPending` observer must re-evaluate after a real error):
|
|
66
66
|
// shared scheduling helper in heap.ts (tracked effects bypass the heap).
|
|
67
|
-
function settlePendingSource(e
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const r = e.m?.values().next().value;
|
|
81
|
-
if (r) {
|
|
82
|
-
setPendingError(e, r);
|
|
83
|
-
u !== null && u(e);
|
|
67
|
+
function settlePendingSource(e) {
|
|
68
|
+
let n = false;
|
|
69
|
+
const r = new Set;
|
|
70
|
+
// Companion updates no-op without the verdict layer (null hook).
|
|
71
|
+
const t = GlobalQueue.ae;
|
|
72
|
+
const settle = o => {
|
|
73
|
+
if (r.has(o) || !removePendingSource(o, e)) return;
|
|
74
|
+
r.add(o);
|
|
75
|
+
o.ce = clock;
|
|
76
|
+
const u = o.oe?.values().next().value;
|
|
77
|
+
if (u) {
|
|
78
|
+
setPendingError(o, u);
|
|
79
|
+
t !== null && t(o);
|
|
84
80
|
} else {
|
|
85
|
-
|
|
86
|
-
setPendingError(
|
|
87
|
-
|
|
88
|
-
if (
|
|
89
|
-
enqueueSub(
|
|
90
|
-
|
|
81
|
+
o.S &= ~STATUS_PENDING;
|
|
82
|
+
setPendingError(o);
|
|
83
|
+
t !== null && t(o);
|
|
84
|
+
if (o.Se) {
|
|
85
|
+
enqueueSub(o);
|
|
86
|
+
n = true;
|
|
91
87
|
}
|
|
92
|
-
|
|
88
|
+
o.Se = false;
|
|
93
89
|
}
|
|
94
|
-
forEachDependent(
|
|
90
|
+
forEachDependent(o, settle);
|
|
95
91
|
};
|
|
96
92
|
forEachDependent(e, settle);
|
|
97
|
-
if (
|
|
93
|
+
if (n) schedule();
|
|
98
94
|
}
|
|
99
95
|
|
|
100
96
|
// Object-thenable detection (Promises/A+ shape).
|
|
@@ -112,34 +108,34 @@ function handleAsync(e, n, r) {
|
|
|
112
108
|
});
|
|
113
109
|
}
|
|
114
110
|
if (!o && !t) {
|
|
115
|
-
e.
|
|
111
|
+
e.Te = null;
|
|
116
112
|
return n;
|
|
117
113
|
}
|
|
118
|
-
e.
|
|
114
|
+
e.Te = n;
|
|
119
115
|
let u;
|
|
120
116
|
const handleError = r => {
|
|
121
|
-
if (e.
|
|
117
|
+
if (e.Te !== n) return;
|
|
122
118
|
globalQueue.initTransition(resolveTransition(e));
|
|
123
119
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
124
120
|
notifyStatus(e, r instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, r);
|
|
125
|
-
e.
|
|
121
|
+
e.ce = clock;
|
|
126
122
|
};
|
|
127
123
|
const asyncWrite = (t, o) => {
|
|
128
|
-
if (e.
|
|
124
|
+
if (e.Te !== n) return;
|
|
129
125
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
130
126
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
131
127
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
132
|
-
if (e.
|
|
128
|
+
if (e.se & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
133
129
|
globalQueue.initTransition(resolveTransition(e));
|
|
134
|
-
const u = !!(e.
|
|
130
|
+
const u = !!(e.S & STATUS_UNINITIALIZED);
|
|
135
131
|
trimStaleDeps(e);
|
|
136
132
|
clearStatus(e);
|
|
137
133
|
const l = resolveLane(e);
|
|
138
|
-
if (l) l.
|
|
134
|
+
if (l) l.de.delete(e);
|
|
139
135
|
if (r) {
|
|
140
136
|
r(t);
|
|
141
137
|
if (u) clearStatus(e, true);
|
|
142
|
-
} else if (e.
|
|
138
|
+
} else if (e.Ee !== undefined) {
|
|
143
139
|
// Optimistic node — resting OR covered by an active override — holds
|
|
144
140
|
// through the shared pending-node path, exactly like a plain async memo,
|
|
145
141
|
// so the commit clears STATUS_UNINITIALIZED (#2806) and elevation to
|
|
@@ -149,8 +145,8 @@ function handleAsync(e, n, r) {
|
|
|
149
145
|
// (A17 — every reader sees the override); the revert reveals whatever
|
|
150
146
|
// has committed by then, so corrections reveal atomically with their
|
|
151
147
|
// transition rather than escaping it.
|
|
152
|
-
if (e.
|
|
153
|
-
e.
|
|
148
|
+
if (e.Ne === NOT_PENDING) queuePendingNode(e);
|
|
149
|
+
e.Ne = t;
|
|
154
150
|
// The hold is a companion-visible write like any other (A13/A19): the
|
|
155
151
|
// clearStatus() above computed its verdict before the hold existed, so
|
|
156
152
|
// isPending must re-derive (the value is not final until commit — V1)
|
|
@@ -158,22 +154,22 @@ function handleAsync(e, n, r) {
|
|
|
158
154
|
// only notified when the hold is visible to them: under an active
|
|
159
155
|
// override every reader sees the override (A17), so waking subs would
|
|
160
156
|
// re-show an unchanged view — the revert is the notification point.
|
|
161
|
-
GlobalQueue.
|
|
157
|
+
GlobalQueue.Ie !== null && GlobalQueue.Ie(e, t);
|
|
162
158
|
if (!hasActiveOverride(e)) insertSubs(e);
|
|
163
|
-
e.
|
|
159
|
+
e.ce = clock;
|
|
164
160
|
} else if (l) {
|
|
165
161
|
// Route through lane's effect queue for independent flushing
|
|
166
|
-
const n = e.
|
|
167
|
-
const r = e.
|
|
168
|
-
const o = e.
|
|
162
|
+
const n = e.Ae;
|
|
163
|
+
const r = e.Pe;
|
|
164
|
+
const o = e.Re;
|
|
169
165
|
try {
|
|
170
166
|
if (!n && u || !o || !o(t, r)) {
|
|
171
|
-
e.
|
|
172
|
-
e.
|
|
167
|
+
e.Pe = t;
|
|
168
|
+
e.ce = clock;
|
|
173
169
|
// The latest() shadow write gives latest() effects independent lanes; the
|
|
174
170
|
// _pendingSignal update is a no-op repeat of the clearStatus() call above
|
|
175
171
|
// (computePendingState doesn't read _value).
|
|
176
|
-
GlobalQueue.
|
|
172
|
+
GlobalQueue.Ie !== null && GlobalQueue.Ie(e, t);
|
|
177
173
|
insertSubs(e, true);
|
|
178
174
|
}
|
|
179
175
|
} catch (n) {
|
|
@@ -197,18 +193,34 @@ function handleAsync(e, n, r) {
|
|
|
197
193
|
flush();
|
|
198
194
|
o?.();
|
|
199
195
|
};
|
|
196
|
+
// A pending node's in-flight promise is an observer: `unlinkSubs` skips
|
|
197
|
+
// autodispose while STATUS_PENDING so subscriber churn can't orphan the
|
|
198
|
+
// work (a lazy async memo would otherwise tear down and re-execute — one
|
|
199
|
+
// fetch per suspended re-read). Settling is that observer's release, so
|
|
200
|
+
// it runs the same last-one-out check the other release sites run.
|
|
201
|
+
const settleAutodispose = () => {
|
|
202
|
+
if (e.T & CONFIG_AUTO_DISPOSE && !e.o && !(e.S & STATUS_PENDING)) {
|
|
203
|
+
unobserved(e);
|
|
204
|
+
}
|
|
205
|
+
};
|
|
200
206
|
if (o) {
|
|
201
207
|
let r = false, t = false, o, l = true;
|
|
202
208
|
n.then(e => {
|
|
203
209
|
if (l) {
|
|
204
210
|
u = e;
|
|
205
211
|
r = true;
|
|
206
|
-
} else
|
|
212
|
+
} else {
|
|
213
|
+
asyncWrite(e);
|
|
214
|
+
settleAutodispose();
|
|
215
|
+
}
|
|
207
216
|
}, e => {
|
|
208
217
|
if (l) {
|
|
209
218
|
o = e;
|
|
210
219
|
t = true;
|
|
211
|
-
} else
|
|
220
|
+
} else {
|
|
221
|
+
handleError(e);
|
|
222
|
+
settleAutodispose();
|
|
223
|
+
}
|
|
212
224
|
});
|
|
213
225
|
l = false;
|
|
214
226
|
if (t) {
|
|
@@ -242,7 +254,7 @@ function handleAsync(e, n, r) {
|
|
|
242
254
|
i = r;
|
|
243
255
|
f = true;
|
|
244
256
|
if (r.done) o = true;
|
|
245
|
-
} else if (e.
|
|
257
|
+
} else if (e.Te !== n) {
|
|
246
258
|
return;
|
|
247
259
|
} else if (!r.done) {
|
|
248
260
|
t = true;
|
|
@@ -261,7 +273,7 @@ function handleAsync(e, n, r) {
|
|
|
261
273
|
if (c) {
|
|
262
274
|
s = r;
|
|
263
275
|
a = true;
|
|
264
|
-
} else if (e.
|
|
276
|
+
} else if (e.Te === n) {
|
|
265
277
|
o = true;
|
|
266
278
|
handleError(r);
|
|
267
279
|
}
|
|
@@ -293,86 +305,74 @@ function handleAsync(e, n, r) {
|
|
|
293
305
|
}
|
|
294
306
|
|
|
295
307
|
function clearStatus(e, n = false) {
|
|
296
|
-
if (e.
|
|
297
|
-
if (e.
|
|
308
|
+
if (e.oe) clearPendingSources(e);
|
|
309
|
+
if (e.Se) e.Se = false;
|
|
298
310
|
// The pending window is over; its quiet classification dies with it.
|
|
299
311
|
// (Unconditional: _reask is baked into the node literals, so this is a
|
|
300
312
|
// plain store to an existing slot — no shape change.)
|
|
301
|
-
e.
|
|
302
|
-
e.
|
|
303
|
-
if (e.
|
|
313
|
+
e._e = false;
|
|
314
|
+
e.S = n ? 0 : e.S & STATUS_UNINITIALIZED;
|
|
315
|
+
if (e._) setPendingError(e);
|
|
304
316
|
// Update pending signal for isPending() reactivity (companions only exist
|
|
305
317
|
// once the verdict layer created them, which installs the hooks).
|
|
306
|
-
if (e.
|
|
307
|
-
if (e.
|
|
308
|
-
if (e.
|
|
318
|
+
if (e.be || e.ge) GlobalQueue.ae(e);
|
|
319
|
+
if (e.u && GlobalQueue.he !== null) GlobalQueue.he(e);
|
|
320
|
+
if (e.i) e.i();
|
|
309
321
|
}
|
|
310
322
|
|
|
311
323
|
function notifyStatus(e, n, r, t, o) {
|
|
312
324
|
// Wrap regular errors to track source node
|
|
313
325
|
if (n === STATUS_ERROR && !(r instanceof StatusError) && !(r instanceof NotReadyError)) r = new StatusError(e, r);
|
|
314
326
|
const u = n === STATUS_PENDING && r instanceof NotReadyError ? r.source : undefined;
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
// freeze unrelated writes that share a downstream memo until the action
|
|
319
|
-
// settles. Real async keeps queuing (its commits ride the transition).
|
|
320
|
-
const l = u?.l !== undefined;
|
|
321
|
-
// A real error is a settled verdict a mark must not erase (#2893): landing
|
|
322
|
-
// STATUS_PENDING here would clobber `_error` with the sentinel's
|
|
323
|
-
// NotReadyError, and unlike real async there is no arriving value whose
|
|
324
|
-
// recompute would surface the error again. Descent stops too — everything
|
|
325
|
-
// downstream holds the propagated error for the same reason.
|
|
326
|
-
if (l && e.i & STATUS_ERROR) return;
|
|
327
|
-
const i = u === e;
|
|
328
|
-
const s = n === STATUS_PENDING && e.be !== undefined && !i;
|
|
329
|
-
const f = s && hasActiveOverride(e);
|
|
327
|
+
const l = u === e;
|
|
328
|
+
const i = n === STATUS_PENDING && e.Ee !== undefined && !l;
|
|
329
|
+
const s = i && hasActiveOverride(e);
|
|
330
330
|
if (!t) {
|
|
331
331
|
if (n === STATUS_PENDING && u) {
|
|
332
332
|
addPendingSource(e, u);
|
|
333
|
-
e.
|
|
333
|
+
e.S = STATUS_PENDING | e.S & STATUS_UNINITIALIZED;
|
|
334
334
|
// Preserve the current source on this propagation so render-effect notification
|
|
335
335
|
// can register every distinct pending source with the transition.
|
|
336
336
|
setPendingError(e, u, r);
|
|
337
337
|
} else {
|
|
338
338
|
clearPendingSources(e);
|
|
339
|
-
e.
|
|
340
|
-
e.
|
|
339
|
+
e.S = n | (n !== STATUS_ERROR ? e.S & STATUS_UNINITIALIZED : 0);
|
|
340
|
+
e._ = r;
|
|
341
341
|
}
|
|
342
|
-
GlobalQueue.
|
|
343
|
-
if (e.
|
|
342
|
+
GlobalQueue.ae !== null && GlobalQueue.ae(e);
|
|
343
|
+
if (e.u && GlobalQueue.he !== null) GlobalQueue.he(e);
|
|
344
344
|
}
|
|
345
345
|
if (o && !t) {
|
|
346
346
|
assignOrMergeLane(e, o);
|
|
347
347
|
}
|
|
348
|
-
const
|
|
349
|
-
const
|
|
350
|
-
if (e.
|
|
348
|
+
const f = t || s;
|
|
349
|
+
const a = t || i ? undefined : o;
|
|
350
|
+
if (e.i) {
|
|
351
351
|
if (t && n === STATUS_PENDING) {
|
|
352
352
|
return;
|
|
353
353
|
}
|
|
354
|
-
if (
|
|
355
|
-
e.
|
|
354
|
+
if (f) {
|
|
355
|
+
e.i(n, r);
|
|
356
356
|
} else {
|
|
357
|
-
e.
|
|
357
|
+
e.i();
|
|
358
358
|
}
|
|
359
359
|
return;
|
|
360
360
|
}
|
|
361
361
|
forEachDependent(e, (e, t) => {
|
|
362
|
-
e.
|
|
363
|
-
if (n === STATUS_PENDING && u && !e.
|
|
362
|
+
e.ce = clock;
|
|
363
|
+
if (n === STATUS_PENDING && u && !e.oe?.has(u) || n !== STATUS_PENDING && (e._ !== r || e.oe)) {
|
|
364
364
|
// A pending-observer link is the subscription an `isPending` read created.
|
|
365
365
|
// It exists so the observer re-runs when the source settles, but it must
|
|
366
366
|
// not carry a real (non-NotReadyError) error — the synchronous `isPending`
|
|
367
367
|
// read swallows those, and the async path must match. Re-run the observer
|
|
368
368
|
// so `isPending` re-evaluates (to not-pending) instead of forwarding.
|
|
369
|
-
if (t.
|
|
369
|
+
if (t.De && n !== STATUS_PENDING && !(r instanceof NotReadyError)) {
|
|
370
370
|
enqueueSub(e);
|
|
371
371
|
schedule();
|
|
372
372
|
return;
|
|
373
373
|
}
|
|
374
|
-
if (!
|
|
375
|
-
notifyStatus(e, n, r,
|
|
374
|
+
if (!f && !e.Ue) queuePendingNode(e);
|
|
375
|
+
notifyStatus(e, n, r, f, a);
|
|
376
376
|
}
|
|
377
377
|
});
|
|
378
378
|
}
|