@solidjs/signals 2.0.0-beta.20 → 2.0.0-beta.22
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/README.md +5 -1
- package/dist/dev.js +267 -307
- package/dist/node.cjs +1125 -1168
- package/dist/prod/affects.js +71 -163
- package/dist/prod/boundaries.js +141 -137
- package/dist/prod/core/action.js +50 -12
- package/dist/prod/core/async.js +83 -99
- package/dist/prod/core/core.js +255 -298
- package/dist/prod/core/effect.js +46 -46
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +54 -46
- package/dist/prod/core/heap.js +58 -50
- package/dist/prod/core/lanes.js +34 -34
- package/dist/prod/core/optimistic.js +64 -106
- package/dist/prod/core/owner.js +52 -52
- package/dist/prod/core/scheduler.js +217 -211
- package/dist/prod/core/verdict.js +144 -78
- package/dist/prod/map.js +101 -101
- package/dist/prod/signals.js +23 -5
- package/dist/prod/store/optimistic.js +11 -11
- package/dist/prod/store/projection.js +2 -2
- package/dist/prod/store/store.js +14 -14
- package/dist/types/affects.d.ts +9 -9
- package/dist/types/core/action.d.ts +16 -0
- package/dist/types/core/async.d.ts +1 -1
- package/dist/types/core/error.d.ts +7 -0
- package/dist/types/core/scheduler.d.ts +1 -6
- package/dist/types/core/types.d.ts +6 -11
- package/dist/types-cjs/affects.d.cts +9 -9
- package/dist/types-cjs/core/action.d.cts +16 -0
- package/dist/types-cjs/core/async.d.cts +1 -1
- package/dist/types-cjs/core/error.d.cts +7 -0
- package/dist/types-cjs/core/scheduler.d.cts +1 -6
- package/dist/types-cjs/core/types.d.cts +6 -11
- package/package.json +1 -1
|
@@ -19,14 +19,14 @@ const transitions = new Set;
|
|
|
19
19
|
const dirtyQueue = {
|
|
20
20
|
eE: new Array(2e3).fill(undefined),
|
|
21
21
|
tE: false,
|
|
22
|
-
|
|
22
|
+
Fe: 0,
|
|
23
23
|
EE: 0
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
const zombieQueue = {
|
|
27
27
|
eE: new Array(2e3).fill(undefined),
|
|
28
28
|
tE: false,
|
|
29
|
-
|
|
29
|
+
Fe: 0,
|
|
30
30
|
EE: 0
|
|
31
31
|
};
|
|
32
32
|
|
|
@@ -55,25 +55,25 @@ function registerTransientStoreNode(e) {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
function canUseSimpleSyncFlush(e) {
|
|
58
|
-
const t = e.
|
|
59
|
-
return transitions.size === 0 && activeLanes.size === 0 && e.
|
|
58
|
+
const t = e.m;
|
|
59
|
+
return transitions.size === 0 && activeLanes.size === 0 && e.vt.length === 0 && t.Ze.length === 0 && t.A.length === 0 && t.cn.size === 0 && transientStoreNodes.size === 0;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
function sweepTransientStoreNodes() {
|
|
63
63
|
if (transientStoreNodes.size === 0) return;
|
|
64
64
|
for (const e of transientStoreNodes) {
|
|
65
|
-
if (e.
|
|
65
|
+
if (e.o !== null) {
|
|
66
66
|
transientStoreNodes.delete(e);
|
|
67
67
|
continue;
|
|
68
68
|
}
|
|
69
|
-
if (e.
|
|
70
|
-
if (e.
|
|
69
|
+
if (e.Ne !== NOT_PENDING) continue;
|
|
70
|
+
if (e.Ee !== undefined && e.Ee !== NOT_PENDING) continue;
|
|
71
71
|
// A live affects() mark keeps the node addressable: sweeping it would
|
|
72
72
|
// detach the refcount from the slot (a fresh probe would upsert a new,
|
|
73
73
|
// unmarked node for the same property).
|
|
74
|
-
if (e.
|
|
74
|
+
if (e.t) continue;
|
|
75
75
|
transientStoreNodes.delete(e);
|
|
76
|
-
e.
|
|
76
|
+
e.it?.();
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
@@ -100,47 +100,47 @@ function setProjectionWriteActive(e) {
|
|
|
100
100
|
* land there directly — no per-field aliasing.
|
|
101
101
|
*/ function createBatch() {
|
|
102
102
|
return {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
103
|
+
ce: clock,
|
|
104
|
+
Qt: [],
|
|
105
|
+
yt: new Map,
|
|
106
|
+
Ze: [],
|
|
107
|
+
A: [],
|
|
108
|
+
cn: new Set,
|
|
109
|
+
ie: [],
|
|
110
|
+
gt: {
|
|
111
|
+
bt: [ [], [] ],
|
|
112
|
+
vt: []
|
|
113
113
|
},
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
fn: false,
|
|
115
|
+
ln: new Set
|
|
116
116
|
};
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
function mergeTransitionState(e, t) {
|
|
120
|
-
t.
|
|
121
|
-
e.
|
|
122
|
-
for (const i of activeLanes) if (i.
|
|
123
|
-
if (t.
|
|
120
|
+
t.fn = e;
|
|
121
|
+
e.ie.push(...t.ie);
|
|
122
|
+
for (const i of activeLanes) if (i.Ue === t) i.Ue = e;
|
|
123
|
+
if (t.Ze.length) {
|
|
124
124
|
// Move (don't copy): the global queue's batch may still be the outgoing
|
|
125
125
|
// transition, and the adoption pass in initTransition would re-push its
|
|
126
126
|
// contents into the target — duplicating every entry.
|
|
127
|
-
e.
|
|
128
|
-
t.
|
|
127
|
+
e.Ze.push(...t.Ze);
|
|
128
|
+
t.Ze.length = 0;
|
|
129
129
|
}
|
|
130
|
-
if (t.
|
|
130
|
+
if (t.A.length) {
|
|
131
131
|
// Move (don't copy): the global queue's batch may still be the outgoing
|
|
132
132
|
// transition, and the adoption pass in initTransition would re-push its
|
|
133
133
|
// contents into the target — double-releasing every mark.
|
|
134
|
-
e.
|
|
135
|
-
t.
|
|
134
|
+
e.A.push(...t.A);
|
|
135
|
+
t.A.length = 0;
|
|
136
136
|
}
|
|
137
|
-
for (const i of t.
|
|
138
|
-
for (const [i, n] of t.
|
|
139
|
-
let t = e.
|
|
140
|
-
if (!t) e.
|
|
137
|
+
for (const i of t.cn) e.cn.add(i);
|
|
138
|
+
for (const [i, n] of t.yt) {
|
|
139
|
+
let t = e.yt.get(i);
|
|
140
|
+
if (!t) e.yt.set(i, t = new Set);
|
|
141
141
|
for (const e of n) t.add(e);
|
|
142
142
|
}
|
|
143
|
-
for (const i of t.
|
|
143
|
+
for (const i of t.ln) e.ln.add(i);
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
function schedule() {
|
|
@@ -150,7 +150,7 @@ function schedule() {
|
|
|
150
150
|
}
|
|
151
151
|
if (scheduled) return;
|
|
152
152
|
scheduled = true;
|
|
153
|
-
if (!syncDepth && !globalQueue.
|
|
153
|
+
if (!syncDepth && !globalQueue.kt && !projectionWriteActive) queueMicrotask(flush);
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
/**
|
|
@@ -180,116 +180,113 @@ function notifyHalted() {
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
class Queue {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
Ge=null;
|
|
184
|
+
bt=[ [], [] ];
|
|
185
|
+
vt=[];
|
|
186
186
|
created=clock;
|
|
187
187
|
addChild(e) {
|
|
188
|
-
this.
|
|
189
|
-
e.
|
|
188
|
+
this.vt.push(e);
|
|
189
|
+
e.Ge = this;
|
|
190
190
|
}
|
|
191
191
|
removeChild(e) {
|
|
192
|
-
const t = this.
|
|
192
|
+
const t = this.vt.indexOf(e);
|
|
193
193
|
if (t >= 0) {
|
|
194
|
-
this.
|
|
195
|
-
e.
|
|
194
|
+
this.vt.splice(t, 1);
|
|
195
|
+
e.Ge = null;
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
notify(e, t, i, n) {
|
|
199
|
-
if (this.
|
|
199
|
+
if (this.Ge) return this.Ge.notify(e, t, i, n);
|
|
200
200
|
return false;
|
|
201
201
|
}
|
|
202
202
|
run(e) {
|
|
203
|
-
if (this.
|
|
204
|
-
const t = this.
|
|
205
|
-
this.
|
|
203
|
+
if (this.bt[e - 1].length) {
|
|
204
|
+
const t = this.bt[e - 1];
|
|
205
|
+
this.bt[e - 1] = [];
|
|
206
206
|
runQueue(t, e);
|
|
207
207
|
}
|
|
208
|
-
for (let t = 0; t < this.
|
|
208
|
+
for (let t = 0; t < this.vt.length; t++) this.vt[t].run?.(e);
|
|
209
209
|
}
|
|
210
210
|
enqueue(e, t) {
|
|
211
211
|
if (e) {
|
|
212
212
|
// Route to lane's effect queue if we're in an optimistic recomputation
|
|
213
213
|
if (currentOptimisticLane) {
|
|
214
214
|
const i = findLane(currentOptimisticLane);
|
|
215
|
-
i.
|
|
215
|
+
i.rn[e - 1].push(t);
|
|
216
216
|
} else {
|
|
217
|
-
this.
|
|
217
|
+
this.bt[e - 1].push(t);
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
220
|
schedule();
|
|
221
221
|
}
|
|
222
222
|
stashQueues(e) {
|
|
223
|
-
e.
|
|
224
|
-
e.
|
|
225
|
-
this.
|
|
226
|
-
for (let t = 0; t < this.
|
|
227
|
-
let i = this.
|
|
228
|
-
let n = e.
|
|
223
|
+
e.bt[0].push(...this.bt[0]);
|
|
224
|
+
e.bt[1].push(...this.bt[1]);
|
|
225
|
+
this.bt = [ [], [] ];
|
|
226
|
+
for (let t = 0; t < this.vt.length; t++) {
|
|
227
|
+
let i = this.vt[t];
|
|
228
|
+
let n = e.vt[t];
|
|
229
229
|
if (!n) {
|
|
230
230
|
n = {
|
|
231
|
-
|
|
232
|
-
|
|
231
|
+
bt: [ [], [] ],
|
|
232
|
+
vt: []
|
|
233
233
|
};
|
|
234
|
-
e.
|
|
234
|
+
e.vt[t] = n;
|
|
235
235
|
}
|
|
236
236
|
i.stashQueues(n);
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
239
|
restoreQueues(e) {
|
|
240
|
-
this.
|
|
241
|
-
this.
|
|
242
|
-
for (let t = 0; t < e.
|
|
243
|
-
const i = e.
|
|
244
|
-
let n = this.
|
|
240
|
+
this.bt[0].push(...e.bt[0]);
|
|
241
|
+
this.bt[1].push(...e.bt[1]);
|
|
242
|
+
for (let t = 0; t < e.vt.length; t++) {
|
|
243
|
+
const i = e.vt[t];
|
|
244
|
+
let n = this.vt[t];
|
|
245
245
|
if (n) n.restoreQueues(i);
|
|
246
246
|
}
|
|
247
247
|
}
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
class GlobalQueue extends Queue {
|
|
251
|
-
|
|
251
|
+
kt=false;
|
|
252
252
|
// The current transaction-shaped batch: a plain ambient batch while no
|
|
253
253
|
// transition is active, the active transition itself after initTransition.
|
|
254
|
-
|
|
254
|
+
m=createBatch();
|
|
255
|
+
static pe;
|
|
255
256
|
static Ce;
|
|
256
|
-
static
|
|
257
|
-
static
|
|
258
|
-
static Vt=null;
|
|
257
|
+
static Je;
|
|
258
|
+
static Dt=null;
|
|
259
259
|
// Store-side hook: drops a keyless affects() mark's identity scope when the
|
|
260
260
|
// carrier node's last registration releases (wired by store.ts, mirroring
|
|
261
261
|
// _clearOptimisticStore).
|
|
262
|
-
static
|
|
262
|
+
static p=null;
|
|
263
263
|
// affects()-side hooks (wired by affects.ts, mirroring _update): the mark
|
|
264
|
-
// engine — count/register/release
|
|
265
|
-
//
|
|
266
|
-
//
|
|
267
|
-
static
|
|
264
|
+
// engine — count/register/release — lives with the feature. Every call site
|
|
265
|
+
// is gated by state only that module creates, so `!` invocations are safe
|
|
266
|
+
// once the gate holds.
|
|
267
|
+
static G=null;
|
|
268
|
+
static M=null;
|
|
268
269
|
static h=null;
|
|
269
|
-
static D=null;
|
|
270
|
-
static F=null;
|
|
271
|
-
static $=null;
|
|
272
|
-
static I=null;
|
|
273
270
|
// External-source bridge (wired by enableExternalSource(); null while no
|
|
274
271
|
// config is active — including after _resetExternalSourceConfig()).
|
|
275
|
-
static
|
|
276
|
-
static
|
|
272
|
+
static Tt=null;
|
|
273
|
+
static It=null;
|
|
277
274
|
// Verdict-layer hooks (wired by verdict.ts when isPending()/latest() are
|
|
278
275
|
// imported; null in apps that never use them). Call sites either guard for
|
|
279
276
|
// null or sit behind state only the verdict layer can create (`!` is safe
|
|
280
277
|
// there: `_pendingSignal`/`_latestValueComputed` are only ever assigned by
|
|
281
278
|
// verdict.ts, and `pendingCheckActive`/`latestReadActive` only flip inside
|
|
282
279
|
// isPending()/latest()).
|
|
280
|
+
static Ie=null;
|
|
281
|
+
static ae=null;
|
|
283
282
|
static _e=null;
|
|
284
|
-
static
|
|
285
|
-
static
|
|
286
|
-
static
|
|
287
|
-
static
|
|
288
|
-
static
|
|
289
|
-
static
|
|
290
|
-
static
|
|
291
|
-
static nt=null;
|
|
292
|
-
static wt=null;
|
|
283
|
+
static un=null;
|
|
284
|
+
static St=null;
|
|
285
|
+
static dt=null;
|
|
286
|
+
static Rt=null;
|
|
287
|
+
static ze=null;
|
|
288
|
+
static k=null;
|
|
289
|
+
static Lt=null;
|
|
293
290
|
// Optimistic-engine hooks (wired by core/optimistic.ts via
|
|
294
291
|
// installOptimisticEngine(), called from verdict.ts / createOptimistic /
|
|
295
292
|
// createOptimisticStore — every module that can create optimistic state).
|
|
@@ -297,109 +294,112 @@ class GlobalQueue extends Queue {
|
|
|
297
294
|
// `_overrideValue` slot, a lane in `activeLanes`, an `_optimisticNodes`
|
|
298
295
|
// entry, or a non-null `currentOptimisticLane`, so `!` invocations are safe
|
|
299
296
|
// once the gate holds.
|
|
300
|
-
static
|
|
297
|
+
static Pt=null;
|
|
301
298
|
static En=null;
|
|
302
299
|
static Tn=null;
|
|
300
|
+
static dn=null;
|
|
303
301
|
static In=null;
|
|
302
|
+
static Ct=null;
|
|
303
|
+
static At=null;
|
|
304
|
+
static Ot=null;
|
|
305
|
+
static We=null;
|
|
306
|
+
static Ke=null;
|
|
307
|
+
static Me=null;
|
|
304
308
|
static Nn=null;
|
|
305
|
-
static On=null;
|
|
306
|
-
static Dt=null;
|
|
307
|
-
static gt=null;
|
|
308
|
-
static ht=null;
|
|
309
|
-
static vt=null;
|
|
310
|
-
static $e=null;
|
|
311
|
-
static et=null;
|
|
312
|
-
static Xe=null;
|
|
313
|
-
static mn=null;
|
|
314
309
|
flush() {
|
|
315
|
-
if (this.
|
|
316
|
-
this.
|
|
310
|
+
if (this.kt) return;
|
|
311
|
+
this.kt = true;
|
|
317
312
|
try {
|
|
318
313
|
if (false) ;
|
|
319
|
-
runHeap(dirtyQueue, GlobalQueue.
|
|
314
|
+
runHeap(dirtyQueue, GlobalQueue.pe);
|
|
320
315
|
if (activeTransition) {
|
|
321
316
|
const e = transitionComplete(activeTransition);
|
|
322
317
|
if (!e) {
|
|
323
318
|
const e = activeTransition;
|
|
324
|
-
runHeap(zombieQueue, GlobalQueue.
|
|
319
|
+
runHeap(zombieQueue, GlobalQueue.pe);
|
|
325
320
|
// Detach: the stashed transition keeps its batch; ambient work that
|
|
326
|
-
// follows lands in a fresh one.
|
|
327
|
-
|
|
321
|
+
// follows lands in a fresh one. If the batch is already a separate
|
|
322
|
+
// ambient one — action done() restored activeTransition without
|
|
323
|
+
// adopting the batch, and an ordinary write landed there before
|
|
324
|
+
// the scheduled flush (#2916) — keep it: replacing it would strand
|
|
325
|
+
// its queued pending nodes with held _pendingValues forever.
|
|
326
|
+
if (this.m === e) currentBatch = this.m = createBatch();
|
|
328
327
|
// Run lane effects immediately (before stashing) - lanes with no pending async
|
|
329
328
|
if (activeLanes.size) {
|
|
330
|
-
GlobalQueue.
|
|
331
|
-
GlobalQueue.
|
|
329
|
+
GlobalQueue.In(EFFECT_RENDER);
|
|
330
|
+
GlobalQueue.In(EFFECT_USER);
|
|
332
331
|
}
|
|
333
|
-
this.stashQueues(e.
|
|
332
|
+
this.stashQueues(e.gt);
|
|
334
333
|
clock++;
|
|
335
|
-
|
|
336
|
-
|
|
334
|
+
// A kept ambient batch may hold pending nodes (#2916): stay
|
|
335
|
+
// scheduled so the outer drain loop commits them via the plain
|
|
336
|
+
// flush path instead of leaving them until the next natural flush.
|
|
337
|
+
scheduled = dirtyQueue.EE >= dirtyQueue.Fe || this.m.Qt.length > 0;
|
|
338
|
+
reassignPendingTransition(e.Qt);
|
|
337
339
|
activeTransition = null;
|
|
338
|
-
|
|
339
|
-
// wraps finalizePureQueue in the engine; a non-empty _optimisticNodes
|
|
340
|
-
// means _optimisticWrite ran, which installed the hook.
|
|
341
|
-
if (!e.Te.length && !e.Lt.size && e.Be.length) {
|
|
342
|
-
GlobalQueue.Tn(e);
|
|
343
|
-
} else {
|
|
344
|
-
finalizePureQueue(null, true);
|
|
345
|
-
}
|
|
340
|
+
finalizePureQueue(null, true);
|
|
346
341
|
return;
|
|
347
342
|
}
|
|
348
343
|
const t = activeTransition;
|
|
349
|
-
const i = this.
|
|
350
|
-
i !== t && i.
|
|
351
|
-
this.restoreQueues(t.
|
|
344
|
+
const i = this.m;
|
|
345
|
+
i !== t && i.Qt.push(...t.Qt);
|
|
346
|
+
this.restoreQueues(t.gt);
|
|
352
347
|
transitions.delete(t);
|
|
353
348
|
activeTransition = null;
|
|
354
|
-
reassignPendingTransition(i.
|
|
349
|
+
reassignPendingTransition(i.Qt);
|
|
355
350
|
finalizePureQueue(t);
|
|
356
351
|
if (i === t) {
|
|
357
352
|
// Drop the dead Transition wrapper but keep its (drained) containers
|
|
358
353
|
// as the ambient batch — late registrations during finalization live
|
|
359
354
|
// there and must survive to the next flush.
|
|
360
355
|
const e = createBatch();
|
|
361
|
-
e.
|
|
362
|
-
e.
|
|
363
|
-
e.
|
|
364
|
-
e.
|
|
365
|
-
currentBatch = this.
|
|
356
|
+
e.Qt = i.Qt;
|
|
357
|
+
e.Ze = i.Ze;
|
|
358
|
+
e.A = i.A;
|
|
359
|
+
e.cn = i.cn;
|
|
360
|
+
currentBatch = this.m = e;
|
|
366
361
|
}
|
|
367
362
|
} else {
|
|
368
363
|
if (canUseSimpleSyncFlush(this)) {
|
|
369
364
|
commitPendingNodes();
|
|
370
|
-
if (dirtyQueue.EE >= dirtyQueue.
|
|
371
|
-
runHeap(dirtyQueue, GlobalQueue.
|
|
365
|
+
if (dirtyQueue.EE >= dirtyQueue.Fe) {
|
|
366
|
+
runHeap(dirtyQueue, GlobalQueue.pe);
|
|
372
367
|
commitPendingNodes();
|
|
373
368
|
}
|
|
374
369
|
} else {
|
|
375
|
-
if (transitions.size) runHeap(zombieQueue, GlobalQueue.
|
|
370
|
+
if (transitions.size) runHeap(zombieQueue, GlobalQueue.pe);
|
|
376
371
|
finalizePureQueue();
|
|
377
372
|
}
|
|
378
373
|
}
|
|
379
374
|
clock++;
|
|
380
375
|
// Check if finalization added items to the heap (from optimistic reversion)
|
|
381
|
-
scheduled = dirtyQueue.EE >= dirtyQueue.
|
|
376
|
+
scheduled = dirtyQueue.EE >= dirtyQueue.Fe;
|
|
382
377
|
// Run lane effects first (for ready lanes), then regular effects
|
|
383
|
-
activeLanes.size && GlobalQueue.
|
|
378
|
+
activeLanes.size && GlobalQueue.In(EFFECT_RENDER);
|
|
384
379
|
this.run(EFFECT_RENDER);
|
|
385
|
-
activeLanes.size && GlobalQueue.
|
|
380
|
+
activeLanes.size && GlobalQueue.In(EFFECT_USER);
|
|
386
381
|
this.run(EFFECT_USER);
|
|
387
382
|
if (false) ;
|
|
388
383
|
if (false && !scheduled && !activeTransition && transitions.size === 0 && activeLanes.size === 0) ;
|
|
389
384
|
if (false) ;
|
|
390
385
|
} finally {
|
|
391
|
-
this.
|
|
386
|
+
this.kt = false;
|
|
392
387
|
}
|
|
393
388
|
}
|
|
394
389
|
notify(e, t, i, n) {
|
|
395
390
|
// Only track async if the boundary is propagating STATUS_PENDING (not caught by boundary)
|
|
396
391
|
if (t & STATUS_PENDING) {
|
|
397
392
|
if (i & STATUS_PENDING) {
|
|
398
|
-
const t = n !== undefined ? n : e.
|
|
393
|
+
const t = n !== undefined ? n : e._;
|
|
394
|
+
// A visibility-only mark notification (the affects() boundary
|
|
395
|
+
// channel) updates display state on its way up but must be invisible
|
|
396
|
+
// to completion accounting BY CONSTRUCTION: it never registers a
|
|
397
|
+
// reporter and never counts toward the loading-boundary diagnostic.
|
|
398
|
+
if (t?.l) return true;
|
|
399
399
|
if (activeTransition && t) {
|
|
400
400
|
const i = t.source;
|
|
401
|
-
let n = activeTransition.
|
|
402
|
-
if (!n) activeTransition.
|
|
401
|
+
let n = activeTransition.yt.get(i);
|
|
402
|
+
if (!n) activeTransition.yt.set(i, n = new Set);
|
|
403
403
|
const s = n.size;
|
|
404
404
|
n.add(e);
|
|
405
405
|
if (n.size !== s) schedule();
|
|
@@ -412,7 +412,7 @@ class GlobalQueue extends Queue {
|
|
|
412
412
|
initTransition(e) {
|
|
413
413
|
if (e) e = currentTransition(e);
|
|
414
414
|
if (e && e === activeTransition) return;
|
|
415
|
-
if (!e && activeTransition && activeTransition.
|
|
415
|
+
if (!e && activeTransition && activeTransition.ce === clock) return;
|
|
416
416
|
if (!activeTransition) {
|
|
417
417
|
activeTransition = e ?? createBatch();
|
|
418
418
|
} else if (e) {
|
|
@@ -422,8 +422,8 @@ class GlobalQueue extends Queue {
|
|
|
422
422
|
activeTransition = e;
|
|
423
423
|
}
|
|
424
424
|
transitions.add(activeTransition);
|
|
425
|
-
activeTransition.
|
|
426
|
-
const t = this.
|
|
425
|
+
activeTransition.ce = clock;
|
|
426
|
+
const t = this.m;
|
|
427
427
|
if (t !== activeTransition) {
|
|
428
428
|
// Adopt the ambient batch into the transaction, then make the
|
|
429
429
|
// transaction the batch so later registrations land there directly.
|
|
@@ -432,28 +432,28 @@ class GlobalQueue extends Queue {
|
|
|
432
432
|
// must not entangle unrelated writes to it; the same rule holds one hop
|
|
433
433
|
// downstream: propagation never queues pended subscribers as pending
|
|
434
434
|
// nodes, see propagateAffectsMark, #2893.
|
|
435
|
-
for (let e = 0; e < t.
|
|
436
|
-
const i = t.
|
|
437
|
-
i.
|
|
438
|
-
activeTransition.
|
|
435
|
+
for (let e = 0; e < t.Qt.length; e++) {
|
|
436
|
+
const i = t.Qt[e];
|
|
437
|
+
i.Ue = activeTransition;
|
|
438
|
+
activeTransition.Qt.push(i);
|
|
439
439
|
}
|
|
440
|
-
for (let e = 0; e < t.
|
|
441
|
-
const i = t.
|
|
442
|
-
i.
|
|
443
|
-
activeTransition.
|
|
440
|
+
for (let e = 0; e < t.Ze.length; e++) {
|
|
441
|
+
const i = t.Ze[e];
|
|
442
|
+
i.Ue = activeTransition;
|
|
443
|
+
activeTransition.Ze.push(i);
|
|
444
444
|
}
|
|
445
|
-
if (t.
|
|
446
|
-
for (const e of t.
|
|
447
|
-
currentBatch = this.
|
|
445
|
+
if (t.A.length) activeTransition.A.push(...t.A);
|
|
446
|
+
for (const e of t.cn) activeTransition.cn.add(e);
|
|
447
|
+
currentBatch = this.m = activeTransition;
|
|
448
448
|
}
|
|
449
449
|
for (const e of activeLanes) {
|
|
450
|
-
if (!e.
|
|
450
|
+
if (!e.Ue) e.Ue = activeTransition;
|
|
451
451
|
}
|
|
452
452
|
}
|
|
453
453
|
}
|
|
454
454
|
|
|
455
455
|
function queuePendingNode(e) {
|
|
456
|
-
currentBatch.
|
|
456
|
+
currentBatch.Qt.push(e);
|
|
457
457
|
}
|
|
458
458
|
|
|
459
459
|
// Sticky: flips true on the first refresh() ever (the only setter of
|
|
@@ -468,53 +468,53 @@ function armReaskClear() {
|
|
|
468
468
|
function insertSubs(e, t = false) {
|
|
469
469
|
// Get source lane: prefer node's own lane over current context
|
|
470
470
|
// This is important for isPending signals which need their own lane to flush immediately
|
|
471
|
-
const i = e.
|
|
472
|
-
const n = e.
|
|
471
|
+
const i = e.je || currentOptimisticLane;
|
|
472
|
+
const n = e.Ve !== undefined;
|
|
473
473
|
const s = reaskArmed;
|
|
474
|
-
for (let r = e.
|
|
474
|
+
for (let r = e.o; r !== null; r = r.ue) {
|
|
475
475
|
// A value-change notification is a new question for the subscriber: any
|
|
476
476
|
// pending re-ask mark (refresh) it carried is superseded.
|
|
477
|
-
if (s) r.
|
|
478
|
-
if (n && r.
|
|
479
|
-
r.
|
|
477
|
+
if (s) r.le.se &= ~REACTIVE_REASK;
|
|
478
|
+
if (n && r.le.T & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
479
|
+
r.le.se |= REACTIVE_SNAPSHOT_STALE;
|
|
480
480
|
continue;
|
|
481
481
|
}
|
|
482
482
|
if (t && i) {
|
|
483
|
-
r.
|
|
484
|
-
assignOrMergeLane(r.
|
|
483
|
+
r.le.se |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
484
|
+
assignOrMergeLane(r.le, i);
|
|
485
485
|
} else if (t) {
|
|
486
|
-
r.
|
|
486
|
+
r.le.se |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
487
487
|
// No source lane means reversion - clear subscriber's lane so effects go to regular queue
|
|
488
|
-
r.
|
|
488
|
+
r.le.je = undefined;
|
|
489
489
|
}
|
|
490
|
-
enqueueSub(r.
|
|
490
|
+
enqueueSub(r.le);
|
|
491
491
|
}
|
|
492
492
|
}
|
|
493
493
|
|
|
494
494
|
function commitPendingNode(e) {
|
|
495
495
|
const t = e;
|
|
496
|
-
if (!t.
|
|
497
|
-
if (e.
|
|
498
|
-
e.
|
|
499
|
-
e.
|
|
496
|
+
if (!t.ke) {
|
|
497
|
+
if (e.Ne !== NOT_PENDING) {
|
|
498
|
+
e.Re = e.Ne;
|
|
499
|
+
e.Ne = NOT_PENDING;
|
|
500
500
|
}
|
|
501
|
-
if (e.
|
|
501
|
+
if (e.ge || e.he) GlobalQueue.un(e);
|
|
502
502
|
return;
|
|
503
503
|
}
|
|
504
|
-
if (e.
|
|
505
|
-
e.
|
|
506
|
-
e.
|
|
504
|
+
if (e.Ne !== NOT_PENDING) {
|
|
505
|
+
e.Re = e.Ne;
|
|
506
|
+
e.Ne = NOT_PENDING;
|
|
507
507
|
// Set _modified for effects, but not for tracked effects (they handle their own scheduling)
|
|
508
|
-
if (e.
|
|
508
|
+
if (e.Ae && e.Ae !== EFFECT_TRACKED) e.$e = true;
|
|
509
509
|
}
|
|
510
|
-
t.
|
|
511
|
-
if (!(t.
|
|
512
|
-
if (t.
|
|
513
|
-
if (e.
|
|
510
|
+
t.se &= ~REACTIVE_MANUAL_WRITE;
|
|
511
|
+
if (!(t.S & STATUS_PENDING)) t.S &= ~STATUS_UNINITIALIZED;
|
|
512
|
+
if (t.Le !== null || t.ye !== null) GlobalQueue.Ce(t, false, true);
|
|
513
|
+
if (e.ge || e.he) GlobalQueue.un(e);
|
|
514
514
|
}
|
|
515
515
|
|
|
516
516
|
function commitPendingNodes() {
|
|
517
|
-
const e = currentBatch.
|
|
517
|
+
const e = currentBatch.Qt;
|
|
518
518
|
for (let t = 0; t < e.length; t++) {
|
|
519
519
|
commitPendingNode(e[t]);
|
|
520
520
|
}
|
|
@@ -526,43 +526,49 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
526
526
|
// For completing transitions or no-transition, resolve pending and revert optimistic
|
|
527
527
|
const i = !t;
|
|
528
528
|
if (i) commitPendingNodes();
|
|
529
|
-
if (!t && globalQueue.
|
|
530
|
-
const n = dirtyQueue.EE >= dirtyQueue.
|
|
531
|
-
if (n) runHeap(dirtyQueue, GlobalQueue.
|
|
529
|
+
if (!t && globalQueue.vt.length) checkBoundaryChildren(globalQueue);
|
|
530
|
+
const n = dirtyQueue.EE >= dirtyQueue.Fe;
|
|
531
|
+
if (n) runHeap(dirtyQueue, GlobalQueue.pe);
|
|
532
532
|
if (i) {
|
|
533
533
|
if (n) commitPendingNodes();
|
|
534
534
|
// The settling batch: the completing transaction's, or the ambient one.
|
|
535
|
-
const t = e ?? globalQueue.
|
|
535
|
+
const t = e ?? globalQueue.m;
|
|
536
536
|
// Optimistic reversion: a non-empty batch means _optimisticWrite ran,
|
|
537
537
|
// which installed the engine's hooks.
|
|
538
|
-
if (t.
|
|
538
|
+
if (t.Ze.length) GlobalQueue.En(t.Ze);
|
|
539
539
|
// Replay entanglement: subs recorded by the read-time gate get rescheduled
|
|
540
540
|
// so they re-run with the now-committed values visible.
|
|
541
|
-
if (e && e.
|
|
542
|
-
for (const t of e.
|
|
543
|
-
if (t.
|
|
541
|
+
if (e && e.ln.size) {
|
|
542
|
+
for (const t of e.ln) {
|
|
543
|
+
if (t.se & REACTIVE_DISPOSED) continue;
|
|
544
544
|
enqueueSub(t);
|
|
545
545
|
}
|
|
546
|
-
e.
|
|
546
|
+
e.ln.clear();
|
|
547
547
|
}
|
|
548
548
|
// Declared motion ends with the transaction: settle (or plain flush end
|
|
549
549
|
// for ambient marks) releases each registration's refcount. A non-empty
|
|
550
|
-
// batch means registerAffectsMark ran, which installed the hook.
|
|
551
|
-
|
|
550
|
+
// batch means registerAffectsMark ran, which installed the hook. Marks
|
|
551
|
+
// held boundary display state through the visual channel, and their
|
|
552
|
+
// release is the display-state update point — re-run the boundary sweep
|
|
553
|
+
// (the earlier sweep above ran while the marks were still live).
|
|
554
|
+
if (t.A.length) {
|
|
555
|
+
GlobalQueue.G(t.A);
|
|
556
|
+
if (globalQueue.vt.length) checkBoundaryChildren(globalQueue);
|
|
557
|
+
}
|
|
552
558
|
// A non-empty set means trackOptimisticStore ran, which installed the
|
|
553
559
|
// hook; the hook iterates, clears, and schedules (keeping the loop out of
|
|
554
560
|
// core lets esbuild shake it — rollup already folds the null guard). The
|
|
555
561
|
// completing transition scopes the clear to its own layer keys (#2899).
|
|
556
|
-
if (t.
|
|
562
|
+
if (t.cn.size) GlobalQueue.Dt(t.cn, e);
|
|
557
563
|
sweepTransientStoreNodes();
|
|
558
564
|
// Lanes only enter activeLanes through the engine's getOrCreateLane.
|
|
559
|
-
if (activeLanes.size) GlobalQueue.
|
|
565
|
+
if (activeLanes.size) GlobalQueue.dn(e);
|
|
560
566
|
}
|
|
561
567
|
}
|
|
562
568
|
|
|
563
569
|
function checkBoundaryChildren(e) {
|
|
564
|
-
for (const t of e.
|
|
565
|
-
t.
|
|
570
|
+
for (const t of e.vt) {
|
|
571
|
+
t.ne?.();
|
|
566
572
|
checkBoundaryChildren(t);
|
|
567
573
|
}
|
|
568
574
|
}
|
|
@@ -585,7 +591,7 @@ function checkBoundaryChildren(e) {
|
|
|
585
591
|
|
|
586
592
|
function reassignPendingTransition(e) {
|
|
587
593
|
for (let t = 0; t < e.length; t++) {
|
|
588
|
-
e[t].
|
|
594
|
+
e[t].Ue = activeTransition;
|
|
589
595
|
}
|
|
590
596
|
}
|
|
591
597
|
|
|
@@ -596,7 +602,7 @@ const globalQueue = new GlobalQueue;
|
|
|
596
602
|
// property hop through `_batch` was a measured instruction-count regression
|
|
597
603
|
// (CodSpeed update1to1, PR #2905). The field stays authoritative for
|
|
598
604
|
// cross-module readers; every `_batch` assignment updates both.
|
|
599
|
-
let currentBatch = globalQueue.
|
|
605
|
+
let currentBatch = globalQueue.m;
|
|
600
606
|
|
|
601
607
|
function flush(e) {
|
|
602
608
|
if (e) {
|
|
@@ -613,7 +619,7 @@ function flush(e) {
|
|
|
613
619
|
}
|
|
614
620
|
}
|
|
615
621
|
}
|
|
616
|
-
if (globalQueue.
|
|
622
|
+
if (globalQueue.kt) {
|
|
617
623
|
return;
|
|
618
624
|
}
|
|
619
625
|
if (halted) return;
|
|
@@ -629,23 +635,23 @@ function runQueue(e, t) {
|
|
|
629
635
|
}
|
|
630
636
|
|
|
631
637
|
function reporterBlocksSource(e, t) {
|
|
632
|
-
if (e.
|
|
633
|
-
if (e.
|
|
634
|
-
for (let i = e.
|
|
635
|
-
let e = i.
|
|
638
|
+
if (e.se & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
|
|
639
|
+
if (e.oe?.has(t)) return true;
|
|
640
|
+
for (let i = e.Xe; i; i = i.et) {
|
|
641
|
+
let e = i.tt;
|
|
636
642
|
while (e) {
|
|
637
|
-
if (e === t || e.
|
|
638
|
-
e = e.
|
|
643
|
+
if (e === t || e.nt === t) return true;
|
|
644
|
+
e = e.nn;
|
|
639
645
|
}
|
|
640
646
|
}
|
|
641
|
-
return !!(e.
|
|
647
|
+
return !!(e.S & STATUS_PENDING && e._ instanceof NotReadyError && e._.source === t);
|
|
642
648
|
}
|
|
643
649
|
|
|
644
650
|
function transitionComplete(e) {
|
|
645
|
-
if (e.
|
|
646
|
-
if (e.
|
|
651
|
+
if (e.fn) return true;
|
|
652
|
+
if (e.ie.length) return false;
|
|
647
653
|
let t = true;
|
|
648
|
-
for (const [i, n] of e.
|
|
654
|
+
for (const [i, n] of e.yt) {
|
|
649
655
|
let s = false;
|
|
650
656
|
for (const e of n) {
|
|
651
657
|
if (reporterBlocksSource(e, i)) {
|
|
@@ -654,7 +660,7 @@ function transitionComplete(e) {
|
|
|
654
660
|
}
|
|
655
661
|
n.delete(e);
|
|
656
662
|
}
|
|
657
|
-
if (!s) e.
|
|
663
|
+
if (!s) e.yt.delete(i); else if (i.S & STATUS_PENDING && i._?.source === i) {
|
|
658
664
|
t = false;
|
|
659
665
|
break;
|
|
660
666
|
}
|
|
@@ -662,13 +668,13 @@ function transitionComplete(e) {
|
|
|
662
668
|
// Override blockage lives with the engine. Absent hook = "no optimistic
|
|
663
669
|
// blockage", which is exact: only _optimisticWrite (engine) pushes to
|
|
664
670
|
// _optimisticNodes, so without the engine the loop was vacuous anyway.
|
|
665
|
-
if (t && e.
|
|
666
|
-
t && (e.
|
|
671
|
+
if (t && e.Ze.length && GlobalQueue.Tn(e)) t = false;
|
|
672
|
+
t && (e.fn = true);
|
|
667
673
|
return t;
|
|
668
674
|
}
|
|
669
675
|
|
|
670
676
|
function currentTransition(e) {
|
|
671
|
-
while (e.
|
|
677
|
+
while (e.fn && typeof e.fn === "object") e = e.fn;
|
|
672
678
|
return e;
|
|
673
679
|
}
|
|
674
680
|
|