@solidjs/signals 2.0.0-beta.18 → 2.0.0-beta.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.js +2743 -694
- package/dist/node.cjs +6419 -4234
- package/dist/prod/affects.js +222 -0
- package/dist/prod/boundaries.js +568 -0
- package/dist/prod/core/action.js +83 -0
- package/dist/prod/core/async.js +394 -0
- package/dist/prod/core/constants.js +78 -0
- package/dist/prod/core/context.js +67 -0
- package/dist/prod/core/core.js +772 -0
- package/dist/prod/core/dev.js +3 -0
- package/dist/prod/core/effect.js +145 -0
- package/dist/prod/core/error.js +59 -0
- package/dist/prod/core/external.js +98 -0
- package/dist/prod/core/graph.js +91 -0
- package/dist/prod/core/heap.js +132 -0
- package/dist/prod/core/invariants.js +42 -0
- package/dist/prod/core/lanes.js +130 -0
- package/dist/prod/core/optimistic.js +265 -0
- package/dist/prod/core/owner.js +293 -0
- package/dist/prod/core/scheduler.js +689 -0
- package/dist/prod/core/verdict.js +293 -0
- package/dist/prod/index.js +45 -0
- package/dist/prod/map.js +264 -0
- package/dist/prod/signals.js +389 -0
- package/dist/prod/store/optimistic.js +149 -0
- package/dist/prod/store/projection.js +184 -0
- package/dist/prod/store/reconcile.js +392 -0
- package/dist/prod/store/store.js +739 -0
- package/dist/prod/store/storePath.js +103 -0
- package/dist/prod/store/utils.js +297 -0
- package/dist/types/affects.d.ts +1 -1
- package/dist/types/boundaries.d.ts +6 -6
- package/dist/types/core/async.d.ts +4 -38
- package/dist/types/core/core.d.ts +12 -78
- package/dist/types/core/external.d.ts +0 -30
- package/dist/types/core/heap.d.ts +8 -0
- package/dist/types/core/index.d.ts +3 -2
- package/dist/types/core/optimistic.d.ts +6 -0
- package/dist/types/core/owner.d.ts +8 -0
- package/dist/types/core/scheduler.d.ts +39 -34
- package/dist/types/core/verdict.d.ts +2 -0
- package/dist/types/store/projection.d.ts +0 -1
- package/dist/types-cjs/affects.d.cts +1 -1
- package/dist/types-cjs/boundaries.d.cts +6 -6
- package/dist/types-cjs/core/async.d.cts +4 -38
- package/dist/types-cjs/core/core.d.cts +12 -78
- package/dist/types-cjs/core/external.d.cts +0 -30
- package/dist/types-cjs/core/heap.d.cts +8 -0
- package/dist/types-cjs/core/index.d.cts +3 -2
- package/dist/types-cjs/core/optimistic.d.cts +6 -0
- package/dist/types-cjs/core/owner.d.cts +8 -0
- package/dist/types-cjs/core/scheduler.d.cts +39 -34
- package/dist/types-cjs/core/verdict.d.cts +2 -0
- package/dist/types-cjs/store/projection.d.cts +0 -1
- package/package.json +8 -6
- package/dist/prod.js +0 -4637
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import { STATUS_UNINITIALIZED, STATUS_ERROR, STATUS_PENDING, REACTIVE_DIRTY, REACTIVE_OPTIMISTIC_DIRTY, NOT_PENDING } from "./constants.js";
|
|
2
|
+
|
|
3
|
+
import { untrack, context, setSignal } from "./core.js";
|
|
4
|
+
|
|
5
|
+
import "./invariants.js";
|
|
6
|
+
|
|
7
|
+
import { NotReadyError, StatusError } from "./error.js";
|
|
8
|
+
|
|
9
|
+
import { trimStaleDeps } from "./graph.js";
|
|
10
|
+
|
|
11
|
+
import { enqueueSub } from "./heap.js";
|
|
12
|
+
|
|
13
|
+
import { resolveTransition, hasActiveOverride, assignOrMergeLane, resolveLane } from "./lanes.js";
|
|
14
|
+
|
|
15
|
+
import { cleanup } from "./owner.js";
|
|
16
|
+
|
|
17
|
+
import { globalQueue, GlobalQueue, clock, schedule, queuePendingNode, flush, insertSubs } from "./scheduler.js";
|
|
18
|
+
|
|
19
|
+
function addPendingSource(e, n) {
|
|
20
|
+
if (e.m === n || e.M?.has(n)) return false;
|
|
21
|
+
// Once the Set exists it is THE container — the singular slot stays empty
|
|
22
|
+
// from migration until removePendingSource collapses back to one entry.
|
|
23
|
+
// Landing a third source in the singular slot instead created dual state
|
|
24
|
+
// that removePendingSource refused to clear, stranding the Set members'
|
|
25
|
+
// pending forever (#2893).
|
|
26
|
+
if (e.M) e.M.add(n); else if (!e.m) e.m = n; else {
|
|
27
|
+
e.M = new Set([ e.m, n ]);
|
|
28
|
+
e.m = undefined;
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function removePendingSource(e, n) {
|
|
34
|
+
if (e.m) {
|
|
35
|
+
if (e.m !== n) return false;
|
|
36
|
+
e.m = undefined;
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
if (!e.M?.delete(n)) return false;
|
|
40
|
+
if (e.M.size === 1) {
|
|
41
|
+
e.m = e.M.values().next().value;
|
|
42
|
+
e.M = undefined;
|
|
43
|
+
} else if (e.M.size === 0) {
|
|
44
|
+
e.M = undefined;
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function clearPendingSources(e) {
|
|
50
|
+
e.m = undefined;
|
|
51
|
+
e.M?.clear();
|
|
52
|
+
e.M = undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function setPendingError(e, n, r) {
|
|
56
|
+
if (!n) {
|
|
57
|
+
e.k = null;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (r instanceof NotReadyError && r.source === n) {
|
|
61
|
+
e.k = r;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const t = e.k;
|
|
65
|
+
if (!(t instanceof NotReadyError) || t.source !== n) {
|
|
66
|
+
e.k = new NotReadyError(n);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function forEachDependent(e, n) {
|
|
71
|
+
for (let r = e.p; r !== null; r = r.de) n(r.Ee, r);
|
|
72
|
+
// `?? null`: affects() marks route plain signals (no `_child` slot) through here.
|
|
73
|
+
for (let r = e.G ?? null; r !== null; r = r.Ne) {
|
|
74
|
+
for (let e = r.p; e !== null; e = e.de) n(e.Ee, e);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Queue a node to re-run on the next flush (used both when a pending source
|
|
79
|
+
// settles and when an `isPending` observer must re-evaluate after a real error):
|
|
80
|
+
// shared scheduling helper in heap.ts (tracked effects bypass the heap).
|
|
81
|
+
function settlePendingSource(e, n = e,
|
|
82
|
+
// Mark release runs inside queue finalization: companion writes must go
|
|
83
|
+
// through the settlement snap (committed), because a setSignal here would
|
|
84
|
+
// open a fresh transition-scoped override window that nothing reverts.
|
|
85
|
+
r = false) {
|
|
86
|
+
let t = false;
|
|
87
|
+
const u = new Set;
|
|
88
|
+
// Companion updates no-op without the verdict layer (null hooks).
|
|
89
|
+
const o = r ? GlobalQueue.R : GlobalQueue._;
|
|
90
|
+
const settle = e => {
|
|
91
|
+
if (u.has(e) || !removePendingSource(e, n)) return;
|
|
92
|
+
u.add(e);
|
|
93
|
+
e.Ie = clock;
|
|
94
|
+
const r = e.m ?? e.M?.values().next().value;
|
|
95
|
+
if (r) {
|
|
96
|
+
setPendingError(e, r);
|
|
97
|
+
o !== null && o(e);
|
|
98
|
+
} else {
|
|
99
|
+
e.i &= ~STATUS_PENDING;
|
|
100
|
+
setPendingError(e);
|
|
101
|
+
o !== null && o(e);
|
|
102
|
+
if (e.Re) {
|
|
103
|
+
enqueueSub(e);
|
|
104
|
+
t = true;
|
|
105
|
+
}
|
|
106
|
+
e.Re = false;
|
|
107
|
+
}
|
|
108
|
+
forEachDependent(e, settle);
|
|
109
|
+
};
|
|
110
|
+
forEachDependent(e, settle);
|
|
111
|
+
if (t) schedule();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Object-thenable detection (Promises/A+ shape).
|
|
115
|
+
function isThenable(e) {
|
|
116
|
+
return e != null && typeof e === "object" && typeof e.then === "function";
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function handleAsync(e, n, r) {
|
|
120
|
+
let t = false;
|
|
121
|
+
let u = false;
|
|
122
|
+
if (typeof n === "object" && n !== null) {
|
|
123
|
+
untrack(() => {
|
|
124
|
+
t = n[Symbol.asyncIterator];
|
|
125
|
+
u = !t && isThenable(n);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
if (!u && !t) {
|
|
129
|
+
e.Ae = null;
|
|
130
|
+
return n;
|
|
131
|
+
}
|
|
132
|
+
e.Ae = n;
|
|
133
|
+
let o;
|
|
134
|
+
const handleError = r => {
|
|
135
|
+
if (e.Ae !== n) return;
|
|
136
|
+
globalQueue.initTransition(resolveTransition(e));
|
|
137
|
+
// NotReadyError from rejected promises should be treated as pending, not error
|
|
138
|
+
notifyStatus(e, r instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, r);
|
|
139
|
+
e.Ie = clock;
|
|
140
|
+
};
|
|
141
|
+
const asyncWrite = (t, u) => {
|
|
142
|
+
if (e.Ae !== n) return;
|
|
143
|
+
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
144
|
+
// skip this stale async result — the upcoming flush will recompute the node
|
|
145
|
+
// with the new value, creating a fresh Promise that supersedes this one.
|
|
146
|
+
if (e.u & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
147
|
+
globalQueue.initTransition(resolveTransition(e));
|
|
148
|
+
const o = !!(e.i & STATUS_UNINITIALIZED);
|
|
149
|
+
trimStaleDeps(e);
|
|
150
|
+
clearStatus(e);
|
|
151
|
+
const l = resolveLane(e);
|
|
152
|
+
if (l) l.Pe.delete(e);
|
|
153
|
+
if (r) {
|
|
154
|
+
r(t);
|
|
155
|
+
if (o) clearStatus(e, true);
|
|
156
|
+
} else if (e.be !== undefined) {
|
|
157
|
+
// Optimistic node — resting OR covered by an active override — holds
|
|
158
|
+
// through the shared pending-node path, exactly like a plain async memo,
|
|
159
|
+
// so the commit clears STATUS_UNINITIALIZED (#2806) and elevation to
|
|
160
|
+
// _value happens on this value's OWN transition schedule (A18 as
|
|
161
|
+
// re-ruled 2026-07-07: _value only changes at commit points). With an
|
|
162
|
+
// override active the hold and its eventual commit are unobservable
|
|
163
|
+
// (A17 — every reader sees the override); the revert reveals whatever
|
|
164
|
+
// has committed by then, so corrections reveal atomically with their
|
|
165
|
+
// transition rather than escaping it.
|
|
166
|
+
if (e.ge === NOT_PENDING) queuePendingNode(e);
|
|
167
|
+
e.ge = t;
|
|
168
|
+
// The hold is a companion-visible write like any other (A13/A19): the
|
|
169
|
+
// clearStatus() above computed its verdict before the hold existed, so
|
|
170
|
+
// isPending must re-derive (the value is not final until commit — V1)
|
|
171
|
+
// and latest() must see the fresh in-flight value (V2). Subscribers are
|
|
172
|
+
// only notified when the hold is visible to them: under an active
|
|
173
|
+
// override every reader sees the override (A17), so waking subs would
|
|
174
|
+
// re-show an unchanged view — the revert is the notification point.
|
|
175
|
+
GlobalQueue._e !== null && GlobalQueue._e(e, t);
|
|
176
|
+
if (!hasActiveOverride(e)) insertSubs(e);
|
|
177
|
+
e.Ie = clock;
|
|
178
|
+
} else if (l) {
|
|
179
|
+
// Route through lane's effect queue for independent flushing
|
|
180
|
+
const n = e.De;
|
|
181
|
+
const r = e.Ue;
|
|
182
|
+
const u = e.Ge;
|
|
183
|
+
try {
|
|
184
|
+
if (!n && o || !u || !u(t, r)) {
|
|
185
|
+
e.Ue = t;
|
|
186
|
+
e.Ie = clock;
|
|
187
|
+
// The latest() shadow write gives latest() effects independent lanes; the
|
|
188
|
+
// _pendingSignal update is a no-op repeat of the clearStatus() call above
|
|
189
|
+
// (computePendingState doesn't read _value).
|
|
190
|
+
GlobalQueue._e !== null && GlobalQueue._e(e, t);
|
|
191
|
+
insertSubs(e, true);
|
|
192
|
+
}
|
|
193
|
+
} catch (n) {
|
|
194
|
+
// A user comparator throwing during async resolution has no caller to
|
|
195
|
+
// surface to (we're in promise machinery) — route it through the node's
|
|
196
|
+
// error status so boundaries contain it instead of an unhandled
|
|
197
|
+
// rejection (#2837).
|
|
198
|
+
notifyStatus(e, STATUS_ERROR, n);
|
|
199
|
+
}
|
|
200
|
+
} else {
|
|
201
|
+
try {
|
|
202
|
+
setSignal(e, () => t);
|
|
203
|
+
} catch (n) {
|
|
204
|
+
// Same containment as above: setSignal's comparator throw is the only
|
|
205
|
+
// pre-commit failure here, and there is no user callsite to throw to.
|
|
206
|
+
notifyStatus(e, STATUS_ERROR, n);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
settlePendingSource(e);
|
|
210
|
+
schedule();
|
|
211
|
+
flush();
|
|
212
|
+
u?.();
|
|
213
|
+
};
|
|
214
|
+
if (u) {
|
|
215
|
+
let r = false, t = false, u, l = true;
|
|
216
|
+
n.then(e => {
|
|
217
|
+
if (l) {
|
|
218
|
+
o = e;
|
|
219
|
+
r = true;
|
|
220
|
+
} else asyncWrite(e);
|
|
221
|
+
}, e => {
|
|
222
|
+
if (l) {
|
|
223
|
+
u = e;
|
|
224
|
+
t = true;
|
|
225
|
+
} else handleError(e);
|
|
226
|
+
});
|
|
227
|
+
l = false;
|
|
228
|
+
if (t) {
|
|
229
|
+
// Settle through the same status path an async rejection uses, then
|
|
230
|
+
// unwind the in-progress synchronous read so the errored node isn't
|
|
231
|
+
// momentarily read as `undefined`.
|
|
232
|
+
handleError(u);
|
|
233
|
+
throw u;
|
|
234
|
+
} else if (!r) {
|
|
235
|
+
globalQueue.initTransition(resolveTransition(e));
|
|
236
|
+
throw new NotReadyError(context);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (t) {
|
|
240
|
+
const r = n[Symbol.asyncIterator]();
|
|
241
|
+
let t = false;
|
|
242
|
+
let u = false;
|
|
243
|
+
let l = true;
|
|
244
|
+
cleanup(() => {
|
|
245
|
+
if (u) return;
|
|
246
|
+
u = true;
|
|
247
|
+
try {
|
|
248
|
+
const e = r.return?.();
|
|
249
|
+
if (isThenable(e)) e.then(undefined, () => {});
|
|
250
|
+
} catch {}
|
|
251
|
+
});
|
|
252
|
+
const iterate = () => {
|
|
253
|
+
let i, s, f = false, a = false, c = true;
|
|
254
|
+
r.next().then(r => {
|
|
255
|
+
if (c) {
|
|
256
|
+
i = r;
|
|
257
|
+
f = true;
|
|
258
|
+
if (r.done) u = true;
|
|
259
|
+
} else if (e.Ae !== n) {
|
|
260
|
+
return;
|
|
261
|
+
} else if (!r.done) {
|
|
262
|
+
t = true;
|
|
263
|
+
asyncWrite(r.value, iterate);
|
|
264
|
+
} else {
|
|
265
|
+
u = true;
|
|
266
|
+
if (t) {
|
|
267
|
+
schedule();
|
|
268
|
+
flush();
|
|
269
|
+
} else {
|
|
270
|
+
// Empty completion settles like the immediately-done sync path.
|
|
271
|
+
asyncWrite(undefined);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}, r => {
|
|
275
|
+
if (c) {
|
|
276
|
+
s = r;
|
|
277
|
+
a = true;
|
|
278
|
+
} else if (e.Ae === n) {
|
|
279
|
+
u = true;
|
|
280
|
+
handleError(r);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
c = false;
|
|
284
|
+
if (a) {
|
|
285
|
+
// Match the promise branch, but only rethrow during the initial read.
|
|
286
|
+
u = true;
|
|
287
|
+
handleError(s);
|
|
288
|
+
if (l) throw s;
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
if (f && !i.done) {
|
|
292
|
+
o = i.value;
|
|
293
|
+
t = true;
|
|
294
|
+
return iterate();
|
|
295
|
+
}
|
|
296
|
+
return f && i.done;
|
|
297
|
+
};
|
|
298
|
+
const i = iterate();
|
|
299
|
+
// Later iterate() calls run from asyncWrite, where rethrowing would be unhandled.
|
|
300
|
+
l = false;
|
|
301
|
+
if (!t && !i) {
|
|
302
|
+
globalQueue.initTransition(resolveTransition(e));
|
|
303
|
+
throw new NotReadyError(context);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return o;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function clearStatus(e, n = false) {
|
|
310
|
+
if (e.m || e.M) clearPendingSources(e);
|
|
311
|
+
if (e.Re) e.Re = false;
|
|
312
|
+
// The pending window is over; its quiet classification dies with it.
|
|
313
|
+
// (Unconditional: _reask is baked into the node literals, so this is a
|
|
314
|
+
// plain store to an existing slot — no shape change.)
|
|
315
|
+
e.A = false;
|
|
316
|
+
e.i = n ? 0 : e.i & STATUS_UNINITIALIZED;
|
|
317
|
+
if (e.k) setPendingError(e);
|
|
318
|
+
// Update pending signal for isPending() reactivity (companions only exist
|
|
319
|
+
// once the verdict layer created them, which installs the hooks).
|
|
320
|
+
if (e.ye || e.pe) GlobalQueue._(e);
|
|
321
|
+
if (e.G && GlobalQueue.me !== null) GlobalQueue.me(e);
|
|
322
|
+
if (e.C) e.C();
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function notifyStatus(e, n, r, t, u) {
|
|
326
|
+
// Wrap regular errors to track source node
|
|
327
|
+
if (n === STATUS_ERROR && !(r instanceof StatusError) && !(r instanceof NotReadyError)) r = new StatusError(e, r);
|
|
328
|
+
const o = n === STATUS_PENDING && r instanceof NotReadyError ? r.source : undefined;
|
|
329
|
+
// Mark-sourced propagation must not capture subscribers into the marking
|
|
330
|
+
// action's transaction (#2893): they carry no held value needing a
|
|
331
|
+
// transition-scheduled commit, and stamping `_transition` on them would
|
|
332
|
+
// freeze unrelated writes that share a downstream memo until the action
|
|
333
|
+
// settles. Real async keeps queuing (its commits ride the transition).
|
|
334
|
+
const l = o?.l !== undefined;
|
|
335
|
+
// A real error is a settled verdict a mark must not erase (#2893): landing
|
|
336
|
+
// STATUS_PENDING here would clobber `_error` with the sentinel's
|
|
337
|
+
// NotReadyError, and unlike real async there is no arriving value whose
|
|
338
|
+
// recompute would surface the error again. Descent stops too — everything
|
|
339
|
+
// downstream holds the propagated error for the same reason.
|
|
340
|
+
if (l && e.i & STATUS_ERROR) return;
|
|
341
|
+
const i = o === e;
|
|
342
|
+
const s = n === STATUS_PENDING && e.be !== undefined && !i;
|
|
343
|
+
const f = s && hasActiveOverride(e);
|
|
344
|
+
if (!t) {
|
|
345
|
+
if (n === STATUS_PENDING && o) {
|
|
346
|
+
addPendingSource(e, o);
|
|
347
|
+
e.i = STATUS_PENDING | e.i & STATUS_UNINITIALIZED;
|
|
348
|
+
// Preserve the current source on this propagation so render-effect notification
|
|
349
|
+
// can register every distinct pending source with the transition.
|
|
350
|
+
setPendingError(e, o, r);
|
|
351
|
+
} else {
|
|
352
|
+
clearPendingSources(e);
|
|
353
|
+
e.i = n | (n !== STATUS_ERROR ? e.i & STATUS_UNINITIALIZED : 0);
|
|
354
|
+
e.k = r;
|
|
355
|
+
}
|
|
356
|
+
GlobalQueue._ !== null && GlobalQueue._(e);
|
|
357
|
+
if (e.G && GlobalQueue.me !== null) GlobalQueue.me(e);
|
|
358
|
+
}
|
|
359
|
+
if (u && !t) {
|
|
360
|
+
assignOrMergeLane(e, u);
|
|
361
|
+
}
|
|
362
|
+
const a = t || f;
|
|
363
|
+
const c = t || s ? undefined : u;
|
|
364
|
+
if (e.C) {
|
|
365
|
+
if (t && n === STATUS_PENDING) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
if (a) {
|
|
369
|
+
e.C(n, r);
|
|
370
|
+
} else {
|
|
371
|
+
e.C();
|
|
372
|
+
}
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
forEachDependent(e, (e, t) => {
|
|
376
|
+
e.Ie = clock;
|
|
377
|
+
if (n === STATUS_PENDING && o && e.m !== o && !e.M?.has(o) || n !== STATUS_PENDING && (e.k !== r || e.m || e.M)) {
|
|
378
|
+
// A pending-observer link is the subscription an `isPending` read created.
|
|
379
|
+
// It exists so the observer re-runs when the source settles, but it must
|
|
380
|
+
// not carry a real (non-NotReadyError) error — the synchronous `isPending`
|
|
381
|
+
// read swallows those, and the async path must match. Re-run the observer
|
|
382
|
+
// so `isPending` re-evaluates (to not-pending) instead of forwarding.
|
|
383
|
+
if (t.Qe && n !== STATUS_PENDING && !(r instanceof NotReadyError)) {
|
|
384
|
+
enqueueSub(e);
|
|
385
|
+
schedule();
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
if (!a && !l && !e.ve) queuePendingNode(e);
|
|
389
|
+
notifyStatus(e, n, r, a, c);
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export { addPendingSource, clearStatus, forEachDependent, handleAsync, isThenable, notifyStatus, setPendingError, settlePendingSource };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const REACTIVE_NONE = 0;
|
|
2
|
+
|
|
3
|
+
const REACTIVE_CHECK = 1 << 0;
|
|
4
|
+
|
|
5
|
+
const REACTIVE_DIRTY = 1 << 1;
|
|
6
|
+
|
|
7
|
+
const REACTIVE_RECOMPUTING_DEPS = 1 << 2;
|
|
8
|
+
|
|
9
|
+
const REACTIVE_IN_HEAP = 1 << 3;
|
|
10
|
+
|
|
11
|
+
const REACTIVE_IN_HEAP_HEIGHT = 1 << 4;
|
|
12
|
+
|
|
13
|
+
const REACTIVE_ZOMBIE = 1 << 5;
|
|
14
|
+
|
|
15
|
+
const REACTIVE_DISPOSED = 1 << 6;
|
|
16
|
+
|
|
17
|
+
const REACTIVE_OPTIMISTIC_DIRTY = 1 << 7;
|
|
18
|
+
|
|
19
|
+
const REACTIVE_SNAPSHOT_STALE = 1 << 8;
|
|
20
|
+
|
|
21
|
+
const REACTIVE_LAZY = 1 << 9;
|
|
22
|
+
|
|
23
|
+
const REACTIVE_MANUAL_WRITE = 1 << 10;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The pending recompute is a re-ask of the same question: `refresh()` dirtied
|
|
27
|
+
* the node while no tracked input changed value. Cleared whenever a real
|
|
28
|
+
* value-change notification arrives (`insertSubs`), and consumed by
|
|
29
|
+
* `recompute` into the node's `_reask` classification — a quiet (re-ask)
|
|
30
|
+
* pending window does not read as pending (question-scoped pending model).
|
|
31
|
+
*/ const REACTIVE_REASK = 1 << 11;
|
|
32
|
+
|
|
33
|
+
// Static configuration bits packed into Owner/Computed/Signal _config.
|
|
34
|
+
const CONFIG_OWNED_WRITE = 1 << 0;
|
|
35
|
+
|
|
36
|
+
const CONFIG_NO_SNAPSHOT = 1 << 1;
|
|
37
|
+
|
|
38
|
+
const CONFIG_TRANSPARENT = 1 << 2;
|
|
39
|
+
|
|
40
|
+
const CONFIG_IN_SNAPSHOT_SCOPE = 1 << 3;
|
|
41
|
+
|
|
42
|
+
const CONFIG_CHILDREN_FORBIDDEN = 1 << 4;
|
|
43
|
+
|
|
44
|
+
const CONFIG_AUTO_DISPOSE = 1 << 5;
|
|
45
|
+
|
|
46
|
+
const CONFIG_SYNC = 1 << 6;
|
|
47
|
+
|
|
48
|
+
const STATUS_PENDING = 1 << 0;
|
|
49
|
+
|
|
50
|
+
const STATUS_ERROR = 1 << 1;
|
|
51
|
+
|
|
52
|
+
const STATUS_UNINITIALIZED = 1 << 2;
|
|
53
|
+
|
|
54
|
+
const EFFECT_RENDER = 1;
|
|
55
|
+
|
|
56
|
+
const EFFECT_USER = 2;
|
|
57
|
+
|
|
58
|
+
const EFFECT_TRACKED = 3;
|
|
59
|
+
|
|
60
|
+
const NOT_PENDING = {};
|
|
61
|
+
|
|
62
|
+
const NO_SNAPSHOT = {};
|
|
63
|
+
|
|
64
|
+
const STORE_SNAPSHOT_PROPS = "sp";
|
|
65
|
+
|
|
66
|
+
const SUPPORTS_PROXY = typeof Proxy === "function";
|
|
67
|
+
|
|
68
|
+
const defaultContext = {};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Brand symbol used by `Refreshable<T>` values (projection stores, async
|
|
72
|
+
* memos) to expose their underlying computation to `refresh()`. Not part of
|
|
73
|
+
* the user-facing API.
|
|
74
|
+
*
|
|
75
|
+
* @internal
|
|
76
|
+
*/ const $REFRESH = Symbol("refresh");
|
|
77
|
+
|
|
78
|
+
export { $REFRESH, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_NO_SNAPSHOT, CONFIG_OWNED_WRITE, CONFIG_SYNC, CONFIG_TRANSPARENT, EFFECT_RENDER, EFFECT_TRACKED, EFFECT_USER, NOT_PENDING, NO_SNAPSHOT, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_DISPOSED, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_LAZY, REACTIVE_MANUAL_WRITE, REACTIVE_NONE, REACTIVE_OPTIMISTIC_DIRTY, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, REACTIVE_SNAPSHOT_STALE, REACTIVE_ZOMBIE, STATUS_ERROR, STATUS_PENDING, STATUS_UNINITIALIZED, STORE_SNAPSHOT_PROPS, SUPPORTS_PROXY, defaultContext };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { NoOwnerError, ContextNotFoundError } from "./error.js";
|
|
2
|
+
|
|
3
|
+
import { getOwner } from "./owner.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Context provides a form of dependency injection. It is used to save from needing to pass
|
|
7
|
+
* data as props through intermediate components. This function creates a new context object
|
|
8
|
+
* that can be used with `getContext` and `setContext`.
|
|
9
|
+
*
|
|
10
|
+
* A default value can be provided here which will be used when a specific value is not provided
|
|
11
|
+
* via a `setContext` call.
|
|
12
|
+
*/ function createContext(e, t) {
|
|
13
|
+
return {
|
|
14
|
+
id: Symbol(t),
|
|
15
|
+
defaultValue: e
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Low-level owner-targeted context read. The user-facing read API is
|
|
21
|
+
* `useContext` (in `solid-js`), which wraps this primitive. Exposed here for
|
|
22
|
+
* cross-package wiring (e.g. hydration-aware context plumbing).
|
|
23
|
+
*
|
|
24
|
+
* @throws `NoOwnerError` if there's no owner at the time of call.
|
|
25
|
+
* @throws `ContextNotFoundError` if a context value has not been set yet.
|
|
26
|
+
*
|
|
27
|
+
* @internal
|
|
28
|
+
*/ function getContext(e, t = getOwner()) {
|
|
29
|
+
if (!t) {
|
|
30
|
+
throw new NoOwnerError;
|
|
31
|
+
}
|
|
32
|
+
const n = hasContext(e, t) ? t.we[e.id] : e.defaultValue;
|
|
33
|
+
if (isUndefined(n)) {
|
|
34
|
+
throw new ContextNotFoundError;
|
|
35
|
+
}
|
|
36
|
+
return n;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Low-level owner-targeted context write. The user-facing API is
|
|
41
|
+
* `createContext` (in `solid-js`); its provider component wraps this
|
|
42
|
+
* primitive. Exposed here for cross-package wiring.
|
|
43
|
+
*
|
|
44
|
+
* @throws `NoOwnerError` if there's no owner at the time of call.
|
|
45
|
+
*
|
|
46
|
+
* @internal
|
|
47
|
+
*/ function setContext(e, t, n = getOwner()) {
|
|
48
|
+
if (!n) {
|
|
49
|
+
throw new NoOwnerError;
|
|
50
|
+
}
|
|
51
|
+
// We're creating a new object to avoid child context values being exposed to parent owners. If
|
|
52
|
+
// we don't do this, everything will be a singleton and all hell will break lose.
|
|
53
|
+
n.we = {
|
|
54
|
+
...n.we,
|
|
55
|
+
[e.id]: isUndefined(t) ? e.defaultValue : t
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function hasContext(e, t) {
|
|
60
|
+
return !isUndefined(t?.we[e.id]);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isUndefined(e) {
|
|
64
|
+
return typeof e === "undefined";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export { createContext, getContext, setContext };
|