@solidjs/signals 2.0.0-beta.25 → 2.0.0-beta.27
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 +370 -73
- package/dist/node.cjs +1247 -946
- package/dist/prod/core/action.js +11 -6
- package/dist/prod/core/async.js +212 -108
- package/dist/prod/core/core.js +203 -189
- package/dist/prod/core/effect.js +28 -28
- package/dist/prod/core/external.js +3 -3
- package/dist/prod/core/graph.js +28 -28
- package/dist/prod/core/heap.js +30 -30
- package/dist/prod/core/lanes.js +15 -15
- package/dist/prod/core/optimistic.js +39 -39
- package/dist/prod/core/owner.js +44 -44
- package/dist/prod/core/scheduler.js +127 -106
- package/dist/prod/core/verdict.js +54 -54
- package/dist/prod/map.js +60 -60
- package/dist/prod/signals.js +1 -1
- package/dist/prod/store/optimistic.js +55 -36
- package/dist/prod/store/projection.js +38 -33
- package/dist/prod/store/reconcile.js +299 -243
- package/dist/prod/store/store.js +127 -50
- package/dist/types/core/async.d.ts +2 -0
- package/dist/types/core/scheduler.d.ts +1 -0
- package/dist/types/store/optimistic.d.ts +2 -2
- package/dist/types/store/projection.d.ts +7 -2
- package/dist/types/store/reconcile.d.ts +14 -0
- package/dist/types/store/store.d.ts +2 -2
- package/dist/types-cjs/core/async.d.cts +2 -0
- package/dist/types-cjs/core/scheduler.d.cts +1 -0
- package/dist/types-cjs/store/optimistic.d.cts +2 -2
- package/dist/types-cjs/store/projection.d.cts +7 -2
- package/dist/types-cjs/store/reconcile.d.cts +14 -0
- package/dist/types-cjs/store/store.d.cts +2 -2
- 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_SHALLOW, STORE_OVERRIDE, STORE_OPTIMISTIC_OVERRIDE, STORE_VALUE, STORE_LOOKUP, $PROXY, storeLookup, markRawIngest, STORE_NODE, $TRACK, STORE_HAS, notifySelf, isWrappable, wrap, rawValuesUsed, STORE_DESC, symbolKeyedRecords, $DELETED,
|
|
11
|
+
import { $TARGET, STORE_SHALLOW, STORE_OVERRIDE, STORE_OPTIMISTIC_OVERRIDE, STORE_VALUE, STORE_LOOKUP, $PROXY, storeLookup, markRawIngest, STORE_NODE, $TRACK, STORE_HAS, notifySelf, isWrappable, wrap, rawValuesUsed, isRawValue, STORE_DESC, symbolKeyedRecords, $DELETED, getKeys, getStoreSymbols, STORE_WRAP, lookupTarget } 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
|
|
@@ -18,7 +18,7 @@ function nodeKeys(e) {
|
|
|
18
18
|
const t = Object.keys(e);
|
|
19
19
|
if (symbolKeyedRecords.has(e)) {
|
|
20
20
|
const n = Object.getOwnPropertySymbols(e);
|
|
21
|
-
for (let e = 0,
|
|
21
|
+
for (let e = 0, r = n.length; e < r; e++) {
|
|
22
22
|
if (n[e] !== $TRACK) t.push(n[e]);
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -32,57 +32,57 @@ function unwrap(e) {
|
|
|
32
32
|
return e[$TARGET]?.[STORE_VALUE] ?? e;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
function getOverrideValue(e, t, n,
|
|
36
|
-
if (
|
|
35
|
+
function getOverrideValue(e, t, n, r) {
|
|
36
|
+
if (r && n in r) return r[n];
|
|
37
37
|
return t && n in t ? t[n] : e[n];
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
// Append `o`'s *enumerable* own symbol keys from a pre-fetched symbol list.
|
|
41
41
|
function addEnumSymbols(e, t, n) {
|
|
42
|
-
for (let
|
|
43
|
-
if (Object.prototype.propertyIsEnumerable.call(e, t[
|
|
42
|
+
for (let r = 0, a = t.length; r < a; r++) {
|
|
43
|
+
if (Object.prototype.propertyIsEnumerable.call(e, t[r])) n.add(t[r]);
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
function getAllKeys(e, t, n) {
|
|
48
48
|
// Symbols are merged explicitly below; keep the common string-key path on
|
|
49
49
|
// Object.keys() and avoid reflecting the base symbols twice.
|
|
50
|
-
const
|
|
51
|
-
const
|
|
50
|
+
const r = getKeys(e, t);
|
|
51
|
+
const a = Object.keys(n);
|
|
52
52
|
// `value` can be a wrapped store (store-in-store) whose ownKeys trap tracks;
|
|
53
53
|
// mirror `getKeys` and enumerate its symbols untracked in that case.
|
|
54
54
|
const i = e[$TARGET] ? untrack(() => Object.getOwnPropertySymbols(e)) : Object.getOwnPropertySymbols(e);
|
|
55
|
-
const
|
|
55
|
+
const l = Object.getOwnPropertySymbols(n);
|
|
56
56
|
// Symbol-free diff (the overwhelmingly common case) stays on the exact
|
|
57
57
|
// pre-#2851 path, including the identical-key-sets fast path from #2756.
|
|
58
|
-
if (i.length === 0 &&
|
|
59
|
-
if (
|
|
58
|
+
if (i.length === 0 && l.length === 0) {
|
|
59
|
+
if (r.length === a.length) {
|
|
60
60
|
let e = true;
|
|
61
|
-
for (let t = 0; t <
|
|
62
|
-
if (
|
|
61
|
+
for (let t = 0; t < r.length; t++) {
|
|
62
|
+
if (r[t] !== a[t]) {
|
|
63
63
|
e = false;
|
|
64
64
|
break;
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
-
if (e) return
|
|
67
|
+
if (e) return r;
|
|
68
68
|
}
|
|
69
|
-
const e = new Set(
|
|
70
|
-
for (let t = 0; t <
|
|
69
|
+
const e = new Set(r);
|
|
70
|
+
for (let t = 0; t < a.length; t++) e.add(a[t]);
|
|
71
71
|
return Array.from(e);
|
|
72
72
|
}
|
|
73
73
|
// Symbol-aware diff (#2851): base symbols join the set, then override
|
|
74
74
|
// adds/deletes are re-applied so a `$DELETED` symbol stays deleted, then
|
|
75
75
|
// `next`'s keys (a key present in next is never deleted by the diff).
|
|
76
|
-
const
|
|
77
|
-
addEnumSymbols(e, i,
|
|
76
|
+
const s = new Set(r);
|
|
77
|
+
addEnumSymbols(e, i, s);
|
|
78
78
|
if (t) {
|
|
79
79
|
for (const e of Reflect.ownKeys(t)) {
|
|
80
|
-
t[e] === $DELETED ?
|
|
80
|
+
t[e] === $DELETED ? s.delete(e) : s.add(e);
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
-
for (let e = 0; e <
|
|
84
|
-
addEnumSymbols(n,
|
|
85
|
-
return Array.from(
|
|
83
|
+
for (let e = 0; e < a.length; e++) s.add(a[e]);
|
|
84
|
+
addEnumSymbols(n, l, s);
|
|
85
|
+
return Array.from(s);
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
// Array entries can be `null`/`undefined`/primitives, not just keyed objects.
|
|
@@ -100,6 +100,17 @@ function keyedMatch(e, t, n) {
|
|
|
100
100
|
return e === t || isWrappable(e) && isWrappable(t) && n(e) === n(t);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
// A pair of array slots may only be merged into when both sides are real store
|
|
104
|
+
// children of the SAME container kind. An array and an object are different
|
|
105
|
+
// shapes, and merging one into the other leaves the slot's proxy permanently
|
|
106
|
+
// mismatched with its value (an array target holding an object, so
|
|
107
|
+
// `Array.isArray`/spread/`map` lie). The object diff has always applied this
|
|
108
|
+
// rule; the array paths reach the same recursion through `keyedMatch` /
|
|
109
|
+
// positional pairing, where two keyless wrappables "match" regardless of kind.
|
|
110
|
+
function recursablePair(e, t) {
|
|
111
|
+
return isWrappable(e) && isWrappable(t) && !(rawValuesUsed && (isRawValue(e) || isRawValue(t))) && Array.isArray(e) === Array.isArray(t);
|
|
112
|
+
}
|
|
113
|
+
|
|
103
114
|
// Array reconciliation updates the slots it visits, then swaps STORE_VALUE.
|
|
104
115
|
// Previously tracked keys that are absent from `next` still need invalidating,
|
|
105
116
|
// and `in` dependencies should follow the new value's membership. Use
|
|
@@ -114,8 +125,8 @@ function syncArrayNodeMembership(e, t) {
|
|
|
114
125
|
if (n) {
|
|
115
126
|
if (symbolKeyedRecords.has(n)) {
|
|
116
127
|
const e = nodeKeys(n);
|
|
117
|
-
for (let
|
|
118
|
-
e[
|
|
128
|
+
for (let r = 0, a = e.length; r < a; r++) {
|
|
129
|
+
e[r] in t || setSignal(n[e[r]], undefined);
|
|
119
130
|
}
|
|
120
131
|
} else {
|
|
121
132
|
for (const e in n) {
|
|
@@ -126,8 +137,8 @@ function syncArrayNodeMembership(e, t) {
|
|
|
126
137
|
if (n = e[STORE_HAS]) {
|
|
127
138
|
if (symbolKeyedRecords.has(n)) {
|
|
128
139
|
const e = nodeKeys(n);
|
|
129
|
-
for (let
|
|
130
|
-
setSignal(n[e[
|
|
140
|
+
for (let r = 0, a = e.length; r < a; r++) {
|
|
141
|
+
setSignal(n[e[r]], e[r] in t);
|
|
131
142
|
}
|
|
132
143
|
} else {
|
|
133
144
|
for (const e in n) {
|
|
@@ -146,31 +157,31 @@ function syncArrayNodeMembership(e, t) {
|
|
|
146
157
|
// and drops the wrap()/$PROXY/$TARGET round-trip per visited child.
|
|
147
158
|
// Wrap-family stores (projections/optimistic) own child proxy creation and
|
|
148
159
|
// keep the proxy-based recursion.
|
|
149
|
-
function applyStateChild(e, t, n,
|
|
160
|
+
function applyStateChild(e, t, n, r) {
|
|
150
161
|
if (n[STORE_WRAP] !== undefined) {
|
|
151
|
-
applyState(e, wrap(t, n),
|
|
162
|
+
applyState(e, wrap(t, n), r);
|
|
152
163
|
return;
|
|
153
164
|
}
|
|
154
|
-
const
|
|
155
|
-
if (
|
|
165
|
+
const a = t[$TARGET] ?? storeLookup.get(t);
|
|
166
|
+
if (a === undefined) return;
|
|
156
167
|
e = unwrap(e);
|
|
157
|
-
if (
|
|
158
|
-
applyStateShallow(e,
|
|
159
|
-
} else if (
|
|
160
|
-
applyStateSlow(e,
|
|
168
|
+
if (a[STORE_SHALLOW]) {
|
|
169
|
+
applyStateShallow(e, a);
|
|
170
|
+
} else if (a[STORE_OVERRIDE] || a[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
171
|
+
applyStateSlow(e, a, r);
|
|
161
172
|
} else {
|
|
162
|
-
applyStateFast(e,
|
|
173
|
+
applyStateFast(e, a, r);
|
|
163
174
|
}
|
|
164
175
|
}
|
|
165
176
|
|
|
166
177
|
// Reconcile a single array slot: recurse into a wrappable pair, otherwise replace
|
|
167
178
|
// the node's value outright (covers object→primitive and primitive→object).
|
|
168
|
-
function applyArrayItem(e, t, n,
|
|
169
|
-
if (
|
|
179
|
+
function applyArrayItem(e, t, n, r, a) {
|
|
180
|
+
if (recursablePair(t, e)) {
|
|
170
181
|
const i = wrap(t, n);
|
|
171
|
-
|
|
172
|
-
applyState(e, i,
|
|
173
|
-
} else
|
|
182
|
+
r && setSignal(r, i);
|
|
183
|
+
applyState(e, i, a);
|
|
184
|
+
} else r && setSignal(r, wrapValue(e, n));
|
|
174
185
|
}
|
|
175
186
|
|
|
176
187
|
/**
|
|
@@ -184,17 +195,17 @@ function applyArrayItem(e, t, n, a, r) {
|
|
|
184
195
|
* and stay pruned exactly as before; keys the main loop already visited
|
|
185
196
|
* (node present) are skipped. Callers gate on the parent's own flag and on
|
|
186
197
|
* `$TRACK` absence (an enumeration-tracked record already diffs every key).
|
|
187
|
-
*/ function applyDescendants(e, t, n,
|
|
188
|
-
const
|
|
198
|
+
*/ function applyDescendants(e, t, n, r, a, i, l) {
|
|
199
|
+
const s = n[STORE_LOOKUP] || storeLookup;
|
|
189
200
|
if (i) {
|
|
190
201
|
const n = getKeys(e, i).concat(getStoreSymbols(e, i));
|
|
191
202
|
for (let o = 0, f = n.length; o < f; o++) {
|
|
192
203
|
const f = n[o];
|
|
193
|
-
if (
|
|
204
|
+
if (r?.[f]) continue;
|
|
194
205
|
// main loop already diffed this slot
|
|
195
|
-
const
|
|
196
|
-
if (!isWrappable(
|
|
197
|
-
descendInto(
|
|
206
|
+
const u = unwrap(getOverrideValue(e, i, f, l));
|
|
207
|
+
if (!isWrappable(u)) continue;
|
|
208
|
+
descendInto(u, t[f], s, a);
|
|
198
209
|
}
|
|
199
210
|
return;
|
|
200
211
|
}
|
|
@@ -203,34 +214,34 @@ function applyArrayItem(e, t, n, a, r) {
|
|
|
203
214
|
// bails (noded key, primitive value) stay inline — only genuine descent
|
|
204
215
|
// candidates pay a call.
|
|
205
216
|
for (const n in e) {
|
|
206
|
-
if (
|
|
217
|
+
if (r?.[n]) continue;
|
|
207
218
|
// main loop already diffed this slot
|
|
208
219
|
const i = unwrap(e[n]);
|
|
209
220
|
if (!isWrappable(i)) continue;
|
|
210
|
-
descendInto(i, t[n],
|
|
221
|
+
descendInto(i, t[n], s, a);
|
|
211
222
|
}
|
|
212
223
|
const o = Object.getOwnPropertySymbols(e);
|
|
213
224
|
for (let n = 0, i = o.length; n < i; n++) {
|
|
214
225
|
if (Object.prototype.propertyIsEnumerable.call(e, o[n])) {
|
|
215
|
-
if (
|
|
226
|
+
if (r?.[o[n]]) continue;
|
|
216
227
|
const i = unwrap(e[o[n]]);
|
|
217
228
|
if (!isWrappable(i)) continue;
|
|
218
|
-
descendInto(i, t[o[n]],
|
|
229
|
+
descendInto(i, t[o[n]], s, a);
|
|
219
230
|
}
|
|
220
231
|
}
|
|
221
232
|
}
|
|
222
233
|
|
|
223
|
-
function descendInto(e, t, n,
|
|
224
|
-
const
|
|
225
|
-
if (!
|
|
234
|
+
function descendInto(e, t, n, r) {
|
|
235
|
+
const a = lookupTarget(e, n);
|
|
236
|
+
if (!a?.[STORE_DESC]) return;
|
|
226
237
|
const i = unwrap(t);
|
|
227
|
-
if (e === i || !isWrappable(i) || Array.isArray(e) !== Array.isArray(i) ||
|
|
228
|
-
if (
|
|
229
|
-
applyStateShallow(i,
|
|
230
|
-
} else if (
|
|
231
|
-
applyStateSlow(i,
|
|
238
|
+
if (e === i || !isWrappable(i) || Array.isArray(e) !== Array.isArray(i) || r(e) != null && r(e) !== r(i)) return;
|
|
239
|
+
if (a[STORE_SHALLOW]) {
|
|
240
|
+
applyStateShallow(i, a);
|
|
241
|
+
} else if (a[STORE_OVERRIDE] || a[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
242
|
+
applyStateSlow(i, a, r);
|
|
232
243
|
} else {
|
|
233
|
-
applyStateFast(i,
|
|
244
|
+
applyStateFast(i, a, r);
|
|
234
245
|
}
|
|
235
246
|
}
|
|
236
247
|
|
|
@@ -243,14 +254,14 @@ function applyState(e, t, n) {
|
|
|
243
254
|
// Array items and root calls can pass a store proxy as `next`; normalize to
|
|
244
255
|
// its raw value or the swap would set a store's STORE_VALUE to its own proxy.
|
|
245
256
|
e = unwrap(e);
|
|
246
|
-
const
|
|
247
|
-
if (!
|
|
248
|
-
if (
|
|
249
|
-
applyStateShallow(e,
|
|
250
|
-
} else if (
|
|
251
|
-
applyStateSlow(e,
|
|
257
|
+
const r = t?.[$TARGET];
|
|
258
|
+
if (!r) return;
|
|
259
|
+
if (r[STORE_SHALLOW]) {
|
|
260
|
+
applyStateShallow(e, r);
|
|
261
|
+
} else if (r[STORE_OVERRIDE] || r[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
262
|
+
applyStateSlow(e, r, n);
|
|
252
263
|
} else {
|
|
253
|
-
applyStateFast(e,
|
|
264
|
+
applyStateFast(e, r, n);
|
|
254
265
|
}
|
|
255
266
|
}
|
|
256
267
|
|
|
@@ -262,50 +273,50 @@ function applyState(e, t, n) {
|
|
|
262
273
|
// One pass over a shallow target's node record: replace changed slots with
|
|
263
274
|
// raw next values, null out slots absent from next. Returns whether anything
|
|
264
275
|
// differed.
|
|
265
|
-
function shallowDiffNodes(e, t, n,
|
|
266
|
-
let
|
|
276
|
+
function shallowDiffNodes(e, t, n, r) {
|
|
277
|
+
let a = false;
|
|
267
278
|
for (const i in e) {
|
|
268
|
-
if (
|
|
279
|
+
if (r && i === "length") continue;
|
|
269
280
|
if (i in t) {
|
|
270
|
-
const
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
setSignal(e[i],
|
|
281
|
+
const r = t[i];
|
|
282
|
+
if (r !== n(i)) {
|
|
283
|
+
a = true;
|
|
284
|
+
setSignal(e[i], r);
|
|
274
285
|
}
|
|
275
286
|
} else {
|
|
276
|
-
|
|
287
|
+
a = true;
|
|
277
288
|
setSignal(e[i], undefined);
|
|
278
289
|
}
|
|
279
290
|
}
|
|
280
|
-
return
|
|
291
|
+
return a;
|
|
281
292
|
}
|
|
282
293
|
|
|
283
294
|
function applyStateShallow(e, t, n) {
|
|
284
|
-
const
|
|
285
|
-
const
|
|
295
|
+
const r = t[STORE_VALUE];
|
|
296
|
+
const a = t[STORE_OVERRIDE];
|
|
286
297
|
const i = t[STORE_OPTIMISTIC_OVERRIDE];
|
|
287
|
-
if (e ===
|
|
298
|
+
if (e === r && !a && !i) return;
|
|
288
299
|
// Setter-staged writes fold into the diff: previous values resolve through
|
|
289
300
|
// the override layers (so a replaced slot compares against what readers
|
|
290
301
|
// saw), and the regular override clears with the swap — reconcile makes
|
|
291
302
|
// `next` the authoritative base, same as the deep slow path.
|
|
292
303
|
const prevAt = e => {
|
|
293
|
-
const t = getOverrideValue(
|
|
304
|
+
const t = getOverrideValue(r, a, e, i);
|
|
294
305
|
return t === $DELETED ? undefined : t;
|
|
295
306
|
};
|
|
296
307
|
t[STORE_OVERRIDE] = undefined;
|
|
297
|
-
const
|
|
298
|
-
|
|
308
|
+
const l = t[STORE_LOOKUP];
|
|
309
|
+
l !== undefined ? l.set(e, t[$PROXY]) : storeLookup.set(e, t);
|
|
299
310
|
t[STORE_VALUE] = e;
|
|
300
311
|
markRawIngest(e);
|
|
301
|
-
const
|
|
302
|
-
const o =
|
|
312
|
+
const s = t[STORE_NODE];
|
|
313
|
+
const o = s && s[$TRACK];
|
|
303
314
|
let f = false;
|
|
304
|
-
if (Array.isArray(
|
|
305
|
-
const n =
|
|
306
|
-
if (
|
|
307
|
-
f = shallowDiffNodes(
|
|
308
|
-
if (
|
|
315
|
+
if (Array.isArray(r)) {
|
|
316
|
+
const n = a?.length ?? i?.length ?? r.length;
|
|
317
|
+
if (s) {
|
|
318
|
+
f = shallowDiffNodes(s, e, prevAt, true);
|
|
319
|
+
if (s.length && n !== e.length) setSignal(s.length, e.length);
|
|
309
320
|
}
|
|
310
321
|
if (!f && (o || t[STORE_HAS])) {
|
|
311
322
|
// Slots without nodes still feed $TRACK enumerators / `in` probes.
|
|
@@ -319,24 +330,24 @@ function applyStateShallow(e, t, n) {
|
|
|
319
330
|
}
|
|
320
331
|
}
|
|
321
332
|
} else {
|
|
322
|
-
if (
|
|
323
|
-
f = shallowDiffNodes(
|
|
333
|
+
if (s) {
|
|
334
|
+
f = shallowDiffNodes(s, e, prevAt, false);
|
|
324
335
|
}
|
|
325
336
|
if (!f && (o || t[STORE_HAS])) f = true;
|
|
326
337
|
}
|
|
327
|
-
let
|
|
328
|
-
if (
|
|
329
|
-
for (const t in
|
|
330
|
-
setSignal(
|
|
338
|
+
let u = t[STORE_HAS];
|
|
339
|
+
if (u) {
|
|
340
|
+
for (const t in u) {
|
|
341
|
+
setSignal(u[t], t in e);
|
|
331
342
|
}
|
|
332
343
|
}
|
|
333
344
|
f && notifySelf(t);
|
|
334
345
|
}
|
|
335
346
|
|
|
336
347
|
function applyStateFast(e, t, n) {
|
|
337
|
-
const
|
|
338
|
-
if (e ===
|
|
339
|
-
const
|
|
348
|
+
const r = t[STORE_VALUE];
|
|
349
|
+
if (e === r) return;
|
|
350
|
+
const a = t[STORE_NODE];
|
|
340
351
|
// swap
|
|
341
352
|
{
|
|
342
353
|
const n = t[STORE_LOOKUP];
|
|
@@ -344,20 +355,20 @@ function applyStateFast(e, t, n) {
|
|
|
344
355
|
}
|
|
345
356
|
t[STORE_VALUE] = e;
|
|
346
357
|
// merge
|
|
347
|
-
if (Array.isArray(
|
|
358
|
+
if (Array.isArray(r)) {
|
|
348
359
|
let i = false;
|
|
349
|
-
const
|
|
350
|
-
if (e.length &&
|
|
351
|
-
let
|
|
352
|
-
for (f = 0,
|
|
360
|
+
const l = r.length;
|
|
361
|
+
if (e.length && l && isWrappable(e[0]) && n(e[0]) != null) {
|
|
362
|
+
let s, o, f, u, p, c, S, E;
|
|
363
|
+
for (f = 0, u = Math.min(l, e.length); f < u && keyedMatch(c = r[f], e[f], n); f++) {
|
|
353
364
|
// keyedMatch established both sides wrappable unless they're the
|
|
354
365
|
// SAME reference — and an identical slot is a guaranteed no-op
|
|
355
366
|
// (the child's STORE_VALUE tracks the previous graph), so skip
|
|
356
367
|
// the recursion dispatch entirely. Raw-marked values are leaves:
|
|
357
368
|
// replace the slot node instead of recursing.
|
|
358
369
|
if (c !== e[f]) {
|
|
359
|
-
if (
|
|
360
|
-
|
|
370
|
+
if (!recursablePair(c, e[f])) {
|
|
371
|
+
a?.[f] && setSignal(a[f], wrapValue(e[f], t));
|
|
361
372
|
} else applyStateChild(e[f], c, t, n);
|
|
362
373
|
}
|
|
363
374
|
}
|
|
@@ -365,129 +376,129 @@ function applyStateFast(e, t, n) {
|
|
|
365
376
|
// of a polling tick): membership, length, and order are unchanged —
|
|
366
377
|
// nothing below could do observable work, so skip the staging
|
|
367
378
|
// allocations and membership sync outright.
|
|
368
|
-
if (f === e.length && f ===
|
|
369
|
-
const
|
|
370
|
-
for (
|
|
371
|
-
|
|
372
|
-
|
|
379
|
+
if (f === e.length && f === l) return;
|
|
380
|
+
const O = new Array(e.length), R = new Map;
|
|
381
|
+
for (u = l - 1, p = e.length - 1; u >= f && p >= f && keyedMatch(c = r[u], e[p], n); u--,
|
|
382
|
+
p--) {
|
|
383
|
+
O[p] = c;
|
|
373
384
|
}
|
|
374
|
-
if (f >
|
|
375
|
-
for (o = f; o <=
|
|
385
|
+
if (f > p || f > u) {
|
|
386
|
+
for (o = f; o <= p; o++) {
|
|
376
387
|
i = true;
|
|
377
|
-
|
|
388
|
+
a?.[o] && setSignal(a[o], wrapValue(e[o], t));
|
|
378
389
|
}
|
|
379
390
|
for (;o < e.length; o++) {
|
|
380
391
|
i = true;
|
|
381
|
-
applyArrayItem(e[o],
|
|
392
|
+
applyArrayItem(e[o], O[o], t, a?.[o], n);
|
|
382
393
|
}
|
|
383
394
|
syncArrayNodeMembership(t, e);
|
|
384
|
-
(i ||
|
|
385
|
-
|
|
395
|
+
(i || l !== e.length) && notifySelf(t);
|
|
396
|
+
l !== e.length && a?.length && setSignal(a.length, e.length);
|
|
386
397
|
return;
|
|
387
398
|
}
|
|
388
|
-
S = new Array(
|
|
389
|
-
for (o =
|
|
399
|
+
S = new Array(p + 1);
|
|
400
|
+
for (o = p; o >= f; o--) {
|
|
390
401
|
c = e[o];
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
S[o] =
|
|
394
|
-
|
|
402
|
+
E = itemKey(c, n);
|
|
403
|
+
s = R.get(E);
|
|
404
|
+
S[o] = s === undefined ? -1 : s;
|
|
405
|
+
R.set(E, o);
|
|
395
406
|
}
|
|
396
|
-
for (
|
|
397
|
-
c =
|
|
398
|
-
|
|
399
|
-
o =
|
|
407
|
+
for (s = f; s <= u; s++) {
|
|
408
|
+
c = r[s];
|
|
409
|
+
E = itemKey(c, n);
|
|
410
|
+
o = R.get(E);
|
|
400
411
|
if (o !== undefined && o !== -1) {
|
|
401
|
-
|
|
412
|
+
O[o] = c;
|
|
402
413
|
o = S[o];
|
|
403
|
-
|
|
414
|
+
R.set(E, o);
|
|
404
415
|
}
|
|
405
416
|
}
|
|
406
417
|
for (o = f; o < e.length; o++) {
|
|
407
|
-
if (o in
|
|
408
|
-
applyArrayItem(e[o],
|
|
409
|
-
} else
|
|
418
|
+
if (o in O) {
|
|
419
|
+
applyArrayItem(e[o], O[o], t, a?.[o], n);
|
|
420
|
+
} else a?.[o] && setSignal(a[o], wrapValue(e[o], t));
|
|
410
421
|
}
|
|
411
422
|
if (f < e.length) i = true;
|
|
412
423
|
} else if (e.length) {
|
|
413
|
-
for (let
|
|
414
|
-
const
|
|
415
|
-
if (
|
|
416
|
-
if (
|
|
424
|
+
for (let l = 0, s = e.length; l < s; l++) {
|
|
425
|
+
const s = r[l];
|
|
426
|
+
if (recursablePair(s, e[l])) {
|
|
427
|
+
if (s !== e[l]) applyStateChild(e[l], s, t, n);
|
|
417
428
|
} else {
|
|
418
|
-
if (
|
|
419
|
-
|
|
429
|
+
if (s !== e[l]) i = true;
|
|
430
|
+
a?.[l] && setSignal(a[l], wrapValue(e[l], t));
|
|
420
431
|
}
|
|
421
432
|
}
|
|
422
433
|
}
|
|
423
434
|
syncArrayNodeMembership(t, e);
|
|
424
|
-
if (
|
|
435
|
+
if (l !== e.length) {
|
|
425
436
|
i = true;
|
|
426
|
-
|
|
437
|
+
a?.length && setSignal(a.length, e.length);
|
|
427
438
|
}
|
|
428
439
|
i && notifySelf(t);
|
|
429
440
|
return;
|
|
430
441
|
}
|
|
431
442
|
// values
|
|
432
443
|
let i = t[STORE_NODE];
|
|
433
|
-
let
|
|
444
|
+
let l;
|
|
434
445
|
if (i) {
|
|
435
|
-
|
|
446
|
+
l = i[$TRACK];
|
|
436
447
|
// The per-key body is duplicated across both loops on purpose: this is
|
|
437
448
|
// the hottest object-diff site and a shared helper costs a per-key call
|
|
438
449
|
// in instruction counts (CodSpeed regressed ~7% on deep-tree reconciles
|
|
439
450
|
// with the extracted form).
|
|
440
|
-
if (
|
|
441
|
-
const
|
|
442
|
-
for (let
|
|
443
|
-
const o =
|
|
451
|
+
if (l || symbolKeyedRecords.has(i)) {
|
|
452
|
+
const a = l ? getAllKeys(r, undefined, e) : nodeKeys(i);
|
|
453
|
+
for (let s = 0, o = a.length; s < o; s++) {
|
|
454
|
+
const o = a[s];
|
|
444
455
|
const f = i[o];
|
|
445
|
-
const
|
|
446
|
-
const
|
|
447
|
-
if (
|
|
448
|
-
if (!
|
|
456
|
+
const u = unwrap(r[o]);
|
|
457
|
+
const p = unwrap(e[o]);
|
|
458
|
+
if (u === p) continue;
|
|
459
|
+
if (!u || !isWrappable(u) || !isWrappable(p) ||
|
|
449
460
|
// Raw-marked values are leaves replaced by reference — a "wrappable
|
|
450
461
|
// pair" is only recursable when both sides are actual store children.
|
|
451
|
-
rawValuesUsed && (isRawValue(
|
|
452
|
-
|
|
453
|
-
f && setSignal(f, isWrappable(
|
|
454
|
-
} else applyStateChild(
|
|
462
|
+
rawValuesUsed && (isRawValue(u) || isRawValue(p)) || Array.isArray(u) !== Array.isArray(p) || n(u) != null && n(u) !== n(p)) {
|
|
463
|
+
l && setSignal(l, void 0);
|
|
464
|
+
f && setSignal(f, isWrappable(p) ? wrap(p, t) : p);
|
|
465
|
+
} else applyStateChild(p, u, t, n);
|
|
455
466
|
}
|
|
456
467
|
} else {
|
|
457
468
|
// Untracked, string-only node records (the overwhelmingly common case)
|
|
458
469
|
// iterate in place — nodeKeys() allocated a fresh key array per object
|
|
459
470
|
// per pass, which dominates allocation on large-graph reconciles.
|
|
460
|
-
for (const
|
|
461
|
-
const
|
|
462
|
-
const o = unwrap(a
|
|
463
|
-
const f = unwrap(e[
|
|
471
|
+
for (const a in i) {
|
|
472
|
+
const s = i[a];
|
|
473
|
+
const o = unwrap(r[a]);
|
|
474
|
+
const f = unwrap(e[a]);
|
|
464
475
|
if (o === f) continue;
|
|
465
476
|
if (!o || !isWrappable(o) || !isWrappable(f) ||
|
|
466
477
|
// Raw-marked values are leaves replaced by reference — a "wrappable
|
|
467
478
|
// pair" is only recursable when both sides are actual store children.
|
|
468
479
|
rawValuesUsed && (isRawValue(o) || isRawValue(f)) || Array.isArray(o) !== Array.isArray(f) || n(o) != null && n(o) !== n(f)) {
|
|
469
|
-
|
|
470
|
-
|
|
480
|
+
l && setSignal(l, void 0);
|
|
481
|
+
s && setSignal(s, isWrappable(f) ? wrap(f, t) : f);
|
|
471
482
|
} else applyStateChild(f, o, t, n);
|
|
472
483
|
}
|
|
473
484
|
}
|
|
474
485
|
}
|
|
475
|
-
if (!
|
|
486
|
+
if (!l && t[STORE_DESC]) applyDescendants(r, e, t, i, n);
|
|
476
487
|
// has
|
|
477
488
|
if (i = t[STORE_HAS]) {
|
|
478
489
|
const t = nodeKeys(i);
|
|
479
|
-
for (let n = 0,
|
|
480
|
-
const
|
|
481
|
-
setSignal(i[
|
|
490
|
+
for (let n = 0, r = t.length; n < r; n++) {
|
|
491
|
+
const r = t[n];
|
|
492
|
+
setSignal(i[r], r in e);
|
|
482
493
|
}
|
|
483
494
|
}
|
|
484
495
|
}
|
|
485
496
|
|
|
486
497
|
function applyStateSlow(e, t, n) {
|
|
487
|
-
const
|
|
488
|
-
const
|
|
498
|
+
const r = t[STORE_VALUE];
|
|
499
|
+
const a = t[STORE_OVERRIDE];
|
|
489
500
|
const i = t[STORE_OPTIMISTIC_OVERRIDE];
|
|
490
|
-
let
|
|
501
|
+
let l = t[STORE_NODE];
|
|
491
502
|
// swap
|
|
492
503
|
{
|
|
493
504
|
const n = t[STORE_LOOKUP];
|
|
@@ -496,106 +507,106 @@ function applyStateSlow(e, t, n) {
|
|
|
496
507
|
t[STORE_VALUE] = e;
|
|
497
508
|
t[STORE_OVERRIDE] = undefined;
|
|
498
509
|
// merge
|
|
499
|
-
if (Array.isArray(
|
|
500
|
-
let
|
|
501
|
-
const o = getOverrideValue(
|
|
510
|
+
if (Array.isArray(r)) {
|
|
511
|
+
let s = false;
|
|
512
|
+
const o = getOverrideValue(r, a, "length", i);
|
|
502
513
|
if (e.length && o && isWrappable(e[0]) && n(e[0]) != null) {
|
|
503
|
-
let f,
|
|
504
|
-
for (
|
|
505
|
-
if (
|
|
506
|
-
if (
|
|
507
|
-
|
|
508
|
-
} else applyState(e[
|
|
514
|
+
let f, u, p, c, S, E, O, R;
|
|
515
|
+
for (p = 0, c = Math.min(o, e.length); p < c && keyedMatch(E = getOverrideValue(r, a, p, i), e[p], n); p++) {
|
|
516
|
+
if (E !== e[p] && isWrappable(E) && isWrappable(e[p])) {
|
|
517
|
+
if (!recursablePair(E, e[p])) {
|
|
518
|
+
l?.[p] && setSignal(l[p], wrapValue(e[p], t));
|
|
519
|
+
} else applyState(e[p], wrap(E, t), n);
|
|
509
520
|
}
|
|
510
521
|
}
|
|
511
|
-
const
|
|
512
|
-
for (c = o - 1, S = e.length - 1; c >=
|
|
522
|
+
const d = new Array(e.length), y = new Map;
|
|
523
|
+
for (c = o - 1, S = e.length - 1; c >= p && S >= p && keyedMatch(E = getOverrideValue(r, a, c, i), e[S], n); c--,
|
|
513
524
|
S--) {
|
|
514
|
-
|
|
525
|
+
d[S] = E;
|
|
515
526
|
}
|
|
516
|
-
if (
|
|
517
|
-
for (
|
|
518
|
-
|
|
519
|
-
|
|
527
|
+
if (p > S || p > c) {
|
|
528
|
+
for (u = p; u <= S; u++) {
|
|
529
|
+
s = true;
|
|
530
|
+
l?.[u] && setSignal(l[u], wrapValue(e[u], t));
|
|
520
531
|
}
|
|
521
|
-
for (;
|
|
522
|
-
|
|
523
|
-
applyArrayItem(e[
|
|
532
|
+
for (;u < e.length; u++) {
|
|
533
|
+
s = true;
|
|
534
|
+
applyArrayItem(e[u], d[u], t, l?.[u], n);
|
|
524
535
|
}
|
|
525
|
-
const
|
|
536
|
+
const r = e.length;
|
|
526
537
|
syncArrayNodeMembership(t, e);
|
|
527
|
-
(
|
|
528
|
-
o !==
|
|
538
|
+
(s || o !== r) && notifySelf(t);
|
|
539
|
+
o !== r && l?.length && setSignal(l.length, r);
|
|
529
540
|
return;
|
|
530
541
|
}
|
|
531
|
-
|
|
532
|
-
for (
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
f =
|
|
536
|
-
|
|
537
|
-
|
|
542
|
+
O = new Array(S + 1);
|
|
543
|
+
for (u = S; u >= p; u--) {
|
|
544
|
+
E = e[u];
|
|
545
|
+
R = itemKey(E, n);
|
|
546
|
+
f = y.get(R);
|
|
547
|
+
O[u] = f === undefined ? -1 : f;
|
|
548
|
+
y.set(R, u);
|
|
538
549
|
}
|
|
539
|
-
for (f =
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
if (
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
550
|
+
for (f = p; f <= c; f++) {
|
|
551
|
+
E = getOverrideValue(r, a, f, i);
|
|
552
|
+
R = itemKey(E, n);
|
|
553
|
+
u = y.get(R);
|
|
554
|
+
if (u !== undefined && u !== -1) {
|
|
555
|
+
d[u] = E;
|
|
556
|
+
u = O[u];
|
|
557
|
+
y.set(R, u);
|
|
547
558
|
}
|
|
548
559
|
}
|
|
549
|
-
for (
|
|
550
|
-
if (
|
|
551
|
-
applyArrayItem(e[
|
|
552
|
-
} else
|
|
560
|
+
for (u = p; u < e.length; u++) {
|
|
561
|
+
if (u in d) {
|
|
562
|
+
applyArrayItem(e[u], d[u], t, l?.[u], n);
|
|
563
|
+
} else l?.[u] && setSignal(l[u], wrapValue(e[u], t));
|
|
553
564
|
}
|
|
554
|
-
if (
|
|
565
|
+
if (p < e.length) s = true;
|
|
555
566
|
} else if (e.length) {
|
|
556
567
|
for (let o = 0, f = e.length; o < f; o++) {
|
|
557
|
-
const f = getOverrideValue(
|
|
558
|
-
if (
|
|
568
|
+
const f = getOverrideValue(r, a, o, i);
|
|
569
|
+
if (recursablePair(f, e[o])) {
|
|
559
570
|
if (f !== e[o]) applyState(e[o], wrap(f, t), n);
|
|
560
571
|
} else {
|
|
561
|
-
if (f !== e[o])
|
|
562
|
-
|
|
572
|
+
if (f !== e[o]) s = true;
|
|
573
|
+
l?.[o] && setSignal(l[o], wrapValue(e[o], t));
|
|
563
574
|
}
|
|
564
575
|
}
|
|
565
576
|
}
|
|
566
577
|
const f = e.length;
|
|
567
578
|
syncArrayNodeMembership(t, e);
|
|
568
579
|
if (o !== f) {
|
|
569
|
-
|
|
570
|
-
|
|
580
|
+
s = true;
|
|
581
|
+
l?.length && setSignal(l.length, f);
|
|
571
582
|
}
|
|
572
|
-
|
|
583
|
+
s && notifySelf(t);
|
|
573
584
|
return;
|
|
574
585
|
}
|
|
575
586
|
// values
|
|
576
|
-
let
|
|
577
|
-
if (
|
|
578
|
-
|
|
579
|
-
const o =
|
|
580
|
-
for (let f = 0,
|
|
581
|
-
const
|
|
582
|
-
const
|
|
583
|
-
const c = unwrap(getOverrideValue(
|
|
584
|
-
let S = unwrap(e[
|
|
587
|
+
let s;
|
|
588
|
+
if (l) {
|
|
589
|
+
s = l[$TRACK];
|
|
590
|
+
const o = s ? getAllKeys(r, a, e) : nodeKeys(l);
|
|
591
|
+
for (let f = 0, u = o.length; f < u; f++) {
|
|
592
|
+
const u = o[f];
|
|
593
|
+
const p = l[u];
|
|
594
|
+
const c = unwrap(getOverrideValue(r, a, u, i));
|
|
595
|
+
let S = unwrap(e[u]);
|
|
585
596
|
if (c === S) continue;
|
|
586
597
|
if (!c || !isWrappable(c) || !isWrappable(S) || rawValuesUsed && (isRawValue(c) || isRawValue(S)) || Array.isArray(c) !== Array.isArray(S) || n(c) != null && n(c) !== n(S)) {
|
|
587
|
-
|
|
588
|
-
|
|
598
|
+
s && setSignal(s, void 0);
|
|
599
|
+
p && setSignal(p, isWrappable(S) ? wrap(S, t) : S);
|
|
589
600
|
} else applyState(S, wrap(c, t), n);
|
|
590
601
|
}
|
|
591
602
|
}
|
|
592
|
-
if (!
|
|
603
|
+
if (!s && t[STORE_DESC]) applyDescendants(r, e, t, l, n, a, i);
|
|
593
604
|
// has
|
|
594
|
-
if (
|
|
595
|
-
const t = nodeKeys(
|
|
596
|
-
for (let n = 0,
|
|
597
|
-
const
|
|
598
|
-
setSignal(
|
|
605
|
+
if (l = t[STORE_HAS]) {
|
|
606
|
+
const t = nodeKeys(l);
|
|
607
|
+
for (let n = 0, r = t.length; n < r; n++) {
|
|
608
|
+
const r = t[n];
|
|
609
|
+
setSignal(l[r], r in e);
|
|
599
610
|
}
|
|
600
611
|
}
|
|
601
612
|
}
|
|
@@ -604,6 +615,58 @@ function applyStateSlow(e, t, n) {
|
|
|
604
615
|
// the positional branch and object descent to plain per-property merging.
|
|
605
616
|
const NOKEY = () => null;
|
|
606
617
|
|
|
618
|
+
// Identity-as-key: distinct objects never match, so every slot takes the diff's
|
|
619
|
+
// "not the same entity" branch and is replaced by reference rather than merged
|
|
620
|
+
// into. Slots holding the same raw on both sides still keep their proxy.
|
|
621
|
+
const IDENTITY = e => e;
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Shared body of `reconcile()` and the projection commit. `replace` is the
|
|
625
|
+
* only difference: a projection commit is a value swap, not a merge — its root
|
|
626
|
+
* proxy is a cell handed out by `createProjection` that can never change
|
|
627
|
+
* reference, so a derive returning a different entity is not the slot mistake
|
|
628
|
+
* `reconcile()` throws on. Nothing below the root survives that swap, which is
|
|
629
|
+
* the rule the keyed diff already applies at a nested slot on a key mismatch.
|
|
630
|
+
*
|
|
631
|
+
* @internal
|
|
632
|
+
*/ function reconcileState(e, t, n, r) {
|
|
633
|
+
if (t == null) throw new Error("");
|
|
634
|
+
// A projection commit whose derive returns a foreign store adopts it as the
|
|
635
|
+
// live backing (store-in-store chain — the same shape as a store-proxy
|
|
636
|
+
// seed): reads route through the inner store's own graph, so its updates
|
|
637
|
+
// flow with no re-derive, and a derive with no dependencies never recomputes
|
|
638
|
+
// (#2941). The diff below still runs against raw values so THIS store's
|
|
639
|
+
// existing subscribers see the swap; the live proxy is installed after.
|
|
640
|
+
// Shallow projections keep their raw-ingest contract and never chain.
|
|
641
|
+
let a;
|
|
642
|
+
const i = r ? t[$TARGET] : undefined;
|
|
643
|
+
if (i !== undefined) {
|
|
644
|
+
if (e?.[$TARGET] !== undefined && e[$TARGET] !== i && !i[STORE_SHALLOW]) {
|
|
645
|
+
if (i[STORE_VALUE] === e) return;
|
|
646
|
+
// already chained to this store
|
|
647
|
+
a = e;
|
|
648
|
+
}
|
|
649
|
+
// Re-diffing a previously chained backing goes through its raw — reads
|
|
650
|
+
// off the outgoing proxy would subscribe this computed to a store it is
|
|
651
|
+
// about to drop.
|
|
652
|
+
while (i[STORE_VALUE]?.[$TARGET] !== undefined) i[STORE_VALUE] = unwrap(i[STORE_VALUE]);
|
|
653
|
+
}
|
|
654
|
+
if (n === null) applyState(e, t, NOKEY); else {
|
|
655
|
+
let a = typeof n === "string" ? e => e[n] : n;
|
|
656
|
+
const i = a(t);
|
|
657
|
+
if (i !== undefined && a(e) !== i) {
|
|
658
|
+
if (!r) throw new Error("");
|
|
659
|
+
// Or the outgoing raw keeps resolving to this proxy and surfaces the
|
|
660
|
+
// incoming entity wherever it reappears in this family.
|
|
661
|
+
const n = t[$TARGET];
|
|
662
|
+
if (n && n[STORE_VALUE] !== unwrap(e)) n[STORE_LOOKUP]?.delete(n[STORE_VALUE]);
|
|
663
|
+
a = IDENTITY;
|
|
664
|
+
}
|
|
665
|
+
applyState(e, t, a);
|
|
666
|
+
}
|
|
667
|
+
if (a !== undefined) i[STORE_VALUE] = a;
|
|
668
|
+
}
|
|
669
|
+
|
|
607
670
|
/**
|
|
608
671
|
* Returns a draft-mutating function that smart-merges `value` into a store,
|
|
609
672
|
* preserving fine-grained reactivity: only changed leaves trigger updates.
|
|
@@ -618,6 +681,9 @@ const NOKEY = () => null;
|
|
|
618
681
|
* the classic pattern for fixed-shape data that churns in place (dashboards,
|
|
619
682
|
* monitors), where no keyed diff pass is needed or wanted.
|
|
620
683
|
*
|
|
684
|
+
* Merging into a slot that holds a *different* entity throws — the caller
|
|
685
|
+
* picked the slot, so a key mismatch there is a bug.
|
|
686
|
+
*
|
|
621
687
|
* @param value the next state to merge in
|
|
622
688
|
* @param key property name (string) or extractor function for stable
|
|
623
689
|
* identity (default `"id"`); pass `null` for positional merging
|
|
@@ -635,17 +701,7 @@ const NOKEY = () => null;
|
|
|
635
701
|
* setStats(reconcile(nextStats, null));
|
|
636
702
|
* ```
|
|
637
703
|
*/ function reconcile(e, t = "id") {
|
|
638
|
-
return n =>
|
|
639
|
-
if (n == null) throw new Error("");
|
|
640
|
-
if (t === null) {
|
|
641
|
-
applyState(e, n, NOKEY);
|
|
642
|
-
return;
|
|
643
|
-
}
|
|
644
|
-
const a = typeof t === "string" ? e => e[t] : t;
|
|
645
|
-
const r = a(n);
|
|
646
|
-
if (r !== undefined && a(e) !== r) throw new Error("");
|
|
647
|
-
applyState(e, n, a);
|
|
648
|
-
};
|
|
704
|
+
return n => reconcileState(e, n, t, false);
|
|
649
705
|
}
|
|
650
706
|
|
|
651
|
-
export { reconcile };
|
|
707
|
+
export { reconcile, reconcileState };
|