@solidjs/signals 0.13.3 → 0.13.5
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 +588 -354
- package/dist/node.cjs +1211 -1016
- package/dist/prod.js +1054 -852
- package/dist/types/core/async.d.ts +2 -1
- package/dist/types/core/effect.d.ts +2 -2
- package/dist/types/core/index.d.ts +1 -1
- package/dist/types/core/lanes.d.ts +4 -0
- package/dist/types/core/owner.d.ts +1 -1
- package/dist/types/core/scheduler.d.ts +3 -0
- package/dist/types/core/types.d.ts +4 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/signals.d.ts +2 -0
- package/dist/types/store/projection.d.ts +1 -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
|
-
}
|
|
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);
|
|
751
906
|
}
|
|
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;
|
|
790
|
-
}
|
|
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) {
|
|
@@ -900,7 +1016,7 @@ function getObserver() {
|
|
|
900
1016
|
function getOwner() {
|
|
901
1017
|
return context;
|
|
902
1018
|
}
|
|
903
|
-
function
|
|
1019
|
+
function cleanup(fn) {
|
|
904
1020
|
if (!context) return fn;
|
|
905
1021
|
if (!context._disposal) context._disposal = fn;
|
|
906
1022
|
else if (Array.isArray(context._disposal)) context._disposal.push(fn);
|
|
@@ -933,8 +1049,10 @@ function createOwner(options) {
|
|
|
933
1049
|
disposeChildren(owner, self);
|
|
934
1050
|
}
|
|
935
1051
|
};
|
|
936
|
-
if (
|
|
937
|
-
throw new Error(
|
|
1052
|
+
if (parent?._childrenForbidden) {
|
|
1053
|
+
throw new Error(
|
|
1054
|
+
"Cannot create reactive primitives inside createTrackedEffect or owner-backed onSettled"
|
|
1055
|
+
);
|
|
938
1056
|
}
|
|
939
1057
|
if (parent) {
|
|
940
1058
|
const lastChild = parent._firstChild;
|
|
@@ -951,136 +1069,67 @@ function createRoot(init, options) {
|
|
|
951
1069
|
const owner = createOwner(options);
|
|
952
1070
|
return runWithOwner(owner, () => init(owner.dispose));
|
|
953
1071
|
}
|
|
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
|
-
}
|
|
1072
|
+
function unlinkSubs(link) {
|
|
1073
|
+
const dep = link._dep;
|
|
1074
|
+
const nextDep = link._nextDep;
|
|
1075
|
+
const nextSub = link._nextSub;
|
|
1076
|
+
const prevSub = link._prevSub;
|
|
1077
|
+
if (nextSub !== null) nextSub._prevSub = prevSub;
|
|
1078
|
+
else dep._subsTail = prevSub;
|
|
1079
|
+
if (prevSub !== null) prevSub._nextSub = nextSub;
|
|
1080
|
+
else {
|
|
1081
|
+
dep._subs = nextSub;
|
|
1082
|
+
if (nextSub === null) {
|
|
1083
|
+
dep._unobserved?.();
|
|
1084
|
+
dep._fn && !dep._preventAutoDisposal && !(dep._flags & REACTIVE_ZOMBIE) && unobserved(dep);
|
|
1001
1085
|
}
|
|
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
1086
|
}
|
|
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;
|
|
1087
|
+
return nextDep;
|
|
1088
|
+
}
|
|
1089
|
+
function unobserved(el) {
|
|
1090
|
+
deleteFromHeap(el, el._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
|
|
1091
|
+
let dep = el._deps;
|
|
1092
|
+
while (dep !== null) {
|
|
1093
|
+
dep = unlinkSubs(dep);
|
|
1031
1094
|
}
|
|
1095
|
+
el._deps = null;
|
|
1096
|
+
disposeChildren(el, true);
|
|
1032
1097
|
}
|
|
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");
|
|
1098
|
+
function link(dep, sub) {
|
|
1099
|
+
const prevDep = sub._depsTail;
|
|
1100
|
+
if (prevDep !== null && prevDep._dep === dep) return;
|
|
1101
|
+
let nextDep = null;
|
|
1102
|
+
const isRecomputing = sub._flags & REACTIVE_RECOMPUTING_DEPS;
|
|
1103
|
+
if (isRecomputing) {
|
|
1104
|
+
nextDep = prevDep !== null ? prevDep._nextDep : sub._deps;
|
|
1105
|
+
if (nextDep !== null && nextDep._dep === dep) {
|
|
1106
|
+
sub._depsTail = nextDep;
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
const prevSub = dep._subsTail;
|
|
1111
|
+
if (prevSub !== null && prevSub._sub === sub && (!isRecomputing || isValidLink(prevSub, sub)))
|
|
1112
|
+
return;
|
|
1113
|
+
const newLink =
|
|
1114
|
+
(sub._depsTail =
|
|
1115
|
+
dep._subsTail =
|
|
1116
|
+
{ _dep: dep, _sub: sub, _nextDep: nextDep, _prevSub: prevSub, _nextSub: null });
|
|
1117
|
+
if (prevDep !== null) prevDep._nextDep = newLink;
|
|
1118
|
+
else sub._deps = newLink;
|
|
1119
|
+
if (prevSub !== null) prevSub._nextSub = newLink;
|
|
1120
|
+
else dep._subs = newLink;
|
|
1061
1121
|
}
|
|
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 };
|
|
1122
|
+
function isValidLink(checkLink, sub) {
|
|
1123
|
+
const depsTail = sub._depsTail;
|
|
1124
|
+
if (depsTail !== null) {
|
|
1125
|
+
let link = sub._deps;
|
|
1126
|
+
do {
|
|
1127
|
+
if (link === checkLink) return true;
|
|
1128
|
+
if (link === depsTail) break;
|
|
1129
|
+
link = link._nextDep;
|
|
1130
|
+
} while (link !== null);
|
|
1083
1131
|
}
|
|
1132
|
+
return false;
|
|
1084
1133
|
}
|
|
1085
1134
|
GlobalQueue._update = recompute;
|
|
1086
1135
|
GlobalQueue._dispose = disposeChildren;
|
|
@@ -1184,7 +1233,7 @@ function recompute(el, create = false) {
|
|
|
1184
1233
|
}
|
|
1185
1234
|
try {
|
|
1186
1235
|
value = handleAsync(el, el._fn(value));
|
|
1187
|
-
clearStatus(el);
|
|
1236
|
+
clearStatus(el, create);
|
|
1188
1237
|
const resolvedLane = resolveLane(el);
|
|
1189
1238
|
if (resolvedLane) {
|
|
1190
1239
|
resolvedLane._pendingAsync.delete(el);
|
|
@@ -1199,6 +1248,7 @@ function recompute(el, create = false) {
|
|
|
1199
1248
|
updatePendingSignal(lane._source);
|
|
1200
1249
|
}
|
|
1201
1250
|
}
|
|
1251
|
+
if (e instanceof NotReadyError) el._blocked = true;
|
|
1202
1252
|
notifyStatus(
|
|
1203
1253
|
el,
|
|
1204
1254
|
e instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR,
|
|
@@ -1319,8 +1369,10 @@ function computed(fn, initialValue, options) {
|
|
|
1319
1369
|
self._name = options?.name ?? "computed";
|
|
1320
1370
|
self._prevHeap = self;
|
|
1321
1371
|
const parent = context?._root ? context._parentComputed : context;
|
|
1322
|
-
if (
|
|
1323
|
-
throw new Error(
|
|
1372
|
+
if (context?._childrenForbidden) {
|
|
1373
|
+
throw new Error(
|
|
1374
|
+
"Cannot create reactive primitives inside createTrackedEffect or owner-backed onSettled"
|
|
1375
|
+
);
|
|
1324
1376
|
}
|
|
1325
1377
|
if (context) {
|
|
1326
1378
|
const lastChild = context._firstChild;
|
|
@@ -1338,7 +1390,7 @@ function computed(fn, initialValue, options) {
|
|
|
1338
1390
|
const source = externalSourceConfig.factory(self._fn, () => {
|
|
1339
1391
|
setSignal(bridgeSignal, undefined);
|
|
1340
1392
|
});
|
|
1341
|
-
|
|
1393
|
+
cleanup(() => source.dispose());
|
|
1342
1394
|
self._fn = prev => {
|
|
1343
1395
|
read(bridgeSignal);
|
|
1344
1396
|
return source.track(prev);
|
|
@@ -1441,12 +1493,19 @@ function read(el) {
|
|
|
1441
1493
|
return value;
|
|
1442
1494
|
}
|
|
1443
1495
|
if (pendingCheckActive) {
|
|
1444
|
-
const
|
|
1445
|
-
const pendingSig = getPendingSignal(target);
|
|
1496
|
+
const firewall = el._firewall;
|
|
1446
1497
|
const prevCheck = pendingCheckActive;
|
|
1447
1498
|
pendingCheckActive = false;
|
|
1448
|
-
if (
|
|
1449
|
-
|
|
1499
|
+
if (firewall && el._overrideValue !== undefined) {
|
|
1500
|
+
if (
|
|
1501
|
+
el._overrideValue !== NOT_PENDING &&
|
|
1502
|
+
(firewall._inFlight || !!(firewall._statusFlags & STATUS_PENDING))
|
|
1503
|
+
) {
|
|
1504
|
+
foundPending = true;
|
|
1505
|
+
}
|
|
1506
|
+
} else {
|
|
1507
|
+
if (read(getPendingSignal(el))) foundPending = true;
|
|
1508
|
+
if (firewall && read(getPendingSignal(firewall))) foundPending = true;
|
|
1450
1509
|
}
|
|
1451
1510
|
pendingCheckActive = prevCheck;
|
|
1452
1511
|
return el._value;
|
|
@@ -1482,9 +1541,13 @@ function read(el) {
|
|
|
1482
1541
|
}
|
|
1483
1542
|
}
|
|
1484
1543
|
if (owner._statusFlags & STATUS_PENDING) {
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1544
|
+
if (c && !(stale && owner._transition && activeTransition !== owner._transition)) {
|
|
1545
|
+
if (c?._childrenForbidden) {
|
|
1546
|
+
console.warn(
|
|
1547
|
+
"Reading a pending async value inside createTrackedEffect or onSettled will throw. " +
|
|
1548
|
+
"Use createEffect instead which supports async-aware reactivity."
|
|
1549
|
+
);
|
|
1550
|
+
}
|
|
1488
1551
|
if (currentOptimisticLane) {
|
|
1489
1552
|
const pendingLane = owner._optimisticLane;
|
|
1490
1553
|
const lane = findLane(currentOptimisticLane);
|
|
@@ -1520,8 +1583,10 @@ function read(el) {
|
|
|
1520
1583
|
`Reactive value read directly in ${strictRead} will not update. ` +
|
|
1521
1584
|
`Move it into a tracking scope (JSX, a memo, or an effect's compute function).`
|
|
1522
1585
|
);
|
|
1523
|
-
if (el._overrideValue !== undefined && el._overrideValue !== NOT_PENDING)
|
|
1586
|
+
if (el._overrideValue !== undefined && el._overrideValue !== NOT_PENDING) {
|
|
1587
|
+
if (c && stale && shouldReadStashedOptimisticValue(el)) return el._value;
|
|
1524
1588
|
return el._overrideValue;
|
|
1589
|
+
}
|
|
1525
1590
|
return !c ||
|
|
1526
1591
|
(currentOptimisticLane !== null &&
|
|
1527
1592
|
(el._overrideValue !== undefined ||
|
|
@@ -1534,7 +1599,7 @@ function read(el) {
|
|
|
1534
1599
|
: el._pendingValue;
|
|
1535
1600
|
}
|
|
1536
1601
|
function setSignal(el, v) {
|
|
1537
|
-
if (!el._pureWrite && !
|
|
1602
|
+
if (!el._pureWrite && !context?._childrenForbidden && context && el._firewall !== context)
|
|
1538
1603
|
console.warn("A Signal was written to in an owned scope.");
|
|
1539
1604
|
if (el._transition && activeTransition !== el._transition)
|
|
1540
1605
|
globalQueue.initTransition(el._transition);
|
|
@@ -1559,7 +1624,7 @@ function setSignal(el, v) {
|
|
|
1559
1624
|
}
|
|
1560
1625
|
if (isOptimistic) {
|
|
1561
1626
|
const firstOverride = el._overrideValue === NOT_PENDING;
|
|
1562
|
-
if (!firstOverride
|
|
1627
|
+
if (!firstOverride) globalQueue.initTransition(resolveTransition(el));
|
|
1563
1628
|
if (firstOverride) {
|
|
1564
1629
|
el._pendingValue = el._value;
|
|
1565
1630
|
globalQueue._optimisticNodes.push(el);
|
|
@@ -1582,6 +1647,10 @@ function setSignal(el, v) {
|
|
|
1582
1647
|
return v;
|
|
1583
1648
|
}
|
|
1584
1649
|
function runWithOwner(owner, fn) {
|
|
1650
|
+
if (owner && owner._flags & REACTIVE_DISPOSED)
|
|
1651
|
+
console.warn(
|
|
1652
|
+
"runWithOwner called with a disposed owner. Children created inside will never be disposed."
|
|
1653
|
+
);
|
|
1585
1654
|
const oldContext = context;
|
|
1586
1655
|
const prevTracking = tracking;
|
|
1587
1656
|
context = owner;
|
|
@@ -1605,6 +1674,10 @@ function getPendingSignal(el) {
|
|
|
1605
1674
|
}
|
|
1606
1675
|
function computePendingState(el) {
|
|
1607
1676
|
const comp = el;
|
|
1677
|
+
const firewall = el._firewall;
|
|
1678
|
+
if (firewall && el._pendingValue !== NOT_PENDING) {
|
|
1679
|
+
return !firewall._inFlight && !(firewall._statusFlags & STATUS_PENDING);
|
|
1680
|
+
}
|
|
1608
1681
|
if (el._overrideValue !== undefined && el._overrideValue !== NOT_PENDING) {
|
|
1609
1682
|
if (comp._statusFlags & STATUS_PENDING && !(comp._statusFlags & STATUS_UNINITIALIZED))
|
|
1610
1683
|
return true;
|
|
@@ -1614,6 +1687,9 @@ function computePendingState(el) {
|
|
|
1614
1687
|
}
|
|
1615
1688
|
return true;
|
|
1616
1689
|
}
|
|
1690
|
+
if (el._overrideValue !== undefined && el._overrideValue === NOT_PENDING && !el._parentSource) {
|
|
1691
|
+
return false;
|
|
1692
|
+
}
|
|
1617
1693
|
if (el._pendingValue !== NOT_PENDING && !(comp._statusFlags & STATUS_UNINITIALIZED)) return true;
|
|
1618
1694
|
return !!(comp._statusFlags & STATUS_PENDING && !(comp._statusFlags & STATUS_UNINITIALIZED));
|
|
1619
1695
|
}
|
|
@@ -1731,6 +1807,117 @@ function hasContext(context, owner) {
|
|
|
1731
1807
|
function isUndefined(value) {
|
|
1732
1808
|
return typeof value === "undefined";
|
|
1733
1809
|
}
|
|
1810
|
+
function effect(compute, effect, error, initialValue, options) {
|
|
1811
|
+
let initialized = false;
|
|
1812
|
+
const node = computed(
|
|
1813
|
+
options?.render ? p => staleValues(() => compute(p)) : compute,
|
|
1814
|
+
initialValue,
|
|
1815
|
+
{
|
|
1816
|
+
...options,
|
|
1817
|
+
equals: () => {
|
|
1818
|
+
node._modified = !node._error;
|
|
1819
|
+
if (initialized) node._queue.enqueue(node._type, runEffect.bind(node));
|
|
1820
|
+
return false;
|
|
1821
|
+
},
|
|
1822
|
+
lazy: true
|
|
1823
|
+
}
|
|
1824
|
+
);
|
|
1825
|
+
node._prevValue = initialValue;
|
|
1826
|
+
node._effectFn = effect;
|
|
1827
|
+
node._errorFn = error;
|
|
1828
|
+
node._cleanup = undefined;
|
|
1829
|
+
node._type = options?.render ? EFFECT_RENDER : EFFECT_USER;
|
|
1830
|
+
node._notifyStatus = (status, error) => {
|
|
1831
|
+
const actualStatus = status !== undefined ? status : node._statusFlags;
|
|
1832
|
+
const actualError = error !== undefined ? error : node._error;
|
|
1833
|
+
if (actualStatus & STATUS_ERROR) {
|
|
1834
|
+
let err = actualError;
|
|
1835
|
+
node._queue.notify(node, STATUS_PENDING, 0);
|
|
1836
|
+
if (node._type === EFFECT_USER) {
|
|
1837
|
+
try {
|
|
1838
|
+
return node._errorFn
|
|
1839
|
+
? node._errorFn(err, () => {
|
|
1840
|
+
node._cleanup?.();
|
|
1841
|
+
node._cleanup = undefined;
|
|
1842
|
+
})
|
|
1843
|
+
: console.error(err);
|
|
1844
|
+
} catch (e) {
|
|
1845
|
+
err = e;
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) throw err;
|
|
1849
|
+
} else if (node._type === EFFECT_RENDER) {
|
|
1850
|
+
node._queue.notify(node, STATUS_PENDING | STATUS_ERROR, actualStatus, actualError);
|
|
1851
|
+
if (_hitUnhandledAsync) {
|
|
1852
|
+
resetUnhandledAsync();
|
|
1853
|
+
const err = new Error("An async value must be rendered inside a Loading boundary.");
|
|
1854
|
+
if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) throw err;
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
};
|
|
1858
|
+
recompute(node, true);
|
|
1859
|
+
!options?.defer &&
|
|
1860
|
+
(node._type === EFFECT_USER
|
|
1861
|
+
? node._queue.enqueue(node._type, runEffect.bind(node))
|
|
1862
|
+
: runEffect.call(node));
|
|
1863
|
+
initialized = true;
|
|
1864
|
+
cleanup(() => node._cleanup?.());
|
|
1865
|
+
if (!node._parent)
|
|
1866
|
+
console.warn("Effects created outside a reactive context will never be disposed");
|
|
1867
|
+
}
|
|
1868
|
+
function runEffect() {
|
|
1869
|
+
if (!this._modified || this._flags & REACTIVE_DISPOSED) return;
|
|
1870
|
+
let prevStrictRead = false;
|
|
1871
|
+
{
|
|
1872
|
+
prevStrictRead = setStrictRead("an effect callback");
|
|
1873
|
+
}
|
|
1874
|
+
this._cleanup?.();
|
|
1875
|
+
this._cleanup = undefined;
|
|
1876
|
+
try {
|
|
1877
|
+
this._cleanup = this._effectFn(this._value, this._prevValue);
|
|
1878
|
+
} catch (error) {
|
|
1879
|
+
this._error = new StatusError(this, error);
|
|
1880
|
+
this._statusFlags |= STATUS_ERROR;
|
|
1881
|
+
if (!this._queue.notify(this, STATUS_ERROR, STATUS_ERROR)) throw error;
|
|
1882
|
+
} finally {
|
|
1883
|
+
setStrictRead(prevStrictRead);
|
|
1884
|
+
this._prevValue = this._value;
|
|
1885
|
+
this._modified = false;
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
function trackedEffect(fn, options) {
|
|
1889
|
+
const run = () => {
|
|
1890
|
+
if (!node._modified || node._flags & REACTIVE_DISPOSED) return;
|
|
1891
|
+
node._modified = false;
|
|
1892
|
+
recompute(node);
|
|
1893
|
+
};
|
|
1894
|
+
const node = computed(
|
|
1895
|
+
() => {
|
|
1896
|
+
node._cleanup?.();
|
|
1897
|
+
node._cleanup = undefined;
|
|
1898
|
+
node._cleanup = staleValues(fn) || undefined;
|
|
1899
|
+
},
|
|
1900
|
+
undefined,
|
|
1901
|
+
{ ...options, lazy: true }
|
|
1902
|
+
);
|
|
1903
|
+
node._cleanup = undefined;
|
|
1904
|
+
node._childrenForbidden = true;
|
|
1905
|
+
node._modified = true;
|
|
1906
|
+
node._type = EFFECT_TRACKED;
|
|
1907
|
+
node._notifyStatus = (status, error) => {
|
|
1908
|
+
const actualStatus = status !== undefined ? status : node._statusFlags;
|
|
1909
|
+
if (actualStatus & STATUS_ERROR) {
|
|
1910
|
+
node._queue.notify(node, STATUS_PENDING, 0);
|
|
1911
|
+
const err = error !== undefined ? error : node._error;
|
|
1912
|
+
if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) throw err;
|
|
1913
|
+
}
|
|
1914
|
+
};
|
|
1915
|
+
node._run = run;
|
|
1916
|
+
node._queue.enqueue(EFFECT_USER, run);
|
|
1917
|
+
cleanup(() => node._cleanup?.());
|
|
1918
|
+
if (!node._parent)
|
|
1919
|
+
console.warn("Effects created outside a reactive context will never be disposed");
|
|
1920
|
+
}
|
|
1734
1921
|
function restoreTransition(transition, fn) {
|
|
1735
1922
|
globalQueue.initTransition(transition);
|
|
1736
1923
|
const result = fn();
|
|
@@ -1775,6 +1962,17 @@ function action(genFn) {
|
|
|
1775
1962
|
step();
|
|
1776
1963
|
});
|
|
1777
1964
|
}
|
|
1965
|
+
function onCleanup(fn) {
|
|
1966
|
+
{
|
|
1967
|
+
const owner = getOwner();
|
|
1968
|
+
if (!owner) console.warn("onCleanup called outside a reactive context will never be run");
|
|
1969
|
+
else if (owner._childrenForbidden)
|
|
1970
|
+
throw new Error(
|
|
1971
|
+
"Cannot use onCleanup inside createTrackedEffect or onSettled; return a cleanup function instead"
|
|
1972
|
+
);
|
|
1973
|
+
}
|
|
1974
|
+
return cleanup(fn);
|
|
1975
|
+
}
|
|
1778
1976
|
function accessor(node) {
|
|
1779
1977
|
const fn = read.bind(null, node);
|
|
1780
1978
|
fn.$r = true;
|
|
@@ -1808,16 +2006,16 @@ function createTrackedEffect(compute, options) {
|
|
|
1808
2006
|
trackedEffect(compute, { ...options, name: options?.name ?? "trackedEffect" });
|
|
1809
2007
|
}
|
|
1810
2008
|
function createReaction(effectFn, options) {
|
|
1811
|
-
let
|
|
1812
|
-
|
|
2009
|
+
let cl = undefined;
|
|
2010
|
+
cleanup(() => cl?.());
|
|
1813
2011
|
const owner = getOwner();
|
|
1814
2012
|
return tracking => {
|
|
1815
2013
|
runWithOwner(owner, () => {
|
|
1816
2014
|
effect(
|
|
1817
2015
|
() => (tracking(), getOwner()),
|
|
1818
2016
|
node => {
|
|
1819
|
-
|
|
1820
|
-
|
|
2017
|
+
cl?.();
|
|
2018
|
+
cl = (effectFn.effect || effectFn)?.();
|
|
1821
2019
|
dispose(node);
|
|
1822
2020
|
},
|
|
1823
2021
|
effectFn.error,
|
|
@@ -1828,6 +2026,11 @@ function createReaction(effectFn, options) {
|
|
|
1828
2026
|
};
|
|
1829
2027
|
}
|
|
1830
2028
|
function resolve(fn) {
|
|
2029
|
+
if (getObserver()) {
|
|
2030
|
+
throw new Error(
|
|
2031
|
+
"Cannot call resolve inside a reactive scope; it only resolves the current value and does not track updates."
|
|
2032
|
+
);
|
|
2033
|
+
}
|
|
1831
2034
|
return new Promise((res, rej) => {
|
|
1832
2035
|
createRoot(dispose => {
|
|
1833
2036
|
computed(() => {
|
|
@@ -1850,7 +2053,8 @@ function createOptimistic(first, second, third) {
|
|
|
1850
2053
|
return [accessor(node), setSignal.bind(null, node)];
|
|
1851
2054
|
}
|
|
1852
2055
|
function onSettled(callback) {
|
|
1853
|
-
getOwner()
|
|
2056
|
+
const owner = getOwner();
|
|
2057
|
+
owner && !owner._childrenForbidden
|
|
1854
2058
|
? createTrackedEffect(() => untrack(callback))
|
|
1855
2059
|
: globalQueue.enqueue(EFFECT_USER, () => {
|
|
1856
2060
|
const cleanup = callback();
|
|
@@ -2025,8 +2229,16 @@ function createProjectionInternal(fn, initialValue = {}, options) {
|
|
|
2025
2229
|
const wrappedStore = wrapProjection(initialValue);
|
|
2026
2230
|
node = computed(() => {
|
|
2027
2231
|
const owner = getOwner();
|
|
2028
|
-
|
|
2029
|
-
|
|
2232
|
+
let settled = false;
|
|
2233
|
+
let result;
|
|
2234
|
+
const draft = new Proxy(
|
|
2235
|
+
wrappedStore,
|
|
2236
|
+
createWriteTraps(() => !settled || owner._inFlight === result)
|
|
2237
|
+
);
|
|
2238
|
+
storeSetter(draft, s => {
|
|
2239
|
+
result = fn(s);
|
|
2240
|
+
settled = true;
|
|
2241
|
+
const value = handleAsync(owner, result, value => {
|
|
2030
2242
|
value !== s &&
|
|
2031
2243
|
value !== undefined &&
|
|
2032
2244
|
storeSetter(wrappedStore, reconcile(value, options?.key || "id"));
|
|
@@ -2040,42 +2252,47 @@ function createProjectionInternal(fn, initialValue = {}, options) {
|
|
|
2040
2252
|
function createProjection(fn, initialValue = {}, options) {
|
|
2041
2253
|
return createProjectionInternal(fn, initialValue, options).store;
|
|
2042
2254
|
}
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2255
|
+
function createWriteTraps(isActive) {
|
|
2256
|
+
const traps = {
|
|
2257
|
+
get(_, prop) {
|
|
2258
|
+
let value;
|
|
2259
|
+
setWriteOverride(true);
|
|
2260
|
+
setProjectionWriteActive(true);
|
|
2261
|
+
try {
|
|
2262
|
+
value = _[prop];
|
|
2263
|
+
} finally {
|
|
2264
|
+
setWriteOverride(false);
|
|
2265
|
+
setProjectionWriteActive(false);
|
|
2266
|
+
}
|
|
2267
|
+
return typeof value === "object" && value !== null ? new Proxy(value, traps) : value;
|
|
2268
|
+
},
|
|
2269
|
+
set(_, prop, value) {
|
|
2270
|
+
if (isActive && !isActive()) return true;
|
|
2271
|
+
setWriteOverride(true);
|
|
2272
|
+
setProjectionWriteActive(true);
|
|
2273
|
+
try {
|
|
2274
|
+
_[prop] = value;
|
|
2275
|
+
} finally {
|
|
2276
|
+
setWriteOverride(false);
|
|
2277
|
+
setProjectionWriteActive(false);
|
|
2278
|
+
}
|
|
2279
|
+
return true;
|
|
2280
|
+
},
|
|
2281
|
+
deleteProperty(_, prop) {
|
|
2282
|
+
if (isActive && !isActive()) return true;
|
|
2283
|
+
setWriteOverride(true);
|
|
2284
|
+
setProjectionWriteActive(true);
|
|
2285
|
+
try {
|
|
2286
|
+
delete _[prop];
|
|
2287
|
+
} finally {
|
|
2288
|
+
setWriteOverride(false);
|
|
2289
|
+
setProjectionWriteActive(false);
|
|
2290
|
+
}
|
|
2291
|
+
return true;
|
|
2075
2292
|
}
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
}
|
|
2293
|
+
};
|
|
2294
|
+
return traps;
|
|
2295
|
+
}
|
|
2079
2296
|
const $TRACK = Symbol("STORE_TRACK"),
|
|
2080
2297
|
$TARGET = Symbol("STORE_TARGET"),
|
|
2081
2298
|
$PROXY = Symbol("STORE_PROXY"),
|
|
@@ -2485,10 +2702,18 @@ function createOptimisticProjectionInternal(fn, initialValue = {}, options) {
|
|
|
2485
2702
|
if (fn) {
|
|
2486
2703
|
node = computed(() => {
|
|
2487
2704
|
const owner = getOwner();
|
|
2705
|
+
let settled = false;
|
|
2706
|
+
let result;
|
|
2707
|
+
const draft = new Proxy(
|
|
2708
|
+
wrappedStore,
|
|
2709
|
+
createWriteTraps(() => !settled || owner._inFlight === result)
|
|
2710
|
+
);
|
|
2488
2711
|
setProjectionWriteActive(true);
|
|
2489
2712
|
try {
|
|
2490
|
-
storeSetter(
|
|
2491
|
-
|
|
2713
|
+
storeSetter(draft, s => {
|
|
2714
|
+
result = fn(s);
|
|
2715
|
+
settled = true;
|
|
2716
|
+
const value = handleAsync(owner, result, value => {
|
|
2492
2717
|
setProjectionWriteActive(true);
|
|
2493
2718
|
try {
|
|
2494
2719
|
value !== s &&
|
|
@@ -3013,7 +3238,7 @@ function boundaryComputed(fn, propagationMask) {
|
|
|
3013
3238
|
function createBoundChildren(owner, fn, queue, mask) {
|
|
3014
3239
|
const parentQueue = owner._queue;
|
|
3015
3240
|
parentQueue.addChild((owner._queue = queue));
|
|
3016
|
-
|
|
3241
|
+
cleanup(() => parentQueue.removeChild(owner._queue));
|
|
3017
3242
|
return runWithOwner(owner, () => {
|
|
3018
3243
|
const c = computed(fn);
|
|
3019
3244
|
return boundaryComputed(() => staleValues(() => flatten(read(c))), mask);
|
|
@@ -3053,6 +3278,9 @@ class CollectionQueue extends Queue {
|
|
|
3053
3278
|
}
|
|
3054
3279
|
if (this._collectionType & STATUS_PENDING && this._initialized)
|
|
3055
3280
|
return super.notify(node, type, flags, error);
|
|
3281
|
+
if (this._collectionType & STATUS_PENDING && flags & STATUS_ERROR) {
|
|
3282
|
+
return super.notify(node, STATUS_ERROR, flags, error);
|
|
3283
|
+
}
|
|
3056
3284
|
if (flags & this._collectionType) {
|
|
3057
3285
|
const source = error?.source || node._error?.source;
|
|
3058
3286
|
if (source) {
|
|
@@ -3066,7 +3294,11 @@ class CollectionQueue extends Queue {
|
|
|
3066
3294
|
}
|
|
3067
3295
|
checkSources() {
|
|
3068
3296
|
for (const source of this._sources) {
|
|
3069
|
-
if (
|
|
3297
|
+
if (
|
|
3298
|
+
!(source._statusFlags & this._collectionType) &&
|
|
3299
|
+
!(this._collectionType & STATUS_ERROR && source._statusFlags & STATUS_PENDING)
|
|
3300
|
+
)
|
|
3301
|
+
this._sources.delete(source);
|
|
3070
3302
|
}
|
|
3071
3303
|
if (!this._sources.size) {
|
|
3072
3304
|
setSignal(this._disabled, false);
|
|
@@ -3079,6 +3311,8 @@ class CollectionQueue extends Queue {
|
|
|
3079
3311
|
}
|
|
3080
3312
|
}
|
|
3081
3313
|
function createCollectionBoundary(type, fn, fallback, onFn) {
|
|
3314
|
+
if (!getOwner())
|
|
3315
|
+
console.warn("Boundaries created outside a reactive context will never be disposed.");
|
|
3082
3316
|
const owner = createOwner();
|
|
3083
3317
|
const queue = new CollectionQueue(type);
|
|
3084
3318
|
if (onFn) queue._onFn = onFn;
|