@solidjs/signals 0.13.2 → 0.13.4
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 +515 -312
- package/dist/node.cjs +1271 -1106
- package/dist/prod.js +970 -798
- package/dist/types/core/async.d.ts +2 -1
- package/dist/types/core/effect.d.ts +2 -2
- package/dist/types/core/lanes.d.ts +4 -0
- package/dist/types/core/scheduler.d.ts +3 -0
- package/dist/types/core/types.d.ts +7 -0
- package/package.json +1 -1
package/dist/dev.js
CHANGED
|
@@ -153,12 +153,16 @@ let scheduled = false;
|
|
|
153
153
|
let projectionWriteActive = false;
|
|
154
154
|
let _enforceLoadingBoundary = false;
|
|
155
155
|
let _hitUnhandledAsync = false;
|
|
156
|
+
let stashedOptimisticReads = null;
|
|
156
157
|
function resetUnhandledAsync() {
|
|
157
158
|
_hitUnhandledAsync = false;
|
|
158
159
|
}
|
|
159
160
|
function enforceLoadingBoundary(enabled) {
|
|
160
161
|
_enforceLoadingBoundary = enabled;
|
|
161
162
|
}
|
|
163
|
+
function shouldReadStashedOptimisticValue(node) {
|
|
164
|
+
return !!stashedOptimisticReads?.has(node);
|
|
165
|
+
}
|
|
162
166
|
function runLaneEffects(type) {
|
|
163
167
|
for (const lane of activeLanes) {
|
|
164
168
|
if (lane._mergedInto || lane._pendingAsync.size > 0) continue;
|
|
@@ -169,14 +173,89 @@ function runLaneEffects(type) {
|
|
|
169
173
|
}
|
|
170
174
|
}
|
|
171
175
|
}
|
|
176
|
+
function queueStashedOptimisticEffects(node) {
|
|
177
|
+
for (let s = node._subs; s !== null; s = s._nextSub) {
|
|
178
|
+
const sub = s._sub;
|
|
179
|
+
if (!sub._type) continue;
|
|
180
|
+
if (sub._type === EFFECT_TRACKED) {
|
|
181
|
+
if (!sub._modified) {
|
|
182
|
+
sub._modified = true;
|
|
183
|
+
sub._queue.enqueue(EFFECT_USER, sub._run);
|
|
184
|
+
}
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const queue = sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
|
|
188
|
+
if (queue._min > sub._height) queue._min = sub._height;
|
|
189
|
+
insertIntoHeap(sub, queue);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
172
192
|
function setProjectionWriteActive(value) {
|
|
173
193
|
projectionWriteActive = value;
|
|
174
194
|
}
|
|
195
|
+
function mergeTransitionState(target, outgoing) {
|
|
196
|
+
outgoing._done = target;
|
|
197
|
+
target._actions.push(...outgoing._actions);
|
|
198
|
+
for (const lane of activeLanes) {
|
|
199
|
+
if (lane._transition === outgoing) lane._transition = target;
|
|
200
|
+
}
|
|
201
|
+
target._optimisticNodes.push(...outgoing._optimisticNodes);
|
|
202
|
+
for (const store of outgoing._optimisticStores) target._optimisticStores.add(store);
|
|
203
|
+
for (const node of outgoing._asyncNodes) {
|
|
204
|
+
if (!target._asyncNodes.includes(node)) target._asyncNodes.push(node);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function resolveOptimisticNodes(nodes) {
|
|
208
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
209
|
+
const node = nodes[i];
|
|
210
|
+
node._optimisticLane = undefined;
|
|
211
|
+
if (node._pendingValue !== NOT_PENDING) {
|
|
212
|
+
node._value = node._pendingValue;
|
|
213
|
+
node._pendingValue = NOT_PENDING;
|
|
214
|
+
}
|
|
215
|
+
const prevOverride = node._overrideValue;
|
|
216
|
+
node._overrideValue = NOT_PENDING;
|
|
217
|
+
if (prevOverride !== NOT_PENDING && node._value !== prevOverride) insertSubs(node, true);
|
|
218
|
+
node._transition = null;
|
|
219
|
+
}
|
|
220
|
+
nodes.length = 0;
|
|
221
|
+
}
|
|
222
|
+
function cleanupCompletedLanes(completingTransition) {
|
|
223
|
+
for (const lane of activeLanes) {
|
|
224
|
+
const owned = completingTransition
|
|
225
|
+
? lane._transition === completingTransition
|
|
226
|
+
: !lane._transition;
|
|
227
|
+
if (!owned) continue;
|
|
228
|
+
if (!lane._mergedInto) {
|
|
229
|
+
if (lane._effectQueues[0].length) runQueue(lane._effectQueues[0], EFFECT_RENDER);
|
|
230
|
+
if (lane._effectQueues[1].length) runQueue(lane._effectQueues[1], EFFECT_USER);
|
|
231
|
+
}
|
|
232
|
+
if (lane._source._optimisticLane === lane) lane._source._optimisticLane = undefined;
|
|
233
|
+
lane._pendingAsync.clear();
|
|
234
|
+
lane._effectQueues[0].length = 0;
|
|
235
|
+
lane._effectQueues[1].length = 0;
|
|
236
|
+
activeLanes.delete(lane);
|
|
237
|
+
signalLanes.delete(lane._source);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
175
240
|
function schedule() {
|
|
176
241
|
if (scheduled) return;
|
|
177
242
|
scheduled = true;
|
|
178
243
|
if (!globalQueue._running && !projectionWriteActive) queueMicrotask(flush);
|
|
179
244
|
}
|
|
245
|
+
function addTransitionBlocker(node) {
|
|
246
|
+
if (activeTransition && !activeTransition._asyncNodes.includes(node)) {
|
|
247
|
+
activeTransition._asyncNodes.push(node);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function removeTransitionBlocker(node) {
|
|
251
|
+
const remove = list => {
|
|
252
|
+
if (!list) return;
|
|
253
|
+
const index = list.indexOf(node);
|
|
254
|
+
if (index >= 0) list.splice(index, 1);
|
|
255
|
+
};
|
|
256
|
+
remove(node._transition?._asyncNodes);
|
|
257
|
+
remove(activeTransition?._asyncNodes);
|
|
258
|
+
}
|
|
180
259
|
class Queue {
|
|
181
260
|
_parent = null;
|
|
182
261
|
_queues = [[], []];
|
|
@@ -256,19 +335,32 @@ class GlobalQueue extends Queue {
|
|
|
256
335
|
if (activeTransition) {
|
|
257
336
|
const isComplete = transitionComplete(activeTransition);
|
|
258
337
|
if (!isComplete) {
|
|
259
|
-
|
|
338
|
+
const stashedTransition = activeTransition;
|
|
260
339
|
runHeap(zombieQueue, GlobalQueue._update);
|
|
261
340
|
this._pendingNodes = [];
|
|
262
341
|
this._optimisticNodes = [];
|
|
263
342
|
this._optimisticStores = new Set();
|
|
264
343
|
runLaneEffects(EFFECT_RENDER);
|
|
265
344
|
runLaneEffects(EFFECT_USER);
|
|
266
|
-
this.stashQueues(
|
|
345
|
+
this.stashQueues(stashedTransition._queueStash);
|
|
267
346
|
clock++;
|
|
268
347
|
scheduled = dirtyQueue._max >= dirtyQueue._min;
|
|
269
|
-
reassignPendingTransition(
|
|
348
|
+
reassignPendingTransition(stashedTransition._pendingNodes);
|
|
270
349
|
activeTransition = null;
|
|
271
|
-
|
|
350
|
+
if (!stashedTransition._actions.length && stashedTransition._optimisticNodes.length) {
|
|
351
|
+
stashedOptimisticReads = new Set();
|
|
352
|
+
for (let i = 0; i < stashedTransition._optimisticNodes.length; i++) {
|
|
353
|
+
const node = stashedTransition._optimisticNodes[i];
|
|
354
|
+
if (node._fn || node._pureWrite) continue;
|
|
355
|
+
stashedOptimisticReads.add(node);
|
|
356
|
+
queueStashedOptimisticEffects(node);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
try {
|
|
360
|
+
finalizePureQueue(null, true);
|
|
361
|
+
} finally {
|
|
362
|
+
stashedOptimisticReads = null;
|
|
363
|
+
}
|
|
272
364
|
return;
|
|
273
365
|
}
|
|
274
366
|
this._pendingNodes !== activeTransition._pendingNodes &&
|
|
@@ -297,13 +389,12 @@ class GlobalQueue extends Queue {
|
|
|
297
389
|
if (mask & STATUS_PENDING) {
|
|
298
390
|
if (flags & STATUS_PENDING) {
|
|
299
391
|
const actualError = error !== undefined ? error : node._error;
|
|
300
|
-
if (
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
schedule();
|
|
392
|
+
if (activeTransition && actualError) {
|
|
393
|
+
const source = actualError.source;
|
|
394
|
+
if (!activeTransition._asyncNodes.includes(source)) {
|
|
395
|
+
activeTransition._asyncNodes.push(source);
|
|
396
|
+
schedule();
|
|
397
|
+
}
|
|
307
398
|
}
|
|
308
399
|
if (_enforceLoadingBoundary) _hitUnhandledAsync = true;
|
|
309
400
|
}
|
|
@@ -328,37 +419,35 @@ class GlobalQueue extends Queue {
|
|
|
328
419
|
};
|
|
329
420
|
} else if (transition) {
|
|
330
421
|
const outgoing = activeTransition;
|
|
331
|
-
outgoing
|
|
332
|
-
transition._actions.push(...outgoing._actions);
|
|
333
|
-
for (const lane of activeLanes) {
|
|
334
|
-
if (lane._transition === outgoing) lane._transition = transition;
|
|
335
|
-
}
|
|
336
|
-
transition._optimisticNodes.push(...outgoing._optimisticNodes);
|
|
337
|
-
for (const store of outgoing._optimisticStores) {
|
|
338
|
-
transition._optimisticStores.add(store);
|
|
339
|
-
}
|
|
422
|
+
mergeTransitionState(transition, outgoing);
|
|
340
423
|
transitions.delete(outgoing);
|
|
341
424
|
activeTransition = transition;
|
|
342
425
|
}
|
|
343
426
|
transitions.add(activeTransition);
|
|
344
427
|
activeTransition._time = clock;
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
428
|
+
if (this._pendingNodes !== activeTransition._pendingNodes) {
|
|
429
|
+
for (let i = 0; i < this._pendingNodes.length; i++) {
|
|
430
|
+
const node = this._pendingNodes[i];
|
|
431
|
+
node._transition = activeTransition;
|
|
432
|
+
activeTransition._pendingNodes.push(node);
|
|
433
|
+
}
|
|
434
|
+
this._pendingNodes = activeTransition._pendingNodes;
|
|
435
|
+
}
|
|
436
|
+
if (this._optimisticNodes !== activeTransition._optimisticNodes) {
|
|
437
|
+
for (let i = 0; i < this._optimisticNodes.length; i++) {
|
|
438
|
+
const node = this._optimisticNodes[i];
|
|
439
|
+
node._transition = activeTransition;
|
|
440
|
+
activeTransition._optimisticNodes.push(node);
|
|
441
|
+
}
|
|
442
|
+
this._optimisticNodes = activeTransition._optimisticNodes;
|
|
443
|
+
}
|
|
357
444
|
for (const lane of activeLanes) {
|
|
358
445
|
if (!lane._transition) lane._transition = activeTransition;
|
|
359
446
|
}
|
|
360
|
-
|
|
361
|
-
|
|
447
|
+
if (this._optimisticStores !== activeTransition._optimisticStores) {
|
|
448
|
+
for (const store of this._optimisticStores) activeTransition._optimisticStores.add(store);
|
|
449
|
+
this._optimisticStores = activeTransition._optimisticStores;
|
|
450
|
+
}
|
|
362
451
|
}
|
|
363
452
|
}
|
|
364
453
|
function insertSubs(node, optimistic = false) {
|
|
@@ -398,40 +487,21 @@ function commitPendingNodes() {
|
|
|
398
487
|
n._pendingValue = NOT_PENDING;
|
|
399
488
|
if (n._type && n._type !== EFFECT_TRACKED) n._modified = true;
|
|
400
489
|
}
|
|
401
|
-
if (n._statusFlags & STATUS_PENDING)
|
|
402
|
-
const _src = n._error?.source;
|
|
403
|
-
if (_src && !(_src._statusFlags & STATUS_PENDING)) {
|
|
404
|
-
n._statusFlags &= -6;
|
|
405
|
-
n._error = null;
|
|
406
|
-
}
|
|
407
|
-
} else n._statusFlags &= ~STATUS_UNINITIALIZED;
|
|
490
|
+
if (!(n._statusFlags & STATUS_PENDING)) n._statusFlags &= ~STATUS_UNINITIALIZED;
|
|
408
491
|
if (n._fn) GlobalQueue._dispose(n, false, true);
|
|
409
492
|
}
|
|
410
493
|
pendingNodes.length = 0;
|
|
411
494
|
}
|
|
412
495
|
function finalizePureQueue(completingTransition = null, incomplete = false) {
|
|
413
|
-
|
|
496
|
+
const resolvePending = !incomplete;
|
|
414
497
|
if (resolvePending) commitPendingNodes();
|
|
415
498
|
if (!incomplete) checkBoundaryChildren(globalQueue);
|
|
416
499
|
if (dirtyQueue._max >= dirtyQueue._min) runHeap(dirtyQueue, GlobalQueue._update);
|
|
417
500
|
if (resolvePending) {
|
|
418
501
|
commitPendingNodes();
|
|
419
|
-
|
|
420
|
-
? completingTransition._optimisticNodes
|
|
421
|
-
|
|
422
|
-
for (let i = 0; i < optimisticNodes.length; i++) {
|
|
423
|
-
const n = optimisticNodes[i];
|
|
424
|
-
n._optimisticLane = undefined;
|
|
425
|
-
if (n._pendingValue !== NOT_PENDING) {
|
|
426
|
-
n._value = n._pendingValue;
|
|
427
|
-
n._pendingValue = NOT_PENDING;
|
|
428
|
-
}
|
|
429
|
-
const prevOverride = n._overrideValue;
|
|
430
|
-
n._overrideValue = NOT_PENDING;
|
|
431
|
-
if (prevOverride !== NOT_PENDING && n._value !== prevOverride) insertSubs(n, true);
|
|
432
|
-
n._transition = null;
|
|
433
|
-
}
|
|
434
|
-
optimisticNodes.length = 0;
|
|
502
|
+
resolveOptimisticNodes(
|
|
503
|
+
completingTransition ? completingTransition._optimisticNodes : globalQueue._optimisticNodes
|
|
504
|
+
);
|
|
435
505
|
const optimisticStores = completingTransition
|
|
436
506
|
? completingTransition._optimisticStores
|
|
437
507
|
: globalQueue._optimisticStores;
|
|
@@ -442,22 +512,7 @@ function finalizePureQueue(completingTransition = null, incomplete = false) {
|
|
|
442
512
|
optimisticStores.clear();
|
|
443
513
|
schedule();
|
|
444
514
|
}
|
|
445
|
-
|
|
446
|
-
const owned = completingTransition
|
|
447
|
-
? lane._transition === completingTransition
|
|
448
|
-
: !lane._transition;
|
|
449
|
-
if (!owned) continue;
|
|
450
|
-
if (!lane._mergedInto) {
|
|
451
|
-
if (lane._effectQueues[0].length) runQueue(lane._effectQueues[0], EFFECT_RENDER);
|
|
452
|
-
if (lane._effectQueues[1].length) runQueue(lane._effectQueues[1], EFFECT_USER);
|
|
453
|
-
}
|
|
454
|
-
if (lane._source._optimisticLane === lane) lane._source._optimisticLane = undefined;
|
|
455
|
-
lane._pendingAsync.clear();
|
|
456
|
-
lane._effectQueues[0].length = 0;
|
|
457
|
-
lane._effectQueues[1].length = 0;
|
|
458
|
-
activeLanes.delete(lane);
|
|
459
|
-
signalLanes.delete(lane._source);
|
|
460
|
-
}
|
|
515
|
+
cleanupCompletedLanes(completingTransition);
|
|
461
516
|
}
|
|
462
517
|
}
|
|
463
518
|
function checkBoundaryChildren(queue) {
|
|
@@ -478,7 +533,7 @@ function reassignPendingTransition(pendingNodes) {
|
|
|
478
533
|
const globalQueue = new GlobalQueue();
|
|
479
534
|
function flush() {
|
|
480
535
|
let count = 0;
|
|
481
|
-
while (scheduled) {
|
|
536
|
+
while (scheduled || activeTransition) {
|
|
482
537
|
if (++count === 1e5) throw new Error("Potential Infinite Loop Detected.");
|
|
483
538
|
globalQueue.flush();
|
|
484
539
|
}
|
|
@@ -560,6 +615,9 @@ function resolveLane(el) {
|
|
|
560
615
|
el._optimisticLane = undefined;
|
|
561
616
|
return undefined;
|
|
562
617
|
}
|
|
618
|
+
function resolveTransition(el) {
|
|
619
|
+
return resolveLane(el)?._transition ?? el._transition;
|
|
620
|
+
}
|
|
563
621
|
function hasActiveOverride(el) {
|
|
564
622
|
return !!(el._overrideValue !== undefined && el._overrideValue !== NOT_PENDING);
|
|
565
623
|
}
|
|
@@ -584,6 +642,96 @@ function assignOrMergeLane(el, sourceLane) {
|
|
|
584
642
|
}
|
|
585
643
|
el._optimisticLane = sourceLane;
|
|
586
644
|
}
|
|
645
|
+
function addPendingSource(el, source) {
|
|
646
|
+
if (el._pendingSource === source || el._pendingSources?.has(source)) return false;
|
|
647
|
+
if (!el._pendingSource) {
|
|
648
|
+
el._pendingSource = source;
|
|
649
|
+
return true;
|
|
650
|
+
}
|
|
651
|
+
if (!el._pendingSources) {
|
|
652
|
+
el._pendingSources = new Set([el._pendingSource, source]);
|
|
653
|
+
} else {
|
|
654
|
+
el._pendingSources.add(source);
|
|
655
|
+
}
|
|
656
|
+
el._pendingSource = undefined;
|
|
657
|
+
return true;
|
|
658
|
+
}
|
|
659
|
+
function removePendingSource(el, source) {
|
|
660
|
+
if (el._pendingSource) {
|
|
661
|
+
if (el._pendingSource !== source) return false;
|
|
662
|
+
el._pendingSource = undefined;
|
|
663
|
+
return true;
|
|
664
|
+
}
|
|
665
|
+
if (!el._pendingSources?.delete(source)) return false;
|
|
666
|
+
if (el._pendingSources.size === 1) {
|
|
667
|
+
el._pendingSource = el._pendingSources.values().next().value;
|
|
668
|
+
el._pendingSources = undefined;
|
|
669
|
+
} else if (el._pendingSources.size === 0) {
|
|
670
|
+
el._pendingSources = undefined;
|
|
671
|
+
}
|
|
672
|
+
return true;
|
|
673
|
+
}
|
|
674
|
+
function clearPendingSources(el) {
|
|
675
|
+
el._pendingSource = undefined;
|
|
676
|
+
el._pendingSources?.clear();
|
|
677
|
+
el._pendingSources = undefined;
|
|
678
|
+
}
|
|
679
|
+
function setPendingError(el, source, error) {
|
|
680
|
+
if (!source) {
|
|
681
|
+
el._error = null;
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
if (error instanceof NotReadyError && error.source === source) {
|
|
685
|
+
el._error = error;
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
const current = el._error;
|
|
689
|
+
if (!(current instanceof NotReadyError) || current.source !== source) {
|
|
690
|
+
el._error = new NotReadyError(source);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
function forEachDependent(el, fn) {
|
|
694
|
+
for (let s = el._subs; s !== null; s = s._nextSub) fn(s._sub);
|
|
695
|
+
for (let child = el._child; child !== null; child = child._nextChild) {
|
|
696
|
+
for (let s = child._subs; s !== null; s = s._nextSub) fn(s._sub);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
function settlePendingSource(el) {
|
|
700
|
+
let scheduled = false;
|
|
701
|
+
const visited = new Set();
|
|
702
|
+
const settle = node => {
|
|
703
|
+
if (visited.has(node) || !removePendingSource(node, el)) return;
|
|
704
|
+
visited.add(node);
|
|
705
|
+
node._time = clock;
|
|
706
|
+
const source = node._pendingSource ?? node._pendingSources?.values().next().value;
|
|
707
|
+
if (source) {
|
|
708
|
+
setPendingError(node, source);
|
|
709
|
+
updatePendingSignal(node);
|
|
710
|
+
} else {
|
|
711
|
+
node._statusFlags &= ~STATUS_PENDING;
|
|
712
|
+
setPendingError(node);
|
|
713
|
+
updatePendingSignal(node);
|
|
714
|
+
if (node._blocked) {
|
|
715
|
+
if (node._type === EFFECT_TRACKED) {
|
|
716
|
+
const tracked = node;
|
|
717
|
+
if (!tracked._modified) {
|
|
718
|
+
tracked._modified = true;
|
|
719
|
+
tracked._queue.enqueue(EFFECT_USER, tracked._run);
|
|
720
|
+
}
|
|
721
|
+
} else {
|
|
722
|
+
const queue = node._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
|
|
723
|
+
if (queue._min > node._height) queue._min = node._height;
|
|
724
|
+
insertIntoHeap(node, queue);
|
|
725
|
+
}
|
|
726
|
+
scheduled = true;
|
|
727
|
+
}
|
|
728
|
+
node._blocked = false;
|
|
729
|
+
}
|
|
730
|
+
forEachDependent(node, settle);
|
|
731
|
+
};
|
|
732
|
+
forEachDependent(el, settle);
|
|
733
|
+
if (scheduled) schedule();
|
|
734
|
+
}
|
|
587
735
|
function handleAsync(el, result, setter) {
|
|
588
736
|
const isObject = typeof result === "object" && result !== null;
|
|
589
737
|
const iterator = isObject && untrack(() => result[Symbol.asyncIterator]);
|
|
@@ -596,14 +744,14 @@ function handleAsync(el, result, setter) {
|
|
|
596
744
|
let syncValue;
|
|
597
745
|
const handleError = error => {
|
|
598
746
|
if (el._inFlight !== result) return;
|
|
599
|
-
globalQueue.initTransition(el
|
|
747
|
+
globalQueue.initTransition(resolveTransition(el));
|
|
600
748
|
notifyStatus(el, error instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, error);
|
|
601
749
|
el._time = clock;
|
|
602
750
|
};
|
|
603
751
|
const asyncWrite = (value, then) => {
|
|
604
752
|
if (el._inFlight !== result) return;
|
|
605
753
|
if (el._flags & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
606
|
-
globalQueue.initTransition(el
|
|
754
|
+
globalQueue.initTransition(resolveTransition(el));
|
|
607
755
|
clearStatus(el);
|
|
608
756
|
const lane = resolveLane(el);
|
|
609
757
|
if (lane) lane._pendingAsync.delete(el);
|
|
@@ -630,6 +778,7 @@ function handleAsync(el, result, setter) {
|
|
|
630
778
|
} else {
|
|
631
779
|
setSignal(el, () => value);
|
|
632
780
|
}
|
|
781
|
+
settlePendingSource(el);
|
|
633
782
|
schedule();
|
|
634
783
|
flush();
|
|
635
784
|
then?.();
|
|
@@ -650,7 +799,7 @@ function handleAsync(el, result, setter) {
|
|
|
650
799
|
);
|
|
651
800
|
isSync = false;
|
|
652
801
|
if (!resolved) {
|
|
653
|
-
globalQueue.initTransition(el
|
|
802
|
+
globalQueue.initTransition(resolveTransition(el));
|
|
654
803
|
throw new NotReadyError(context);
|
|
655
804
|
}
|
|
656
805
|
}
|
|
@@ -686,15 +835,18 @@ function handleAsync(el, result, setter) {
|
|
|
686
835
|
};
|
|
687
836
|
const immediatelyDone = iterate();
|
|
688
837
|
if (!hadSyncValue && !immediatelyDone) {
|
|
689
|
-
globalQueue.initTransition(el
|
|
838
|
+
globalQueue.initTransition(resolveTransition(el));
|
|
690
839
|
throw new NotReadyError(context);
|
|
691
840
|
}
|
|
692
841
|
}
|
|
693
842
|
return syncValue;
|
|
694
843
|
}
|
|
695
|
-
function clearStatus(el) {
|
|
696
|
-
el
|
|
697
|
-
el
|
|
844
|
+
function clearStatus(el, clearUninitialized = false) {
|
|
845
|
+
clearPendingSources(el);
|
|
846
|
+
removeTransitionBlocker(el);
|
|
847
|
+
el._blocked = false;
|
|
848
|
+
el._statusFlags = clearUninitialized ? 0 : el._statusFlags & STATUS_UNINITIALIZED;
|
|
849
|
+
setPendingError(el);
|
|
698
850
|
updatePendingSignal(el);
|
|
699
851
|
el._notifyStatus?.();
|
|
700
852
|
}
|
|
@@ -705,25 +857,30 @@ function notifyStatus(el, status, error, blockStatus, lane) {
|
|
|
705
857
|
!(error instanceof NotReadyError)
|
|
706
858
|
)
|
|
707
859
|
error = new StatusError(el, error);
|
|
708
|
-
const
|
|
860
|
+
const pendingSource =
|
|
861
|
+
status === STATUS_PENDING && error instanceof NotReadyError ? error.source : undefined;
|
|
862
|
+
const isSource = pendingSource === el;
|
|
709
863
|
const isOptimisticBoundary =
|
|
710
864
|
status === STATUS_PENDING && el._overrideValue !== undefined && !isSource;
|
|
711
865
|
const startsBlocking = isOptimisticBoundary && hasActiveOverride(el);
|
|
712
866
|
if (!blockStatus) {
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
867
|
+
if (status === STATUS_PENDING && pendingSource) {
|
|
868
|
+
addPendingSource(el, pendingSource);
|
|
869
|
+
el._statusFlags = STATUS_PENDING | (el._statusFlags & STATUS_UNINITIALIZED);
|
|
870
|
+
setPendingError(el, el._pendingSource ?? el._pendingSources?.values().next().value, error);
|
|
871
|
+
if (pendingSource === el) addTransitionBlocker(el);
|
|
872
|
+
} else {
|
|
873
|
+
clearPendingSources(el);
|
|
874
|
+
removeTransitionBlocker(el);
|
|
875
|
+
el._statusFlags =
|
|
876
|
+
status | (status !== STATUS_ERROR ? el._statusFlags & STATUS_UNINITIALIZED : 0);
|
|
877
|
+
el._error = error;
|
|
878
|
+
}
|
|
716
879
|
updatePendingSignal(el);
|
|
717
880
|
}
|
|
718
881
|
if (lane && !blockStatus) {
|
|
719
882
|
assignOrMergeLane(el, lane);
|
|
720
883
|
}
|
|
721
|
-
if (startsBlocking && activeTransition && error instanceof NotReadyError) {
|
|
722
|
-
const source = error.source;
|
|
723
|
-
if (!activeTransition._asyncNodes.includes(source)) {
|
|
724
|
-
activeTransition._asyncNodes.push(source);
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
884
|
const downstreamBlockStatus = blockStatus || startsBlocking;
|
|
728
885
|
const downstreamLane = blockStatus || isOptimisticBoundary ? undefined : lane;
|
|
729
886
|
if (el._notifyStatus) {
|
|
@@ -734,84 +891,43 @@ function notifyStatus(el, status, error, blockStatus, lane) {
|
|
|
734
891
|
}
|
|
735
892
|
return;
|
|
736
893
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
if (
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
notifyStatus(s._sub, status, error, downstreamBlockStatus, downstreamLane);
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
function unlinkSubs(link) {
|
|
755
|
-
const dep = link._dep;
|
|
756
|
-
const nextDep = link._nextDep;
|
|
757
|
-
const nextSub = link._nextSub;
|
|
758
|
-
const prevSub = link._prevSub;
|
|
759
|
-
if (nextSub !== null) nextSub._prevSub = prevSub;
|
|
760
|
-
else dep._subsTail = prevSub;
|
|
761
|
-
if (prevSub !== null) prevSub._nextSub = nextSub;
|
|
762
|
-
else {
|
|
763
|
-
dep._subs = nextSub;
|
|
764
|
-
if (nextSub === null) {
|
|
765
|
-
dep._unobserved?.();
|
|
766
|
-
dep._fn && !dep._preventAutoDisposal && !(dep._flags & REACTIVE_ZOMBIE) && unobserved(dep);
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
return nextDep;
|
|
770
|
-
}
|
|
771
|
-
function unobserved(el) {
|
|
772
|
-
deleteFromHeap(el, el._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
|
|
773
|
-
let dep = el._deps;
|
|
774
|
-
while (dep !== null) {
|
|
775
|
-
dep = unlinkSubs(dep);
|
|
776
|
-
}
|
|
777
|
-
el._deps = null;
|
|
778
|
-
disposeChildren(el, true);
|
|
779
|
-
}
|
|
780
|
-
function link(dep, sub) {
|
|
781
|
-
const prevDep = sub._depsTail;
|
|
782
|
-
if (prevDep !== null && prevDep._dep === dep) return;
|
|
783
|
-
let nextDep = null;
|
|
784
|
-
const isRecomputing = sub._flags & REACTIVE_RECOMPUTING_DEPS;
|
|
785
|
-
if (isRecomputing) {
|
|
786
|
-
nextDep = prevDep !== null ? prevDep._nextDep : sub._deps;
|
|
787
|
-
if (nextDep !== null && nextDep._dep === dep) {
|
|
788
|
-
sub._depsTail = nextDep;
|
|
789
|
-
return;
|
|
894
|
+
forEachDependent(el, sub => {
|
|
895
|
+
sub._time = clock;
|
|
896
|
+
if (
|
|
897
|
+
(status === STATUS_PENDING &&
|
|
898
|
+
pendingSource &&
|
|
899
|
+
sub._pendingSource !== pendingSource &&
|
|
900
|
+
!sub._pendingSources?.has(pendingSource)) ||
|
|
901
|
+
(status !== STATUS_PENDING &&
|
|
902
|
+
(sub._error !== error || sub._pendingSource || sub._pendingSources))
|
|
903
|
+
) {
|
|
904
|
+
!sub._transition && globalQueue._pendingNodes.push(sub);
|
|
905
|
+
notifyStatus(sub, status, error, downstreamBlockStatus, downstreamLane);
|
|
790
906
|
}
|
|
791
|
-
}
|
|
792
|
-
const prevSub = dep._subsTail;
|
|
793
|
-
if (prevSub !== null && prevSub._sub === sub && (!isRecomputing || isValidLink(prevSub, sub)))
|
|
794
|
-
return;
|
|
795
|
-
const newLink =
|
|
796
|
-
(sub._depsTail =
|
|
797
|
-
dep._subsTail =
|
|
798
|
-
{ _dep: dep, _sub: sub, _nextDep: nextDep, _prevSub: prevSub, _nextSub: null });
|
|
799
|
-
if (prevDep !== null) prevDep._nextDep = newLink;
|
|
800
|
-
else sub._deps = newLink;
|
|
801
|
-
if (prevSub !== null) prevSub._nextSub = newLink;
|
|
802
|
-
else dep._subs = newLink;
|
|
907
|
+
});
|
|
803
908
|
}
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
909
|
+
let externalSourceConfig = null;
|
|
910
|
+
function enableExternalSource(config) {
|
|
911
|
+
const { factory: factory, untrack: untrackFn = fn => fn() } = config;
|
|
912
|
+
if (externalSourceConfig) {
|
|
913
|
+
const { factory: oldFactory, untrack: oldUntrack } = externalSourceConfig;
|
|
914
|
+
externalSourceConfig = {
|
|
915
|
+
factory: (fn, trigger) => {
|
|
916
|
+
const oldSource = oldFactory(fn, trigger);
|
|
917
|
+
const source = factory(x => oldSource.track(x), trigger);
|
|
918
|
+
return {
|
|
919
|
+
track: x => source.track(x),
|
|
920
|
+
dispose() {
|
|
921
|
+
source.dispose();
|
|
922
|
+
oldSource.dispose();
|
|
923
|
+
}
|
|
924
|
+
};
|
|
925
|
+
},
|
|
926
|
+
untrack: fn => oldUntrack(() => untrackFn(fn))
|
|
927
|
+
};
|
|
928
|
+
} else {
|
|
929
|
+
externalSourceConfig = { factory: factory, untrack: untrackFn };
|
|
813
930
|
}
|
|
814
|
-
return false;
|
|
815
931
|
}
|
|
816
932
|
const PENDING_OWNER = {};
|
|
817
933
|
function markDisposal(el) {
|
|
@@ -901,7 +1017,15 @@ function getOwner() {
|
|
|
901
1017
|
return context;
|
|
902
1018
|
}
|
|
903
1019
|
function onCleanup(fn) {
|
|
904
|
-
if (!context)
|
|
1020
|
+
if (!context) {
|
|
1021
|
+
console.warn("onCleanup called outside a reactive context will never be run");
|
|
1022
|
+
return fn;
|
|
1023
|
+
}
|
|
1024
|
+
if (context._childrenForbidden) {
|
|
1025
|
+
throw new Error(
|
|
1026
|
+
"Cannot use onCleanup inside createTrackedEffect or onSettled; return a cleanup function instead"
|
|
1027
|
+
);
|
|
1028
|
+
}
|
|
905
1029
|
if (!context._disposal) context._disposal = fn;
|
|
906
1030
|
else if (Array.isArray(context._disposal)) context._disposal.push(fn);
|
|
907
1031
|
else context._disposal = [context._disposal, fn];
|
|
@@ -933,8 +1057,10 @@ function createOwner(options) {
|
|
|
933
1057
|
disposeChildren(owner, self);
|
|
934
1058
|
}
|
|
935
1059
|
};
|
|
936
|
-
if (
|
|
937
|
-
throw new Error(
|
|
1060
|
+
if (parent?._childrenForbidden) {
|
|
1061
|
+
throw new Error(
|
|
1062
|
+
"Cannot create reactive primitives inside createTrackedEffect or owner-backed onSettled"
|
|
1063
|
+
);
|
|
938
1064
|
}
|
|
939
1065
|
if (parent) {
|
|
940
1066
|
const lastChild = parent._firstChild;
|
|
@@ -951,136 +1077,67 @@ function createRoot(init, options) {
|
|
|
951
1077
|
const owner = createOwner(options);
|
|
952
1078
|
return runWithOwner(owner, () => init(owner.dispose));
|
|
953
1079
|
}
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
const
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
lazy: true
|
|
968
|
-
}
|
|
969
|
-
);
|
|
970
|
-
node._prevValue = initialValue;
|
|
971
|
-
node._effectFn = effect;
|
|
972
|
-
node._errorFn = error;
|
|
973
|
-
node._cleanup = undefined;
|
|
974
|
-
node._type = options?.render ? EFFECT_RENDER : EFFECT_USER;
|
|
975
|
-
node._notifyStatus = (status, error) => {
|
|
976
|
-
const actualStatus = status !== undefined ? status : node._statusFlags;
|
|
977
|
-
const actualError = error !== undefined ? error : node._error;
|
|
978
|
-
if (actualStatus & STATUS_ERROR) {
|
|
979
|
-
let err = actualError;
|
|
980
|
-
node._queue.notify(node, STATUS_PENDING, 0);
|
|
981
|
-
if (node._type === EFFECT_USER) {
|
|
982
|
-
try {
|
|
983
|
-
return node._errorFn
|
|
984
|
-
? node._errorFn(err, () => {
|
|
985
|
-
node._cleanup?.();
|
|
986
|
-
node._cleanup = undefined;
|
|
987
|
-
})
|
|
988
|
-
: console.error(err);
|
|
989
|
-
} catch (e) {
|
|
990
|
-
err = e;
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) throw err;
|
|
994
|
-
} else if (node._type === EFFECT_RENDER) {
|
|
995
|
-
node._queue.notify(node, STATUS_PENDING | STATUS_ERROR, actualStatus, actualError);
|
|
996
|
-
if (_hitUnhandledAsync) {
|
|
997
|
-
resetUnhandledAsync();
|
|
998
|
-
const err = new Error("An async value must be rendered inside a Loading boundary.");
|
|
999
|
-
if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) throw err;
|
|
1000
|
-
}
|
|
1080
|
+
function unlinkSubs(link) {
|
|
1081
|
+
const dep = link._dep;
|
|
1082
|
+
const nextDep = link._nextDep;
|
|
1083
|
+
const nextSub = link._nextSub;
|
|
1084
|
+
const prevSub = link._prevSub;
|
|
1085
|
+
if (nextSub !== null) nextSub._prevSub = prevSub;
|
|
1086
|
+
else dep._subsTail = prevSub;
|
|
1087
|
+
if (prevSub !== null) prevSub._nextSub = nextSub;
|
|
1088
|
+
else {
|
|
1089
|
+
dep._subs = nextSub;
|
|
1090
|
+
if (nextSub === null) {
|
|
1091
|
+
dep._unobserved?.();
|
|
1092
|
+
dep._fn && !dep._preventAutoDisposal && !(dep._flags & REACTIVE_ZOMBIE) && unobserved(dep);
|
|
1001
1093
|
}
|
|
1002
|
-
};
|
|
1003
|
-
recompute(node, true);
|
|
1004
|
-
!options?.defer &&
|
|
1005
|
-
(node._type === EFFECT_USER
|
|
1006
|
-
? node._queue.enqueue(node._type, runEffect.bind(node))
|
|
1007
|
-
: runEffect.call(node));
|
|
1008
|
-
initialized = true;
|
|
1009
|
-
onCleanup(() => node._cleanup?.());
|
|
1010
|
-
if (!node._parent)
|
|
1011
|
-
console.warn("Effects created outside a reactive context will never be disposed");
|
|
1012
|
-
}
|
|
1013
|
-
function runEffect() {
|
|
1014
|
-
if (!this._modified || this._flags & REACTIVE_DISPOSED) return;
|
|
1015
|
-
let prevStrictRead = false;
|
|
1016
|
-
{
|
|
1017
|
-
prevStrictRead = setStrictRead("an effect callback");
|
|
1018
1094
|
}
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
if (!this._queue.notify(this, STATUS_ERROR, STATUS_ERROR)) throw error;
|
|
1027
|
-
} finally {
|
|
1028
|
-
setStrictRead(prevStrictRead);
|
|
1029
|
-
this._prevValue = this._value;
|
|
1030
|
-
this._modified = false;
|
|
1095
|
+
return nextDep;
|
|
1096
|
+
}
|
|
1097
|
+
function unobserved(el) {
|
|
1098
|
+
deleteFromHeap(el, el._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
|
|
1099
|
+
let dep = el._deps;
|
|
1100
|
+
while (dep !== null) {
|
|
1101
|
+
dep = unlinkSubs(dep);
|
|
1031
1102
|
}
|
|
1103
|
+
el._deps = null;
|
|
1104
|
+
disposeChildren(el, true);
|
|
1032
1105
|
}
|
|
1033
|
-
function
|
|
1034
|
-
const
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
()
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
);
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
node._run = run;
|
|
1057
|
-
node._queue.enqueue(EFFECT_USER, run);
|
|
1058
|
-
onCleanup(() => node._cleanup?.());
|
|
1059
|
-
if (!node._parent)
|
|
1060
|
-
console.warn("Effects created outside a reactive context will never be disposed");
|
|
1106
|
+
function link(dep, sub) {
|
|
1107
|
+
const prevDep = sub._depsTail;
|
|
1108
|
+
if (prevDep !== null && prevDep._dep === dep) return;
|
|
1109
|
+
let nextDep = null;
|
|
1110
|
+
const isRecomputing = sub._flags & REACTIVE_RECOMPUTING_DEPS;
|
|
1111
|
+
if (isRecomputing) {
|
|
1112
|
+
nextDep = prevDep !== null ? prevDep._nextDep : sub._deps;
|
|
1113
|
+
if (nextDep !== null && nextDep._dep === dep) {
|
|
1114
|
+
sub._depsTail = nextDep;
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
const prevSub = dep._subsTail;
|
|
1119
|
+
if (prevSub !== null && prevSub._sub === sub && (!isRecomputing || isValidLink(prevSub, sub)))
|
|
1120
|
+
return;
|
|
1121
|
+
const newLink =
|
|
1122
|
+
(sub._depsTail =
|
|
1123
|
+
dep._subsTail =
|
|
1124
|
+
{ _dep: dep, _sub: sub, _nextDep: nextDep, _prevSub: prevSub, _nextSub: null });
|
|
1125
|
+
if (prevDep !== null) prevDep._nextDep = newLink;
|
|
1126
|
+
else sub._deps = newLink;
|
|
1127
|
+
if (prevSub !== null) prevSub._nextSub = newLink;
|
|
1128
|
+
else dep._subs = newLink;
|
|
1061
1129
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
return {
|
|
1072
|
-
track: x => source.track(x),
|
|
1073
|
-
dispose() {
|
|
1074
|
-
source.dispose();
|
|
1075
|
-
oldSource.dispose();
|
|
1076
|
-
}
|
|
1077
|
-
};
|
|
1078
|
-
},
|
|
1079
|
-
untrack: fn => oldUntrack(() => untrackFn(fn))
|
|
1080
|
-
};
|
|
1081
|
-
} else {
|
|
1082
|
-
externalSourceConfig = { factory: factory, untrack: untrackFn };
|
|
1130
|
+
function isValidLink(checkLink, sub) {
|
|
1131
|
+
const depsTail = sub._depsTail;
|
|
1132
|
+
if (depsTail !== null) {
|
|
1133
|
+
let link = sub._deps;
|
|
1134
|
+
do {
|
|
1135
|
+
if (link === checkLink) return true;
|
|
1136
|
+
if (link === depsTail) break;
|
|
1137
|
+
link = link._nextDep;
|
|
1138
|
+
} while (link !== null);
|
|
1083
1139
|
}
|
|
1140
|
+
return false;
|
|
1084
1141
|
}
|
|
1085
1142
|
GlobalQueue._update = recompute;
|
|
1086
1143
|
GlobalQueue._dispose = disposeChildren;
|
|
@@ -1184,7 +1241,7 @@ function recompute(el, create = false) {
|
|
|
1184
1241
|
}
|
|
1185
1242
|
try {
|
|
1186
1243
|
value = handleAsync(el, el._fn(value));
|
|
1187
|
-
clearStatus(el);
|
|
1244
|
+
clearStatus(el, create);
|
|
1188
1245
|
const resolvedLane = resolveLane(el);
|
|
1189
1246
|
if (resolvedLane) {
|
|
1190
1247
|
resolvedLane._pendingAsync.delete(el);
|
|
@@ -1199,6 +1256,7 @@ function recompute(el, create = false) {
|
|
|
1199
1256
|
updatePendingSignal(lane._source);
|
|
1200
1257
|
}
|
|
1201
1258
|
}
|
|
1259
|
+
if (e instanceof NotReadyError) el._blocked = true;
|
|
1202
1260
|
notifyStatus(
|
|
1203
1261
|
el,
|
|
1204
1262
|
e instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR,
|
|
@@ -1319,8 +1377,10 @@ function computed(fn, initialValue, options) {
|
|
|
1319
1377
|
self._name = options?.name ?? "computed";
|
|
1320
1378
|
self._prevHeap = self;
|
|
1321
1379
|
const parent = context?._root ? context._parentComputed : context;
|
|
1322
|
-
if (
|
|
1323
|
-
throw new Error(
|
|
1380
|
+
if (context?._childrenForbidden) {
|
|
1381
|
+
throw new Error(
|
|
1382
|
+
"Cannot create reactive primitives inside createTrackedEffect or owner-backed onSettled"
|
|
1383
|
+
);
|
|
1324
1384
|
}
|
|
1325
1385
|
if (context) {
|
|
1326
1386
|
const lastChild = context._firstChild;
|
|
@@ -1357,6 +1417,7 @@ function signal(v, options, firewall = null) {
|
|
|
1357
1417
|
const s = {
|
|
1358
1418
|
_equals: options?.equals != null ? options.equals : isEqual,
|
|
1359
1419
|
_pureWrite: !!options?.pureWrite,
|
|
1420
|
+
_noSnapshot: !!options?._noSnapshot,
|
|
1360
1421
|
_unobserved: options?.unobserved,
|
|
1361
1422
|
_value: v,
|
|
1362
1423
|
_subs: null,
|
|
@@ -1368,7 +1429,11 @@ function signal(v, options, firewall = null) {
|
|
|
1368
1429
|
};
|
|
1369
1430
|
s._name = options?.name ?? "signal";
|
|
1370
1431
|
firewall && (firewall._child = s);
|
|
1371
|
-
if (
|
|
1432
|
+
if (
|
|
1433
|
+
snapshotCaptureActive &&
|
|
1434
|
+
!s._noSnapshot &&
|
|
1435
|
+
!((firewall?._statusFlags ?? 0) & STATUS_PENDING)
|
|
1436
|
+
) {
|
|
1372
1437
|
s._snapshotValue = v === undefined ? NO_SNAPSHOT : v;
|
|
1373
1438
|
snapshotSources.add(s);
|
|
1374
1439
|
}
|
|
@@ -1436,13 +1501,11 @@ function read(el) {
|
|
|
1436
1501
|
return value;
|
|
1437
1502
|
}
|
|
1438
1503
|
if (pendingCheckActive) {
|
|
1439
|
-
const
|
|
1440
|
-
const pendingSig = getPendingSignal(target);
|
|
1504
|
+
const firewall = el._firewall;
|
|
1441
1505
|
const prevCheck = pendingCheckActive;
|
|
1442
1506
|
pendingCheckActive = false;
|
|
1443
|
-
if (read(
|
|
1444
|
-
|
|
1445
|
-
}
|
|
1507
|
+
if (read(getPendingSignal(el))) foundPending = true;
|
|
1508
|
+
if (firewall && read(getPendingSignal(firewall))) foundPending = true;
|
|
1446
1509
|
pendingCheckActive = prevCheck;
|
|
1447
1510
|
return el._value;
|
|
1448
1511
|
}
|
|
@@ -1477,9 +1540,13 @@ function read(el) {
|
|
|
1477
1540
|
}
|
|
1478
1541
|
}
|
|
1479
1542
|
if (owner._statusFlags & STATUS_PENDING) {
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1543
|
+
if (c && !(stale && owner._transition && activeTransition !== owner._transition)) {
|
|
1544
|
+
if (c?._childrenForbidden) {
|
|
1545
|
+
console.warn(
|
|
1546
|
+
"Reading a pending async value inside createTrackedEffect or onSettled will throw. " +
|
|
1547
|
+
"Use createEffect instead which supports async-aware reactivity."
|
|
1548
|
+
);
|
|
1549
|
+
}
|
|
1483
1550
|
if (currentOptimisticLane) {
|
|
1484
1551
|
const pendingLane = owner._optimisticLane;
|
|
1485
1552
|
const lane = findLane(currentOptimisticLane);
|
|
@@ -1515,8 +1582,10 @@ function read(el) {
|
|
|
1515
1582
|
`Reactive value read directly in ${strictRead} will not update. ` +
|
|
1516
1583
|
`Move it into a tracking scope (JSX, a memo, or an effect's compute function).`
|
|
1517
1584
|
);
|
|
1518
|
-
if (el._overrideValue !== undefined && el._overrideValue !== NOT_PENDING)
|
|
1585
|
+
if (el._overrideValue !== undefined && el._overrideValue !== NOT_PENDING) {
|
|
1586
|
+
if (c && stale && shouldReadStashedOptimisticValue(el)) return el._value;
|
|
1519
1587
|
return el._overrideValue;
|
|
1588
|
+
}
|
|
1520
1589
|
return !c ||
|
|
1521
1590
|
(currentOptimisticLane !== null &&
|
|
1522
1591
|
(el._overrideValue !== undefined ||
|
|
@@ -1529,7 +1598,7 @@ function read(el) {
|
|
|
1529
1598
|
: el._pendingValue;
|
|
1530
1599
|
}
|
|
1531
1600
|
function setSignal(el, v) {
|
|
1532
|
-
if (!el._pureWrite && !
|
|
1601
|
+
if (!el._pureWrite && !context?._childrenForbidden && context && el._firewall !== context)
|
|
1533
1602
|
console.warn("A Signal was written to in an owned scope.");
|
|
1534
1603
|
if (el._transition && activeTransition !== el._transition)
|
|
1535
1604
|
globalQueue.initTransition(el._transition);
|
|
@@ -1554,7 +1623,7 @@ function setSignal(el, v) {
|
|
|
1554
1623
|
}
|
|
1555
1624
|
if (isOptimistic) {
|
|
1556
1625
|
const firstOverride = el._overrideValue === NOT_PENDING;
|
|
1557
|
-
if (!firstOverride
|
|
1626
|
+
if (!firstOverride) globalQueue.initTransition(resolveTransition(el));
|
|
1558
1627
|
if (firstOverride) {
|
|
1559
1628
|
el._pendingValue = el._value;
|
|
1560
1629
|
globalQueue._optimisticNodes.push(el);
|
|
@@ -1577,6 +1646,10 @@ function setSignal(el, v) {
|
|
|
1577
1646
|
return v;
|
|
1578
1647
|
}
|
|
1579
1648
|
function runWithOwner(owner, fn) {
|
|
1649
|
+
if (owner && owner._flags & REACTIVE_DISPOSED)
|
|
1650
|
+
console.warn(
|
|
1651
|
+
"runWithOwner called with a disposed owner. Children created inside will never be disposed."
|
|
1652
|
+
);
|
|
1580
1653
|
const oldContext = context;
|
|
1581
1654
|
const prevTracking = tracking;
|
|
1582
1655
|
context = owner;
|
|
@@ -1600,6 +1673,10 @@ function getPendingSignal(el) {
|
|
|
1600
1673
|
}
|
|
1601
1674
|
function computePendingState(el) {
|
|
1602
1675
|
const comp = el;
|
|
1676
|
+
const firewall = el._firewall;
|
|
1677
|
+
if (firewall && el._pendingValue !== NOT_PENDING) {
|
|
1678
|
+
return !firewall._inFlight && !(firewall._statusFlags & STATUS_PENDING);
|
|
1679
|
+
}
|
|
1603
1680
|
if (el._overrideValue !== undefined && el._overrideValue !== NOT_PENDING) {
|
|
1604
1681
|
if (comp._statusFlags & STATUS_PENDING && !(comp._statusFlags & STATUS_UNINITIALIZED))
|
|
1605
1682
|
return true;
|
|
@@ -1726,6 +1803,117 @@ function hasContext(context, owner) {
|
|
|
1726
1803
|
function isUndefined(value) {
|
|
1727
1804
|
return typeof value === "undefined";
|
|
1728
1805
|
}
|
|
1806
|
+
function effect(compute, effect, error, initialValue, options) {
|
|
1807
|
+
let initialized = false;
|
|
1808
|
+
const node = computed(
|
|
1809
|
+
options?.render ? p => staleValues(() => compute(p)) : compute,
|
|
1810
|
+
initialValue,
|
|
1811
|
+
{
|
|
1812
|
+
...options,
|
|
1813
|
+
equals: () => {
|
|
1814
|
+
node._modified = !node._error;
|
|
1815
|
+
if (initialized) node._queue.enqueue(node._type, runEffect.bind(node));
|
|
1816
|
+
return false;
|
|
1817
|
+
},
|
|
1818
|
+
lazy: true
|
|
1819
|
+
}
|
|
1820
|
+
);
|
|
1821
|
+
node._prevValue = initialValue;
|
|
1822
|
+
node._effectFn = effect;
|
|
1823
|
+
node._errorFn = error;
|
|
1824
|
+
node._cleanup = undefined;
|
|
1825
|
+
node._type = options?.render ? EFFECT_RENDER : EFFECT_USER;
|
|
1826
|
+
node._notifyStatus = (status, error) => {
|
|
1827
|
+
const actualStatus = status !== undefined ? status : node._statusFlags;
|
|
1828
|
+
const actualError = error !== undefined ? error : node._error;
|
|
1829
|
+
if (actualStatus & STATUS_ERROR) {
|
|
1830
|
+
let err = actualError;
|
|
1831
|
+
node._queue.notify(node, STATUS_PENDING, 0);
|
|
1832
|
+
if (node._type === EFFECT_USER) {
|
|
1833
|
+
try {
|
|
1834
|
+
return node._errorFn
|
|
1835
|
+
? node._errorFn(err, () => {
|
|
1836
|
+
node._cleanup?.();
|
|
1837
|
+
node._cleanup = undefined;
|
|
1838
|
+
})
|
|
1839
|
+
: console.error(err);
|
|
1840
|
+
} catch (e) {
|
|
1841
|
+
err = e;
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) throw err;
|
|
1845
|
+
} else if (node._type === EFFECT_RENDER) {
|
|
1846
|
+
node._queue.notify(node, STATUS_PENDING | STATUS_ERROR, actualStatus, actualError);
|
|
1847
|
+
if (_hitUnhandledAsync) {
|
|
1848
|
+
resetUnhandledAsync();
|
|
1849
|
+
const err = new Error("An async value must be rendered inside a Loading boundary.");
|
|
1850
|
+
if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) throw err;
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
};
|
|
1854
|
+
recompute(node, true);
|
|
1855
|
+
!options?.defer &&
|
|
1856
|
+
(node._type === EFFECT_USER
|
|
1857
|
+
? node._queue.enqueue(node._type, runEffect.bind(node))
|
|
1858
|
+
: runEffect.call(node));
|
|
1859
|
+
initialized = true;
|
|
1860
|
+
onCleanup(() => node._cleanup?.());
|
|
1861
|
+
if (!node._parent)
|
|
1862
|
+
console.warn("Effects created outside a reactive context will never be disposed");
|
|
1863
|
+
}
|
|
1864
|
+
function runEffect() {
|
|
1865
|
+
if (!this._modified || this._flags & REACTIVE_DISPOSED) return;
|
|
1866
|
+
let prevStrictRead = false;
|
|
1867
|
+
{
|
|
1868
|
+
prevStrictRead = setStrictRead("an effect callback");
|
|
1869
|
+
}
|
|
1870
|
+
this._cleanup?.();
|
|
1871
|
+
this._cleanup = undefined;
|
|
1872
|
+
try {
|
|
1873
|
+
this._cleanup = this._effectFn(this._value, this._prevValue);
|
|
1874
|
+
} catch (error) {
|
|
1875
|
+
this._error = new StatusError(this, error);
|
|
1876
|
+
this._statusFlags |= STATUS_ERROR;
|
|
1877
|
+
if (!this._queue.notify(this, STATUS_ERROR, STATUS_ERROR)) throw error;
|
|
1878
|
+
} finally {
|
|
1879
|
+
setStrictRead(prevStrictRead);
|
|
1880
|
+
this._prevValue = this._value;
|
|
1881
|
+
this._modified = false;
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
function trackedEffect(fn, options) {
|
|
1885
|
+
const run = () => {
|
|
1886
|
+
if (!node._modified || node._flags & REACTIVE_DISPOSED) return;
|
|
1887
|
+
node._modified = false;
|
|
1888
|
+
recompute(node);
|
|
1889
|
+
};
|
|
1890
|
+
const node = computed(
|
|
1891
|
+
() => {
|
|
1892
|
+
node._cleanup?.();
|
|
1893
|
+
node._cleanup = undefined;
|
|
1894
|
+
node._cleanup = staleValues(fn) || undefined;
|
|
1895
|
+
},
|
|
1896
|
+
undefined,
|
|
1897
|
+
{ ...options, lazy: true }
|
|
1898
|
+
);
|
|
1899
|
+
node._cleanup = undefined;
|
|
1900
|
+
node._childrenForbidden = true;
|
|
1901
|
+
node._modified = true;
|
|
1902
|
+
node._type = EFFECT_TRACKED;
|
|
1903
|
+
node._notifyStatus = (status, error) => {
|
|
1904
|
+
const actualStatus = status !== undefined ? status : node._statusFlags;
|
|
1905
|
+
if (actualStatus & STATUS_ERROR) {
|
|
1906
|
+
node._queue.notify(node, STATUS_PENDING, 0);
|
|
1907
|
+
const err = error !== undefined ? error : node._error;
|
|
1908
|
+
if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) throw err;
|
|
1909
|
+
}
|
|
1910
|
+
};
|
|
1911
|
+
node._run = run;
|
|
1912
|
+
node._queue.enqueue(EFFECT_USER, run);
|
|
1913
|
+
onCleanup(() => node._cleanup?.());
|
|
1914
|
+
if (!node._parent)
|
|
1915
|
+
console.warn("Effects created outside a reactive context will never be disposed");
|
|
1916
|
+
}
|
|
1729
1917
|
function restoreTransition(transition, fn) {
|
|
1730
1918
|
globalQueue.initTransition(transition);
|
|
1731
1919
|
const result = fn();
|
|
@@ -1823,6 +2011,11 @@ function createReaction(effectFn, options) {
|
|
|
1823
2011
|
};
|
|
1824
2012
|
}
|
|
1825
2013
|
function resolve(fn) {
|
|
2014
|
+
if (getObserver()) {
|
|
2015
|
+
throw new Error(
|
|
2016
|
+
"Cannot call resolve inside a reactive scope; it only resolves the current value and does not track updates."
|
|
2017
|
+
);
|
|
2018
|
+
}
|
|
1826
2019
|
return new Promise((res, rej) => {
|
|
1827
2020
|
createRoot(dispose => {
|
|
1828
2021
|
computed(() => {
|
|
@@ -1845,7 +2038,8 @@ function createOptimistic(first, second, third) {
|
|
|
1845
2038
|
return [accessor(node), setSignal.bind(null, node)];
|
|
1846
2039
|
}
|
|
1847
2040
|
function onSettled(callback) {
|
|
1848
|
-
getOwner()
|
|
2041
|
+
const owner = getOwner();
|
|
2042
|
+
owner && !owner._childrenForbidden
|
|
1849
2043
|
? createTrackedEffect(() => untrack(callback))
|
|
1850
2044
|
: globalQueue.enqueue(EFFECT_USER, () => {
|
|
1851
2045
|
const cleanup = callback();
|
|
@@ -3018,7 +3212,7 @@ const ON_INIT = Symbol();
|
|
|
3018
3212
|
class CollectionQueue extends Queue {
|
|
3019
3213
|
_collectionType;
|
|
3020
3214
|
_sources = new Set();
|
|
3021
|
-
_disabled = signal(false, { pureWrite: true });
|
|
3215
|
+
_disabled = signal(false, { pureWrite: true, _noSnapshot: true });
|
|
3022
3216
|
_initialized = false;
|
|
3023
3217
|
_onFn;
|
|
3024
3218
|
_prevOn = ON_INIT;
|
|
@@ -3048,6 +3242,9 @@ class CollectionQueue extends Queue {
|
|
|
3048
3242
|
}
|
|
3049
3243
|
if (this._collectionType & STATUS_PENDING && this._initialized)
|
|
3050
3244
|
return super.notify(node, type, flags, error);
|
|
3245
|
+
if (this._collectionType & STATUS_PENDING && flags & STATUS_ERROR) {
|
|
3246
|
+
return super.notify(node, STATUS_ERROR, flags, error);
|
|
3247
|
+
}
|
|
3051
3248
|
if (flags & this._collectionType) {
|
|
3052
3249
|
const source = error?.source || node._error?.source;
|
|
3053
3250
|
if (source) {
|
|
@@ -3061,7 +3258,11 @@ class CollectionQueue extends Queue {
|
|
|
3061
3258
|
}
|
|
3062
3259
|
checkSources() {
|
|
3063
3260
|
for (const source of this._sources) {
|
|
3064
|
-
if (
|
|
3261
|
+
if (
|
|
3262
|
+
!(source._statusFlags & this._collectionType) &&
|
|
3263
|
+
!(this._collectionType & STATUS_ERROR && source._statusFlags & STATUS_PENDING)
|
|
3264
|
+
)
|
|
3265
|
+
this._sources.delete(source);
|
|
3065
3266
|
}
|
|
3066
3267
|
if (!this._sources.size) {
|
|
3067
3268
|
setSignal(this._disabled, false);
|
|
@@ -3074,6 +3275,8 @@ class CollectionQueue extends Queue {
|
|
|
3074
3275
|
}
|
|
3075
3276
|
}
|
|
3076
3277
|
function createCollectionBoundary(type, fn, fallback, onFn) {
|
|
3278
|
+
if (!getOwner())
|
|
3279
|
+
console.warn("Boundaries created outside a reactive context will never be disposed.");
|
|
3077
3280
|
const owner = createOwner();
|
|
3078
3281
|
const queue = new CollectionQueue(type);
|
|
3079
3282
|
if (onFn) queue._onFn = onFn;
|