@solidjs/signals 2.0.0-beta.19 → 2.0.0-beta.20

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.
Files changed (36) hide show
  1. package/dist/dev.js +670 -371
  2. package/dist/node.cjs +1878 -1606
  3. package/dist/prod/affects.js +17 -21
  4. package/dist/prod/core/action.js +19 -6
  5. package/dist/prod/core/async.js +57 -71
  6. package/dist/prod/core/constants.js +15 -1
  7. package/dist/prod/core/core.js +39 -39
  8. package/dist/prod/core/effect.js +14 -14
  9. package/dist/prod/core/graph.js +1 -1
  10. package/dist/prod/core/heap.js +2 -2
  11. package/dist/prod/core/lanes.js +23 -13
  12. package/dist/prod/core/optimistic.js +107 -99
  13. package/dist/prod/core/owner.js +23 -23
  14. package/dist/prod/core/scheduler.js +180 -180
  15. package/dist/prod/core/verdict.js +12 -13
  16. package/dist/prod/map.js +196 -167
  17. package/dist/prod/signals.js +1 -1
  18. package/dist/prod/store/optimistic.js +103 -68
  19. package/dist/prod/store/reconcile.js +80 -46
  20. package/dist/prod/store/store.js +204 -73
  21. package/dist/prod/store/utils.js +61 -42
  22. package/dist/types/core/action.d.ts +19 -6
  23. package/dist/types/core/constants.d.ts +12 -0
  24. package/dist/types/core/dev.d.ts +7 -0
  25. package/dist/types/core/lanes.d.ts +2 -0
  26. package/dist/types/core/scheduler.d.ts +2 -6
  27. package/dist/types/core/types.d.ts +9 -1
  28. package/dist/types/store/store.d.ts +8 -2
  29. package/dist/types-cjs/core/action.d.cts +19 -6
  30. package/dist/types-cjs/core/constants.d.cts +12 -0
  31. package/dist/types-cjs/core/dev.d.cts +7 -0
  32. package/dist/types-cjs/core/lanes.d.cts +2 -0
  33. package/dist/types-cjs/core/scheduler.d.cts +2 -6
  34. package/dist/types-cjs/core/types.d.cts +9 -1
  35. package/dist/types-cjs/store/store.d.cts +8 -2
  36. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
- import { STATUS_UNINITIALIZED, REACTIVE_DISPOSED, NOT_PENDING, REACTIVE_MANUAL_WRITE, STATUS_PENDING, REACTIVE_DIRTY, REACTIVE_CHECK } from "./constants.js";
1
+ import { NOT_PENDING, REACTIVE_DISPOSED, REACTIVE_DIRTY, REACTIVE_CHECK, unwrapOverride, STATUS_UNINITIALIZED, STATUS_PENDING, REACTIVE_MANUAL_WRITE } from "./constants.js";
2
2
 
3
- import { context, setPendingCheckActive, read, optimisticSignal, setSignal, setLatestReadActive, pendingCheckActive, latestReadActive, stale, currentOptimisticLane, prepareComputed, tracking, setContextInternal, optimisticComputed } from "./core.js";
3
+ import { setSignal, read, context, stale, currentOptimisticLane, prepareComputed, tracking, setLatestReadActive, setContextInternal, optimisticComputed, setPendingCheckActive, latestReadActive, optimisticSignal, pendingCheckActive } from "./core.js";
4
4
 
5
5
  import { NotReadyError } from "./error.js";
6
6
 
@@ -10,7 +10,7 @@ import { insertIntoHeap, queueFor } from "./heap.js";
10
10
 
11
11
  import "./invariants.js";
12
12
 
13
- import { hasActiveOverride, findLane } from "./lanes.js";
13
+ import { findLane, hasActiveOverride } from "./lanes.js";
14
14
 
15
15
  import { installOptimisticEngine } from "./optimistic.js";
16
16
 
@@ -61,11 +61,10 @@ function collectPendingSources(e) {
61
61
  }
62
62
 
63
63
  function quietPending(e) {
64
- if (e.M) {
65
- for (const t of e.M) if (!t.A) return false;
64
+ if (e.m) {
65
+ for (const t of e.m) if (!t.A) return false;
66
66
  return true;
67
67
  }
68
- if (e.m) return e.m.A;
69
68
  return e.A;
70
69
  }
71
70
 
@@ -76,11 +75,11 @@ function newQuestionInFlight(e) {
76
75
  function computePendingState(e) {
77
76
  const t = e;
78
77
  if (t.u & REACTIVE_DISPOSED) return false;
79
- if (e.P) return true;
78
+ if (e.M) return true;
80
79
  const n = e.rt;
81
80
  if (e.en) {
82
81
  const t = e.en;
83
- if (t.P) return true;
82
+ if (t.M) return true;
84
83
  const n = t.rt || t;
85
84
  return newQuestionInFlight(n);
86
85
  }
@@ -88,7 +87,7 @@ function computePendingState(e) {
88
87
  return !!(n.u & REACTIVE_MANUAL_WRITE) || !n.Ae && !(n.i & STATUS_PENDING) || !!(n.i & STATUS_PENDING) && quietPending(n);
89
88
  }
90
89
  if (e.ge !== NOT_PENDING && !(t.i & STATUS_UNINITIALIZED)) {
91
- if (hasActiveOverride(e)) return !e.Ge || !e.Ge(e.ge, e.be);
90
+ if (hasActiveOverride(e)) return !e.Ge || !e.Ge(e.ge, unwrapOverride(e.be));
92
91
  return true;
93
92
  }
94
93
  return newQuestionInFlight(t);
@@ -173,7 +172,7 @@ function getLatestValueComputed(e) {
173
172
  const t = getLatestValueComputed(e);
174
173
  const n = latestReadActive;
175
174
  setLatestReadActive(false);
176
- const i = e.be !== undefined && e.be !== NOT_PENDING ? e.be : e.Ue;
175
+ const i = e.be !== undefined && e.be !== NOT_PENDING ? unwrapOverride(e.be) : e.Ue;
177
176
  let r;
178
177
  try {
179
178
  r = read(t);
@@ -272,7 +271,7 @@ function isPending(e) {
272
271
  // direct calls used, so behavior is identical once this module loads.
273
272
  GlobalQueue._e = syncCompanions;
274
273
 
275
- GlobalQueue._ = updatePendingSignal;
274
+ GlobalQueue.P = updatePendingSignal;
276
275
 
277
276
  GlobalQueue.me = updateChildCompanions;
278
277
 
@@ -282,12 +281,12 @@ GlobalQueue.Gt = latestRead;
282
281
 
283
282
  GlobalQueue.Pt = pendingCheckRead;
284
283
 
285
- GlobalQueue.vt = recordFreshRead;
284
+ GlobalQueue.kt = recordFreshRead;
286
285
 
287
286
  GlobalQueue.tt = applyReask;
288
287
 
289
288
  GlobalQueue.nt = repollDownstreamVerdicts;
290
289
 
291
- GlobalQueue.Zt = witnessAffects;
290
+ GlobalQueue.wt = witnessAffects;
292
291
 
293
292
  export { isPending, latest };
package/dist/prod/map.js CHANGED
@@ -18,26 +18,26 @@ import { $TRACK } from "./store/store.js";
18
18
 
19
19
  function mapArray(t, s, i) {
20
20
  const e = typeof i?.keyed === "function" ? i.keyed : undefined;
21
- const h = s.length > 1;
22
- const r = s;
23
- const n = {
24
- $t: createOwner(),
25
- Xt: 0,
26
- ts: t,
27
- ss: [],
28
- es: r,
29
- hs: [],
30
- rs: [],
31
- ns: e,
32
- cs: e || i?.keyed === false ? [] : undefined,
33
- fs: h && i?.keyed !== false ? [] : undefined,
34
- us: i?.keyed === false,
35
- ps: i?.fallback
21
+ const r = s.length > 1;
22
+ const n = s;
23
+ const h = {
24
+ jt: createOwner(),
25
+ Wt: 0,
26
+ Kt: t,
27
+ xt: [],
28
+ $t: n,
29
+ qt: [],
30
+ zt: [],
31
+ Ht: e,
32
+ Jt: e || i?.keyed === false ? [] : undefined,
33
+ Xt: r && i?.keyed !== false ? [] : undefined,
34
+ Yt: i?.keyed === false,
35
+ Zt: i?.fallback
36
36
  };
37
- const o = computed(updateKeyedMap.bind(n));
37
+ const o = computed(updateKeyedMap.bind(h));
38
38
  // Untracked reads inside the internal owner resolve via _parentComputed; routing
39
39
  // them through node lets store-proxy lookups see pending writes (not stale _value).
40
- n.$t.Ct = o;
40
+ h.jt.Ct = o;
41
41
  o.U &= ~CONFIG_AUTO_DISPOSE;
42
42
  return accessor(o);
43
43
  }
@@ -46,114 +46,149 @@ const pureOptions = {
46
46
  ownedWrite: true
47
47
  };
48
48
 
49
+ // Exception safety (#2903): a map callback can throw NotReadyError mid-pass
50
+ // (async read), and the computed re-runs the whole pass after settle. Every
51
+ // pass therefore STAGES its work — new rows are created into temp arrays and
52
+ // removals are deferred — and commits to `this` only after every mapper
53
+ // succeeded. An aborted pass disposes just the owners it created and leaves
54
+ // `_items`/`_mappings`/`_nodes`/`_rows`/`_indexes`/`_len` exactly as they
55
+ // were, so the retry diffs against uncorrupted state. Consequence of the
56
+ // strong-abort ordering: removed rows now dispose AFTER the pass's new rows
57
+ // are created (you cannot destroy state before knowing the pass will land).
49
58
  function updateKeyedMap() {
50
- const t = this.ts() || [], s = t.length;
59
+ const t = this.Kt() || [], s = t.length;
51
60
  t[$TRACK];
52
61
  // top level tracking
53
- runWithOwner(this.$t, () => {
54
- let i, e, h = this.cs ? this.us ? () => {
55
- this.cs[e] = signal(t[e], pureOptions);
56
- return this.es(accessor(this.cs[e]), e);
62
+ runWithOwner(this.jt, () => {
63
+ let i, e, r, n,
64
+ // Mappers write freshly-created row/index signals into the STAGE
65
+ // arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
66
+ h = this.Jt ? this.Yt ? () => {
67
+ r[e] = signal(t[e], pureOptions);
68
+ return this.$t(accessor(r[e]), e);
57
69
  } : () => {
58
- this.cs[e] = signal(t[e], pureOptions);
59
- this.fs && (this.fs[e] = signal(e, pureOptions));
60
- return this.es(accessor(this.cs[e]), this.fs ? accessor(this.fs[e]) : undefined);
61
- } : this.fs ? () => {
70
+ r[e] = signal(t[e], pureOptions);
71
+ n && (n[e] = signal(e, pureOptions));
72
+ return this.$t(accessor(r[e]), n ? accessor(n[e]) : undefined);
73
+ } : this.Xt ? () => {
62
74
  const s = t[e];
63
- this.fs[e] = signal(e, pureOptions);
64
- return this.es(s, accessor(this.fs[e]));
75
+ n[e] = signal(e, pureOptions);
76
+ return this.$t(s, accessor(n[e]));
65
77
  } : () => {
66
78
  const s = t[e];
67
- return this.es(s);
79
+ return this.$t(s);
68
80
  };
69
81
  // fast path for empty arrays
70
82
  if (s === 0) {
71
- if (this.Xt !== 0) {
72
- this.$t.dispose(false);
73
- this.rs = [];
74
- this.ss = [];
75
- this.hs = [];
76
- this.Xt = 0;
77
- this.cs && (this.cs = []);
78
- this.fs && (this.fs = []);
83
+ if (this.Wt !== 0) {
84
+ this.jt.dispose(false);
85
+ this.zt = [];
86
+ this.xt = [];
87
+ this.qt = [];
88
+ this.Wt = 0;
89
+ this.Jt && (this.Jt = []);
90
+ this.Xt && (this.Xt = []);
79
91
  }
80
- if (this.ps && !this.hs[0]) {
81
- // create fallback
82
- this.hs[0] = runWithOwner(this.rs[0] = createOwner(), this.ps);
92
+ if (this.Zt && !this.qt[0]) {
93
+ // an aborted fallback attempt leaves an owner without a mapping;
94
+ // dispose it before re-creating
95
+ this.zt[0]?.dispose();
96
+ this.qt[0] = runWithOwner(this.zt[0] = createOwner(), this.Zt);
83
97
  }
84
98
  }
85
99
  // fast path for new create
86
- else if (this.Xt === 0) {
87
- // dispose previous fallback
88
- if (this.rs[0]) this.rs[0].dispose();
89
- this.hs = new Array(s);
90
- for (e = 0; e < s; e++) {
91
- this.ss[e] = t[e];
92
- this.hs[e] = runWithOwner(this.rs[e] = createOwner(), h);
100
+ else if (this.Wt === 0) {
101
+ const o = new Array(s);
102
+ const c = new Array(s);
103
+ r = this.Jt && new Array(s);
104
+ n = this.Xt && new Array(s);
105
+ try {
106
+ for (e = 0; e < s; e++) o[e] = runWithOwner(c[e] = createOwner(), h);
107
+ } catch (t) {
108
+ for (i = 0; i <= e; i++) c[i]?.dispose();
109
+ throw t;
93
110
  }
94
- this.Xt = s;
111
+ // commit
112
+ if (this.zt[0]) this.zt[0].dispose();
113
+ // previous fallback
114
+ this.qt = o;
115
+ this.zt = c;
116
+ r && (this.Jt = r);
117
+ n && (this.Xt = n);
118
+ this.xt = t.slice(0);
119
+ this.Wt = s;
95
120
  } else {
96
- let r, n, o, a, c, f, u, p = new Array(s), l = new Array(s), w = this.cs ? new Array(s) : undefined, O = this.fs ? new Array(s) : undefined;
121
+ let o, c, a, f, u, p, w, l, d, O = new Array(s), m = new Array(s);
122
+ r = this.Jt ? new Array(s) : undefined;
123
+ n = this.Xt ? new Array(s) : undefined;
97
124
  // skip common prefix
98
- for (r = 0, n = Math.min(this.Xt, s); r < n && (this.ss[r] === t[r] || this.cs && compare(this.ns, this.ss[r], t[r])); r++) {
99
- if (this.cs) setSignal(this.cs[r], t[r]);
125
+ for (o = 0, c = Math.min(this.Wt, s); o < c && (this.xt[o] === t[o] || this.Jt && compare(this.Ht, this.xt[o], t[o])); o++) {
126
+ if (this.Jt) setSignal(this.Jt[o], t[o]);
100
127
  }
101
128
  // common suffix
102
- for (n = this.Xt - 1, o = s - 1; n >= r && o >= r && (this.ss[n] === t[o] || this.cs && compare(this.ns, this.ss[n], t[o])); n--,
103
- o--) {
104
- p[o] = this.hs[n];
105
- l[o] = this.rs[n];
106
- w && (w[o] = this.cs[n]);
107
- O && (O[o] = this.fs[n]);
129
+ for (c = this.Wt - 1, a = s - 1; c >= o && a >= o && (this.xt[c] === t[a] || this.Jt && compare(this.Ht, this.xt[c], t[a])); c--,
130
+ a--) {
131
+ O[a] = this.qt[c];
132
+ m[a] = this.zt[c];
133
+ r && (r[a] = this.Jt[c]);
134
+ n && (n[a] = this.Xt[c]);
108
135
  }
109
136
  // 0) prepare a map of all indices in newItems, scanning backwards so we encounter them in natural order
110
- f = new Map;
111
- u = new Array(o + 1);
112
- for (e = o; e >= r; e--) {
113
- a = t[e];
114
- c = this.ns ? this.ns(a) : a;
115
- i = f.get(c);
116
- u[e] = i === undefined ? -1 : i;
117
- f.set(c, e);
137
+ p = new Map;
138
+ w = new Array(a + 1);
139
+ for (e = a; e >= o; e--) {
140
+ f = t[e];
141
+ u = this.Ht ? this.Ht(f) : f;
142
+ i = p.get(u);
143
+ w[e] = i === undefined ? -1 : i;
144
+ p.set(u, e);
118
145
  }
119
- // 1) step through all old items and see if they can be found in the new set; if so, save them in a temp array and mark them moved; if not, exit them
120
- for (i = r; i <= n; i++) {
121
- a = this.ss[i];
122
- c = this.ns ? this.ns(a) : a;
123
- e = f.get(c);
146
+ // 1) step through all old items and see if they can be found in the new set; if so, save them in a temp array and mark them moved; if not, queue them for disposal at commit
147
+ for (i = o; i <= c; i++) {
148
+ f = this.xt[i];
149
+ u = this.Ht ? this.Ht(f) : f;
150
+ e = p.get(u);
124
151
  if (e !== undefined && e !== -1) {
125
- p[e] = this.hs[i];
126
- l[e] = this.rs[i];
127
- w && (w[e] = this.cs[i]);
128
- O && (O[e] = this.fs[i]);
129
- e = u[e];
130
- f.set(c, e);
131
- } else this.rs[i].dispose();
152
+ O[e] = this.qt[i];
153
+ m[e] = this.zt[i];
154
+ r && (r[e] = this.Jt[i]);
155
+ n && (n[e] = this.Xt[i]);
156
+ e = w[e];
157
+ p.set(u, e);
158
+ } else (l ??= []).push(this.zt[i]);
132
159
  }
133
- // 2) set all the new values, pulling from the temp array if copied, otherwise entering the new value
134
- for (e = r; e < s; e++) {
135
- if (e in p) {
136
- this.hs[e] = p[e];
137
- this.rs[e] = l[e];
138
- if (w) {
139
- this.cs[e] = w[e];
140
- setSignal(this.cs[e], t[e]);
141
- }
142
- if (O) {
143
- this.fs[e] = O[e];
144
- setSignal(this.fs[e], e);
145
- }
146
- } else {
147
- this.hs[e] = runWithOwner(this.rs[e] = createOwner(), h);
160
+ // 2) create new rows into the temp arrays; an abort disposes only these
161
+ try {
162
+ for (e = o; e < s; e++) {
163
+ if (e in O) continue;
164
+ (d ??= []).push(m[e] = createOwner());
165
+ O[e] = runWithOwner(m[e], h);
148
166
  }
167
+ } catch (t) {
168
+ if (d) for (i = 0; i < d.length; i++) d[i].dispose();
169
+ throw t;
149
170
  }
150
- // 3) in case the new set is shorter than the old, set the length of the mapped array
151
- this.hs = this.hs.slice(0, this.Xt = s);
152
- // 4) save a copy of the mapped items for the next update
153
- this.ss = t.slice(0);
171
+ // 3) commit: land positions, then dispose exited rows
172
+ for (e = o; e < s; e++) {
173
+ this.qt[e] = O[e];
174
+ this.zt[e] = m[e];
175
+ if (r) {
176
+ this.Jt[e] = r[e];
177
+ setSignal(this.Jt[e], t[e]);
178
+ }
179
+ if (n) {
180
+ this.Xt[e] = n[e];
181
+ setSignal(this.Xt[e], e);
182
+ }
183
+ }
184
+ if (l) for (i = 0; i < l.length; i++) l[i].dispose();
185
+ // 4) in case the new set is shorter than the old, set the length of the mapped array
186
+ this.qt = this.qt.slice(0, this.Wt = s);
187
+ // 5) save a copy of the mapped items for the next update
188
+ this.xt = t.slice(0);
154
189
  }
155
190
  });
156
- return this.hs;
191
+ return this.qt;
157
192
  }
158
193
 
159
194
  /**
@@ -172,89 +207,83 @@ function updateKeyedMap() {
172
207
  * @description https://docs.solidjs.com/reference/reactive-utilities/repeat
173
208
  */ function repeat(t, s, i) {
174
209
  const e = s;
175
- const h = computed(updateRepeat.bind({
176
- $t: createOwner(),
177
- Xt: 0,
178
- ls: 0,
179
- ws: t,
180
- es: e,
181
- rs: [],
182
- hs: [],
183
- Os: i?.from,
184
- ps: i?.fallback
185
- }));
186
- h.U &= ~CONFIG_AUTO_DISPOSE;
187
- return accessor(h);
210
+ const r = {
211
+ jt: createOwner(),
212
+ Wt: 0,
213
+ ts: 0,
214
+ ss: t,
215
+ $t: e,
216
+ zt: [],
217
+ qt: [],
218
+ es: i?.from,
219
+ Zt: i?.fallback
220
+ };
221
+ const n = computed(updateRepeat.bind(r));
222
+ // Same as mapArray: untracked reads inside the internal owner resolve via
223
+ // _parentComputed, so async reads in row callbacks register with the node
224
+ // (pending tracking + post-settle retry) instead of vanishing.
225
+ r.jt.Ct = n;
226
+ n.U &= ~CONFIG_AUTO_DISPOSE;
227
+ return accessor(n);
188
228
  }
189
229
 
230
+ // Same staged-commit discipline as `updateKeyedMap` (#2903): the retained
231
+ // window overlap is copied into fresh arrays, missing indexes are created
232
+ // into them, and `this` is only touched — including disposal of rows leaving
233
+ // the window — after every `_map` call succeeded. A NotReadyError mid-pass
234
+ // disposes only the owners this pass created and leaves prior state intact
235
+ // for the post-settle retry. The overlap math also subsumes the previous
236
+ // disjoint-window/front-clear/end-clear/shift special cases.
190
237
  function updateRepeat() {
191
- const t = this.ws();
192
- const s = this.Os?.() || 0;
193
- runWithOwner(this.$t, () => {
238
+ const t = this.ss();
239
+ const s = this.es?.() || 0;
240
+ runWithOwner(this.jt, () => {
194
241
  if (t === 0) {
195
- if (this.Xt !== 0) {
196
- this.$t.dispose(false);
197
- this.rs = [];
198
- this.hs = [];
199
- this.Xt = 0;
200
- // Reset offset to match the cleared data. Without this, a subsequent
201
- // nonzero render with a smaller `from` would enter the end-clear loop
202
- // with `prevTo = stale_offset + 0` > `to` and dispose `_nodes[-1]`
203
- // (#2767, repro 2).
204
- this.ls = 0;
242
+ if (this.Wt !== 0) {
243
+ this.jt.dispose(false);
244
+ this.zt = [];
245
+ this.qt = [];
246
+ this.Wt = 0;
247
+ // Reset offset to match the cleared data (#2767, repro 2).
248
+ this.ts = 0;
205
249
  }
206
- if (this.ps && !this.hs[0]) {
207
- // create fallback
208
- this.hs[0] = runWithOwner(this.rs[0] = createOwner(), this.ps);
250
+ if (this.Zt && !this.qt[0]) {
251
+ // an aborted fallback attempt leaves an owner without a mapping;
252
+ // dispose it before re-creating
253
+ this.zt[0]?.dispose();
254
+ this.qt[0] = runWithOwner(this.zt[0] = createOwner(), this.Zt);
209
255
  }
210
256
  return;
211
257
  }
212
258
  const i = s + t;
213
- const e = this.ls + this.Xt;
214
- // remove fallback
215
- if (this.Xt === 0 && this.rs[0]) this.rs[0].dispose();
216
- // Disjoint windows have no rows to retain; replace them wholesale.
217
- if (s >= e || i <= this.ls) {
218
- for (let t = 0; t < this.Xt; t++) this.rs[t].dispose();
219
- this.rs = new Array(t);
220
- this.hs = new Array(t);
221
- for (let i = 0; i < t; i++) this.hs[i] = runWithOwner(this.rs[i] = createOwner(), () => this.es(s + i));
222
- this.ls = s;
223
- this.Xt = t;
224
- return;
259
+ const e = this.ts + this.Wt;
260
+ // Retained overlap [keepStart, keepEnd) in global indexes; empty when the
261
+ // windows are disjoint or when coming from empty/fallback.
262
+ const r = Math.max(s, this.ts);
263
+ const n = Math.min(i, e);
264
+ const h = new Array(t);
265
+ const o = new Array(t);
266
+ for (let t = r; t < n; t++) {
267
+ o[t - s] = this.zt[t - this.ts];
268
+ h[t - s] = this.qt[t - this.ts];
225
269
  }
226
- // clear the end
227
- for (let t = i; t < e; t++) this.rs[t - this.ls].dispose();
228
- if (this.ls < s) {
229
- // clear beginning `_nodes` is local-indexed, so the rows leaving the
230
- // front sit at local positions 0..(from - _offset), clamped to old len.
231
- const t = s - this.ls;
232
- for (let s = 0; s < t && s < this.Xt; s++) this.rs[s].dispose();
233
- // shift indexes
234
- this.rs.splice(0, t);
235
- this.hs.splice(0, t);
236
- } else if (this.ls > s) {
237
- // shift indexes
238
- let i = e - this.ls - 1;
239
- let h = this.ls - s;
240
- this.rs.length = this.hs.length = t;
241
- while (i >= h) {
242
- this.rs[i] = this.rs[i - h];
243
- this.hs[i] = this.hs[i - h];
244
- i--;
245
- }
246
- for (let t = 0; t < h; t++) {
247
- this.hs[t] = runWithOwner(this.rs[t] = createOwner(), () => this.es(t + s));
270
+ try {
271
+ for (let t = s; t < i; t++) {
272
+ if (t >= r && t < n) continue;
273
+ h[t - s] = runWithOwner(o[t - s] = createOwner(), () => this.$t(t));
248
274
  }
275
+ } catch (t) {
276
+ for (let t = s; t < i; t++) if ((t < r || t >= n) && o[t - s]) o[t - s].dispose();
277
+ throw t;
249
278
  }
250
- for (let t = e; t < i; t++) {
251
- this.hs[t - s] = runWithOwner(this.rs[t - s] = createOwner(), () => this.es(t));
252
- }
253
- this.hs = this.hs.slice(0, t);
254
- this.ls = s;
255
- this.Xt = t;
279
+ // commit: dispose the previous fallback or the rows leaving the window
280
+ if (this.Wt === 0) this.zt[0]?.dispose(); else for (let t = this.ts; t < e; t++) if (t < s || t >= i) this.zt[t - this.ts].dispose();
281
+ this.qt = h;
282
+ this.zt = o;
283
+ this.ts = s;
284
+ this.Wt = t;
256
285
  });
257
- return this.hs;
286
+ return this.qt;
258
287
  }
259
288
 
260
289
  function compare(t, s, i) {
@@ -4,7 +4,7 @@ import { cleanup, createRoot, getOwner, dispose } from "./core/owner.js";
4
4
 
5
5
  import { globalQueue } from "./core/scheduler.js";
6
6
 
7
- import { CONFIG_CHILDREN_FORBIDDEN, EFFECT_USER, $REFRESH, CONFIG_AUTO_DISPOSE } from "./core/constants.js";
7
+ import { CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, EFFECT_USER, $REFRESH } from "./core/constants.js";
8
8
 
9
9
  import "./core/invariants.js";
10
10