@solidjs/signals 2.0.0-rc.1 → 2.0.0-rc.2

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 (50) hide show
  1. package/dist/dev.js +1661 -361
  2. package/dist/node.cjs +1939 -1331
  3. package/dist/prod/affects.js +16 -16
  4. package/dist/prod/boundaries.js +90 -90
  5. package/dist/prod/core/action.js +3 -3
  6. package/dist/prod/core/async.js +74 -72
  7. package/dist/prod/core/constants.js +39 -1
  8. package/dist/prod/core/core.js +332 -224
  9. package/dist/prod/core/effect.js +56 -56
  10. package/dist/prod/core/external.js +4 -4
  11. package/dist/prod/core/graph.js +65 -54
  12. package/dist/prod/core/heap.js +52 -44
  13. package/dist/prod/core/invariants.js +3 -2
  14. package/dist/prod/core/lanes.js +41 -34
  15. package/dist/prod/core/optimistic.js +63 -60
  16. package/dist/prod/core/owner.js +97 -96
  17. package/dist/prod/core/scheduler.js +243 -194
  18. package/dist/prod/core/verdict.js +184 -77
  19. package/dist/prod/map.js +104 -104
  20. package/dist/prod/signals.js +1 -1
  21. package/dist/prod/store/next/optimistic.js +31 -23
  22. package/dist/prod/store/next/projection.js +3 -3
  23. package/dist/prod/store/next/reconcile.js +78 -74
  24. package/dist/prod/store/next/store.js +357 -90
  25. package/dist/prod/store/store.js +7 -7
  26. package/dist/types/core/attribution-hooks.d.ts +52 -0
  27. package/dist/types/core/attribution.d.ts +186 -0
  28. package/dist/types/core/constants.d.ts +26 -0
  29. package/dist/types/core/core.d.ts +8 -1
  30. package/dist/types/core/dev.d.ts +20 -3
  31. package/dist/types/core/graph.d.ts +1 -0
  32. package/dist/types/core/lanes.d.ts +4 -16
  33. package/dist/types/core/scheduler.d.ts +8 -0
  34. package/dist/types/core/types.d.ts +85 -41
  35. package/dist/types/store/next/projection.d.ts +0 -16
  36. package/dist/types/store/next/store.d.ts +6 -0
  37. package/dist/types/store/next/target.d.ts +18 -0
  38. package/dist/types-cjs/core/attribution-hooks.d.cts +52 -0
  39. package/dist/types-cjs/core/attribution.d.cts +186 -0
  40. package/dist/types-cjs/core/constants.d.cts +26 -0
  41. package/dist/types-cjs/core/core.d.cts +8 -1
  42. package/dist/types-cjs/core/dev.d.cts +20 -3
  43. package/dist/types-cjs/core/graph.d.cts +1 -0
  44. package/dist/types-cjs/core/lanes.d.cts +4 -16
  45. package/dist/types-cjs/core/scheduler.d.cts +8 -0
  46. package/dist/types-cjs/core/types.d.cts +85 -41
  47. package/dist/types-cjs/store/next/projection.d.cts +0 -16
  48. package/dist/types-cjs/store/next/store.d.cts +6 -0
  49. package/dist/types-cjs/store/next/target.d.cts +18 -0
  50. package/package.json +1 -1
@@ -1,11 +1,11 @@
1
1
  import { forEachDependent } from "./core/async.js";
2
2
 
3
+ import { ext } from "./core/core.js";
4
+
3
5
  import { $REFRESH, STATUS_PENDING } from "./core/constants.js";
4
6
 
5
7
  import { NotReadyError } from "./core/error.js";
6
8
 
7
- import "./core/core.js";
8
-
9
9
  import { GlobalQueue, globalQueue, schedule, shiftAffectsMarks } from "./core/scheduler.js";
10
10
 
11
11
  import "./core/verdict.js";
@@ -24,7 +24,7 @@ import { $TARGET, getStoreAffectsNodes } from "./store/store.js";
24
24
  * nothing is stored downstream and nothing can be stranded or stripped by
25
25
  * mid-window recomputes.
26
26
  */ function markAffects(e) {
27
- e.t = (e.t || 0) + 1;
27
+ ext(e).t = (e.o?.t || 0) + 1;
28
28
  shiftAffectsMarks(1);
29
29
  }
30
30
 
@@ -40,17 +40,17 @@ import { $TARGET, getStoreAffectsNodes } from "./store/store.js";
40
40
  * flush that would surface them, before effects run — verdict-only, netting
41
41
  * no visual change.
42
42
  */ function notifyMarkBoundaries(e) {
43
- if (!e.o && !e.u) return;
43
+ if (!e.u && !e.o?.l) return;
44
44
  const r = new NotReadyError(e);
45
- r.l = true;
45
+ r.i = true;
46
46
  const t = new Set;
47
47
  const visit = e => {
48
48
  if (t.has(e)) return;
49
49
  t.add(e);
50
50
  // Display consumers (render effects, boundary computeds) act on the
51
51
  // notification; descent stops there, exactly like the status rails.
52
- if (e.i) {
53
- e.i(STATUS_PENDING, r);
52
+ if (e.o?.A) {
53
+ e.o.A.call(e, STATUS_PENDING, r);
54
54
  return;
55
55
  }
56
56
  forEachDependent(e, visit);
@@ -68,10 +68,10 @@ import { $TARGET, getStoreAffectsNodes } from "./store/store.js";
68
68
  * earlier overlapping registration get covered, and dedup stops re-descent.
69
69
  */ function registerAffectsMark(e) {
70
70
  markAffects(e);
71
- globalQueue.m.A.push(e);
71
+ globalQueue.k.m.push(e);
72
72
  // Companions only exist once the verdict layer (isPending/latest) loaded;
73
73
  // without them there is no materialized verdict to poke.
74
- GlobalQueue.k !== null && GlobalQueue.k(e);
74
+ GlobalQueue.p !== null && GlobalQueue.p(e);
75
75
  notifyMarkBoundaries(e);
76
76
  schedule();
77
77
  }
@@ -83,10 +83,10 @@ import { $TARGET, getStoreAffectsNodes } from "./store/store.js";
83
83
  * setSignal would open a fresh override window that nothing settles).
84
84
  */ function releaseAffectsMark(e) {
85
85
  shiftAffectsMarks(-1);
86
- e.t--;
87
- if (!e.t) {
88
- GlobalQueue.k !== null && GlobalQueue.k(e, true);
89
- GlobalQueue.p?.(e);
86
+ e.o.t--;
87
+ if (!e.o.t) {
88
+ GlobalQueue.p !== null && GlobalQueue.p(e, true);
89
+ GlobalQueue.G?.(e);
90
90
  }
91
91
  }
92
92
 
@@ -103,11 +103,11 @@ import { $TARGET, getStoreAffectsNodes } from "./store/store.js";
103
103
  // Each call site is gated by state only this module creates (a non-empty
104
104
  // `_affectsNodes` batch, a live scope in the store's `affectsScopes`), so the
105
105
  // hooks are installed before the first time any of them can fire.
106
- GlobalQueue.G = releaseAffectsMarks;
106
+ GlobalQueue.M = releaseAffectsMarks;
107
107
 
108
- GlobalQueue.M = markAffects;
108
+ GlobalQueue.h = markAffects;
109
109
 
110
- GlobalQueue.h = releaseAffectsMark;
110
+ GlobalQueue.j = releaseAffectsMark;
111
111
 
112
112
  function affects(e, r) {
113
113
  const t = e?.[$TARGET];
@@ -1,4 +1,4 @@
1
- import { runWithOwner, signal, untrack, read, computed, setSignal, recompute } from "./core/core.js";
1
+ import { runWithOwner, signal, untrack, read, computed, setSignal, ext, recompute } from "./core/core.js";
2
2
 
3
3
  import { NotReadyError, unwrapStatusError } from "./core/error.js";
4
4
 
@@ -22,10 +22,10 @@ function boundaryComputed(e, t) {
22
22
  const r = computed(e, {
23
23
  lazy: true
24
24
  });
25
- r.i = (e, t) => {
25
+ ext(r).A = (e, t) => {
26
26
  // Use passed values if provided, otherwise read from node
27
27
  const n = e !== undefined ? e : r.S;
28
- const s = t !== undefined ? t : r._;
28
+ const s = t !== undefined ? t : r.o?._;
29
29
  // Notify both status dimensions like a render effect does; the queue chain
30
30
  // consumes this boundary's own type and forwards the remainder upward until
31
31
  // a boundary that handles it is found.
@@ -38,7 +38,7 @@ function boundaryComputed(e, t) {
38
38
  const o = n & ~r.R & (STATUS_PENDING | STATUS_ERROR);
39
39
  if (o) {
40
40
  r.S &= ~o;
41
- if (r._ === s && !(r.S & (STATUS_PENDING | STATUS_ERROR))) r._ = undefined;
41
+ if (r.o?._ === s && !(r.S & (STATUS_PENDING | STATUS_ERROR))) if (r.o !== null) r.o._ = undefined;
42
42
  }
43
43
  // An ERROR the chain could not deliver to any boundary is uncaught. The
44
44
  // scrub above already removed it from reader-visible state, so without
@@ -92,41 +92,41 @@ function setSlotState(e, t, r, n) {
92
92
  setSignal(e.D, n);
93
93
  if (isRevealController(e)) {
94
94
  if (!r && e.P === t) e.P = undefined;
95
- return e.j(r, n);
95
+ return e.B(r, n);
96
96
  }
97
- if (!r && e.B === t && e.W) e.B = undefined;
97
+ if (!r && e.W === t && e.L) e.W = undefined;
98
98
  }
99
99
 
100
100
  class RevealController {
101
- L;
102
101
  F;
103
- q=[];
102
+ q;
103
+ V=[];
104
104
  P;
105
105
  I=signal(false, {
106
106
  ownedWrite: true,
107
- V: true
107
+ H: true
108
108
  });
109
109
  D=signal(false, {
110
110
  ownedWrite: true,
111
- V: true
111
+ H: true
112
112
  });
113
- H=true;
114
113
  J=true;
115
- K=false;
114
+ K=true;
115
+ X=false;
116
116
  constructor(e, t) {
117
- this.L = e;
118
- this.F = t;
117
+ this.F = e;
118
+ this.q = t;
119
119
  }
120
- X(e) {
121
- for (let t = 0; t < this.q.length; t++) {
122
- const r = this.q[t];
123
- if ((isRevealController(r) ? r.P : r.B) !== this) continue;
120
+ Y(e) {
121
+ for (let t = 0; t < this.V.length; t++) {
122
+ const r = this.V[t];
123
+ if ((isRevealController(r) ? r.P : r.W) !== this) continue;
124
124
  if (e(r) === false) return false;
125
125
  }
126
126
  return true;
127
127
  }
128
128
  O() {
129
- return this.X(isSlotReady);
129
+ return this.Y(isSlotReady);
130
130
  }
131
131
  /**
132
132
  * "Minimally ready" = this group has something visible to show under its own policy.
@@ -135,12 +135,12 @@ class RevealController {
135
135
  * - `sequential`: the first owned slot is minimally ready (frontier can advance).
136
136
  * - `natural`: any owned slot is minimally ready.
137
137
  */ U() {
138
- const e = untrack(this.L);
139
- if (e === "together") return this.X(isSlotMinimallyReady);
138
+ const e = untrack(this.F);
139
+ if (e === "together") return this.Y(isSlotMinimallyReady);
140
140
  if (e === "natural") {
141
141
  let e = false;
142
142
  let t = false;
143
- this.X(r => {
143
+ this.Y(r => {
144
144
  e = true;
145
145
  if (isSlotMinimallyReady(r)) {
146
146
  t = true;
@@ -151,45 +151,45 @@ class RevealController {
151
151
  }
152
152
  // sequential: only the first owned slot matters.
153
153
  let t = true;
154
- this.X(e => {
154
+ this.Y(e => {
155
155
  t = isSlotMinimallyReady(e);
156
156
  return false;
157
157
  });
158
158
  return t;
159
159
  }
160
- Y(e) {
161
- if (this.q.includes(e)) return;
162
- this.q.push(e);
163
- const t = untrack(this.L);
164
- setSignal(e.I, true), setSignal(e.D, t === "sequential" ? !!untrack(this.F) : false);
165
- untrack(() => this.j());
166
- }
167
160
  Z(e) {
168
- const t = this.q.indexOf(e);
169
- if (t >= 0) this.q.splice(t, 1);
170
- untrack(() => this.j());
161
+ if (this.V.includes(e)) return;
162
+ this.V.push(e);
163
+ const t = untrack(this.F);
164
+ setSignal(e.I, true), setSignal(e.D, t === "sequential" ? !!untrack(this.q) : false);
165
+ untrack(() => this.B());
166
+ }
167
+ $(e) {
168
+ const t = this.V.indexOf(e);
169
+ if (t >= 0) this.V.splice(t, 1);
170
+ untrack(() => this.B());
171
171
  }
172
- j(e, t) {
173
- if (this.K) return;
174
- this.K = true;
175
- const r = this.H;
176
- const n = this.J;
172
+ B(e, t) {
173
+ if (this.X) return;
174
+ this.X = true;
175
+ const r = this.J;
176
+ const n = this.K;
177
177
  try {
178
- const r = e ?? read(this.I), n = untrack(this.L), s = n === "sequential" && !!untrack(this.F), i = t ?? s;
178
+ const r = e ?? read(this.I), n = untrack(this.F), s = n === "sequential" && !!untrack(this.q), i = t ?? s;
179
179
  if (r) {
180
180
  // Held by an outer group. Propagate the hold (and whatever collapsed policy
181
181
  // the outer asked for) down the whole subtree. Inner order is ignored while
182
182
  // held; it resumes once the outer releases us.
183
- this.X(e => setSlotState(e, this, true, i));
183
+ this.Y(e => setSlotState(e, this, true, i));
184
184
  } else if (n === "natural") {
185
185
  // Each child reveals based on its own readiness. A nested controller slot
186
186
  // is released to run its own order locally — we bypass setSlotState for it
187
187
  // so the parent backpointer survives for upward readiness notifications.
188
- this.X(e => {
188
+ this.Y(e => {
189
189
  if (isRevealController(e)) {
190
190
  setSignal(e.D, false);
191
191
  setSignal(e.I, false);
192
- e.j(false, false);
192
+ e.B(false, false);
193
193
  } else {
194
194
  setSlotState(e, this, !isSlotReady(e), false);
195
195
  }
@@ -200,11 +200,11 @@ class RevealController {
200
200
  // sequential's first slot being ready is minimally ready; natural having any
201
201
  // ready child is minimally ready. This lets `together` guarantee a single
202
202
  // cohesive reveal without waiting for every grandchild.
203
- const e = this.X(isSlotMinimallyReady);
204
- this.X(t => setSlotState(t, this, !e, false));
203
+ const e = this.Y(isSlotMinimallyReady);
204
+ this.Y(t => setSlotState(t, this, !e, false));
205
205
  } else {
206
206
  let e = false;
207
- this.X(t => {
207
+ this.Y(t => {
208
208
  if (e) return setSlotState(t, this, true, s);
209
209
  if (isSlotReady(t)) return setSlotState(t, this, false, false);
210
210
  e = true;
@@ -217,60 +217,60 @@ class RevealController {
217
217
  if (isRevealController(t)) {
218
218
  setSignal(t.D, false);
219
219
  setSignal(t.I, false);
220
- t.j(false, false);
220
+ t.B(false, false);
221
221
  } else {
222
222
  setSlotState(t, this, true, false);
223
223
  }
224
224
  });
225
225
  }
226
226
  } finally {
227
- this.H = this.O();
228
- this.J = this.U();
229
- this.K = false;
227
+ this.J = this.O();
228
+ this.K = this.U();
229
+ this.X = false;
230
230
  }
231
- if (this.P && (r !== this.H || n !== this.J)) this.P.j();
231
+ if (this.P && (r !== this.J || n !== this.K)) this.P.B();
232
232
  }
233
233
  }
234
234
 
235
235
  class CollectionQueue extends Queue {
236
- $;
237
- v=new Set;
238
236
  ee;
237
+ v=new Set;
238
+ te;
239
239
  N=true;
240
240
  I=signal(false, {
241
241
  ownedWrite: true,
242
- V: true
242
+ H: true
243
243
  });
244
244
  _;
245
245
  D=signal(false, {
246
246
  ownedWrite: true,
247
- V: true
247
+ H: true
248
248
  });
249
- B;
250
- W=false;
251
- te;
252
- re=ON_INIT;
249
+ W;
250
+ L=false;
251
+ re;
252
+ ne=ON_INIT;
253
253
  constructor(e) {
254
254
  super();
255
- this.$ = e;
255
+ this.ee = e;
256
256
  }
257
257
  run(e) {
258
258
  if (!e || read(this.I) && (!_revealUsed || read(this.D))) return;
259
259
  return super.run(e);
260
260
  }
261
261
  notify(e, t, r, n) {
262
- if (!(t & this.$)) return super.notify(e, t, r, n);
263
- if (this.W && this.te) {
262
+ if (!(t & this.ee)) return super.notify(e, t, r, n);
263
+ if (this.L && this.re) {
264
264
  const e = untrack(() => {
265
265
  try {
266
- return this.te();
266
+ return this.re();
267
267
  } catch {
268
268
  return ON_INIT;
269
269
  }
270
270
  });
271
- if (e !== this.re) {
272
- this.re = e;
273
- this.W = false;
271
+ if (e !== this.ne) {
272
+ this.ne = e;
273
+ this.L = false;
274
274
  this.v.clear();
275
275
  }
276
276
  }
@@ -284,47 +284,47 @@ class CollectionQueue extends Queue {
284
284
  // dimension, while a status already caught by an inner boundary arrives with
285
285
  // its dimension consumed from the mask and is correctly not re-routed
286
286
  // (the Loading > Errored > content composition escape, #2856).
287
- if (this.$ & STATUS_PENDING && this.W) return super.notify(e, t, r, n);
288
- if (r & this.$) {
287
+ if (this.ee & STATUS_PENDING && this.L) return super.notify(e, t, r, n);
288
+ if (r & this.ee) {
289
289
  this.N = true;
290
- const t = n?.source || e._?.source;
290
+ const t = n?.source || e.o?._?.source;
291
291
  if (t) {
292
292
  const e = this.v.size === 0;
293
293
  this.v.add(t);
294
294
  if (e) setSignal(this.I, true);
295
- if (this.$ & STATUS_ERROR) {
296
- setSignal(this._, unwrapStatusError(t._));
295
+ if (this.ee & STATUS_ERROR) {
296
+ setSignal(this._, unwrapStatusError(t.o?._));
297
297
  }
298
298
  }
299
299
  }
300
- t &= ~this.$;
300
+ t &= ~this.ee;
301
301
  return t ? super.notify(e, t, r, n) : true;
302
302
  }
303
- ne() {
303
+ se() {
304
304
  for (const e of this.v) {
305
305
  // A source with a live affects() mark holds display state for the
306
306
  // mark's lifetime (the visual channel): the marked node carries no
307
307
  // status of its own, so the count is the liveness test. The release
308
308
  // sweep (finalizePureQueue after mark release) re-runs this check.
309
- if (e.se & REACTIVE_DISPOSED || !e.t && !(e.S & this.$) && !(this.$ & STATUS_ERROR && e.S & STATUS_PENDING)) this.v.delete(e);
309
+ if (e.ie & REACTIVE_DISPOSED || !e.o?.t && !(e.S & this.ee) && !(this.ee & STATUS_ERROR && e.S & STATUS_PENDING)) this.v.delete(e);
310
310
  }
311
311
  if (!this.v.size) {
312
- if (this.$ & STATUS_PENDING && this.N && !this.W && this.ee) {
313
- this.N = !!(this.ee.S & this.$);
312
+ if (this.ee & STATUS_PENDING && this.N && !this.L && this.te) {
313
+ this.N = !!(this.te.S & this.ee);
314
314
  } else {
315
315
  this.N = false;
316
316
  }
317
317
  if (!this.N) {
318
318
  setSignal(this.I, false);
319
- if (this.te) {
319
+ if (this.re) {
320
320
  try {
321
- this.re = untrack(() => this.te());
321
+ this.ne = untrack(() => this.re());
322
322
  } catch {
323
323
  /* value not yet committed — _prevOn stays stale, next notify will reset */}
324
324
  }
325
325
  }
326
326
  }
327
- if (_revealUsed) this.B?.j();
327
+ if (_revealUsed) this.W?.B();
328
328
  }
329
329
  }
330
330
 
@@ -334,10 +334,10 @@ function createCollectionBoundary(e, t, r, n) {
334
334
  const i = new CollectionQueue(e);
335
335
  if (e === STATUS_ERROR) i._ = signal(undefined, {
336
336
  ownedWrite: true,
337
- V: true
337
+ H: true
338
338
  });
339
- if (n) i.te = n;
340
- const o = i.ee = createBoundChildren(s, t, i, e);
339
+ if (n) i.re = n;
340
+ const o = i.te = createBoundChildren(s, t, i, e);
341
341
  // Prime source tracking so reveal registration sees pending sources.
342
342
  untrack(() => {
343
343
  let t = false;
@@ -346,18 +346,18 @@ function createCollectionBoundary(e, t, r, n) {
346
346
  } catch (e) {
347
347
  if (e instanceof NotReadyError) t = true; else throw e;
348
348
  }
349
- i.N = t || !!(o.S & e) || o._ instanceof NotReadyError;
349
+ i.N = t || !!(o.S & e) || o.o?._ instanceof NotReadyError;
350
350
  });
351
351
  const l = _revealUsed && e === STATUS_PENDING ? getContext(RevealControllerContext) : null;
352
352
  if (l) {
353
- i.B = l;
354
- l.Y(i);
355
- cleanup(() => l.Z(i));
353
+ i.W = l;
354
+ l.Z(i);
355
+ cleanup(() => l.$(i));
356
356
  }
357
357
  return accessor(computed(() => {
358
358
  if (!read(i.I)) {
359
359
  const e = read(o);
360
- if (!untrack(() => read(i.I))) return i.W = true, e;
360
+ if (!untrack(() => read(i.I))) return i.L = true, e;
361
361
  }
362
362
  // Collapsed reveal slots suppress their own output entirely; the
363
363
  // renderer treats the hole as empty, so the cast never leaks to users
@@ -370,7 +370,7 @@ function createCollectionBoundary(e, t, r, n) {
370
370
  // by snapshot capture. The tree no longer carries foreign status flags, so
371
371
  // capture can't rely on PENDING to skip this node the way it used to.
372
372
  {
373
- V: true
373
+ H: true
374
374
  }));
375
375
  }
376
376
 
@@ -481,12 +481,12 @@ function createCollectionBoundary(e, t, r, n) {
481
481
  computed(() => {
482
482
  s();
483
483
  i();
484
- o.j();
484
+ o.B();
485
485
  });
486
486
  if (n) {
487
487
  o.P = n;
488
- n.Y(o);
489
- cleanup(() => n.Z(o));
488
+ n.Z(o);
489
+ cleanup(() => n.$(o));
490
490
  }
491
491
  return t;
492
492
  });
@@ -78,11 +78,11 @@ function restoreTransition(e, r) {
78
78
  const i = e(...r);
79
79
  globalQueue.initTransition();
80
80
  let o = activeTransition;
81
- o.ie.push(i);
81
+ o.oe.push(i);
82
82
  const done = (e, r, u = false) => {
83
83
  o = currentTransition(o);
84
- const s = o.ie.indexOf(i);
85
- if (s >= 0) o.ie.splice(s, 1);
84
+ const s = o.oe.indexOf(i);
85
+ if (s >= 0) o.oe.splice(s, 1);
86
86
  // Re-adopt through initTransition like every other resumption site:
87
87
  // a bare setActiveTransition leaves globalQueue._batch as a detached
88
88
  // ambient batch, and anything registered before the scheduled flush