@solidjs/signals 2.0.0-rc.14 → 2.0.0-rc.15
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 +248 -189
- package/dist/dev.attribution.js +124 -41
- package/dist/dev.js +553 -322
- package/dist/observe/affects.js +34 -31
- package/dist/observe/boundaries.js +166 -132
- package/dist/observe/core/async.js +90 -83
- package/dist/observe/core/attribution-queries.js +1 -1
- package/dist/observe/core/attribution.js +281 -197
- package/dist/observe/core/constants.js +7 -2
- package/dist/observe/core/context.js +3 -3
- package/dist/observe/core/core.js +277 -245
- package/dist/observe/core/dev.js +3 -3
- package/dist/observe/core/effect.js +21 -21
- package/dist/observe/core/external.js +2 -2
- package/dist/observe/core/graph.js +25 -25
- package/dist/observe/core/heap.js +9 -9
- package/dist/observe/core/lanes.js +206 -160
- package/dist/observe/core/owner.js +27 -27
- package/dist/observe/core/scheduler.js +92 -86
- package/dist/observe/core/verdict.js +66 -54
- package/dist/observe/map.js +35 -35
- package/dist/observe/reveal.js +24 -24
- package/dist/observe/signals.js +38 -28
- package/dist/observe/store/affects.js +75 -68
- package/dist/observe/store/hooks.js +13 -0
- package/dist/observe/store/index.js +0 -2
- package/dist/observe/store/optimistic.js +67 -34
- package/dist/observe/store/projection.js +37 -31
- package/dist/observe/store/reconcile.js +32 -30
- package/dist/observe/store/store.js +128 -85
- package/dist/prod/affects.js +34 -31
- package/dist/prod/boundaries.js +143 -109
- package/dist/prod/core/async.js +64 -67
- package/dist/prod/core/constants.js +7 -2
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +302 -270
- package/dist/prod/core/effect.js +38 -38
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +27 -27
- package/dist/prod/core/heap.js +30 -30
- package/dist/prod/core/lanes.js +257 -211
- package/dist/prod/core/owner.js +39 -39
- package/dist/prod/core/scheduler.js +125 -119
- package/dist/prod/core/verdict.js +70 -58
- package/dist/prod/map.js +73 -73
- package/dist/prod/reveal.js +38 -38
- package/dist/prod/signals.js +30 -20
- package/dist/prod/store/affects.js +75 -68
- package/dist/prod/store/hooks.js +13 -0
- package/dist/prod/store/index.js +0 -2
- package/dist/prod/store/optimistic.js +114 -81
- package/dist/prod/store/projection.js +30 -24
- package/dist/prod/store/reconcile.js +32 -30
- package/dist/prod/store/store.js +136 -93
- package/dist/types/boundaries.d.ts +4 -0
- package/dist/types/core/attribution.d.ts +6 -2
- package/dist/types/core/constants.d.ts +5 -0
- package/dist/types/core/core.d.ts +33 -3
- package/dist/types/core/lanes.d.ts +10 -0
- package/dist/types/core/scheduler.d.ts +12 -6
- package/dist/types/core/types.d.ts +0 -6
- package/dist/types/store/affects.d.ts +11 -0
- package/dist/types/store/hooks.d.ts +48 -0
- package/dist/types/store/index.d.ts +0 -1
- package/dist/types/store/store.d.ts +3 -38
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CONFIG_VERDICT, REACTIVE_PROBED, CONFIG_INPUTS_PUBLISHED, CONFIG_HELD, REACTIVE_JOINED, REACTIVE_STAGED_READ, REACTIVE_LANE_READ, CONFIG_CHILDREN_FORBIDDEN, CONFIG_OVERRIDE, STATUS_PENDING, CONFIG_GUESS, NOT_PENDING, STATUS_UNINITIALIZED, EFFECT_RENDER, STATUS_ERROR, REACTIVE_PROBE_UNANSWERED } from "./constants.js";
|
|
2
2
|
|
|
3
|
-
import { context, setVerdict,
|
|
3
|
+
import { context, tracking, setVerdict, bornInto, verdict, pullComputed, joinPass, markLateLinker, spectating, unflushedValue } from "./core.js";
|
|
4
4
|
|
|
5
5
|
import { NotReadyError } from "./error.js";
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ import { link } from "./graph.js";
|
|
|
8
8
|
|
|
9
9
|
import { verdictLane, laneValueOf, display } from "./lanes.js";
|
|
10
10
|
|
|
11
|
-
import { GlobalQueue, globalQueue, joinFuture, queuePendingNode, staleReader, passLane, setPassLane, flushTransaction,
|
|
11
|
+
import { GlobalQueue, txOf, globalQueue, joinFuture, queuePendingNode, staleReader, passLane, setPassLane, flushTransaction, stagedReaders } from "./scheduler.js";
|
|
12
12
|
|
|
13
13
|
// Verdicts (plan sec. 28 replay, 2026-10-02; maintainer, 2026-10-01: verdicts are
|
|
14
14
|
// optimistic state the system supplies). `isPending(fn)` asks whether what
|
|
@@ -59,11 +59,13 @@ function watchVerdict(e, t = false) {
|
|
|
59
59
|
* every flush (fuzzer F12). True when the reader is served the committed
|
|
60
60
|
* value — not over a flight committed beneath inputs already on screen (A15
|
|
61
61
|
* reveal corollary, #3305): that value would tear against them, and the
|
|
62
|
-
* reveal observes the flight.
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
* reveal observes the flight. Nor for a reader born into the flight's
|
|
63
|
+
* transaction (`bornInto`, #4010): it has no screen — it waits on the flight
|
|
64
|
+
* with the rest of its frame. */ function observeFlight(e, t) {
|
|
65
|
+
if (t.i & CONFIG_INPUTS_PUBLISHED || t.i & CONFIG_HELD && bornInto(e, txOf(t))) return false;
|
|
66
|
+
if (globalQueue.X) {
|
|
65
67
|
joinFuture(null);
|
|
66
|
-
if (!(t.
|
|
68
|
+
if (!(t.i & CONFIG_HELD)) queuePendingNode(t);
|
|
67
69
|
verdictRead(e, flushTransaction, true);
|
|
68
70
|
}
|
|
69
71
|
return true;
|
|
@@ -86,9 +88,9 @@ let probeFound = false;
|
|
|
86
88
|
* value notifying anyone (a held write's commit; a held landing's): its
|
|
87
89
|
* reader re-derives there. `latest` shows the proposal that lands — a
|
|
88
90
|
* rewrite or a landing reaches its reader through the link it holds — so a
|
|
89
|
-
* re-run would only repeat the frame. */ function verdictRead(e, t, n
|
|
91
|
+
* re-run would only repeat the frame. */ function verdictRead(e, t, n) {
|
|
90
92
|
route(e, t);
|
|
91
|
-
if (n) staleReader(e, t);
|
|
93
|
+
if (n) staleReader(e, t); else if (probing && t.fn[t.fn.length - 1] !== e) t.fn.push(e);
|
|
92
94
|
}
|
|
93
95
|
|
|
94
96
|
/** A verdict read of a node staged or in flight but not held yet: whether it
|
|
@@ -134,10 +136,10 @@ let probeFound = false;
|
|
|
134
136
|
const t = e.m;
|
|
135
137
|
if (t === null) return false;
|
|
136
138
|
if (t.Se !== undefined) {
|
|
137
|
-
for (const e of t.Se) if (!e.m?.
|
|
139
|
+
for (const e of t.Se) if (!e.m?.ke) return false;
|
|
138
140
|
return true;
|
|
139
141
|
}
|
|
140
|
-
return t.
|
|
142
|
+
return t.ke;
|
|
141
143
|
}
|
|
142
144
|
|
|
143
145
|
/** `isPending`'s answer for a held node (A19), relative to what the reader
|
|
@@ -152,25 +154,28 @@ let probeFound = false;
|
|
|
152
154
|
* frame with neither is final. A24: pending iff a value change is in
|
|
153
155
|
* flight — a staging equal to what is displayed changes nothing when it
|
|
154
156
|
* lands: final now (maintainer, 2026-10-02). */ function heldNotFinal(e) {
|
|
155
|
-
if ((e.
|
|
156
|
-
return e.
|
|
157
|
+
if ((e.S & STATUS_PENDING) !== 0 && !quietPending(e)) return true;
|
|
158
|
+
return e.Oe !== NOT_PENDING && !latestActive && !e.m.ke && !(e.S & STATUS_UNINITIALIZED) && (!e.ye || !e.ye(e.Ae, e.Oe));
|
|
157
159
|
}
|
|
158
160
|
|
|
159
161
|
/** `isPending`'s answer for an unheld node whose flight is up (cause ii). */ function pendingVerdict(e, t) {
|
|
160
|
-
if (t.
|
|
162
|
+
if (t.S & STATUS_UNINITIALIZED) return;
|
|
161
163
|
if (probing && !quietPending(t)) probeFound = true;
|
|
162
164
|
if (e !== null && tracking) {
|
|
163
|
-
if (t.
|
|
165
|
+
if (t.i & CONFIG_HELD) verdictRead(e, txOf(t)); else if (globalQueue.X) provisionalVerdict(e, false);
|
|
164
166
|
// decided above
|
|
165
167
|
}
|
|
166
168
|
}
|
|
167
169
|
|
|
168
170
|
/** The pass entering a verdict window is a verdict reader (CONFIG_VERDICT):
|
|
169
|
-
* a dependency going pending re-derives it, the verdict having changed.
|
|
171
|
+
* a dependency going pending re-derives it, the verdict having changed. Not
|
|
172
|
+
* an untracked window: that is a snapshot, like any untracked read (#3946 —
|
|
173
|
+
* a router's link claim probing inside the computation that creates the
|
|
174
|
+
* anchor). A throw still reaches the pass through `untrack`. */ function markVerdictReader(e) {
|
|
170
175
|
let t = context;
|
|
171
|
-
if (t
|
|
172
|
-
if (t !== null) {
|
|
173
|
-
t.
|
|
176
|
+
if (t?.$e) t = t.et;
|
|
177
|
+
if (t !== null && tracking) {
|
|
178
|
+
t.i |= CONFIG_VERDICT;
|
|
174
179
|
t.R |= REACTIVE_PROBED;
|
|
175
180
|
}
|
|
176
181
|
}
|
|
@@ -221,7 +226,7 @@ function isPending(e) {
|
|
|
221
226
|
* a tracked reader of a rewrite not yet flushed, the late-linker re-run in
|
|
222
227
|
* the flush that carries it. */ function heldLatest(e, t) {
|
|
223
228
|
const n = unflushedValue(e);
|
|
224
|
-
if (n === NOT_PENDING) return e.
|
|
229
|
+
if (n === NOT_PENDING) return e.Oe;
|
|
225
230
|
if (t !== null) markLateLinker(t);
|
|
226
231
|
return n;
|
|
227
232
|
}
|
|
@@ -248,10 +253,11 @@ function isPending(e) {
|
|
|
248
253
|
* uninitialized one throws NotReady: loading, not pending (A19 exc. 1);
|
|
249
254
|
* - an errored derivation throws for every reader (#2897). */ function verdictValue(e, t) {
|
|
250
255
|
const n = e;
|
|
251
|
-
const r = t !== null &&
|
|
256
|
+
const r = t !== null && !(t.i & CONFIG_CHILDREN_FORBIDDEN);
|
|
257
|
+
const i = r && tracking;
|
|
252
258
|
if (t !== null && tracking) {
|
|
253
259
|
link(e, t);
|
|
254
|
-
if (n.
|
|
260
|
+
if (n.ee !== undefined) {
|
|
255
261
|
// A31: the pulled memo's pass is its own, not the probe's — it reads
|
|
256
262
|
// outside the window, and the probe's read below answers for what
|
|
257
263
|
// the pass produced.
|
|
@@ -264,86 +270,92 @@ function isPending(e) {
|
|
|
264
270
|
// final by declaration — the value itself is read as below. The verdict is
|
|
265
271
|
// display-ahead like any: in a transaction's flush (the declaring action's
|
|
266
272
|
// body) the reader is its verdict lane's, not a staging the frame parks.
|
|
267
|
-
if (probing && GlobalQueue.
|
|
273
|
+
if (probing && GlobalQueue.N !== undefined && GlobalQueue.N(n)) {
|
|
268
274
|
probeFound = true;
|
|
269
|
-
if (
|
|
275
|
+
if (i && flushTransaction !== null) verdictRead(t, flushTransaction);
|
|
270
276
|
}
|
|
271
|
-
if (e.
|
|
272
|
-
const
|
|
273
|
-
if (
|
|
274
|
-
const u = (n.
|
|
275
|
-
if (e.
|
|
276
|
-
if (probing && (u || e.
|
|
277
|
-
return e.m.
|
|
277
|
+
if (e.i & CONFIG_OVERRIDE) {
|
|
278
|
+
const r = txOf(e);
|
|
279
|
+
if (i) verdictRead(t, r._parent ?? r);
|
|
280
|
+
const u = (n.S & STATUS_PENDING) !== 0 && !quietPending(n);
|
|
281
|
+
if (e.i & CONFIG_GUESS) {
|
|
282
|
+
if (probing && (u || e.Oe !== NOT_PENDING && (!e.ye || !e.ye(e.m.B, e.Oe)))) probeFound = true;
|
|
283
|
+
return e.m.B;
|
|
278
284
|
}
|
|
279
285
|
if (probing && u) probeFound = true;
|
|
280
286
|
return latestActive && !u ? laneValueOf(e) : display(e);
|
|
281
287
|
}
|
|
282
|
-
const
|
|
283
|
-
if (e.
|
|
284
|
-
if (!
|
|
285
|
-
const
|
|
288
|
+
const u = (n.S & STATUS_UNINITIALIZED) !== 0;
|
|
289
|
+
if (e.i & CONFIG_HELD) {
|
|
290
|
+
if (!u) {
|
|
291
|
+
const r = txOf(e);
|
|
286
292
|
// A render effect re-run (or mounted) outside the verdict lane's flush
|
|
287
293
|
// while the lane is blocked — its display held on its own derivation
|
|
288
294
|
// in flight — is a stale reader of the lane (#3460, as `laneRead`): the
|
|
289
295
|
// committed value now, re-derived at the reveal. Not inside a probe:
|
|
290
296
|
// `isPending` is answered below either way.
|
|
291
|
-
if (
|
|
292
|
-
staleReader(t,
|
|
293
|
-
return e.
|
|
297
|
+
if (i && !probing && t.u === EFFECT_RENDER && passLane === null && r.xe !== null && r.xe.sn && flushTransaction !== r) {
|
|
298
|
+
staleReader(t, r.xe);
|
|
299
|
+
return e.Ae;
|
|
294
300
|
}
|
|
295
|
-
if (
|
|
301
|
+
if (i) verdictRead(t, r);
|
|
296
302
|
if (probing && heldNotFinal(n)) probeFound = true;
|
|
297
|
-
if (latestActive && e.
|
|
303
|
+
if (latestActive && e.Oe !== NOT_PENDING) {
|
|
298
304
|
// An action body reading another transaction's proposal derives
|
|
299
305
|
// from it: the two settle as one (A15; posture C, 2026-09-15). An
|
|
300
306
|
// untracked read elsewhere has no transaction to entangle.
|
|
301
|
-
if (!
|
|
302
|
-
return heldLatest(e,
|
|
307
|
+
if (!i && flushTransaction !== null && !globalQueue.X) joinFuture(txOf(e));
|
|
308
|
+
return heldLatest(e, i ? t : null);
|
|
303
309
|
}
|
|
304
|
-
return e.
|
|
310
|
+
return e.Ae;
|
|
311
|
+
}
|
|
312
|
+
// Born into the future: its staging is its only value. It has no
|
|
313
|
+
// committed value, so no verdict: `isPending` reads it as its read does —
|
|
314
|
+
// the owner joins the hold (held with it, or caught by a boundary that
|
|
315
|
+
// has not shown content) and answers for the commit, where it is final.
|
|
316
|
+
if (e.Oe !== NOT_PENDING && !(n.S & STATUS_PENDING)) {
|
|
317
|
+
if (probing && r) joinPass(t, e);
|
|
318
|
+
return e.Oe;
|
|
305
319
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
} else if (e.Ae !== NOT_PENDING) {
|
|
309
|
-
if (n.G & STATUS_PENDING && !i) pendingVerdict(r ? t : null, n); else if (r && globalQueue.ee) provisionalVerdict(t, !latestActive && !i);
|
|
320
|
+
} else if (e.Oe !== NOT_PENDING) {
|
|
321
|
+
if (n.S & STATUS_PENDING && !u) pendingVerdict(i ? t : null, n); else if (i && globalQueue.X) provisionalVerdict(t, !latestActive && !u);
|
|
310
322
|
// Outside a flush, the staging is an unflushed write (A28): the probe
|
|
311
323
|
// answers for the flushed world, and watches the seam of the flush that
|
|
312
324
|
// carries the write — a memo of `isPending(x)` created after the write
|
|
313
325
|
// flips if that flush parks (#3078). (The write's own fan-out ran before
|
|
314
326
|
// the reader existed; nothing else would re-derive it.)
|
|
315
|
-
else if (
|
|
327
|
+
else if (i && probing) watchVerdict(t);
|
|
316
328
|
if (latestActive) {
|
|
317
329
|
// A28: an unflushed write is not what `latest` serves; a tracked
|
|
318
330
|
// reader derived from the flushed world runs again in the carrying
|
|
319
331
|
// flush.
|
|
320
|
-
if (globalQueue.
|
|
332
|
+
if (globalQueue.X) return e.Oe;
|
|
321
333
|
if (t !== null) markLateLinker(t);
|
|
322
334
|
}
|
|
323
|
-
return e.
|
|
335
|
+
return e.Ae;
|
|
324
336
|
}
|
|
325
|
-
if (n.
|
|
326
|
-
if (!
|
|
327
|
-
pendingVerdict(
|
|
328
|
-
return e.
|
|
337
|
+
if (n.S & STATUS_PENDING) {
|
|
338
|
+
if (!u) {
|
|
339
|
+
pendingVerdict(i ? t : null, n);
|
|
340
|
+
return e.Ae;
|
|
329
341
|
}
|
|
330
342
|
// As `read()`: an untracked read of a pending node still re-runs its
|
|
331
343
|
// reader when the node settles (a projection's pull reads its firewall
|
|
332
344
|
// untracked, store/store.ts).
|
|
333
345
|
if (t !== null && !tracking && !spectating && e !== t) link(e, t);
|
|
334
|
-
throw n.m?.
|
|
346
|
+
throw n.m?.F;
|
|
335
347
|
}
|
|
336
|
-
if (n.
|
|
337
|
-
return e.
|
|
348
|
+
if (n.ee !== undefined && n.S & STATUS_ERROR) throw n.m.F;
|
|
349
|
+
return e.Ae;
|
|
338
350
|
}
|
|
339
351
|
|
|
340
352
|
// Installed at module evaluation — present exactly when something imports
|
|
341
353
|
// `latest` or `isPending`. (`read` dispatches to `verdictValue` through
|
|
342
354
|
// `verdict`, set while a window is open.)
|
|
343
|
-
GlobalQueue.
|
|
355
|
+
GlobalQueue.It = observeFlight;
|
|
344
356
|
|
|
345
357
|
/** A store read inside an untracked `isPending` probe found a live mark on
|
|
346
|
-
* a record with no node to carry it (store/affects.ts): not final. */ GlobalQueue.
|
|
358
|
+
* a record with no node to carry it (store/affects.ts): not final. */ GlobalQueue.ct = () => {
|
|
347
359
|
if (probing) probeFound = true;
|
|
348
360
|
};
|
|
349
361
|
|
package/dist/prod/map.js
CHANGED
|
@@ -21,21 +21,21 @@ function mapArray(t, s, e) {
|
|
|
21
21
|
const r = s.length > 1;
|
|
22
22
|
const n = s;
|
|
23
23
|
const o = {
|
|
24
|
-
|
|
24
|
+
L: createOwner(),
|
|
25
25
|
ht: 0,
|
|
26
|
-
|
|
26
|
+
dt: t,
|
|
27
27
|
wt: [],
|
|
28
28
|
Ot: n,
|
|
29
29
|
yt: [],
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
ln: [],
|
|
31
|
+
ot: i,
|
|
32
|
+
At: i || e?.keyed === false ? [] : undefined,
|
|
33
|
+
Mt: r && e?.keyed !== false ? [] : undefined,
|
|
34
|
+
gt: e?.keyed === false,
|
|
35
|
+
v: e?.fallback
|
|
36
36
|
};
|
|
37
37
|
const h = computed(updateKeyedMap.bind(o), undefined);
|
|
38
|
-
h.
|
|
38
|
+
h.i &= ~CONFIG_AUTO_DISPOSE;
|
|
39
39
|
return accessor(h);
|
|
40
40
|
}
|
|
41
41
|
|
|
@@ -153,7 +153,7 @@ function trySmallMove(t, s, e, i) {
|
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
155
|
const a = t.yt;
|
|
156
|
-
const u = t.
|
|
156
|
+
const u = t.ln;
|
|
157
157
|
const l = a.slice(0, e);
|
|
158
158
|
const p = u.slice(0, e);
|
|
159
159
|
for (let t = 0; t < n.length; t += 3) {
|
|
@@ -173,7 +173,7 @@ function trySmallMove(t, s, e, i) {
|
|
|
173
173
|
p[t] = u[s];
|
|
174
174
|
}
|
|
175
175
|
t.yt = l;
|
|
176
|
-
t.
|
|
176
|
+
t.ln = p;
|
|
177
177
|
t.ht = e;
|
|
178
178
|
t.wt = s.slice(0);
|
|
179
179
|
// Dispose unmatched sources LAST (general-path ordering).
|
|
@@ -190,22 +190,22 @@ function updateKeyedMap() {
|
|
|
190
190
|
// the flight's reader (pending tracking + post-settle retry) instead of
|
|
191
191
|
// vanishing. Set per pass: the first pass runs inside `computed()`, before
|
|
192
192
|
// the node exists to the caller.
|
|
193
|
-
this.
|
|
194
|
-
const t = this.
|
|
193
|
+
this.L.et = getOwner();
|
|
194
|
+
const t = this.dt() || [], s = t.length;
|
|
195
195
|
t[$TRACK];
|
|
196
196
|
// top level tracking (a store array's container node)
|
|
197
|
-
runWithOwner(this.
|
|
197
|
+
runWithOwner(this.L, () => {
|
|
198
198
|
let e, i, r, n,
|
|
199
199
|
// Mappers write freshly-created row/index signals into the STAGE
|
|
200
200
|
// arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
|
|
201
|
-
o = this.
|
|
201
|
+
o = this.At ? this.gt ? () => {
|
|
202
202
|
r[i] = signal(t[i], pureOptions);
|
|
203
203
|
return this.Ot(accessor(r[i]), i);
|
|
204
204
|
} : () => {
|
|
205
205
|
r[i] = signal(t[i], pureOptions);
|
|
206
206
|
n && (n[i] = signal(i, pureOptions));
|
|
207
207
|
return this.Ot(accessor(r[i]), n ? accessor(n[i]) : undefined);
|
|
208
|
-
} : this.
|
|
208
|
+
} : this.Mt ? () => {
|
|
209
209
|
const s = t[i];
|
|
210
210
|
n[i] = signal(i, pureOptions);
|
|
211
211
|
return this.Ot(s, accessor(n[i]));
|
|
@@ -216,27 +216,27 @@ function updateKeyedMap() {
|
|
|
216
216
|
// fast path for empty arrays
|
|
217
217
|
if (s === 0) {
|
|
218
218
|
if (this.ht !== 0) {
|
|
219
|
-
this.
|
|
220
|
-
this.
|
|
219
|
+
this.L.dispose(false);
|
|
220
|
+
this.ln = [];
|
|
221
221
|
this.wt = [];
|
|
222
222
|
this.yt = [];
|
|
223
223
|
this.ht = 0;
|
|
224
|
+
this.At && (this.At = []);
|
|
224
225
|
this.Mt && (this.Mt = []);
|
|
225
|
-
this.gt && (this.gt = []);
|
|
226
226
|
}
|
|
227
|
-
if (this.
|
|
227
|
+
if (this.v && !this.yt[0]) {
|
|
228
228
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
229
229
|
// dispose it before re-creating
|
|
230
|
-
this.
|
|
231
|
-
this.yt[0] = runWithOwner(this.
|
|
230
|
+
this.ln[0]?.dispose();
|
|
231
|
+
this.yt[0] = runWithOwner(this.ln[0] = createOwner(), this.v);
|
|
232
232
|
}
|
|
233
233
|
}
|
|
234
234
|
// fast path for new create
|
|
235
235
|
else if (this.ht === 0) {
|
|
236
236
|
const h = new Array(s);
|
|
237
237
|
const f = new Array(s);
|
|
238
|
-
r = this.
|
|
239
|
-
n = this.
|
|
238
|
+
r = this.At && new Array(s);
|
|
239
|
+
n = this.Mt && new Array(s);
|
|
240
240
|
try {
|
|
241
241
|
for (i = 0; i < s; i++) h[i] = runWithOwner(f[i] = createOwner(), o);
|
|
242
242
|
} catch (t) {
|
|
@@ -244,12 +244,12 @@ function updateKeyedMap() {
|
|
|
244
244
|
throw t;
|
|
245
245
|
}
|
|
246
246
|
// commit
|
|
247
|
-
if (this.
|
|
247
|
+
if (this.ln[0]) this.ln[0].dispose();
|
|
248
248
|
// previous fallback
|
|
249
249
|
this.yt = h;
|
|
250
|
-
this.
|
|
251
|
-
r && (this.
|
|
252
|
-
n && (this.
|
|
250
|
+
this.ln = f;
|
|
251
|
+
r && (this.At = r);
|
|
252
|
+
n && (this.Mt = n);
|
|
253
253
|
this.wt = t.slice(0);
|
|
254
254
|
this.ht = s;
|
|
255
255
|
} else {
|
|
@@ -280,12 +280,12 @@ function updateKeyedMap() {
|
|
|
280
280
|
// CARVE 2: the lane-slot arm (`_landOnOverride`, F1) went with the engine.
|
|
281
281
|
const _ = setSignal;
|
|
282
282
|
// skip common prefix
|
|
283
|
-
for (h = 0, f = Math.min(this.ht, s); h < f && (this.wt[h] === t[h] || this.
|
|
284
|
-
if (this.
|
|
283
|
+
for (h = 0, f = Math.min(this.ht, s); h < f && (this.wt[h] === t[h] || this.At && compare(this.ot, this.wt[h], t[h])); h++) {
|
|
284
|
+
if (this.At) _(this.At[h], t[h]);
|
|
285
285
|
}
|
|
286
286
|
// skip common suffix — counted only; retained entries land in one pass
|
|
287
287
|
// at commit instead of being staged and copied twice
|
|
288
|
-
for (f = this.ht - 1, c = s - 1; f >= h && c >= h && (this.wt[f] === t[c] || this.
|
|
288
|
+
for (f = this.ht - 1, c = s - 1; f >= h && c >= h && (this.wt[f] === t[c] || this.At && compare(this.ot, this.wt[f], t[c])); f--,
|
|
289
289
|
c--) ;
|
|
290
290
|
// no structural change (every position matched in place at equal
|
|
291
291
|
// length — the common post-reconcile shape): keep the same mapped
|
|
@@ -301,7 +301,7 @@ function updateKeyedMap() {
|
|
|
301
301
|
// (plain removals, tail edits), the general path is window-
|
|
302
302
|
// proportional and cheap — the fast path would only re-walk what the
|
|
303
303
|
// trims proved.
|
|
304
|
-
if (s <= this.ht && f - h > 64 && this.
|
|
304
|
+
if (s <= this.ht && f - h > 64 && this.At === undefined && this.Mt === undefined) {
|
|
305
305
|
// PROBE before the scan: a small move keeps a mid-window item within
|
|
306
306
|
// ±32 of its old position; a REPLACE (all fresh items — the shape
|
|
307
307
|
// every page's first structural pass usually is) has it nowhere.
|
|
@@ -317,15 +317,15 @@ function updateKeyedMap() {
|
|
|
317
317
|
const y = s - this.ht;
|
|
318
318
|
const A = new Array(s);
|
|
319
319
|
const M = new Array(s);
|
|
320
|
-
r = this.
|
|
321
|
-
n = this.
|
|
320
|
+
r = this.At ? new Array(s) : undefined;
|
|
321
|
+
n = this.Mt ? new Array(s) : undefined;
|
|
322
322
|
// 0) prepare a map of all indices in the changed window of newItems,
|
|
323
323
|
// scanning backwards so we encounter them in natural order
|
|
324
324
|
l = new Map;
|
|
325
325
|
p = new Array(c + 1);
|
|
326
326
|
for (i = c; i >= h; i--) {
|
|
327
327
|
a = t[i];
|
|
328
|
-
u = this.
|
|
328
|
+
u = this.ot ? this.ot(a) : a;
|
|
329
329
|
e = l.get(u);
|
|
330
330
|
p[i] = e === undefined ? -1 : e;
|
|
331
331
|
l.set(u, i);
|
|
@@ -335,17 +335,17 @@ function updateKeyedMap() {
|
|
|
335
335
|
// queue them for disposal at commit
|
|
336
336
|
for (e = h; e <= f; e++) {
|
|
337
337
|
a = this.wt[e];
|
|
338
|
-
u = this.
|
|
338
|
+
u = this.ot ? this.ot(a) : a;
|
|
339
339
|
i = l.get(u);
|
|
340
340
|
if (i !== undefined && i !== -1) {
|
|
341
341
|
A[i] = this.yt[e];
|
|
342
|
-
M[i] = this.
|
|
343
|
-
r && (r[i] = this.
|
|
344
|
-
n && (n[i] = this.
|
|
342
|
+
M[i] = this.ln[e];
|
|
343
|
+
r && (r[i] = this.At[e]);
|
|
344
|
+
n && (n[i] = this.Mt[e]);
|
|
345
345
|
i = p[i];
|
|
346
346
|
l.set(u, i);
|
|
347
347
|
} else {
|
|
348
|
-
(d ??= []).push(this.
|
|
348
|
+
(d ??= []).push(this.ln[e]);
|
|
349
349
|
if (false && attrHooks !== null) ;
|
|
350
350
|
}
|
|
351
351
|
}
|
|
@@ -366,9 +366,9 @@ function updateKeyedMap() {
|
|
|
366
366
|
// change propagation), then dispose exited rows
|
|
367
367
|
for (e = 0; e < h; e++) {
|
|
368
368
|
A[e] = this.yt[e];
|
|
369
|
-
M[e] = this.
|
|
370
|
-
r && (r[e] = this.
|
|
371
|
-
n && (n[e] = this.
|
|
369
|
+
M[e] = this.ln[e];
|
|
370
|
+
r && (r[e] = this.At[e]);
|
|
371
|
+
n && (n[e] = this.Mt[e]);
|
|
372
372
|
}
|
|
373
373
|
for (i = h; i <= c; i++) {
|
|
374
374
|
if (r) _(r[i], t[i]);
|
|
@@ -376,20 +376,20 @@ function updateKeyedMap() {
|
|
|
376
376
|
}
|
|
377
377
|
for (i = c + 1; i < s; i++) {
|
|
378
378
|
A[i] = this.yt[i - y];
|
|
379
|
-
M[i] = this.
|
|
379
|
+
M[i] = this.ln[i - y];
|
|
380
380
|
if (r) {
|
|
381
|
-
r[i] = this.
|
|
381
|
+
r[i] = this.At[i - y];
|
|
382
382
|
_(r[i], t[i]);
|
|
383
383
|
}
|
|
384
384
|
if (n) {
|
|
385
|
-
n[i] = this.
|
|
385
|
+
n[i] = this.Mt[i - y];
|
|
386
386
|
if (y !== 0) _(n[i], i);
|
|
387
387
|
}
|
|
388
388
|
}
|
|
389
389
|
this.yt = A;
|
|
390
|
-
this.
|
|
391
|
-
r && (this.
|
|
392
|
-
n && (this.
|
|
390
|
+
this.ln = M;
|
|
391
|
+
r && (this.At = r);
|
|
392
|
+
n && (this.Mt = n);
|
|
393
393
|
this.ht = s;
|
|
394
394
|
// save a copy of the mapped items for the next update
|
|
395
395
|
this.wt = t.slice(0);
|
|
@@ -417,18 +417,18 @@ function updateKeyedMap() {
|
|
|
417
417
|
*/ function repeat(t, s, e) {
|
|
418
418
|
const i = s;
|
|
419
419
|
const r = {
|
|
420
|
-
|
|
420
|
+
L: createOwner(),
|
|
421
421
|
ht: 0,
|
|
422
|
-
|
|
423
|
-
|
|
422
|
+
St: 0,
|
|
423
|
+
kt: t,
|
|
424
424
|
Ot: i,
|
|
425
|
-
|
|
425
|
+
ln: [],
|
|
426
426
|
yt: [],
|
|
427
|
-
|
|
428
|
-
|
|
427
|
+
jt: e?.from,
|
|
428
|
+
v: e?.fallback
|
|
429
429
|
};
|
|
430
430
|
const n = computed(updateRepeat.bind(r));
|
|
431
|
-
n.
|
|
431
|
+
n.i &= ~CONFIG_AUTO_DISPOSE;
|
|
432
432
|
return accessor(n);
|
|
433
433
|
}
|
|
434
434
|
|
|
@@ -441,38 +441,38 @@ function updateKeyedMap() {
|
|
|
441
441
|
// disjoint-window/front-clear/end-clear/shift special cases.
|
|
442
442
|
function updateRepeat() {
|
|
443
443
|
// As in updateKeyedMap: the node is the row callbacks' reader, per pass.
|
|
444
|
-
this.
|
|
445
|
-
const t = this.
|
|
446
|
-
const s = this.
|
|
447
|
-
runWithOwner(this.
|
|
444
|
+
this.L.et = getOwner();
|
|
445
|
+
const t = this.kt();
|
|
446
|
+
const s = this.jt?.() || 0;
|
|
447
|
+
runWithOwner(this.L, () => {
|
|
448
448
|
if (t === 0) {
|
|
449
449
|
if (this.ht !== 0) {
|
|
450
|
-
this.
|
|
451
|
-
this.
|
|
450
|
+
this.L.dispose(false);
|
|
451
|
+
this.ln = [];
|
|
452
452
|
this.yt = [];
|
|
453
453
|
this.ht = 0;
|
|
454
454
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
455
|
-
this.
|
|
455
|
+
this.St = 0;
|
|
456
456
|
}
|
|
457
|
-
if (this.
|
|
457
|
+
if (this.v && !this.yt[0]) {
|
|
458
458
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
459
459
|
// dispose it before re-creating
|
|
460
|
-
this.
|
|
461
|
-
this.yt[0] = runWithOwner(this.
|
|
460
|
+
this.ln[0]?.dispose();
|
|
461
|
+
this.yt[0] = runWithOwner(this.ln[0] = createOwner(), this.v);
|
|
462
462
|
}
|
|
463
463
|
return;
|
|
464
464
|
}
|
|
465
465
|
const e = s + t;
|
|
466
|
-
const i = this.
|
|
466
|
+
const i = this.St + this.ht;
|
|
467
467
|
// Retained overlap [keepStart, keepEnd) in global indexes; empty when the
|
|
468
468
|
// windows are disjoint or when coming from empty/fallback.
|
|
469
|
-
const r = Math.max(s, this.
|
|
469
|
+
const r = Math.max(s, this.St);
|
|
470
470
|
const n = Math.min(e, i);
|
|
471
471
|
const o = new Array(t);
|
|
472
472
|
const h = new Array(t);
|
|
473
473
|
for (let t = r; t < n; t++) {
|
|
474
|
-
h[t - s] = this.
|
|
475
|
-
o[t - s] = this.yt[t - this.
|
|
474
|
+
h[t - s] = this.ln[t - this.St];
|
|
475
|
+
o[t - s] = this.yt[t - this.St];
|
|
476
476
|
}
|
|
477
477
|
try {
|
|
478
478
|
for (let t = s; t < e; t++) {
|
|
@@ -484,10 +484,10 @@ function updateRepeat() {
|
|
|
484
484
|
throw t;
|
|
485
485
|
}
|
|
486
486
|
// commit: dispose the previous fallback or the rows leaving the window
|
|
487
|
-
if (this.ht === 0) this.
|
|
487
|
+
if (this.ht === 0) this.ln[0]?.dispose(); else for (let t = this.St; t < i; t++) if (t < s || t >= e) this.ln[t - this.St].dispose();
|
|
488
488
|
this.yt = o;
|
|
489
|
-
this.
|
|
490
|
-
this.
|
|
489
|
+
this.ln = h;
|
|
490
|
+
this.St = s;
|
|
491
491
|
this.ht = t;
|
|
492
492
|
});
|
|
493
493
|
return this.yt;
|