@solidjs/signals 2.0.0-rc.14 → 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 +882 -405
- package/dist/dev.attribution.js +172 -66
- package/dist/dev.js +1529 -745
- package/dist/observe/affects-marks.js +86 -0
- package/dist/observe/affects.js +32 -80
- package/dist/observe/boundaries.js +202 -166
- package/dist/observe/core/async.js +192 -141
- package/dist/observe/core/attribution-queries.js +1 -1
- package/dist/observe/core/attribution.js +315 -214
- package/dist/observe/core/constants.js +23 -4
- package/dist/observe/core/context.js +3 -3
- package/dist/observe/core/core.js +532 -360
- package/dist/observe/core/dev.js +63 -35
- package/dist/observe/core/effect.js +47 -47
- package/dist/observe/core/error.js +5 -3
- package/dist/observe/core/external.js +5 -6
- package/dist/observe/core/graph.js +56 -42
- package/dist/observe/core/heap.js +33 -33
- package/dist/observe/core/identities.js +62 -0
- package/dist/observe/core/lanes.js +242 -229
- package/dist/observe/core/owner.js +62 -50
- package/dist/observe/core/scheduler.js +322 -168
- package/dist/observe/core/truth.js +45 -0
- package/dist/observe/core/verdict.js +114 -64
- package/dist/observe/deferred.js +184 -0
- package/dist/observe/index.js +7 -1
- package/dist/observe/map.js +339 -254
- package/dist/observe/reveal.js +77 -77
- package/dist/observe/signals.js +54 -33
- package/dist/observe/store/affects.js +76 -69
- package/dist/observe/store/edges.js +39 -0
- package/dist/observe/store/hooks.js +13 -0
- package/dist/observe/store/index.js +0 -2
- package/dist/observe/store/optimistic.js +82 -44
- package/dist/observe/store/projection.js +83 -64
- package/dist/observe/store/reconcile.js +32 -30
- package/dist/observe/store/store.js +219 -123
- package/dist/prod/affects-marks.js +86 -0
- package/dist/prod/affects.js +33 -79
- package/dist/prod/boundaries.js +185 -149
- package/dist/prod/core/async.js +176 -135
- package/dist/prod/core/constants.js +23 -4
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +521 -353
- package/dist/prod/core/effect.js +66 -66
- package/dist/prod/core/error.js +5 -3
- package/dist/prod/core/external.js +5 -6
- package/dist/prod/core/graph.js +56 -42
- package/dist/prod/core/heap.js +38 -38
- package/dist/prod/core/identities.js +62 -0
- package/dist/prod/core/lanes.js +237 -224
- package/dist/prod/core/owner.js +62 -51
- package/dist/prod/core/scheduler.js +312 -158
- package/dist/prod/core/truth.js +45 -0
- package/dist/prod/core/verdict.js +113 -63
- package/dist/prod/deferred.js +182 -0
- package/dist/prod/index.js +7 -1
- package/dist/prod/map.js +366 -281
- package/dist/prod/reveal.js +77 -77
- package/dist/prod/signals.js +59 -38
- package/dist/prod/store/affects.js +76 -69
- package/dist/prod/store/edges.js +39 -0
- package/dist/prod/store/hooks.js +13 -0
- package/dist/prod/store/index.js +0 -2
- package/dist/prod/store/optimistic.js +121 -84
- package/dist/prod/store/projection.js +46 -34
- package/dist/prod/store/reconcile.js +32 -30
- package/dist/prod/store/store.js +205 -116
- package/dist/types/affects-marks.d.ts +14 -0
- package/dist/types/boundaries.d.ts +5 -1
- package/dist/types/core/async.d.ts +10 -0
- package/dist/types/core/attribution.d.ts +6 -2
- package/dist/types/core/constants.d.ts +18 -1
- package/dist/types/core/core.d.ts +77 -5
- 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 -4
- package/dist/types/core/owner.d.ts +5 -3
- package/dist/types/core/scheduler.d.ts +59 -34
- package/dist/types/core/truth.d.ts +16 -0
- package/dist/types/core/types.d.ts +21 -6
- 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/affects.d.ts +11 -0
- package/dist/types/store/edges.d.ts +9 -0
- package/dist/types/store/hooks.d.ts +48 -0
- package/dist/types/store/index.d.ts +10 -4
- 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 +4 -39
- package/dist/types/store/target.d.ts +16 -8
- package/dist/types/store/types.d.ts +14 -0
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@ import { CONFIG_OVERRIDE, CONFIG_AUTO_DISPOSE, NOT_PENDING } from "../core/const
|
|
|
2
2
|
|
|
3
3
|
import { computed, ext, untrack, read, isEqual } from "../core/core.js";
|
|
4
4
|
|
|
5
|
-
import { pendingGuessOf,
|
|
5
|
+
import { pendingGuessOf, optimisticWrite } from "../core/lanes.js";
|
|
6
6
|
|
|
7
7
|
import { getOwner } from "../core/owner.js";
|
|
8
8
|
|
|
@@ -10,12 +10,16 @@ import { GlobalQueue, txOf, list, insertSubs, laneDirty, notifyEpoch, schedule }
|
|
|
10
10
|
|
|
11
11
|
import { runProjectionComputed } from "./projection.js";
|
|
12
12
|
|
|
13
|
-
import { wrap, storeSetter, LaneView, committed, getNode, unwrapValue, sameKey,
|
|
13
|
+
import { wrap, storeSetter, LaneView, committed, getNode, unwrapValue, sameKey, resolveChainedRaw, getHasNode, targetsEqual, getContainerNode, cloneRaw } from "./store.js";
|
|
14
|
+
|
|
15
|
+
import { installOptHooks } from "./hooks.js";
|
|
14
16
|
|
|
15
17
|
import { $OWNER } from "./target.js";
|
|
16
18
|
|
|
17
19
|
import { $TARGET, markRawIngest, $TRACK, isWrappable } from "./types.js";
|
|
18
20
|
|
|
21
|
+
import { laneValueOf } from "../core/truth.js";
|
|
22
|
+
|
|
19
23
|
/**
|
|
20
24
|
* Store — optimistic stores on lanes (plan sec. 31, S4; INTERNALS §3/§7, RUL-3).
|
|
21
25
|
*
|
|
@@ -79,7 +83,7 @@ function notifyOptimisticWrites(e, n) {
|
|
|
79
83
|
// inner store's truth for its key before guessing over it.
|
|
80
84
|
const o = e.ch ? e.v : null;
|
|
81
85
|
const guess = (e, n, i, r) => {
|
|
82
|
-
if (o !== null) e.
|
|
86
|
+
if (o !== null) e.Ie = i ? n in t : unwrapValue(t[n]);
|
|
83
87
|
// By value: a function leaf is a value, not an updater (#3017).
|
|
84
88
|
optimisticWrite(e, () => r);
|
|
85
89
|
};
|
|
@@ -89,17 +93,17 @@ function notifyOptimisticWrites(e, n) {
|
|
|
89
93
|
// A chained draft holds the inner store's raws; a raw is the inner slot it
|
|
90
94
|
// resolves to (as a read of it serves) — the row a held write staged is
|
|
91
95
|
// the same row, not a guess over the slot (#3796).
|
|
92
|
-
const
|
|
93
|
-
const
|
|
96
|
+
const a = n[t];
|
|
97
|
+
const f = unwrapValue(o && a ? resolveChainedRaw(e, t, a) : a);
|
|
94
98
|
if (!(t in i)) {
|
|
95
|
-
guess(getNode(e, t), t, false,
|
|
99
|
+
guess(getNode(e, t), t, false, f);
|
|
96
100
|
guess(getHasNode(e, t), t, true, true);
|
|
97
101
|
s = true;
|
|
98
102
|
} else {
|
|
99
103
|
const n = i[t];
|
|
100
|
-
const
|
|
101
|
-
if (!isEqual(
|
|
102
|
-
guess(getNode(e, t), t, false,
|
|
104
|
+
const a = unwrapValue(o && n ? resolveChainedRaw(e, t, n) : n);
|
|
105
|
+
if (!isEqual(a, f) && !targetsEqual(a, f)) {
|
|
106
|
+
guess(getNode(e, t), t, false, f);
|
|
103
107
|
if (r) s = true;
|
|
104
108
|
}
|
|
105
109
|
}
|
|
@@ -120,16 +124,16 @@ function notifyOptimisticWrites(e, n) {
|
|
|
120
124
|
// The rows the setter removed from the view it saw, by key: a later
|
|
121
125
|
// re-base over another action's truth must not bring them back.
|
|
122
126
|
let s = null;
|
|
123
|
-
const
|
|
124
|
-
if (r &&
|
|
127
|
+
const a = e.fam.key;
|
|
128
|
+
if (r && a !== null && a !== undefined) {
|
|
125
129
|
const e = new Set;
|
|
126
130
|
for (let n = 0; n < o.length; n++) {
|
|
127
|
-
const t = isWrappable(o[n]) ?
|
|
131
|
+
const t = isWrappable(o[n]) ? a(o[n]) : undefined;
|
|
128
132
|
if (t !== undefined) e.add(t);
|
|
129
133
|
}
|
|
130
134
|
for (let n = 0; n < i.length; n++) {
|
|
131
135
|
const t = unwrapValue(i[n]);
|
|
132
|
-
const r = isWrappable(t) ?
|
|
136
|
+
const r = isWrappable(t) ? a(t) : undefined;
|
|
133
137
|
if (r !== undefined && !e.has(r)) (s ??= new Set).add(r);
|
|
134
138
|
}
|
|
135
139
|
}
|
|
@@ -137,10 +141,10 @@ function notifyOptimisticWrites(e, n) {
|
|
|
137
141
|
}
|
|
138
142
|
if (e.dk !== null) optimisticWrite(e.dk, {});
|
|
139
143
|
markOverlaid(e);
|
|
140
|
-
const
|
|
141
|
-
if (
|
|
144
|
+
const a = optStaged.get(e);
|
|
145
|
+
if (a === undefined) return null;
|
|
142
146
|
optStaged.delete(e);
|
|
143
|
-
return
|
|
147
|
+
return a;
|
|
144
148
|
}
|
|
145
149
|
|
|
146
150
|
/** The container comparator's lane arm (store.ts `containerEquals`): an
|
|
@@ -157,9 +161,40 @@ function rowSame(e, n, t) {
|
|
|
157
161
|
if (t === null || !isWrappable(e) || !isWrappable(n)) return false;
|
|
158
162
|
const i = t(unwrapValue(e));
|
|
159
163
|
const r = t(unwrapValue(n));
|
|
164
|
+
// Keyless rows are identified by position — reconcile's fallback when the
|
|
165
|
+
// key is missing. The caller already paired these by index, so two keyless
|
|
166
|
+
// rows are the same row and the landing confirms the arrangement instead of
|
|
167
|
+
// dissolving it. Dissolving held an external echo under the action, and a
|
|
168
|
+
// mainline `until` then timed out on a source that already contained it
|
|
169
|
+
// (#3898). Keyed rows still match only on the key.
|
|
170
|
+
if (i === undefined && r === undefined) return true;
|
|
160
171
|
return i !== undefined && sameKey(i, r);
|
|
161
172
|
}
|
|
162
173
|
|
|
174
|
+
/** Whether reconcile would write anything into `a` from `b`: wrappable
|
|
175
|
+
* pairs descend, leaves compare as its writes do. A key mismatch is a
|
|
176
|
+
* replacement, which a content difference already says. Plain data — the
|
|
177
|
+
* server's echo of a guessed row is a new object with the same contents. */ function echoes(e, n) {
|
|
178
|
+
if (e === n) return true;
|
|
179
|
+
if (!isWrappable(e) || !isWrappable(n)) return false;
|
|
180
|
+
e = unwrapValue(e);
|
|
181
|
+
n = unwrapValue(n);
|
|
182
|
+
const t = Object.keys(e);
|
|
183
|
+
if (Array.isArray(e) !== Array.isArray(n) || t.length !== Object.keys(n).length) return false;
|
|
184
|
+
for (const i of t) if (!hasOwn.call(n, i) || !echoes(e[i], n[i])) return false;
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// A cycle (a row that references itself) is not plain data: no match, so
|
|
189
|
+
// the landing stays a correction.
|
|
190
|
+
GlobalQueue.nn = (e, n) => {
|
|
191
|
+
try {
|
|
192
|
+
return echoes(e, n);
|
|
193
|
+
} catch {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
163
198
|
function arrangementEqual(e, n, t) {
|
|
164
199
|
if (Array.isArray(e) !== Array.isArray(n)) return false;
|
|
165
200
|
if (Array.isArray(e)) {
|
|
@@ -193,18 +228,18 @@ function arrangementEqual(e, n, t) {
|
|
|
193
228
|
}
|
|
194
229
|
}
|
|
195
230
|
for (let s = 0; s < n.length; s++) {
|
|
196
|
-
const
|
|
197
|
-
let
|
|
198
|
-
if (isWrappable(
|
|
231
|
+
const a = n[s];
|
|
232
|
+
let f;
|
|
233
|
+
if (isWrappable(a)) {
|
|
199
234
|
if (o !== null) {
|
|
200
|
-
const e = t(
|
|
201
|
-
if (e !== undefined)
|
|
202
|
-
} else if (s < i && isWrappable(unwrapValue(r[s])))
|
|
235
|
+
const e = t(a);
|
|
236
|
+
if (e !== undefined) f = o.get(e);
|
|
237
|
+
} else if (s < i && isWrappable(unwrapValue(r[s]))) f = r[s];
|
|
203
238
|
}
|
|
204
|
-
if (
|
|
205
|
-
if (unwrapValue(
|
|
206
|
-
if (e[s] !==
|
|
207
|
-
} else if (unwrapValue(e[s]) !==
|
|
239
|
+
if (f !== undefined) {
|
|
240
|
+
if (unwrapValue(f) !== a) reconcileDraft(f, a, t);
|
|
241
|
+
if (e[s] !== f) e[s] = f;
|
|
242
|
+
} else if (unwrapValue(e[s]) !== a) e[s] = a;
|
|
208
243
|
}
|
|
209
244
|
if (e.length !== n.length) e.length = n.length;
|
|
210
245
|
return;
|
|
@@ -233,10 +268,10 @@ function arrangementEqual(e, n, t) {
|
|
|
233
268
|
* node is born for it as the lane's derivation), on `length` only when the
|
|
234
269
|
* committed length differs, and as the `LaneView`'s base for structural
|
|
235
270
|
* reads. Unkeyed families compose
|
|
236
|
-
* positionally — the guess stands as written (the documented residue). */ GlobalQueue.
|
|
237
|
-
const t = e.
|
|
238
|
-
if (t === undefined || e.
|
|
239
|
-
const i = e.
|
|
271
|
+
* positionally — the guess stands as written (the documented residue). */ GlobalQueue.an = (e, n) => {
|
|
272
|
+
const t = e.O;
|
|
273
|
+
if (t === undefined || e.ze !== $TRACK) return;
|
|
274
|
+
const i = e.T.v;
|
|
240
275
|
if (!(i instanceof LaneView)) return;
|
|
241
276
|
if (!Array.isArray(n) || !Array.isArray(i.rows)) {
|
|
242
277
|
i.base = n;
|
|
@@ -251,45 +286,45 @@ function arrangementEqual(e, n, t) {
|
|
|
251
286
|
if (i !== undefined && !o.has(i)) o.set(i, t);
|
|
252
287
|
}
|
|
253
288
|
const s = new Set;
|
|
254
|
-
const
|
|
255
|
-
const
|
|
256
|
-
for (let e = 0; e <
|
|
257
|
-
const n =
|
|
289
|
+
const a = [];
|
|
290
|
+
const f = i.rows;
|
|
291
|
+
for (let e = 0; e < f.length; e++) {
|
|
292
|
+
const n = f[e];
|
|
258
293
|
const t = isWrappable(n) ? r(n) : undefined;
|
|
259
294
|
const i = t !== undefined ? o.get(t) : undefined;
|
|
260
295
|
if (i !== undefined) {
|
|
261
|
-
|
|
296
|
+
a.push(i);
|
|
262
297
|
s.add(t);
|
|
263
|
-
} else
|
|
298
|
+
} else a.push(n);
|
|
264
299
|
}
|
|
265
|
-
const
|
|
300
|
+
const u = i.removed;
|
|
266
301
|
for (let e = 0; e < n.length; e++) {
|
|
267
302
|
const t = n[e];
|
|
268
303
|
const i = isWrappable(t) ? r(t) : undefined;
|
|
269
|
-
if (i !== undefined && !s.has(i) && (
|
|
304
|
+
if (i !== undefined && !s.has(i) && (u === null || !u.has(i))) a.push(t);
|
|
270
305
|
}
|
|
271
|
-
i.rows =
|
|
272
|
-
i.base =
|
|
273
|
-
const
|
|
306
|
+
i.rows = a;
|
|
307
|
+
i.base = a;
|
|
308
|
+
const l = txOf(e);
|
|
274
309
|
const c = committed(t);
|
|
275
310
|
const d = t.n;
|
|
276
|
-
for (let e = 0; e <
|
|
311
|
+
for (let e = 0; e < a.length; e++) {
|
|
277
312
|
const n = d?.[e];
|
|
278
313
|
// A slot the lane does not own shows the committed row: it becomes the
|
|
279
314
|
// lane's only where the composed row is another row (by key — the same
|
|
280
315
|
// key's new object is the same row, its target adopted it).
|
|
281
316
|
if (n === undefined) {
|
|
282
|
-
if (!sameRow(c[e],
|
|
283
|
-
} else if (!sameRow(n.
|
|
317
|
+
if (!sameRow(c[e], a[e], r)) laneSet(getNode(t, e), a[e], l);
|
|
318
|
+
} else if (!sameRow(n.l & CONFIG_OVERRIDE ? n.T.v : c[e], a[e], r)) laneSet(n, a[e], l);
|
|
284
319
|
}
|
|
285
320
|
if (d !== null) {
|
|
286
|
-
for (let e =
|
|
321
|
+
for (let e = a.length; ;e++) {
|
|
287
322
|
const n = d[e];
|
|
288
323
|
if (n === undefined) break;
|
|
289
|
-
laneSet(n, undefined,
|
|
324
|
+
laneSet(n, undefined, l);
|
|
290
325
|
}
|
|
291
326
|
const e = d.length;
|
|
292
|
-
if (e !== undefined && (e.
|
|
327
|
+
if (e !== undefined && (e.l & CONFIG_OVERRIDE || c.length !== a.length)) laneSet(e, a.length, l);
|
|
293
328
|
}
|
|
294
329
|
};
|
|
295
330
|
|
|
@@ -304,12 +339,12 @@ function sameRow(e, n, t) {
|
|
|
304
339
|
* node that was not the lane's becomes its derivation (its committed value
|
|
305
340
|
* untouched beneath; the lane's end commits the latest). */ function laneSet(e, n, t) {
|
|
306
341
|
const i = ext(e);
|
|
307
|
-
if (!(e.
|
|
308
|
-
e.
|
|
342
|
+
if (!(e.l & CONFIG_OVERRIDE)) {
|
|
343
|
+
e.l |= CONFIG_OVERRIDE;
|
|
309
344
|
list(e, t);
|
|
310
|
-
} else if (i.
|
|
311
|
-
i.
|
|
312
|
-
if (e.
|
|
345
|
+
} else if (i.v === n) return;
|
|
346
|
+
i.v = n;
|
|
347
|
+
if (e.o !== null) {
|
|
313
348
|
insertSubs(e);
|
|
314
349
|
laneDirty(e, t);
|
|
315
350
|
}
|
|
@@ -354,7 +389,7 @@ function sweepOverlaid() {
|
|
|
354
389
|
// The container shows its backing again (a shown arrangement guess
|
|
355
390
|
// that ended without a landing left its `LaneView` as the value).
|
|
356
391
|
const t = e.k;
|
|
357
|
-
if (t !== null && t.
|
|
392
|
+
if (t !== null && t.Ie instanceof LaneView) t.Ie = t.Ie.base;
|
|
358
393
|
}
|
|
359
394
|
if (n.size === 0) overlaidFamilies.delete(e);
|
|
360
395
|
}
|
|
@@ -371,11 +406,11 @@ function sweepOverlaid() {
|
|
|
371
406
|
if (i !== null) for (const e of Reflect.ownKeys(i)) {
|
|
372
407
|
const r = i[e];
|
|
373
408
|
const o = untrack(() => unwrapValue(n[e]));
|
|
374
|
-
if (r.
|
|
375
|
-
r.
|
|
409
|
+
if (r.xe && r.xe(r.Ie, o)) continue;
|
|
410
|
+
r.Ie = o;
|
|
376
411
|
// (The lane's end notified it this epoch when the shown value and the
|
|
377
412
|
// covered one differed — its readers re-derive already.)
|
|
378
|
-
if (r.
|
|
413
|
+
if (r.o !== null && r.Me !== notifyEpoch) {
|
|
379
414
|
insertSubs(r);
|
|
380
415
|
t = true;
|
|
381
416
|
}
|
|
@@ -384,9 +419,9 @@ function sweepOverlaid() {
|
|
|
384
419
|
if (r !== null) for (const e of Reflect.ownKeys(r)) {
|
|
385
420
|
const i = r[e];
|
|
386
421
|
const o = untrack(() => e in n);
|
|
387
|
-
if (i.
|
|
388
|
-
i.
|
|
389
|
-
if (i.
|
|
422
|
+
if (i.Ie === o) continue;
|
|
423
|
+
i.Ie = o;
|
|
424
|
+
if (i.o !== null && i.Me !== notifyEpoch) {
|
|
390
425
|
insertSubs(i);
|
|
391
426
|
t = true;
|
|
392
427
|
}
|
|
@@ -394,9 +429,9 @@ function sweepOverlaid() {
|
|
|
394
429
|
// The arrangement the readers saw (the shown guess) against the inner's
|
|
395
430
|
// now: a structural reader re-derives when they differ.
|
|
396
431
|
const o = e.k;
|
|
397
|
-
if (o !== null && o.
|
|
432
|
+
if (o !== null && o.o !== null && o.Ie instanceof LaneView && o.Me !== notifyEpoch) {
|
|
398
433
|
const i = Array.isArray(n) ? untrack(() => n.map(unwrapValue)) : n;
|
|
399
|
-
if (!arrangementEqual(o.
|
|
434
|
+
if (!arrangementEqual(o.Ie.rows, i, e.fam?.key ?? null)) {
|
|
400
435
|
insertSubs(o);
|
|
401
436
|
t = true;
|
|
402
437
|
}
|
|
@@ -405,12 +440,12 @@ function sweepOverlaid() {
|
|
|
405
440
|
}
|
|
406
441
|
|
|
407
442
|
function carriesLane(e) {
|
|
408
|
-
if (e.k !== null && e.k.
|
|
409
|
-
if (e.dk !== null && e.dk.
|
|
443
|
+
if (e.k !== null && e.k.l & CONFIG_OVERRIDE) return true;
|
|
444
|
+
if (e.dk !== null && e.dk.l & CONFIG_OVERRIDE) return true;
|
|
410
445
|
const n = e.n;
|
|
411
|
-
if (n !== null) for (const e of Reflect.ownKeys(n)) if (n[e].
|
|
446
|
+
if (n !== null) for (const e of Reflect.ownKeys(n)) if (n[e].l & CONFIG_OVERRIDE) return true;
|
|
412
447
|
const t = e.h;
|
|
413
|
-
if (t !== null) for (const e of Reflect.ownKeys(t)) if (t[e].
|
|
448
|
+
if (t !== null) for (const e of Reflect.ownKeys(t)) if (t[e].l & CONFIG_OVERRIDE) return true;
|
|
414
449
|
return false;
|
|
415
450
|
}
|
|
416
451
|
|
|
@@ -428,9 +463,9 @@ function overlaid(e) {
|
|
|
428
463
|
* the backing answers. */ function optimisticHas(e, n) {
|
|
429
464
|
if (!overlaid(e)) return undefined;
|
|
430
465
|
const t = e.h?.[n];
|
|
431
|
-
if (t !== undefined && t.
|
|
466
|
+
if (t !== undefined && t.l & CONFIG_OVERRIDE) return !!shown(t);
|
|
432
467
|
const i = e.n?.[n];
|
|
433
|
-
if (i !== undefined && i.
|
|
468
|
+
if (i !== undefined && i.l & CONFIG_OVERRIDE) return shown(i) !== undefined;
|
|
434
469
|
return undefined;
|
|
435
470
|
}
|
|
436
471
|
|
|
@@ -441,7 +476,7 @@ function overlaid(e) {
|
|
|
441
476
|
if (t === undefined) return undefined;
|
|
442
477
|
if (!t) return null;
|
|
443
478
|
const i = e.n?.[n];
|
|
444
|
-
const r = i !== undefined && i.
|
|
479
|
+
const r = i !== undefined && i.l & CONFIG_OVERRIDE ? shown(i) : e.v[n];
|
|
445
480
|
// An array's `length` is reported as the array has it (non-configurable).
|
|
446
481
|
if (n === "length" && Array.isArray(e.v)) return {
|
|
447
482
|
value: r,
|
|
@@ -474,7 +509,7 @@ i = false) {
|
|
|
474
509
|
for (const e of Reflect.ownKeys(o)) {
|
|
475
510
|
const r = o[e];
|
|
476
511
|
let s;
|
|
477
|
-
if (r.
|
|
512
|
+
if (r.l & CONFIG_OVERRIDE) s = t(r); else if (!i || (s = pendingGuessOf(r)) === NOT_PENDING) continue;
|
|
478
513
|
if (e === "length" && Array.isArray(n)) {
|
|
479
514
|
if (n.length !== s) ensure().length = s;
|
|
480
515
|
} else if (!isEqual(n[e], s) || !hasOwn.call(n, e)) {
|
|
@@ -486,11 +521,11 @@ i = false) {
|
|
|
486
521
|
if (s !== null) {
|
|
487
522
|
for (const e of Reflect.ownKeys(s)) {
|
|
488
523
|
const o = s[e];
|
|
489
|
-
let
|
|
490
|
-
if (o.
|
|
491
|
-
const
|
|
492
|
-
const
|
|
493
|
-
if (!
|
|
524
|
+
let a;
|
|
525
|
+
if (o.l & CONFIG_OVERRIDE) a = t(o); else if (!i || (a = pendingGuessOf(o)) === NOT_PENDING) continue;
|
|
526
|
+
const f = !!a;
|
|
527
|
+
const u = r ?? n;
|
|
528
|
+
if (!f && e in u) delete ensure()[e];
|
|
494
529
|
}
|
|
495
530
|
}
|
|
496
531
|
return r ?? n;
|
|
@@ -499,9 +534,11 @@ i = false) {
|
|
|
499
534
|
function createOptimisticStore(e, n, t) {
|
|
500
535
|
const i = typeof e === "function";
|
|
501
536
|
const r = i ? t : n;
|
|
502
|
-
|
|
537
|
+
// Seedless derived form: the root starts as an empty record (see
|
|
538
|
+
// createProjectionInternal).
|
|
539
|
+
const o = i ? n || {} : e;
|
|
503
540
|
const s = r?.key === undefined ? "id" : r.key;
|
|
504
|
-
const
|
|
541
|
+
const a = {
|
|
505
542
|
map: new WeakMap,
|
|
506
543
|
node: null,
|
|
507
544
|
live: new Set,
|
|
@@ -509,9 +546,9 @@ function createOptimisticStore(e, n, t) {
|
|
|
509
546
|
opt: true,
|
|
510
547
|
key: typeof s === "function" ? s : s === null ? null : e => isWrappable(e) ? e[s] : undefined
|
|
511
548
|
};
|
|
512
|
-
const
|
|
513
|
-
if (
|
|
514
|
-
|
|
549
|
+
const f = wrap(o, null, null, a);
|
|
550
|
+
if (a.shallow) {
|
|
551
|
+
f[$TARGET].s = true;
|
|
515
552
|
markRawIngest(o);
|
|
516
553
|
}
|
|
517
554
|
if (i) {
|
|
@@ -521,13 +558,13 @@ function createOptimisticStore(e, n, t) {
|
|
|
521
558
|
loadingValue: undefined
|
|
522
559
|
};
|
|
523
560
|
const i = computed(() => {
|
|
524
|
-
if (!
|
|
525
|
-
runProjectionComputed(
|
|
561
|
+
if (!a.node) a.node = getOwner();
|
|
562
|
+
runProjectionComputed(f, n, s);
|
|
526
563
|
}, t);
|
|
527
|
-
i.
|
|
528
|
-
|
|
564
|
+
i.l &= ~CONFIG_AUTO_DISPOSE;
|
|
565
|
+
a.node = i;
|
|
529
566
|
}
|
|
530
|
-
return [
|
|
567
|
+
return [ f, e => storeSetter(f, e) ];
|
|
531
568
|
}
|
|
532
569
|
|
|
533
570
|
export { createOptimisticStore, notifyOptimisticWrites, optimisticHas, optimisticOwnDescriptor, optimisticView, sweepOverlaid };
|
|
@@ -10,7 +10,7 @@ import { enqueueSub } from "../core/heap.js";
|
|
|
10
10
|
|
|
11
11
|
import { getOwner, isDisposed } from "../core/owner.js";
|
|
12
12
|
|
|
13
|
-
import { question, setQuestion, schedule } from "../core/scheduler.js";
|
|
13
|
+
import { question, setQuestion, insertSubs, schedule } from "../core/scheduler.js";
|
|
14
14
|
|
|
15
15
|
import { reconcileState } from "./reconcile.js";
|
|
16
16
|
|
|
@@ -18,7 +18,7 @@ import { wrap, storeSetter, runDirect } from "./store.js";
|
|
|
18
18
|
|
|
19
19
|
import { setLookup } from "./target.js";
|
|
20
20
|
|
|
21
|
-
import { $TARGET, markRawIngest, setWriteOverride } from "./types.js";
|
|
21
|
+
import { $TARGET, markRawIngest, isWrappable, setWriteOverride } from "./types.js";
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Store — projections (plan sec. 31, S3; INTERNALS §7/§7b).
|
|
@@ -122,7 +122,7 @@ function cloneState(e, t) {
|
|
|
122
122
|
const r = e.node;
|
|
123
123
|
e.woke = true;
|
|
124
124
|
forEachFamilyNode(e, e => {
|
|
125
|
-
if (e.
|
|
125
|
+
if (e.o === null) return;
|
|
126
126
|
// The leaf carries the derive's pending as a propagated copy, as a memo
|
|
127
127
|
// between them would: a dependent recovering one branch stays pending
|
|
128
128
|
// through a leaf it still reads (core `retryReaches`), and the landing's
|
|
@@ -139,7 +139,7 @@ function cloneState(e, t) {
|
|
|
139
139
|
/** The derive's flight rejected: every live reader of the family
|
|
140
140
|
* re-derives (its pull throws the derive's error). */ function errorFamily(e) {
|
|
141
141
|
forEachFamilyNode(e, e => {
|
|
142
|
-
if (e.
|
|
142
|
+
if (e.o === null) return;
|
|
143
143
|
forEachDependent(e, e => {
|
|
144
144
|
enqueueSub(e);
|
|
145
145
|
});
|
|
@@ -154,7 +154,7 @@ function cloneState(e, t) {
|
|
|
154
154
|
e.woke = false;
|
|
155
155
|
const t = e.node;
|
|
156
156
|
forEachFamilyNode(e, e => {
|
|
157
|
-
if (e.
|
|
157
|
+
if (e.o !== null) settlePendingSource(e, t);
|
|
158
158
|
});
|
|
159
159
|
}
|
|
160
160
|
|
|
@@ -183,16 +183,16 @@ function forEachFamilyNode(e, t) {
|
|
|
183
183
|
// for the whole first flight — the derive works a detached shadow of the
|
|
184
184
|
// seed so draft writes cannot tear through to readers (#2988). Every
|
|
185
185
|
// commit point reconciles the shadow through the normal commit path.
|
|
186
|
-
const a = i.
|
|
186
|
+
const a = i.ce ? cloneState(s.v, s.s) : null;
|
|
187
187
|
// The question a write of this run answers: inside a slice, the slice's
|
|
188
188
|
// (the sync pass); in a continuation — the flight still registered — the
|
|
189
189
|
// flight's (`handleAsync` stamped it with the action that asked).
|
|
190
|
-
const asking = () => question || (i.
|
|
190
|
+
const asking = () => question || (i.T !== null && i.T.Se !== null ? i.T.Ee : 0);
|
|
191
191
|
const f = wrapDraft(e, () => c.run === u && !isDisposed(i), o, s.s,
|
|
192
192
|
// A write after the run returned (a continuation, a callback) arms the
|
|
193
193
|
// drain itself when no landing will.
|
|
194
194
|
() => {
|
|
195
|
-
if (!(i.
|
|
195
|
+
if (!(i.m & STATUS_PENDING) && !i.ce) schedule();
|
|
196
196
|
}, asking);
|
|
197
197
|
// The creation run commits directly (a memo's first value is its
|
|
198
198
|
// `_value`); every later run — a re-derive in a flush, an async landing
|
|
@@ -219,7 +219,12 @@ function forEachFamilyNode(e, t) {
|
|
|
219
219
|
}
|
|
220
220
|
// A landing (not the sync pass's own commit): the readers held
|
|
221
221
|
// pending on the derive settle.
|
|
222
|
-
if (!d || !(i.
|
|
222
|
+
if (!d || !(i.m & STATUS_UNINITIALIZED)) settleFamily(c);
|
|
223
|
+
// A commit is the derive's change for the readers that observed its
|
|
224
|
+
// flight (linked by `pullFamily`; a settled pull does not link), as
|
|
225
|
+
// a memo's landing is for its readers: one that caught the NotReady
|
|
226
|
+
// (a fallback value, not pending) re-runs too (#4070).
|
|
227
|
+
insertSubs(i);
|
|
223
228
|
};
|
|
224
229
|
const u = handleAsync(i, l, commit, (e, t) => {
|
|
225
230
|
// The flight rejected: the leaves' readers learn it from here —
|
|
@@ -228,10 +233,10 @@ function forEachFamilyNode(e, t) {
|
|
|
228
233
|
// reader re-derives and meets the error at its pull (memo parity,
|
|
229
234
|
// #2897) — and the flush that runs them advances the clock, so a
|
|
230
235
|
// later tracked re-read may retry (core `read`).
|
|
231
|
-
if (d && i.
|
|
236
|
+
if (d && i.m & STATUS_UNINITIALIZED) return;
|
|
232
237
|
if (t) wakeFamily(c, e); else errorFamily(c);
|
|
233
238
|
});
|
|
234
|
-
if (!i.
|
|
239
|
+
if (!i.ce) commit(u);
|
|
235
240
|
}, false);
|
|
236
241
|
try {
|
|
237
242
|
d ? runDirect(pass) : pass();
|
|
@@ -239,51 +244,58 @@ function forEachFamilyNode(e, t) {
|
|
|
239
244
|
// A flight went up (NotReady out of the pass — the derive's own, with
|
|
240
245
|
// the derive as its source): the leaves' readers learn it from here —
|
|
241
246
|
// they do not subscribe to the derive.
|
|
242
|
-
|
|
247
|
+
// A synchronous error the same way (#3956: a rerun that finds the
|
|
248
|
+
// entry failed throws): every live reader re-derives and meets it.
|
|
249
|
+
if (!d) e instanceof NotReadyError ? wakeFamily(c, e) : errorFamily(c);
|
|
243
250
|
throw e;
|
|
244
251
|
}
|
|
245
252
|
// A pass that returned with a flight up (an iterator's sync first yield):
|
|
246
253
|
// the wake, as for the throw. Not a sync pass that superseded one — the
|
|
247
254
|
// status it reads is the dead flight's, cleared when this pass settles
|
|
248
255
|
// (#3181: a reader the settle walk had just released, re-parked for good).
|
|
249
|
-
if (i.
|
|
256
|
+
if (i.m & STATUS_PENDING && i.T.Se !== null && !i.ce && !d) wakeFamily(c, i.T?.F);
|
|
250
257
|
return i;
|
|
251
258
|
}
|
|
252
259
|
|
|
253
260
|
function createProjectionInternal(e, t, r) {
|
|
254
|
-
|
|
261
|
+
// Seedless (`fn` takes no draft): the root starts as an empty record. It is
|
|
262
|
+
// a draft like any seed, never observable before the first landing (A25).
|
|
263
|
+
t ||= {};
|
|
264
|
+
const n = r?.key === undefined ? "id" : r.key;
|
|
265
|
+
const o = {
|
|
255
266
|
map: new WeakMap,
|
|
256
267
|
node: null,
|
|
257
268
|
live: new Set,
|
|
258
|
-
shallow: !!r?.shallow
|
|
269
|
+
shallow: !!r?.shallow,
|
|
270
|
+
// The row key, for a child paired after the adoption (store.ts
|
|
271
|
+
// `adoptChild`, #3712) as the adoption pairs them.
|
|
272
|
+
key: typeof n === "function" ? n : n === null ? null : e => isWrappable(e) ? e[n] : undefined
|
|
259
273
|
};
|
|
260
|
-
const
|
|
261
|
-
if (
|
|
262
|
-
|
|
274
|
+
const i = wrap(t, null, null, o);
|
|
275
|
+
if (o.shallow) {
|
|
276
|
+
i[$TARGET].s = true;
|
|
263
277
|
markRawIngest(t);
|
|
264
278
|
}
|
|
265
|
-
let
|
|
266
|
-
if (r?.seedLoadingValue)
|
|
279
|
+
let s;
|
|
280
|
+
if (r?.seedLoadingValue) s = {
|
|
267
281
|
loadingValue: undefined
|
|
268
282
|
};
|
|
269
|
-
const
|
|
270
|
-
if (!
|
|
271
|
-
runProjectionComputed(
|
|
272
|
-
},
|
|
273
|
-
|
|
274
|
-
|
|
283
|
+
const c = computed(() => {
|
|
284
|
+
if (!o.node) o.node = getOwner();
|
|
285
|
+
runProjectionComputed(i, e, n);
|
|
286
|
+
}, s);
|
|
287
|
+
c.l &= ~CONFIG_AUTO_DISPOSE;
|
|
288
|
+
o.node = c;
|
|
289
|
+
// The derive's leaves are not its dependents: a mark's repoll
|
|
290
|
+
// (affects-marks.ts) reaches their readers through this.
|
|
291
|
+
c.fam = o;
|
|
275
292
|
return {
|
|
276
|
-
store:
|
|
277
|
-
node:
|
|
293
|
+
store: i,
|
|
294
|
+
node: c
|
|
278
295
|
};
|
|
279
296
|
}
|
|
280
297
|
|
|
281
|
-
|
|
282
|
-
* A derived store: `fn` runs in a computed and writes its draft; readers of
|
|
283
|
-
* the store's keys re-run only when the keys they read change (the
|
|
284
|
-
* firewall). `fn` may be async or an async iterator; the seed is a draft,
|
|
285
|
-
* never an observable value, until the first landing (A25).
|
|
286
|
-
*/ function createProjection(e, t, r) {
|
|
298
|
+
function createProjection(e, t, r) {
|
|
287
299
|
return createProjectionInternal(e, t, r).store;
|
|
288
300
|
}
|
|
289
301
|
|