@solidjs/signals 2.0.0-beta.21 → 2.0.0-beta.23
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.js +210 -301
- package/dist/node.cjs +1106 -1196
- package/dist/prod/affects.js +71 -163
- package/dist/prod/boundaries.js +141 -137
- package/dist/prod/core/action.js +3 -3
- package/dist/prod/core/async.js +103 -103
- package/dist/prod/core/core.js +254 -297
- package/dist/prod/core/effect.js +46 -46
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +60 -47
- package/dist/prod/core/heap.js +50 -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 +210 -211
- package/dist/prod/core/verdict.js +129 -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/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/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()).
|
|
283
|
-
static
|
|
284
|
-
static
|
|
285
|
-
static
|
|
286
|
-
static
|
|
287
|
-
static
|
|
288
|
-
static
|
|
289
|
-
static
|
|
290
|
-
static
|
|
291
|
-
static
|
|
292
|
-
static
|
|
280
|
+
static Ie=null;
|
|
281
|
+
static ae=null;
|
|
282
|
+
static he=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,116 +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
321
|
// follows lands in a fresh one. If the batch is already a separate
|
|
327
322
|
// ambient one — action done() restored activeTransition without
|
|
328
323
|
// adopting the batch, and an ordinary write landed there before
|
|
329
324
|
// the scheduled flush (#2916) — keep it: replacing it would strand
|
|
330
325
|
// its queued pending nodes with held _pendingValues forever.
|
|
331
|
-
if (this.
|
|
326
|
+
if (this.m === e) currentBatch = this.m = createBatch();
|
|
332
327
|
// Run lane effects immediately (before stashing) - lanes with no pending async
|
|
333
328
|
if (activeLanes.size) {
|
|
334
|
-
GlobalQueue.
|
|
335
|
-
GlobalQueue.
|
|
329
|
+
GlobalQueue.In(EFFECT_RENDER);
|
|
330
|
+
GlobalQueue.In(EFFECT_USER);
|
|
336
331
|
}
|
|
337
|
-
this.stashQueues(e.
|
|
332
|
+
this.stashQueues(e.gt);
|
|
338
333
|
clock++;
|
|
339
334
|
// A kept ambient batch may hold pending nodes (#2916): stay
|
|
340
335
|
// scheduled so the outer drain loop commits them via the plain
|
|
341
336
|
// flush path instead of leaving them until the next natural flush.
|
|
342
|
-
scheduled = dirtyQueue.EE >= dirtyQueue.
|
|
343
|
-
reassignPendingTransition(e.
|
|
337
|
+
scheduled = dirtyQueue.EE >= dirtyQueue.Fe || this.m.Qt.length > 0;
|
|
338
|
+
reassignPendingTransition(e.Qt);
|
|
344
339
|
activeTransition = null;
|
|
345
|
-
|
|
346
|
-
// wraps finalizePureQueue in the engine; a non-empty _optimisticNodes
|
|
347
|
-
// means _optimisticWrite ran, which installed the hook.
|
|
348
|
-
if (!e.Te.length && !e.Lt.size && e.Be.length) {
|
|
349
|
-
GlobalQueue.Tn(e);
|
|
350
|
-
} else {
|
|
351
|
-
finalizePureQueue(null, true);
|
|
352
|
-
}
|
|
340
|
+
finalizePureQueue(null, true);
|
|
353
341
|
return;
|
|
354
342
|
}
|
|
355
343
|
const t = activeTransition;
|
|
356
|
-
const i = this.
|
|
357
|
-
i !== t && i.
|
|
358
|
-
this.restoreQueues(t.
|
|
344
|
+
const i = this.m;
|
|
345
|
+
i !== t && i.Qt.push(...t.Qt);
|
|
346
|
+
this.restoreQueues(t.gt);
|
|
359
347
|
transitions.delete(t);
|
|
360
348
|
activeTransition = null;
|
|
361
|
-
reassignPendingTransition(i.
|
|
349
|
+
reassignPendingTransition(i.Qt);
|
|
362
350
|
finalizePureQueue(t);
|
|
363
351
|
if (i === t) {
|
|
364
352
|
// Drop the dead Transition wrapper but keep its (drained) containers
|
|
365
353
|
// as the ambient batch — late registrations during finalization live
|
|
366
354
|
// there and must survive to the next flush.
|
|
367
355
|
const e = createBatch();
|
|
368
|
-
e.
|
|
369
|
-
e.
|
|
370
|
-
e.
|
|
371
|
-
e.
|
|
372
|
-
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;
|
|
373
361
|
}
|
|
374
362
|
} else {
|
|
375
363
|
if (canUseSimpleSyncFlush(this)) {
|
|
376
364
|
commitPendingNodes();
|
|
377
|
-
if (dirtyQueue.EE >= dirtyQueue.
|
|
378
|
-
runHeap(dirtyQueue, GlobalQueue.
|
|
365
|
+
if (dirtyQueue.EE >= dirtyQueue.Fe) {
|
|
366
|
+
runHeap(dirtyQueue, GlobalQueue.pe);
|
|
379
367
|
commitPendingNodes();
|
|
380
368
|
}
|
|
381
369
|
} else {
|
|
382
|
-
if (transitions.size) runHeap(zombieQueue, GlobalQueue.
|
|
370
|
+
if (transitions.size) runHeap(zombieQueue, GlobalQueue.pe);
|
|
383
371
|
finalizePureQueue();
|
|
384
372
|
}
|
|
385
373
|
}
|
|
386
374
|
clock++;
|
|
387
375
|
// Check if finalization added items to the heap (from optimistic reversion)
|
|
388
|
-
scheduled = dirtyQueue.EE >= dirtyQueue.
|
|
376
|
+
scheduled = dirtyQueue.EE >= dirtyQueue.Fe;
|
|
389
377
|
// Run lane effects first (for ready lanes), then regular effects
|
|
390
|
-
activeLanes.size && GlobalQueue.
|
|
378
|
+
activeLanes.size && GlobalQueue.In(EFFECT_RENDER);
|
|
391
379
|
this.run(EFFECT_RENDER);
|
|
392
|
-
activeLanes.size && GlobalQueue.
|
|
380
|
+
activeLanes.size && GlobalQueue.In(EFFECT_USER);
|
|
393
381
|
this.run(EFFECT_USER);
|
|
394
382
|
if (false) ;
|
|
395
383
|
if (false && !scheduled && !activeTransition && transitions.size === 0 && activeLanes.size === 0) ;
|
|
396
384
|
if (false) ;
|
|
397
385
|
} finally {
|
|
398
|
-
this.
|
|
386
|
+
this.kt = false;
|
|
399
387
|
}
|
|
400
388
|
}
|
|
401
389
|
notify(e, t, i, n) {
|
|
402
390
|
// Only track async if the boundary is propagating STATUS_PENDING (not caught by boundary)
|
|
403
391
|
if (t & STATUS_PENDING) {
|
|
404
392
|
if (i & STATUS_PENDING) {
|
|
405
|
-
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;
|
|
406
399
|
if (activeTransition && t) {
|
|
407
400
|
const i = t.source;
|
|
408
|
-
let n = activeTransition.
|
|
409
|
-
if (!n) activeTransition.
|
|
401
|
+
let n = activeTransition.yt.get(i);
|
|
402
|
+
if (!n) activeTransition.yt.set(i, n = new Set);
|
|
410
403
|
const s = n.size;
|
|
411
404
|
n.add(e);
|
|
412
405
|
if (n.size !== s) schedule();
|
|
@@ -419,7 +412,7 @@ class GlobalQueue extends Queue {
|
|
|
419
412
|
initTransition(e) {
|
|
420
413
|
if (e) e = currentTransition(e);
|
|
421
414
|
if (e && e === activeTransition) return;
|
|
422
|
-
if (!e && activeTransition && activeTransition.
|
|
415
|
+
if (!e && activeTransition && activeTransition.ce === clock) return;
|
|
423
416
|
if (!activeTransition) {
|
|
424
417
|
activeTransition = e ?? createBatch();
|
|
425
418
|
} else if (e) {
|
|
@@ -429,8 +422,8 @@ class GlobalQueue extends Queue {
|
|
|
429
422
|
activeTransition = e;
|
|
430
423
|
}
|
|
431
424
|
transitions.add(activeTransition);
|
|
432
|
-
activeTransition.
|
|
433
|
-
const t = this.
|
|
425
|
+
activeTransition.ce = clock;
|
|
426
|
+
const t = this.m;
|
|
434
427
|
if (t !== activeTransition) {
|
|
435
428
|
// Adopt the ambient batch into the transaction, then make the
|
|
436
429
|
// transaction the batch so later registrations land there directly.
|
|
@@ -439,28 +432,28 @@ class GlobalQueue extends Queue {
|
|
|
439
432
|
// must not entangle unrelated writes to it; the same rule holds one hop
|
|
440
433
|
// downstream: propagation never queues pended subscribers as pending
|
|
441
434
|
// nodes, see propagateAffectsMark, #2893.
|
|
442
|
-
for (let e = 0; e < t.
|
|
443
|
-
const i = t.
|
|
444
|
-
i.
|
|
445
|
-
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);
|
|
446
439
|
}
|
|
447
|
-
for (let e = 0; e < t.
|
|
448
|
-
const i = t.
|
|
449
|
-
i.
|
|
450
|
-
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);
|
|
451
444
|
}
|
|
452
|
-
if (t.
|
|
453
|
-
for (const e of t.
|
|
454
|
-
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;
|
|
455
448
|
}
|
|
456
449
|
for (const e of activeLanes) {
|
|
457
|
-
if (!e.
|
|
450
|
+
if (!e.Ue) e.Ue = activeTransition;
|
|
458
451
|
}
|
|
459
452
|
}
|
|
460
453
|
}
|
|
461
454
|
|
|
462
455
|
function queuePendingNode(e) {
|
|
463
|
-
currentBatch.
|
|
456
|
+
currentBatch.Qt.push(e);
|
|
464
457
|
}
|
|
465
458
|
|
|
466
459
|
// Sticky: flips true on the first refresh() ever (the only setter of
|
|
@@ -475,53 +468,53 @@ function armReaskClear() {
|
|
|
475
468
|
function insertSubs(e, t = false) {
|
|
476
469
|
// Get source lane: prefer node's own lane over current context
|
|
477
470
|
// This is important for isPending signals which need their own lane to flush immediately
|
|
478
|
-
const i = e.
|
|
479
|
-
const n = e.
|
|
471
|
+
const i = e.je || currentOptimisticLane;
|
|
472
|
+
const n = e.Ve !== undefined;
|
|
480
473
|
const s = reaskArmed;
|
|
481
|
-
for (let r = e.
|
|
474
|
+
for (let r = e.o; r !== null; r = r.ue) {
|
|
482
475
|
// A value-change notification is a new question for the subscriber: any
|
|
483
476
|
// pending re-ask mark (refresh) it carried is superseded.
|
|
484
|
-
if (s) r.
|
|
485
|
-
if (n && r.
|
|
486
|
-
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;
|
|
487
480
|
continue;
|
|
488
481
|
}
|
|
489
482
|
if (t && i) {
|
|
490
|
-
r.
|
|
491
|
-
assignOrMergeLane(r.
|
|
483
|
+
r.le.se |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
484
|
+
assignOrMergeLane(r.le, i);
|
|
492
485
|
} else if (t) {
|
|
493
|
-
r.
|
|
486
|
+
r.le.se |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
494
487
|
// No source lane means reversion - clear subscriber's lane so effects go to regular queue
|
|
495
|
-
r.
|
|
488
|
+
r.le.je = undefined;
|
|
496
489
|
}
|
|
497
|
-
enqueueSub(r.
|
|
490
|
+
enqueueSub(r.le);
|
|
498
491
|
}
|
|
499
492
|
}
|
|
500
493
|
|
|
501
494
|
function commitPendingNode(e) {
|
|
502
495
|
const t = e;
|
|
503
|
-
if (!t.
|
|
504
|
-
if (e.
|
|
505
|
-
e.
|
|
506
|
-
e.
|
|
496
|
+
if (!t.ke) {
|
|
497
|
+
if (e.Ne !== NOT_PENDING) {
|
|
498
|
+
e.Pe = e.Ne;
|
|
499
|
+
e.Ne = NOT_PENDING;
|
|
507
500
|
}
|
|
508
|
-
if (e.
|
|
501
|
+
if (e.be || e.ge) GlobalQueue.un(e);
|
|
509
502
|
return;
|
|
510
503
|
}
|
|
511
|
-
if (e.
|
|
512
|
-
e.
|
|
513
|
-
e.
|
|
504
|
+
if (e.Ne !== NOT_PENDING) {
|
|
505
|
+
e.Pe = e.Ne;
|
|
506
|
+
e.Ne = NOT_PENDING;
|
|
514
507
|
// Set _modified for effects, but not for tracked effects (they handle their own scheduling)
|
|
515
|
-
if (e.
|
|
508
|
+
if (e.Ae && e.Ae !== EFFECT_TRACKED) e.$e = true;
|
|
516
509
|
}
|
|
517
|
-
t.
|
|
518
|
-
if (!(t.
|
|
519
|
-
if (t.
|
|
520
|
-
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.be || e.ge) GlobalQueue.un(e);
|
|
521
514
|
}
|
|
522
515
|
|
|
523
516
|
function commitPendingNodes() {
|
|
524
|
-
const e = currentBatch.
|
|
517
|
+
const e = currentBatch.Qt;
|
|
525
518
|
for (let t = 0; t < e.length; t++) {
|
|
526
519
|
commitPendingNode(e[t]);
|
|
527
520
|
}
|
|
@@ -533,43 +526,49 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
533
526
|
// For completing transitions or no-transition, resolve pending and revert optimistic
|
|
534
527
|
const i = !t;
|
|
535
528
|
if (i) commitPendingNodes();
|
|
536
|
-
if (!t && globalQueue.
|
|
537
|
-
const n = dirtyQueue.EE >= dirtyQueue.
|
|
538
|
-
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);
|
|
539
532
|
if (i) {
|
|
540
533
|
if (n) commitPendingNodes();
|
|
541
534
|
// The settling batch: the completing transaction's, or the ambient one.
|
|
542
|
-
const t = e ?? globalQueue.
|
|
535
|
+
const t = e ?? globalQueue.m;
|
|
543
536
|
// Optimistic reversion: a non-empty batch means _optimisticWrite ran,
|
|
544
537
|
// which installed the engine's hooks.
|
|
545
|
-
if (t.
|
|
538
|
+
if (t.Ze.length) GlobalQueue.En(t.Ze);
|
|
546
539
|
// Replay entanglement: subs recorded by the read-time gate get rescheduled
|
|
547
540
|
// so they re-run with the now-committed values visible.
|
|
548
|
-
if (e && e.
|
|
549
|
-
for (const t of e.
|
|
550
|
-
if (t.
|
|
541
|
+
if (e && e.ln.size) {
|
|
542
|
+
for (const t of e.ln) {
|
|
543
|
+
if (t.se & REACTIVE_DISPOSED) continue;
|
|
551
544
|
enqueueSub(t);
|
|
552
545
|
}
|
|
553
|
-
e.
|
|
546
|
+
e.ln.clear();
|
|
554
547
|
}
|
|
555
548
|
// Declared motion ends with the transaction: settle (or plain flush end
|
|
556
549
|
// for ambient marks) releases each registration's refcount. A non-empty
|
|
557
|
-
// batch means registerAffectsMark ran, which installed the hook.
|
|
558
|
-
|
|
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
|
+
}
|
|
559
558
|
// A non-empty set means trackOptimisticStore ran, which installed the
|
|
560
559
|
// hook; the hook iterates, clears, and schedules (keeping the loop out of
|
|
561
560
|
// core lets esbuild shake it — rollup already folds the null guard). The
|
|
562
561
|
// completing transition scopes the clear to its own layer keys (#2899).
|
|
563
|
-
if (t.
|
|
562
|
+
if (t.cn.size) GlobalQueue.Dt(t.cn, e);
|
|
564
563
|
sweepTransientStoreNodes();
|
|
565
564
|
// Lanes only enter activeLanes through the engine's getOrCreateLane.
|
|
566
|
-
if (activeLanes.size) GlobalQueue.
|
|
565
|
+
if (activeLanes.size) GlobalQueue.dn(e);
|
|
567
566
|
}
|
|
568
567
|
}
|
|
569
568
|
|
|
570
569
|
function checkBoundaryChildren(e) {
|
|
571
|
-
for (const t of e.
|
|
572
|
-
t.
|
|
570
|
+
for (const t of e.vt) {
|
|
571
|
+
t.ne?.();
|
|
573
572
|
checkBoundaryChildren(t);
|
|
574
573
|
}
|
|
575
574
|
}
|
|
@@ -592,7 +591,7 @@ function checkBoundaryChildren(e) {
|
|
|
592
591
|
|
|
593
592
|
function reassignPendingTransition(e) {
|
|
594
593
|
for (let t = 0; t < e.length; t++) {
|
|
595
|
-
e[t].
|
|
594
|
+
e[t].Ue = activeTransition;
|
|
596
595
|
}
|
|
597
596
|
}
|
|
598
597
|
|
|
@@ -603,7 +602,7 @@ const globalQueue = new GlobalQueue;
|
|
|
603
602
|
// property hop through `_batch` was a measured instruction-count regression
|
|
604
603
|
// (CodSpeed update1to1, PR #2905). The field stays authoritative for
|
|
605
604
|
// cross-module readers; every `_batch` assignment updates both.
|
|
606
|
-
let currentBatch = globalQueue.
|
|
605
|
+
let currentBatch = globalQueue.m;
|
|
607
606
|
|
|
608
607
|
function flush(e) {
|
|
609
608
|
if (e) {
|
|
@@ -620,7 +619,7 @@ function flush(e) {
|
|
|
620
619
|
}
|
|
621
620
|
}
|
|
622
621
|
}
|
|
623
|
-
if (globalQueue.
|
|
622
|
+
if (globalQueue.kt) {
|
|
624
623
|
return;
|
|
625
624
|
}
|
|
626
625
|
if (halted) return;
|
|
@@ -636,23 +635,23 @@ function runQueue(e, t) {
|
|
|
636
635
|
}
|
|
637
636
|
|
|
638
637
|
function reporterBlocksSource(e, t) {
|
|
639
|
-
if (e.
|
|
640
|
-
if (e.
|
|
641
|
-
for (let i = e.
|
|
642
|
-
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;
|
|
643
642
|
while (e) {
|
|
644
|
-
if (e === t || e.
|
|
645
|
-
e = e.
|
|
643
|
+
if (e === t || e.nt === t) return true;
|
|
644
|
+
e = e.nn;
|
|
646
645
|
}
|
|
647
646
|
}
|
|
648
|
-
return !!(e.
|
|
647
|
+
return !!(e.S & STATUS_PENDING && e._ instanceof NotReadyError && e._.source === t);
|
|
649
648
|
}
|
|
650
649
|
|
|
651
650
|
function transitionComplete(e) {
|
|
652
|
-
if (e.
|
|
653
|
-
if (e.
|
|
651
|
+
if (e.fn) return true;
|
|
652
|
+
if (e.ie.length) return false;
|
|
654
653
|
let t = true;
|
|
655
|
-
for (const [i, n] of e.
|
|
654
|
+
for (const [i, n] of e.yt) {
|
|
656
655
|
let s = false;
|
|
657
656
|
for (const e of n) {
|
|
658
657
|
if (reporterBlocksSource(e, i)) {
|
|
@@ -661,7 +660,7 @@ function transitionComplete(e) {
|
|
|
661
660
|
}
|
|
662
661
|
n.delete(e);
|
|
663
662
|
}
|
|
664
|
-
if (!s) e.
|
|
663
|
+
if (!s) e.yt.delete(i); else if (i.S & STATUS_PENDING && i._?.source === i) {
|
|
665
664
|
t = false;
|
|
666
665
|
break;
|
|
667
666
|
}
|
|
@@ -669,13 +668,13 @@ function transitionComplete(e) {
|
|
|
669
668
|
// Override blockage lives with the engine. Absent hook = "no optimistic
|
|
670
669
|
// blockage", which is exact: only _optimisticWrite (engine) pushes to
|
|
671
670
|
// _optimisticNodes, so without the engine the loop was vacuous anyway.
|
|
672
|
-
if (t && e.
|
|
673
|
-
t && (e.
|
|
671
|
+
if (t && e.Ze.length && GlobalQueue.Tn(e)) t = false;
|
|
672
|
+
t && (e.fn = true);
|
|
674
673
|
return t;
|
|
675
674
|
}
|
|
676
675
|
|
|
677
676
|
function currentTransition(e) {
|
|
678
|
-
while (e.
|
|
677
|
+
while (e.fn && typeof e.fn === "object") e = e.fn;
|
|
679
678
|
return e;
|
|
680
679
|
}
|
|
681
680
|
|