@solidjs/signals 2.0.0-beta.23 → 2.0.0-beta.24
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 +171 -65
- package/dist/node.cjs +1116 -995
- package/dist/prod/core/core.js +14 -11
- package/dist/prod/core/error.js +9 -0
- package/dist/prod/core/heap.js +12 -12
- package/dist/prod/core/scheduler.js +6 -6
- package/dist/prod/core/verdict.js +1 -1
- package/dist/prod/map.js +53 -29
- package/dist/prod/store/optimistic.js +29 -27
- package/dist/prod/store/reconcile.js +92 -61
- package/dist/prod/store/store.js +142 -102
- package/dist/prod/store/utils.js +12 -0
- package/dist/types/core/error.d.ts +1 -1
- package/dist/types/store/reconcile.d.ts +17 -8
- package/dist/types-cjs/core/error.d.cts +1 -1
- package/dist/types-cjs/store/reconcile.d.cts +17 -8
- package/package.json +1 -1
|
@@ -8,7 +8,7 @@ import "../core/verdict.js";
|
|
|
8
8
|
|
|
9
9
|
import "../core/effect.js";
|
|
10
10
|
|
|
11
|
-
import { $TARGET, STORE_OVERRIDE, STORE_OPTIMISTIC_OVERRIDE, STORE_VALUE, STORE_NODE, storeLookup, STORE_LOOKUP, $PROXY, isWrappable, wrap, notifySelf, $TRACK, STORE_DESC, STORE_HAS, getKeys, $DELETED,
|
|
11
|
+
import { $TARGET, STORE_OVERRIDE, STORE_OPTIMISTIC_OVERRIDE, STORE_VALUE, STORE_NODE, storeLookup, STORE_LOOKUP, $PROXY, isWrappable, wrap, notifySelf, $TRACK, STORE_DESC, STORE_HAS, symbolKeyedRecords, getKeys, $DELETED, getStoreSymbols } from "./store.js";
|
|
12
12
|
|
|
13
13
|
// Enumerate a node record's keys. Keeps the common string-key path on the
|
|
14
14
|
// `Object.keys` fast path; only records currently holding a user symbol node
|
|
@@ -155,9 +155,9 @@ function applyArrayItem(e, t, r, n, a) {
|
|
|
155
155
|
if (!isWrappable(c)) continue;
|
|
156
156
|
const u = (l.get(c) ?? storeLookup.get(c))?.[$TARGET];
|
|
157
157
|
if (!u?.[STORE_DESC]) continue;
|
|
158
|
-
const
|
|
159
|
-
if (c ===
|
|
160
|
-
applyState(
|
|
158
|
+
const y = unwrap(t[f]);
|
|
159
|
+
if (c === y || !isWrappable(y) || Array.isArray(c) !== Array.isArray(y) || a(c) != null && a(c) !== a(y)) continue;
|
|
160
|
+
applyState(y, wrap(c, r), a);
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
|
|
@@ -191,7 +191,7 @@ function applyStateFast(e, t, r) {
|
|
|
191
191
|
let i = false;
|
|
192
192
|
const o = n.length;
|
|
193
193
|
if (e.length && o && isWrappable(e[0]) && r(e[0]) != null) {
|
|
194
|
-
let l, s, p, f, c, u,
|
|
194
|
+
let l, s, p, f, c, u, y, S;
|
|
195
195
|
for (p = 0, f = Math.min(o, e.length); p < f && keyedMatch(u = n[p], e[p], r); p++) {
|
|
196
196
|
isWrappable(u) && isWrappable(e[p]) && applyState(e[p], wrap(u, t), r);
|
|
197
197
|
}
|
|
@@ -214,22 +214,22 @@ function applyStateFast(e, t, r) {
|
|
|
214
214
|
o !== e.length && a?.length && setSignal(a.length, e.length);
|
|
215
215
|
return;
|
|
216
216
|
}
|
|
217
|
-
|
|
217
|
+
y = new Array(c + 1);
|
|
218
218
|
for (s = c; s >= p; s--) {
|
|
219
219
|
u = e[s];
|
|
220
|
-
|
|
221
|
-
l = O.get(
|
|
222
|
-
|
|
223
|
-
O.set(
|
|
220
|
+
S = itemKey(u, r);
|
|
221
|
+
l = O.get(S);
|
|
222
|
+
y[s] = l === undefined ? -1 : l;
|
|
223
|
+
O.set(S, s);
|
|
224
224
|
}
|
|
225
225
|
for (l = p; l <= f; l++) {
|
|
226
226
|
u = n[l];
|
|
227
|
-
|
|
228
|
-
s = O.get(
|
|
227
|
+
S = itemKey(u, r);
|
|
228
|
+
s = O.get(S);
|
|
229
229
|
if (s !== undefined && s !== -1) {
|
|
230
230
|
E[s] = u;
|
|
231
|
-
s =
|
|
232
|
-
O.set(
|
|
231
|
+
s = y[s];
|
|
232
|
+
O.set(S, s);
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
235
|
for (s = p; s < e.length; s++) {
|
|
@@ -260,17 +260,18 @@ function applyStateFast(e, t, r) {
|
|
|
260
260
|
let o;
|
|
261
261
|
if (i) {
|
|
262
262
|
o = i[$TRACK];
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
263
|
+
if (o || symbolKeyedRecords.has(i)) {
|
|
264
|
+
const a = o ? getAllKeys(n, undefined, e) : nodeKeys(i);
|
|
265
|
+
for (let l = 0, s = a.length; l < s; l++) {
|
|
266
|
+
diffNodeKey(a[l], i, n, e, t, o, r);
|
|
267
|
+
}
|
|
268
|
+
} else {
|
|
269
|
+
// Untracked, string-only node records (the overwhelmingly common case)
|
|
270
|
+
// iterate in place — nodeKeys() allocated a fresh key array per object
|
|
271
|
+
// per pass, which dominates allocation on large-graph reconciles.
|
|
272
|
+
for (const a in i) {
|
|
273
|
+
diffNodeKey(a, i, n, e, t, o, r);
|
|
274
|
+
}
|
|
274
275
|
}
|
|
275
276
|
}
|
|
276
277
|
if (!o && t[STORE_DESC]) applyDescendants(n, e, t, i, r);
|
|
@@ -284,6 +285,19 @@ function applyStateFast(e, t, r) {
|
|
|
284
285
|
}
|
|
285
286
|
}
|
|
286
287
|
|
|
288
|
+
// One node-key step of the fast object diff — shared by the array-iterating
|
|
289
|
+
// (tracked / symbol-keyed) and for-in (plain) loops in applyStateFast.
|
|
290
|
+
function diffNodeKey(e, t, r, n, a, i, o) {
|
|
291
|
+
const l = t[e];
|
|
292
|
+
const s = unwrap(r[e]);
|
|
293
|
+
let p = unwrap(n[e]);
|
|
294
|
+
if (s === p) return;
|
|
295
|
+
if (!s || !isWrappable(s) || !isWrappable(p) || Array.isArray(s) !== Array.isArray(p) || o(s) != null && o(s) !== o(p)) {
|
|
296
|
+
i && setSignal(i, void 0);
|
|
297
|
+
l && setSignal(l, isWrappable(p) ? wrap(p, a) : p);
|
|
298
|
+
} else applyState(p, wrap(s, a), o);
|
|
299
|
+
}
|
|
300
|
+
|
|
287
301
|
function applyStateSlow(e, t, r) {
|
|
288
302
|
const n = t[STORE_VALUE];
|
|
289
303
|
const a = t[STORE_OVERRIDE];
|
|
@@ -298,23 +312,23 @@ function applyStateSlow(e, t, r) {
|
|
|
298
312
|
let l = false;
|
|
299
313
|
const s = getOverrideValue(n, a, "length", i);
|
|
300
314
|
if (e.length && s && isWrappable(e[0]) && r(e[0]) != null) {
|
|
301
|
-
let p, f, c, u,
|
|
302
|
-
for (c = 0, u = Math.min(s, e.length); c < u && keyedMatch(
|
|
303
|
-
isWrappable(
|
|
315
|
+
let p, f, c, u, y, S, E, O;
|
|
316
|
+
for (c = 0, u = Math.min(s, e.length); c < u && keyedMatch(S = getOverrideValue(n, a, c, i), e[c], r); c++) {
|
|
317
|
+
isWrappable(S) && isWrappable(e[c]) && applyState(e[c], wrap(S, t), r);
|
|
304
318
|
}
|
|
305
|
-
const
|
|
306
|
-
for (u = s - 1,
|
|
307
|
-
|
|
308
|
-
|
|
319
|
+
const d = new Array(e.length), R = new Map;
|
|
320
|
+
for (u = s - 1, y = e.length - 1; u >= c && y >= c && keyedMatch(S = getOverrideValue(n, a, u, i), e[y], r); u--,
|
|
321
|
+
y--) {
|
|
322
|
+
d[y] = S;
|
|
309
323
|
}
|
|
310
|
-
if (c >
|
|
311
|
-
for (f = c; f <=
|
|
324
|
+
if (c > y || c > u) {
|
|
325
|
+
for (f = c; f <= y; f++) {
|
|
312
326
|
l = true;
|
|
313
327
|
o?.[f] && setSignal(o[f], wrapValue(e[f], t));
|
|
314
328
|
}
|
|
315
329
|
for (;f < e.length; f++) {
|
|
316
330
|
l = true;
|
|
317
|
-
applyArrayItem(e[f],
|
|
331
|
+
applyArrayItem(e[f], d[f], t, o?.[f], r);
|
|
318
332
|
}
|
|
319
333
|
const n = e.length;
|
|
320
334
|
syncArrayNodeMembership(t, e);
|
|
@@ -322,27 +336,27 @@ function applyStateSlow(e, t, r) {
|
|
|
322
336
|
s !== n && o?.length && setSignal(o.length, n);
|
|
323
337
|
return;
|
|
324
338
|
}
|
|
325
|
-
E = new Array(
|
|
326
|
-
for (f =
|
|
327
|
-
|
|
328
|
-
O = itemKey(
|
|
329
|
-
p =
|
|
339
|
+
E = new Array(y + 1);
|
|
340
|
+
for (f = y; f >= c; f--) {
|
|
341
|
+
S = e[f];
|
|
342
|
+
O = itemKey(S, r);
|
|
343
|
+
p = R.get(O);
|
|
330
344
|
E[f] = p === undefined ? -1 : p;
|
|
331
|
-
|
|
345
|
+
R.set(O, f);
|
|
332
346
|
}
|
|
333
347
|
for (p = c; p <= u; p++) {
|
|
334
|
-
|
|
335
|
-
O = itemKey(
|
|
336
|
-
f =
|
|
348
|
+
S = getOverrideValue(n, a, p, i);
|
|
349
|
+
O = itemKey(S, r);
|
|
350
|
+
f = R.get(O);
|
|
337
351
|
if (f !== undefined && f !== -1) {
|
|
338
|
-
|
|
352
|
+
d[f] = S;
|
|
339
353
|
f = E[f];
|
|
340
|
-
|
|
354
|
+
R.set(O, f);
|
|
341
355
|
}
|
|
342
356
|
}
|
|
343
357
|
for (f = c; f < e.length; f++) {
|
|
344
|
-
if (f in
|
|
345
|
-
applyArrayItem(e[f],
|
|
358
|
+
if (f in d) {
|
|
359
|
+
applyArrayItem(e[f], d[f], t, o?.[f], r);
|
|
346
360
|
} else o?.[f] && setSignal(o[f], wrapValue(e[f], t));
|
|
347
361
|
}
|
|
348
362
|
if (c < e.length) l = true;
|
|
@@ -373,12 +387,12 @@ function applyStateSlow(e, t, r) {
|
|
|
373
387
|
const f = s[p];
|
|
374
388
|
const c = o[f];
|
|
375
389
|
const u = unwrap(getOverrideValue(n, a, f, i));
|
|
376
|
-
let
|
|
377
|
-
if (u ===
|
|
378
|
-
if (!u || !isWrappable(u) || !isWrappable(
|
|
390
|
+
let y = unwrap(e[f]);
|
|
391
|
+
if (u === y) continue;
|
|
392
|
+
if (!u || !isWrappable(u) || !isWrappable(y) || Array.isArray(u) !== Array.isArray(y) || r(u) != null && r(u) !== r(y)) {
|
|
379
393
|
l && setSignal(l, void 0);
|
|
380
|
-
c && setSignal(c, isWrappable(
|
|
381
|
-
} else applyState(
|
|
394
|
+
c && setSignal(c, isWrappable(y) ? wrap(y, t) : y);
|
|
395
|
+
} else applyState(y, wrap(u, t), r);
|
|
382
396
|
}
|
|
383
397
|
}
|
|
384
398
|
if (!l && t[STORE_DESC]) applyDescendants(n, e, t, o, r, a, i);
|
|
@@ -392,17 +406,27 @@ function applyStateSlow(e, t, r) {
|
|
|
392
406
|
}
|
|
393
407
|
}
|
|
394
408
|
|
|
409
|
+
// No-key reconcile: every item reports "no key", which routes array diffs to
|
|
410
|
+
// the positional branch and object descent to plain per-property merging.
|
|
411
|
+
const NOKEY = () => null;
|
|
412
|
+
|
|
395
413
|
/**
|
|
396
414
|
* Returns a draft-mutating function that smart-merges `value` into a store,
|
|
397
|
-
* preserving
|
|
398
|
-
*
|
|
399
|
-
*
|
|
415
|
+
* preserving fine-grained reactivity: only changed leaves trigger updates.
|
|
416
|
+
*
|
|
417
|
+
* With a `key` (default `"id"`), array items whose key matches between old
|
|
418
|
+
* and new states keep their identity (updated in place, moves and removals
|
|
419
|
+
* update the corresponding signals) — the shape for keyed server payloads.
|
|
420
|
+
* Items without the key field fall back to positional matching.
|
|
400
421
|
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
422
|
+
* With `key: null`, matching is purely positional: index N of the new array
|
|
423
|
+
* merges into index N of the old, and object properties merge recursively —
|
|
424
|
+
* the classic pattern for fixed-shape data that churns in place (dashboards,
|
|
425
|
+
* monitors), where no keyed diff pass is needed or wanted.
|
|
403
426
|
*
|
|
404
427
|
* @param value the next state to merge in
|
|
405
|
-
* @param key property name (string) or extractor function for stable
|
|
428
|
+
* @param key property name (string) or extractor function for stable
|
|
429
|
+
* identity (default `"id"`); pass `null` for positional merging
|
|
406
430
|
*
|
|
407
431
|
* @example
|
|
408
432
|
* ```ts
|
|
@@ -410,12 +434,19 @@ function applyStateSlow(e, t, r) {
|
|
|
410
434
|
*
|
|
411
435
|
* async function refresh() {
|
|
412
436
|
* const fresh = await api.getTodos();
|
|
413
|
-
* setTodos(reconcile(fresh
|
|
437
|
+
* setTodos(reconcile(fresh)); // diff-merge by `id`
|
|
414
438
|
* }
|
|
439
|
+
*
|
|
440
|
+
* // fixed-shape polling data — positional merge
|
|
441
|
+
* setStats(reconcile(nextStats, null));
|
|
415
442
|
* ```
|
|
416
|
-
*/ function reconcile(e, t) {
|
|
443
|
+
*/ function reconcile(e, t = "id") {
|
|
417
444
|
return r => {
|
|
418
445
|
if (r == null) throw new Error("");
|
|
446
|
+
if (t === null) {
|
|
447
|
+
applyState(e, r, NOKEY);
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
419
450
|
const n = typeof t === "string" ? e => e[t] : t;
|
|
420
451
|
const a = n(r);
|
|
421
452
|
if (a !== undefined && n(e) !== a) throw new Error("");
|