@solidjs/signals 2.0.0-beta.29 → 2.0.0-beta.30

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.
@@ -1,4 +1,4 @@
1
- import { REACTIVE_IN_HEAP, EFFECT_TRACKED, EFFECT_USER, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_RECOMPUTING_DEPS, REACTIVE_MANUAL_WRITE, REACTIVE_ZOMBIE, REACTIVE_CHECK, REACTIVE_DIRTY } from "./constants.js";
1
+ import { REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, EFFECT_TRACKED, EFFECT_USER, REACTIVE_RECOMPUTING_DEPS, REACTIVE_MANUAL_WRITE, REACTIVE_ZOMBIE, REACTIVE_CHECK, REACTIVE_DIRTY } from "./constants.js";
2
2
 
3
3
  import { zombieQueue, dirtyQueue } from "./scheduler.js";
4
4
 
@@ -1,4 +1,4 @@
1
- import { EFFECT_RENDER, EFFECT_USER, STATUS_PENDING, REACTIVE_DISPOSED, REACTIVE_ZOMBIE, NOT_PENDING, EFFECT_TRACKED, CONFIG_IN_SNAPSHOT_SCOPE, REACTIVE_SNAPSHOT_STALE, REACTIVE_OPTIMISTIC_DIRTY, REACTIVE_REASK, REACTIVE_MANUAL_WRITE, STATUS_UNINITIALIZED } from "./constants.js";
1
+ import { EFFECT_RENDER, EFFECT_USER, STATUS_PENDING, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_DISPOSED, REACTIVE_ZOMBIE, NOT_PENDING, EFFECT_TRACKED, CONFIG_IN_SNAPSHOT_SCOPE, REACTIVE_SNAPSHOT_STALE, REACTIVE_OPTIMISTIC_DIRTY, REACTIVE_REASK, REACTIVE_MANUAL_WRITE, STATUS_UNINITIALIZED } from "./constants.js";
2
2
 
3
3
  import { currentOptimisticLane } from "./core.js";
4
4
 
@@ -6,7 +6,7 @@ import { DEV } from "./dev.js";
6
6
 
7
7
  import { NotReadyError } from "./error.js";
8
8
 
9
- import { runHeap, enqueueSub } from "./heap.js";
9
+ import { runHeap, deleteFromHeap, enqueueSub } from "./heap.js";
10
10
 
11
11
  import { activeLanes, assignOrMergeLane, findLane } from "./lanes.js";
12
12
 
@@ -30,6 +30,15 @@ const zombieQueue = {
30
30
  EE: 0
31
31
  };
32
32
 
33
+ /** runHeap callback that discards a queued zombie recompute instead of running
34
+ * it: unlink pure recompute entries; strip just the recompute bit from dirtied
35
+ * height-adjust entries so their height work still happens. */ function cancelZombieRecompute(e) {
36
+ if (e.se & REACTIVE_IN_HEAP_HEIGHT) e.se &= -12; else {
37
+ deleteFromHeap(e, zombieQueue);
38
+ e.se &= -4;
39
+ }
40
+ }
41
+
33
42
  let clock = 0;
34
43
 
35
44
  let activeTransition = null;
@@ -108,7 +117,7 @@ function setProjectionWriteActive(e) {
108
117
  cn: new Set,
109
118
  ie: [],
110
119
  yt: {
111
- gt: [ [], [] ],
120
+ bt: [ [], [] ],
112
121
  vt: []
113
122
  },
114
123
  fn: false,
@@ -150,7 +159,7 @@ function schedule() {
150
159
  }
151
160
  if (scheduled) return;
152
161
  scheduled = true;
153
- if (!syncDepth && !globalQueue.bt && !projectionWriteActive) queueMicrotask(flush);
162
+ if (!syncDepth && !globalQueue.gt && !projectionWriteActive) queueMicrotask(flush);
154
163
  }
155
164
 
156
165
  /**
@@ -185,7 +194,7 @@ let queueRunToken = 0;
185
194
 
186
195
  class Queue {
187
196
  ve=null;
188
- gt=[ [], [] ];
197
+ bt=[ [], [] ];
189
198
  vt=[];
190
199
  kt=0;
191
200
  created=clock;
@@ -205,9 +214,9 @@ class Queue {
205
214
  return false;
206
215
  }
207
216
  run(e) {
208
- if (this.gt[e - 1].length) {
209
- const t = this.gt[e - 1];
210
- this.gt[e - 1] = [];
217
+ if (this.bt[e - 1].length) {
218
+ const t = this.bt[e - 1];
219
+ this.bt[e - 1] = [];
211
220
  runQueue(t, e);
212
221
  }
213
222
  // Effects run here can dispose owners, and disposal removes queues from
@@ -239,21 +248,21 @@ class Queue {
239
248
  const i = findLane(currentOptimisticLane);
240
249
  i.rn[e - 1].push(t);
241
250
  } else {
242
- this.gt[e - 1].push(t);
251
+ this.bt[e - 1].push(t);
243
252
  }
244
253
  }
245
254
  schedule();
246
255
  }
247
256
  stashQueues(e) {
248
- e.gt[0].push(...this.gt[0]);
249
- e.gt[1].push(...this.gt[1]);
250
- this.gt = [ [], [] ];
257
+ e.bt[0].push(...this.bt[0]);
258
+ e.bt[1].push(...this.bt[1]);
259
+ this.bt = [ [], [] ];
251
260
  for (let t = 0; t < this.vt.length; t++) {
252
261
  let i = this.vt[t];
253
262
  let n = e.vt[t];
254
263
  if (!n) {
255
264
  n = {
256
- gt: [ [], [] ],
265
+ bt: [ [], [] ],
257
266
  vt: []
258
267
  };
259
268
  e.vt[t] = n;
@@ -262,8 +271,8 @@ class Queue {
262
271
  }
263
272
  }
264
273
  restoreQueues(e) {
265
- this.gt[0].push(...e.gt[0]);
266
- this.gt[1].push(...e.gt[1]);
274
+ this.bt[0].push(...e.bt[0]);
275
+ this.bt[1].push(...e.bt[1]);
267
276
  for (let t = 0; t < e.vt.length; t++) {
268
277
  const i = e.vt[t];
269
278
  let n = this.vt[t];
@@ -273,7 +282,7 @@ class Queue {
273
282
  }
274
283
 
275
284
  class GlobalQueue extends Queue {
276
- bt=false;
285
+ gt=false;
277
286
  // The current transaction-shaped batch: a plain ambient batch while no
278
287
  // transition is active, the active transition itself after initTransition.
279
288
  m=createBatch();
@@ -311,7 +320,7 @@ class GlobalQueue extends Queue {
311
320
  static Pt=null;
312
321
  static $e=null;
313
322
  static k=null;
314
- static Lt=null;
323
+ static Gt=null;
315
324
  // Optimistic-engine hooks (wired by core/optimistic.ts via
316
325
  // installOptimisticEngine(), called from verdict.ts / createOptimistic /
317
326
  // createOptimisticStore — every module that can create optimistic state).
@@ -332,8 +341,8 @@ class GlobalQueue extends Queue {
332
341
  static Ke=null;
333
342
  static Nn=null;
334
343
  flush() {
335
- if (this.bt) return;
336
- this.bt = true;
344
+ if (this.gt) return;
345
+ this.gt = true;
337
346
  try {
338
347
  if (false) ;
339
348
  runHeap(dirtyQueue, GlobalQueue.Ce);
@@ -341,7 +350,15 @@ class GlobalQueue extends Queue {
341
350
  const e = transitionComplete(activeTransition);
342
351
  if (!e) {
343
352
  const e = activeTransition;
344
- runHeap(zombieQueue, GlobalQueue.Ce);
353
+ // When the parking batch IS the transition, all of its writes commit
354
+ // only with it — every zombie recompute they queued would run against
355
+ // a world the zombie never displays (zombies render mainline until
356
+ // commit), so cancel them instead of running them. Only an ambient
357
+ // batch's mainline writes (the #2916 shape below) legitimately reach
358
+ // zombies here. Height-adjust entries still process normally: a
359
+ // dirtied one keeps its height flag and falls through to runHeap's
360
+ // adjustHeight path on the next pass of the bucket.
361
+ runHeap(zombieQueue, this.m === e ? cancelZombieRecompute : GlobalQueue.Ce);
345
362
  // Detach: the stashed transition keeps its batch; ambient work that
346
363
  // follows lands in a fresh one. If the batch is already a separate
347
364
  // ambient one — action done() restored activeTransition without
@@ -408,7 +425,7 @@ class GlobalQueue extends Queue {
408
425
  if (false && !scheduled && !activeTransition && transitions.size === 0 && activeLanes.size === 0) ;
409
426
  if (false) ;
410
427
  } finally {
411
- this.bt = false;
428
+ this.gt = false;
412
429
  }
413
430
  }
414
431
  notify(e, t, i, n) {
@@ -644,7 +661,7 @@ function flush(e) {
644
661
  }
645
662
  }
646
663
  }
647
- if (globalQueue.bt) {
664
+ if (globalQueue.gt) {
648
665
  return;
649
666
  }
650
667
  if (halted) return;
@@ -353,6 +353,6 @@ GlobalQueue.$e = applyReask;
353
353
 
354
354
  GlobalQueue.k = repollDownstreamVerdicts;
355
355
 
356
- GlobalQueue.Lt = witnessAffects;
356
+ GlobalQueue.Gt = witnessAffects;
357
357
 
358
358
  export { isPending, latest };
package/dist/prod/map.js CHANGED
@@ -27,12 +27,12 @@ function mapArray(t, s, i) {
27
27
  Mt: [],
28
28
  Kt: n,
29
29
  xt: [],
30
- Gt: [],
31
- Ut: e,
32
- $t: e || i?.keyed === false ? [] : undefined,
33
- qt: r && i?.keyed !== false ? [] : undefined,
34
- zt: i?.keyed === false,
35
- Bt: i?.fallback
30
+ Ut: [],
31
+ $t: e,
32
+ qt: e || i?.keyed === false ? [] : undefined,
33
+ zt: r && i?.keyed !== false ? [] : undefined,
34
+ Bt: i?.keyed === false,
35
+ Ht: i?.fallback
36
36
  };
37
37
  const o = computed(updateKeyedMap.bind(h));
38
38
  // Untracked reads inside the internal owner resolve via _parentComputed; routing
@@ -63,14 +63,14 @@ function updateKeyedMap() {
63
63
  let i, e, r, n,
64
64
  // Mappers write freshly-created row/index signals into the STAGE
65
65
  // arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
66
- h = this.$t ? this.zt ? () => {
66
+ h = this.qt ? this.Bt ? () => {
67
67
  r[e] = signal(t[e], pureOptions);
68
68
  return this.Kt(accessor(r[e]), e);
69
69
  } : () => {
70
70
  r[e] = signal(t[e], pureOptions);
71
71
  n && (n[e] = signal(e, pureOptions));
72
72
  return this.Kt(accessor(r[e]), n ? accessor(n[e]) : undefined);
73
- } : this.qt ? () => {
73
+ } : this.zt ? () => {
74
74
  const s = t[e];
75
75
  n[e] = signal(e, pureOptions);
76
76
  return this.Kt(s, accessor(n[e]));
@@ -82,26 +82,26 @@ function updateKeyedMap() {
82
82
  if (s === 0) {
83
83
  if (this.jt !== 0) {
84
84
  this.wt.dispose(false);
85
- this.Gt = [];
85
+ this.Ut = [];
86
86
  this.Mt = [];
87
87
  this.xt = [];
88
88
  this.jt = 0;
89
- this.$t && (this.$t = []);
90
89
  this.qt && (this.qt = []);
90
+ this.zt && (this.zt = []);
91
91
  }
92
- if (this.Bt && !this.xt[0]) {
92
+ if (this.Ht && !this.xt[0]) {
93
93
  // an aborted fallback attempt leaves an owner without a mapping;
94
94
  // dispose it before re-creating
95
- this.Gt[0]?.dispose();
96
- this.xt[0] = runWithOwner(this.Gt[0] = createOwner(), this.Bt);
95
+ this.Ut[0]?.dispose();
96
+ this.xt[0] = runWithOwner(this.Ut[0] = createOwner(), this.Ht);
97
97
  }
98
98
  }
99
99
  // fast path for new create
100
100
  else if (this.jt === 0) {
101
101
  const o = new Array(s);
102
102
  const c = new Array(s);
103
- r = this.$t && new Array(s);
104
- n = this.qt && new Array(s);
103
+ r = this.qt && new Array(s);
104
+ n = this.zt && new Array(s);
105
105
  try {
106
106
  for (e = 0; e < s; e++) o[e] = runWithOwner(c[e] = createOwner(), h);
107
107
  } catch (t) {
@@ -109,23 +109,23 @@ function updateKeyedMap() {
109
109
  throw t;
110
110
  }
111
111
  // commit
112
- if (this.Gt[0]) this.Gt[0].dispose();
112
+ if (this.Ut[0]) this.Ut[0].dispose();
113
113
  // previous fallback
114
114
  this.xt = o;
115
- this.Gt = c;
116
- r && (this.$t = r);
117
- n && (this.qt = n);
115
+ this.Ut = c;
116
+ r && (this.qt = r);
117
+ n && (this.zt = n);
118
118
  this.Mt = t.slice(0);
119
119
  this.jt = s;
120
120
  } else {
121
121
  let o, c, a, f, u, p, w, l, d;
122
122
  // skip common prefix
123
- for (o = 0, c = Math.min(this.jt, s); o < c && (this.Mt[o] === t[o] || this.$t && compare(this.Ut, this.Mt[o], t[o])); o++) {
124
- if (this.$t) setSignal(this.$t[o], t[o]);
123
+ for (o = 0, c = Math.min(this.jt, s); o < c && (this.Mt[o] === t[o] || this.qt && compare(this.$t, this.Mt[o], t[o])); o++) {
124
+ if (this.qt) setSignal(this.qt[o], t[o]);
125
125
  }
126
126
  // skip common suffix — counted only; retained entries land in one pass
127
127
  // at commit instead of being staged and copied twice
128
- for (c = this.jt - 1, a = s - 1; c >= o && a >= o && (this.Mt[c] === t[a] || this.$t && compare(this.Ut, this.Mt[c], t[a])); c--,
128
+ for (c = this.jt - 1, a = s - 1; c >= o && a >= o && (this.Mt[c] === t[a] || this.qt && compare(this.$t, this.Mt[c], t[a])); c--,
129
129
  a--) ;
130
130
  // no structural change (every position matched in place at equal
131
131
  // length — the common post-reconcile shape): keep the same mapped
@@ -137,15 +137,15 @@ function updateKeyedMap() {
137
137
  const O = s - this.jt;
138
138
  const m = new Array(s);
139
139
  const _ = new Array(s);
140
- r = this.$t ? new Array(s) : undefined;
141
- n = this.qt ? new Array(s) : undefined;
140
+ r = this.qt ? new Array(s) : undefined;
141
+ n = this.zt ? new Array(s) : undefined;
142
142
  // 0) prepare a map of all indices in the changed window of newItems,
143
143
  // scanning backwards so we encounter them in natural order
144
144
  p = new Map;
145
145
  w = new Array(a + 1);
146
146
  for (e = a; e >= o; e--) {
147
147
  f = t[e];
148
- u = this.Ut ? this.Ut(f) : f;
148
+ u = this.$t ? this.$t(f) : f;
149
149
  i = p.get(u);
150
150
  w[e] = i === undefined ? -1 : i;
151
151
  p.set(u, e);
@@ -155,16 +155,16 @@ function updateKeyedMap() {
155
155
  // queue them for disposal at commit
156
156
  for (i = o; i <= c; i++) {
157
157
  f = this.Mt[i];
158
- u = this.Ut ? this.Ut(f) : f;
158
+ u = this.$t ? this.$t(f) : f;
159
159
  e = p.get(u);
160
160
  if (e !== undefined && e !== -1) {
161
161
  m[e] = this.xt[i];
162
- _[e] = this.Gt[i];
163
- r && (r[e] = this.$t[i]);
164
- n && (n[e] = this.qt[i]);
162
+ _[e] = this.Ut[i];
163
+ r && (r[e] = this.qt[i]);
164
+ n && (n[e] = this.zt[i]);
165
165
  e = w[e];
166
166
  p.set(u, e);
167
- } else (l ??= []).push(this.Gt[i]);
167
+ } else (l ??= []).push(this.Ut[i]);
168
168
  }
169
169
  // 2) create new rows into the temp arrays; an abort disposes only these
170
170
  try {
@@ -182,9 +182,9 @@ function updateKeyedMap() {
182
182
  // change propagation), then dispose exited rows
183
183
  for (i = 0; i < o; i++) {
184
184
  m[i] = this.xt[i];
185
- _[i] = this.Gt[i];
186
- r && (r[i] = this.$t[i]);
187
- n && (n[i] = this.qt[i]);
185
+ _[i] = this.Ut[i];
186
+ r && (r[i] = this.qt[i]);
187
+ n && (n[i] = this.zt[i]);
188
188
  }
189
189
  for (e = o; e <= a; e++) {
190
190
  if (r) setSignal(r[e], t[e]);
@@ -192,20 +192,20 @@ function updateKeyedMap() {
192
192
  }
193
193
  for (e = a + 1; e < s; e++) {
194
194
  m[e] = this.xt[e - O];
195
- _[e] = this.Gt[e - O];
195
+ _[e] = this.Ut[e - O];
196
196
  if (r) {
197
- r[e] = this.$t[e - O];
197
+ r[e] = this.qt[e - O];
198
198
  setSignal(r[e], t[e]);
199
199
  }
200
200
  if (n) {
201
- n[e] = this.qt[e - O];
201
+ n[e] = this.zt[e - O];
202
202
  if (O !== 0) setSignal(n[e], e);
203
203
  }
204
204
  }
205
205
  this.xt = m;
206
- this.Gt = _;
207
- r && (this.$t = r);
208
- n && (this.qt = n);
206
+ this.Ut = _;
207
+ r && (this.qt = r);
208
+ n && (this.zt = n);
209
209
  this.jt = s;
210
210
  // save a copy of the mapped items for the next update
211
211
  this.Mt = t.slice(0);
@@ -234,13 +234,13 @@ function updateKeyedMap() {
234
234
  const r = {
235
235
  wt: createOwner(),
236
236
  jt: 0,
237
- Ht: 0,
238
- Jt: t,
237
+ Jt: 0,
238
+ Lt: t,
239
239
  Kt: e,
240
- Gt: [],
240
+ Ut: [],
241
241
  xt: [],
242
242
  Vt: i?.from,
243
- Bt: i?.fallback
243
+ Ht: i?.fallback
244
244
  };
245
245
  const n = computed(updateRepeat.bind(r));
246
246
  // Same as mapArray: untracked reads inside the internal owner resolve via
@@ -259,37 +259,37 @@ function updateKeyedMap() {
259
259
  // for the post-settle retry. The overlap math also subsumes the previous
260
260
  // disjoint-window/front-clear/end-clear/shift special cases.
261
261
  function updateRepeat() {
262
- const t = this.Jt();
262
+ const t = this.Lt();
263
263
  const s = this.Vt?.() || 0;
264
264
  runWithOwner(this.wt, () => {
265
265
  if (t === 0) {
266
266
  if (this.jt !== 0) {
267
267
  this.wt.dispose(false);
268
- this.Gt = [];
268
+ this.Ut = [];
269
269
  this.xt = [];
270
270
  this.jt = 0;
271
271
  // Reset offset to match the cleared data (#2767, repro 2).
272
- this.Ht = 0;
272
+ this.Jt = 0;
273
273
  }
274
- if (this.Bt && !this.xt[0]) {
274
+ if (this.Ht && !this.xt[0]) {
275
275
  // an aborted fallback attempt leaves an owner without a mapping;
276
276
  // dispose it before re-creating
277
- this.Gt[0]?.dispose();
278
- this.xt[0] = runWithOwner(this.Gt[0] = createOwner(), this.Bt);
277
+ this.Ut[0]?.dispose();
278
+ this.xt[0] = runWithOwner(this.Ut[0] = createOwner(), this.Ht);
279
279
  }
280
280
  return;
281
281
  }
282
282
  const i = s + t;
283
- const e = this.Ht + this.jt;
283
+ const e = this.Jt + this.jt;
284
284
  // Retained overlap [keepStart, keepEnd) in global indexes; empty when the
285
285
  // windows are disjoint or when coming from empty/fallback.
286
- const r = Math.max(s, this.Ht);
286
+ const r = Math.max(s, this.Jt);
287
287
  const n = Math.min(i, e);
288
288
  const h = new Array(t);
289
289
  const o = new Array(t);
290
290
  for (let t = r; t < n; t++) {
291
- o[t - s] = this.Gt[t - this.Ht];
292
- h[t - s] = this.xt[t - this.Ht];
291
+ o[t - s] = this.Ut[t - this.Jt];
292
+ h[t - s] = this.xt[t - this.Jt];
293
293
  }
294
294
  try {
295
295
  for (let t = s; t < i; t++) {
@@ -301,10 +301,10 @@ function updateRepeat() {
301
301
  throw t;
302
302
  }
303
303
  // commit: dispose the previous fallback or the rows leaving the window
304
- if (this.jt === 0) this.Gt[0]?.dispose(); else for (let t = this.Ht; t < e; t++) if (t < s || t >= i) this.Gt[t - this.Ht].dispose();
304
+ if (this.jt === 0) this.Ut[0]?.dispose(); else for (let t = this.Jt; t < e; t++) if (t < s || t >= i) this.Ut[t - this.Jt].dispose();
305
305
  this.xt = h;
306
- this.Gt = o;
307
- this.Ht = s;
306
+ this.Ut = o;
307
+ this.Jt = s;
308
308
  this.jt = t;
309
309
  });
310
310
  return this.xt;
@@ -464,11 +464,11 @@ o) {
464
464
  // Callers guard on `pendingCheckActive`, which only flips inside
465
465
  // isPending() — the verdict layer is loaded and its hook installed.
466
466
  const r = e[STORE_NODE]?.[$AFFECTS];
467
- if (r?.t) GlobalQueue.Lt(r);
467
+ if (r?.t) GlobalQueue.Gt(r);
468
468
  if (affectsScopes.size) {
469
469
  const n = e[STORE_VALUE];
470
470
  for (const [e, o] of affectsScopes) {
471
- if (e !== r && e.t && o.scope.has(n) && (o.key === undefined || o.key === t)) GlobalQueue.Lt(e);
471
+ if (e !== r && e.t && o.scope.has(n) && (o.key === undefined || o.key === t)) GlobalQueue.Gt(e);
472
472
  }
473
473
  }
474
474
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidjs/signals",
3
- "version": "2.0.0-beta.29",
3
+ "version": "2.0.0-beta.30",
4
4
  "description": "Solid's reactive primitives: signals, memos, effects, stores, and async-aware computations.",
5
5
  "author": "Ryan Carniato",
6
6
  "license": "MIT",