@solidjs/signals 0.13.13 → 2.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -7
- package/dist/dev.js +502 -244
- package/dist/node.cjs +1501 -1308
- package/dist/prod.js +1134 -929
- package/dist/types/boundaries.d.ts +124 -3
- package/dist/types/core/action.d.ts +34 -0
- package/dist/types/core/constants.d.ts +24 -0
- package/dist/types/core/context.d.ts +10 -2
- package/dist/types/core/core.d.ts +108 -9
- package/dist/types/core/dev.d.ts +1 -1
- package/dist/types/core/effect.d.ts +3 -2
- package/dist/types/core/error.d.ts +24 -0
- package/dist/types/core/external.d.ts +19 -0
- package/dist/types/core/graph.d.ts +1 -0
- package/dist/types/core/owner.d.ts +93 -3
- package/dist/types/core/scheduler.d.ts +27 -2
- package/dist/types/core/types.d.ts +3 -6
- package/dist/types/index.d.ts +2 -2
- package/dist/types/map.d.ts +32 -3
- package/dist/types/signals.d.ts +338 -39
- package/dist/types/store/optimistic.d.ts +38 -12
- package/dist/types/store/projection.d.ts +55 -15
- package/dist/types/store/reconcile.d.ts +22 -0
- package/dist/types/store/store.d.ts +72 -15
- package/dist/types/store/storePath.d.ts +28 -0
- package/dist/types/store/utils.d.ts +78 -7
- package/dist/types-cjs/boundaries.d.cts +173 -0
- package/dist/types-cjs/core/action.d.cts +35 -0
- package/dist/types-cjs/core/async.d.cts +6 -0
- package/dist/types-cjs/core/constants.d.cts +49 -0
- package/dist/types-cjs/core/context.d.cts +36 -0
- package/dist/types-cjs/core/core.d.cts +153 -0
- package/dist/types-cjs/core/dev.d.cts +49 -0
- package/dist/types-cjs/core/effect.d.cts +31 -0
- package/dist/types-cjs/core/error.d.cts +38 -0
- package/dist/types-cjs/core/external.d.cts +45 -0
- package/dist/types-cjs/core/graph.d.cts +4 -0
- package/dist/types-cjs/core/heap.d.cts +14 -0
- package/dist/types-cjs/core/index.d.cts +12 -0
- package/dist/types-cjs/core/lanes.d.cts +54 -0
- package/dist/types-cjs/core/owner.d.cts +116 -0
- package/dist/types-cjs/core/scheduler.d.cts +106 -0
- package/dist/types-cjs/core/types.d.cts +83 -0
- package/dist/types-cjs/index.d.cts +9 -0
- package/dist/types-cjs/map.d.cts +53 -0
- package/dist/types-cjs/package.json +3 -0
- package/dist/types-cjs/signals.d.cts +491 -0
- package/dist/types-cjs/store/index.d.cts +9 -0
- package/dist/types-cjs/store/optimistic.d.cts +45 -0
- package/dist/types-cjs/store/projection.d.cts +66 -0
- package/dist/types-cjs/store/reconcile.d.cts +23 -0
- package/dist/types-cjs/store/store.d.cts +125 -0
- package/dist/types-cjs/store/storePath.d.cts +58 -0
- package/dist/types-cjs/store/utils.d.cts +114 -0
- package/package.json +32 -24
package/dist/dev.js
CHANGED
|
@@ -35,6 +35,12 @@ const REACTIVE_DISPOSED = 1 << 6;
|
|
|
35
35
|
const REACTIVE_OPTIMISTIC_DIRTY = 1 << 7;
|
|
36
36
|
const REACTIVE_SNAPSHOT_STALE = 1 << 8;
|
|
37
37
|
const REACTIVE_LAZY = 1 << 9;
|
|
38
|
+
const CONFIG_OWNED_WRITE = 1 << 0;
|
|
39
|
+
const CONFIG_NO_SNAPSHOT = 1 << 1;
|
|
40
|
+
const CONFIG_TRANSPARENT = 1 << 2;
|
|
41
|
+
const CONFIG_IN_SNAPSHOT_SCOPE = 1 << 3;
|
|
42
|
+
const CONFIG_CHILDREN_FORBIDDEN = 1 << 4;
|
|
43
|
+
const CONFIG_AUTO_DISPOSE = 1 << 5;
|
|
38
44
|
const STATUS_PENDING = 1 << 0;
|
|
39
45
|
const STATUS_ERROR = 1 << 1;
|
|
40
46
|
const STATUS_UNINITIALIZED = 1 << 2;
|
|
@@ -240,6 +246,23 @@ let inTrackedQueueCallback = false;
|
|
|
240
246
|
let _enforceLoadingBoundary = false;
|
|
241
247
|
let _hitUnhandledAsync = false;
|
|
242
248
|
let stashedOptimisticReads = null;
|
|
249
|
+
const transientStoreNodes = new Set();
|
|
250
|
+
function registerTransientStoreNode(node) {
|
|
251
|
+
transientStoreNodes.add(node);
|
|
252
|
+
}
|
|
253
|
+
function sweepTransientStoreNodes() {
|
|
254
|
+
if (transientStoreNodes.size === 0) return;
|
|
255
|
+
for (const node of transientStoreNodes) {
|
|
256
|
+
if (node._subs !== null) {
|
|
257
|
+
transientStoreNodes.delete(node);
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (node._pendingValue !== NOT_PENDING) continue;
|
|
261
|
+
if (node._overrideValue !== undefined && node._overrideValue !== NOT_PENDING) continue;
|
|
262
|
+
transientStoreNodes.delete(node);
|
|
263
|
+
node._unobserved?.();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
243
266
|
function resetUnhandledAsync() {
|
|
244
267
|
_hitUnhandledAsync = false;
|
|
245
268
|
}
|
|
@@ -292,6 +315,7 @@ function mergeTransitionState(target, outgoing) {
|
|
|
292
315
|
if (!targetReporters) target._asyncReporters.set(source, (targetReporters = new Set()));
|
|
293
316
|
for (const reporter of reporters) targetReporters.add(reporter);
|
|
294
317
|
}
|
|
318
|
+
for (const sub of outgoing._gatedSubs) target._gatedSubs.add(sub);
|
|
295
319
|
}
|
|
296
320
|
function resolveOptimisticNodes(nodes) {
|
|
297
321
|
for (let i = 0; i < nodes.length; i++) {
|
|
@@ -422,11 +446,15 @@ class GlobalQueue extends Queue {
|
|
|
422
446
|
scheduled = dirtyQueue._max >= dirtyQueue._min;
|
|
423
447
|
reassignPendingTransition(stashedTransition._pendingNodes);
|
|
424
448
|
activeTransition = null;
|
|
425
|
-
if (
|
|
449
|
+
if (
|
|
450
|
+
!stashedTransition._actions.length &&
|
|
451
|
+
!stashedTransition._asyncReporters.size &&
|
|
452
|
+
stashedTransition._optimisticNodes.length
|
|
453
|
+
) {
|
|
426
454
|
stashedOptimisticReads = new Set();
|
|
427
455
|
for (let i = 0; i < stashedTransition._optimisticNodes.length; i++) {
|
|
428
456
|
const node = stashedTransition._optimisticNodes[i];
|
|
429
|
-
if (node._fn || node.
|
|
457
|
+
if (node._fn || node._config & CONFIG_OWNED_WRITE) continue;
|
|
430
458
|
stashedOptimisticReads.add(node);
|
|
431
459
|
queueStashedOptimisticEffects(node);
|
|
432
460
|
}
|
|
@@ -492,7 +520,8 @@ class GlobalQueue extends Queue {
|
|
|
492
520
|
_optimisticStores: new Set(),
|
|
493
521
|
_actions: [],
|
|
494
522
|
_queueStash: { _queues: [[], []], _children: [] },
|
|
495
|
-
_done: false
|
|
523
|
+
_done: false,
|
|
524
|
+
_gatedSubs: new Set()
|
|
496
525
|
};
|
|
497
526
|
} else if (transition) {
|
|
498
527
|
const outgoing = activeTransition;
|
|
@@ -531,7 +560,7 @@ function insertSubs(node, optimistic = false) {
|
|
|
531
560
|
const sourceLane = node._optimisticLane || currentOptimisticLane;
|
|
532
561
|
const hasSnapshot = node._snapshotValue !== undefined;
|
|
533
562
|
for (let s = node._subs; s !== null; s = s._nextSub) {
|
|
534
|
-
if (hasSnapshot && s._sub.
|
|
563
|
+
if (hasSnapshot && s._sub._config & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
535
564
|
s._sub._flags |= REACTIVE_SNAPSHOT_STALE;
|
|
536
565
|
continue;
|
|
537
566
|
}
|
|
@@ -579,6 +608,22 @@ function finalizePureQueue(completingTransition = null, incomplete = false) {
|
|
|
579
608
|
resolveOptimisticNodes(
|
|
580
609
|
completingTransition ? completingTransition._optimisticNodes : globalQueue._optimisticNodes
|
|
581
610
|
);
|
|
611
|
+
if (completingTransition && completingTransition._gatedSubs.size) {
|
|
612
|
+
for (const sub of completingTransition._gatedSubs) {
|
|
613
|
+
if (sub._flags & REACTIVE_DISPOSED) continue;
|
|
614
|
+
if (sub._type === EFFECT_TRACKED) {
|
|
615
|
+
if (!sub._modified) {
|
|
616
|
+
sub._modified = true;
|
|
617
|
+
sub._queue.enqueue(EFFECT_USER, sub._run);
|
|
618
|
+
}
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
const queue = sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
|
|
622
|
+
if (queue._min > sub._height) queue._min = sub._height;
|
|
623
|
+
insertIntoHeap(sub, queue);
|
|
624
|
+
}
|
|
625
|
+
completingTransition._gatedSubs.clear();
|
|
626
|
+
}
|
|
582
627
|
const optimisticStores = completingTransition
|
|
583
628
|
? completingTransition._optimisticStores
|
|
584
629
|
: globalQueue._optimisticStores;
|
|
@@ -589,6 +634,7 @@ function finalizePureQueue(completingTransition = null, incomplete = false) {
|
|
|
589
634
|
optimisticStores.clear();
|
|
590
635
|
schedule();
|
|
591
636
|
}
|
|
637
|
+
sweepTransientStoreNodes();
|
|
592
638
|
cleanupCompletedLanes(completingTransition);
|
|
593
639
|
}
|
|
594
640
|
}
|
|
@@ -778,7 +824,8 @@ function unlinkSubs(link) {
|
|
|
778
824
|
dep._subs = nextSub;
|
|
779
825
|
if (nextSub === null) {
|
|
780
826
|
dep._unobserved?.();
|
|
781
|
-
|
|
827
|
+
const c = dep;
|
|
828
|
+
c._fn && c._config & CONFIG_AUTO_DISPOSE && !(c._flags & REACTIVE_ZOMBIE) && unobserved(c);
|
|
782
829
|
}
|
|
783
830
|
}
|
|
784
831
|
return nextDep;
|
|
@@ -790,6 +837,7 @@ function unobserved(el) {
|
|
|
790
837
|
dep = unlinkSubs(dep);
|
|
791
838
|
}
|
|
792
839
|
el._deps = null;
|
|
840
|
+
el._depsTail = null;
|
|
793
841
|
disposeChildren(el, true);
|
|
794
842
|
}
|
|
795
843
|
function link(dep, sub) {
|
|
@@ -894,7 +942,7 @@ function runDisposal(node, zombie) {
|
|
|
894
942
|
}
|
|
895
943
|
function childId(owner, consume) {
|
|
896
944
|
let counter = owner;
|
|
897
|
-
while (counter.
|
|
945
|
+
while (counter._config & CONFIG_TRANSPARENT && counter._parent) counter = counter._parent;
|
|
898
946
|
if (counter.id != null)
|
|
899
947
|
return formatId(counter.id, consume ? counter._childCount++ : counter._childCount);
|
|
900
948
|
throw new Error("Cannot get child id from owner without an id");
|
|
@@ -934,7 +982,7 @@ function createOwner(options) {
|
|
|
934
982
|
id:
|
|
935
983
|
options?.id ??
|
|
936
984
|
(transparent ? parent?.id : parent?.id != null ? getNextChildId(parent) : undefined),
|
|
937
|
-
|
|
985
|
+
_config: transparent ? CONFIG_TRANSPARENT : 0,
|
|
938
986
|
_root: true,
|
|
939
987
|
_parentComputed: parent?._root ? parent._parentComputed : parent,
|
|
940
988
|
_firstChild: null,
|
|
@@ -950,10 +998,16 @@ function createOwner(options) {
|
|
|
950
998
|
disposeChildren(owner, self);
|
|
951
999
|
}
|
|
952
1000
|
};
|
|
953
|
-
if (parent
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
1001
|
+
if (parent && parent._config & CONFIG_CHILDREN_FORBIDDEN) {
|
|
1002
|
+
emitDiagnostic({
|
|
1003
|
+
code: "PRIMITIVE_IN_FORBIDDEN_SCOPE",
|
|
1004
|
+
kind: "lifecycle",
|
|
1005
|
+
severity: "error",
|
|
1006
|
+
message: PRIMITIVE_IN_FORBIDDEN_SCOPE_MESSAGE,
|
|
1007
|
+
ownerId: parent.id,
|
|
1008
|
+
ownerName: parent._name
|
|
1009
|
+
});
|
|
1010
|
+
throw new Error(PRIMITIVE_IN_FORBIDDEN_SCOPE_MESSAGE);
|
|
957
1011
|
}
|
|
958
1012
|
if (parent) {
|
|
959
1013
|
const lastChild = parent._firstChild;
|
|
@@ -1280,6 +1334,8 @@ function enableExternalSource(config) {
|
|
|
1280
1334
|
}
|
|
1281
1335
|
GlobalQueue._update = recompute;
|
|
1282
1336
|
GlobalQueue._dispose = disposeChildren;
|
|
1337
|
+
const PRIMITIVE_IN_FORBIDDEN_SCOPE_MESSAGE =
|
|
1338
|
+
"[PRIMITIVE_IN_FORBIDDEN_SCOPE] Cannot create reactive primitives inside createTrackedEffect or owner-backed onSettled";
|
|
1283
1339
|
let tracking = false;
|
|
1284
1340
|
let stale = false;
|
|
1285
1341
|
let refreshing = false;
|
|
@@ -1318,7 +1374,7 @@ function releaseSubtree(owner) {
|
|
|
1318
1374
|
}
|
|
1319
1375
|
if (child._fn) {
|
|
1320
1376
|
const comp = child;
|
|
1321
|
-
comp.
|
|
1377
|
+
comp._config &= ~CONFIG_IN_SNAPSHOT_SCOPE;
|
|
1322
1378
|
if (comp._flags & REACTIVE_SNAPSHOT_STALE) {
|
|
1323
1379
|
comp._flags &= ~REACTIVE_SNAPSHOT_STALE;
|
|
1324
1380
|
comp._flags |= REACTIVE_DIRTY;
|
|
@@ -1358,7 +1414,7 @@ function recompute(el, create = false) {
|
|
|
1358
1414
|
clearSignals(el);
|
|
1359
1415
|
}
|
|
1360
1416
|
}
|
|
1361
|
-
|
|
1417
|
+
let isOptimisticDirty = !!(el._flags & REACTIVE_OPTIMISTIC_DIRTY);
|
|
1362
1418
|
const hasOverride = el._overrideValue !== undefined && el._overrideValue !== NOT_PENDING;
|
|
1363
1419
|
const wasPending = !!(el._statusFlags & STATUS_PENDING);
|
|
1364
1420
|
const wasUninitialized = !!(el._statusFlags & STATUS_UNINITIALIZED);
|
|
@@ -1380,9 +1436,25 @@ function recompute(el, create = false) {
|
|
|
1380
1436
|
if (isOptimisticDirty) {
|
|
1381
1437
|
const lane = resolveLane(el);
|
|
1382
1438
|
if (lane) currentOptimisticLane = lane;
|
|
1439
|
+
} else if (activeTransition && !create && activeTransition._optimisticNodes.length) {
|
|
1440
|
+
for (let d = el._deps; d; d = d._nextDep) {
|
|
1441
|
+
const dep = d._dep;
|
|
1442
|
+
if (dep._flags & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
1443
|
+
const depLane = resolveLane(dep);
|
|
1444
|
+
if (depLane) {
|
|
1445
|
+
isOptimisticDirty = true;
|
|
1446
|
+
currentOptimisticLane = depLane;
|
|
1447
|
+
el._flags |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
1448
|
+
assignOrMergeLane(el, depLane);
|
|
1449
|
+
break;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1383
1453
|
}
|
|
1384
1454
|
try {
|
|
1385
|
-
|
|
1455
|
+
const prevInFlight = el._inFlight;
|
|
1456
|
+
const fnResult = el._fn(value);
|
|
1457
|
+
value = el._inFlight !== prevInFlight ? fnResult : handleAsync(el, fnResult);
|
|
1386
1458
|
clearStatus(el, create);
|
|
1387
1459
|
const resolvedLane = resolveLane(el);
|
|
1388
1460
|
if (resolvedLane) {
|
|
@@ -1481,22 +1553,25 @@ function updateIfNecessary(el) {
|
|
|
1481
1553
|
}
|
|
1482
1554
|
el._flags = el._flags & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
1483
1555
|
}
|
|
1484
|
-
function computed(fn,
|
|
1556
|
+
function computed(fn, options) {
|
|
1485
1557
|
const transparent = options?.transparent ?? false;
|
|
1486
1558
|
const self = {
|
|
1487
1559
|
id:
|
|
1488
1560
|
options?.id ??
|
|
1489
1561
|
(transparent ? context?.id : context?.id != null ? getNextChildId(context) : undefined),
|
|
1490
|
-
|
|
1562
|
+
_config:
|
|
1563
|
+
(transparent ? CONFIG_TRANSPARENT : 0) |
|
|
1564
|
+
(options?.ownedWrite ? CONFIG_OWNED_WRITE : 0) |
|
|
1565
|
+
(!context || options?.lazy ? CONFIG_AUTO_DISPOSE : 0) |
|
|
1566
|
+
(snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
1491
1567
|
_equals: options?.equals != null ? options.equals : isEqual,
|
|
1492
|
-
_pureWrite: !!options?.pureWrite,
|
|
1493
1568
|
_unobserved: options?.unobserved,
|
|
1494
1569
|
_disposal: null,
|
|
1495
1570
|
_queue: context?._queue ?? globalQueue,
|
|
1496
1571
|
_context: context?._context ?? defaultContext,
|
|
1497
1572
|
_childCount: 0,
|
|
1498
1573
|
_fn: fn,
|
|
1499
|
-
_value:
|
|
1574
|
+
_value: undefined,
|
|
1500
1575
|
_height: 0,
|
|
1501
1576
|
_child: null,
|
|
1502
1577
|
_nextHeap: undefined,
|
|
@@ -1520,10 +1595,16 @@ function computed(fn, initialValue, options) {
|
|
|
1520
1595
|
self._name = options?.name ?? "computed";
|
|
1521
1596
|
self._prevHeap = self;
|
|
1522
1597
|
const parent = context?._root ? context._parentComputed : context;
|
|
1523
|
-
if (context
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1598
|
+
if (context && context._config & CONFIG_CHILDREN_FORBIDDEN) {
|
|
1599
|
+
emitDiagnostic({
|
|
1600
|
+
code: "PRIMITIVE_IN_FORBIDDEN_SCOPE",
|
|
1601
|
+
kind: "lifecycle",
|
|
1602
|
+
severity: "error",
|
|
1603
|
+
message: PRIMITIVE_IN_FORBIDDEN_SCOPE_MESSAGE,
|
|
1604
|
+
ownerId: context.id,
|
|
1605
|
+
ownerName: context._name
|
|
1606
|
+
});
|
|
1607
|
+
throw new Error(PRIMITIVE_IN_FORBIDDEN_SCOPE_MESSAGE);
|
|
1527
1608
|
}
|
|
1528
1609
|
if (context) {
|
|
1529
1610
|
const lastChild = context._firstChild;
|
|
@@ -1536,9 +1617,8 @@ function computed(fn, initialValue, options) {
|
|
|
1536
1617
|
}
|
|
1537
1618
|
DEV$1.hooks.onOwner?.(self);
|
|
1538
1619
|
if (parent) self._height = parent._height + 1;
|
|
1539
|
-
if (snapshotCaptureActive && ownerInSnapshotScope(context)) self._inSnapshotScope = true;
|
|
1540
1620
|
if (externalSourceConfig) {
|
|
1541
|
-
const bridgeSignal = signal(undefined, { equals: false,
|
|
1621
|
+
const bridgeSignal = signal(undefined, { equals: false, ownedWrite: true });
|
|
1542
1622
|
const source = externalSourceConfig.factory(self._fn, () => {
|
|
1543
1623
|
setSignal(bridgeSignal, undefined);
|
|
1544
1624
|
});
|
|
@@ -1560,8 +1640,9 @@ function computed(fn, initialValue, options) {
|
|
|
1560
1640
|
function signal(v, options, firewall = null) {
|
|
1561
1641
|
const s = {
|
|
1562
1642
|
_equals: options?.equals != null ? options.equals : isEqual,
|
|
1563
|
-
|
|
1564
|
-
|
|
1643
|
+
_config:
|
|
1644
|
+
(options?.ownedWrite ? CONFIG_OWNED_WRITE : 0) |
|
|
1645
|
+
(options?._noSnapshot ? CONFIG_NO_SNAPSHOT : 0),
|
|
1565
1646
|
_unobserved: options?.unobserved,
|
|
1566
1647
|
_value: v,
|
|
1567
1648
|
_subs: null,
|
|
@@ -1578,7 +1659,7 @@ function signal(v, options, firewall = null) {
|
|
|
1578
1659
|
firewall && (firewall._child = s);
|
|
1579
1660
|
if (
|
|
1580
1661
|
snapshotCaptureActive &&
|
|
1581
|
-
!s.
|
|
1662
|
+
!(s._config & CONFIG_NO_SNAPSHOT) &&
|
|
1582
1663
|
!((firewall?._statusFlags ?? 0) & STATUS_PENDING)
|
|
1583
1664
|
) {
|
|
1584
1665
|
s._snapshotValue = v === undefined ? NO_SNAPSHOT : v;
|
|
@@ -1591,8 +1672,8 @@ function optimisticSignal(v, options) {
|
|
|
1591
1672
|
s._overrideValue = NOT_PENDING;
|
|
1592
1673
|
return s;
|
|
1593
1674
|
}
|
|
1594
|
-
function optimisticComputed(fn,
|
|
1595
|
-
const c = computed(fn,
|
|
1675
|
+
function optimisticComputed(fn, options) {
|
|
1676
|
+
const c = computed(fn, options);
|
|
1596
1677
|
c._overrideValue = NOT_PENDING;
|
|
1597
1678
|
return c;
|
|
1598
1679
|
}
|
|
@@ -1672,15 +1753,21 @@ function read(el) {
|
|
|
1672
1753
|
}
|
|
1673
1754
|
let c = context;
|
|
1674
1755
|
if (c?._root) c = c._parentComputed;
|
|
1675
|
-
|
|
1676
|
-
if (
|
|
1677
|
-
|
|
1678
|
-
|
|
1756
|
+
const computed = el;
|
|
1757
|
+
if (typeof computed._fn === "function") {
|
|
1758
|
+
const comp = el;
|
|
1759
|
+
if (refreshing && !(comp._flags & REACTIVE_DISPOSED)) recompute(comp);
|
|
1760
|
+
if (comp._flags & REACTIVE_LAZY) {
|
|
1761
|
+
comp._flags &= ~REACTIVE_LAZY;
|
|
1762
|
+
recompute(comp, true);
|
|
1763
|
+
} else if (comp._flags & REACTIVE_DISPOSED) {
|
|
1764
|
+
recompute(comp, true);
|
|
1765
|
+
}
|
|
1679
1766
|
}
|
|
1680
1767
|
const owner = el._firewall || el;
|
|
1681
1768
|
if (strictRead && owner._statusFlags & STATUS_PENDING) {
|
|
1682
1769
|
const message =
|
|
1683
|
-
`Reading a pending async value directly in ${strictRead}. ` +
|
|
1770
|
+
`[PENDING_ASYNC_UNTRACKED_READ] Reading a pending async value directly in ${strictRead}. ` +
|
|
1684
1771
|
`Async values must be read within a tracking scope (JSX, a memo, or an effect's compute function).`;
|
|
1685
1772
|
emitDiagnostic({
|
|
1686
1773
|
code: "PENDING_ASYNC_UNTRACKED_READ",
|
|
@@ -1695,7 +1782,6 @@ function read(el) {
|
|
|
1695
1782
|
throw new Error(message);
|
|
1696
1783
|
}
|
|
1697
1784
|
if (c && tracking) {
|
|
1698
|
-
if (el._fn && el._flags & REACTIVE_DISPOSED) recompute(el);
|
|
1699
1785
|
link(el, c);
|
|
1700
1786
|
if (owner._fn) {
|
|
1701
1787
|
const isZombie = el._flags & REACTIVE_ZOMBIE;
|
|
@@ -1712,9 +1798,9 @@ function read(el) {
|
|
|
1712
1798
|
}
|
|
1713
1799
|
if (owner._statusFlags & STATUS_PENDING) {
|
|
1714
1800
|
if (c && !(stale && owner._transition && activeTransition !== owner._transition)) {
|
|
1715
|
-
if (c
|
|
1801
|
+
if (c && c._config & CONFIG_CHILDREN_FORBIDDEN) {
|
|
1716
1802
|
const message =
|
|
1717
|
-
"Reading a pending async value inside createTrackedEffect or onSettled will throw. " +
|
|
1803
|
+
"[PENDING_ASYNC_FORBIDDEN_SCOPE] Reading a pending async value inside createTrackedEffect or onSettled will throw. " +
|
|
1718
1804
|
"Use createEffect instead which supports async-aware reactivity.";
|
|
1719
1805
|
emitDiagnostic({
|
|
1720
1806
|
code: "PENDING_ASYNC_FORBIDDEN_SCOPE",
|
|
@@ -1751,7 +1837,7 @@ function read(el) {
|
|
|
1751
1837
|
return read(el);
|
|
1752
1838
|
} else throw el._error;
|
|
1753
1839
|
}
|
|
1754
|
-
if (snapshotCaptureActive && c && c.
|
|
1840
|
+
if (snapshotCaptureActive && c && c._config & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
1755
1841
|
const sv = el._snapshotValue;
|
|
1756
1842
|
if (sv !== undefined) {
|
|
1757
1843
|
const snapshot = sv === NO_SNAPSHOT ? undefined : sv;
|
|
@@ -1762,7 +1848,7 @@ function read(el) {
|
|
|
1762
1848
|
}
|
|
1763
1849
|
if (strictRead) {
|
|
1764
1850
|
const message =
|
|
1765
|
-
`Reactive value read directly in ${strictRead} will not update. ` +
|
|
1851
|
+
`[STRICT_READ_UNTRACKED] Reactive value read directly in ${strictRead} will not update. ` +
|
|
1766
1852
|
`Move it into a tracking scope (JSX, a memo, or an effect's compute function).`;
|
|
1767
1853
|
emitDiagnostic({
|
|
1768
1854
|
code: "STRICT_READ_UNTRACKED",
|
|
@@ -1780,7 +1866,20 @@ function read(el) {
|
|
|
1780
1866
|
if (c && stale && shouldReadStashedOptimisticValue(el)) return el._value;
|
|
1781
1867
|
return el._overrideValue;
|
|
1782
1868
|
}
|
|
1783
|
-
|
|
1869
|
+
if (
|
|
1870
|
+
activeTransition !== null &&
|
|
1871
|
+
currentOptimisticLane !== null &&
|
|
1872
|
+
!latestReadActive &&
|
|
1873
|
+
el._pendingValue !== NOT_PENDING &&
|
|
1874
|
+
owner === el &&
|
|
1875
|
+
!el._fn &&
|
|
1876
|
+
c
|
|
1877
|
+
) {
|
|
1878
|
+
activeTransition._gatedSubs.add(c);
|
|
1879
|
+
return el._value;
|
|
1880
|
+
}
|
|
1881
|
+
const value =
|
|
1882
|
+
!c ||
|
|
1784
1883
|
(currentOptimisticLane !== null &&
|
|
1785
1884
|
(el._overrideValue !== undefined ||
|
|
1786
1885
|
el._optimisticLane ||
|
|
@@ -1788,14 +1887,30 @@ function read(el) {
|
|
|
1788
1887
|
!!(owner._statusFlags & STATUS_PENDING))) ||
|
|
1789
1888
|
el._pendingValue === NOT_PENDING ||
|
|
1790
1889
|
(stale && el._transition && activeTransition !== el._transition)
|
|
1791
|
-
|
|
1792
|
-
|
|
1890
|
+
? el._value
|
|
1891
|
+
: el._pendingValue;
|
|
1892
|
+
if (
|
|
1893
|
+
!c &&
|
|
1894
|
+
owner === el &&
|
|
1895
|
+
typeof computed._fn === "function" &&
|
|
1896
|
+
el._config & CONFIG_AUTO_DISPOSE &&
|
|
1897
|
+
!(owner._statusFlags & STATUS_PENDING) &&
|
|
1898
|
+
!el._subs
|
|
1899
|
+
) {
|
|
1900
|
+
unobserved(el);
|
|
1901
|
+
}
|
|
1902
|
+
return value;
|
|
1793
1903
|
}
|
|
1794
1904
|
function setSignal(el, v) {
|
|
1795
|
-
if (
|
|
1905
|
+
if (
|
|
1906
|
+
!(el._config & CONFIG_OWNED_WRITE) &&
|
|
1907
|
+
!(context && context._config & CONFIG_CHILDREN_FORBIDDEN) &&
|
|
1908
|
+
context &&
|
|
1909
|
+
el._firewall !== context
|
|
1910
|
+
) {
|
|
1796
1911
|
const message =
|
|
1797
|
-
"Writing to a Signal inside an owned scope (component, computation) is not allowed. " +
|
|
1798
|
-
"Move the write outside or set the `
|
|
1912
|
+
"[SIGNAL_WRITE_IN_OWNED_SCOPE] Writing to a Signal inside an owned scope (component, computation) is not allowed. " +
|
|
1913
|
+
"Move the write outside or set the `ownedWrite` option if this is intentional.";
|
|
1799
1914
|
emitDiagnostic({
|
|
1800
1915
|
code: "SIGNAL_WRITE_IN_OWNED_SCOPE",
|
|
1801
1916
|
kind: "write",
|
|
@@ -1855,7 +1970,7 @@ function setSignal(el, v) {
|
|
|
1855
1970
|
function runWithOwner(owner, fn) {
|
|
1856
1971
|
if (owner && owner._flags & REACTIVE_DISPOSED) {
|
|
1857
1972
|
const message =
|
|
1858
|
-
"runWithOwner called with a disposed owner. Children created inside will never be disposed.";
|
|
1973
|
+
"[RUN_WITH_DISPOSED_OWNER] runWithOwner called with a disposed owner. Children created inside will never be disposed.";
|
|
1859
1974
|
emitDiagnostic({
|
|
1860
1975
|
code: "RUN_WITH_DISPOSED_OWNER",
|
|
1861
1976
|
kind: "owner",
|
|
@@ -1879,7 +1994,7 @@ function runWithOwner(owner, fn) {
|
|
|
1879
1994
|
}
|
|
1880
1995
|
function getPendingSignal(el) {
|
|
1881
1996
|
if (!el._pendingSignal) {
|
|
1882
|
-
el._pendingSignal = optimisticSignal(false, {
|
|
1997
|
+
el._pendingSignal = optimisticSignal(false, { ownedWrite: true });
|
|
1883
1998
|
if (el._parentSource) {
|
|
1884
1999
|
el._pendingSignal._parentSource = el;
|
|
1885
2000
|
}
|
|
@@ -2022,26 +2137,24 @@ function hasContext(context, owner) {
|
|
|
2022
2137
|
function isUndefined(value) {
|
|
2023
2138
|
return typeof value === "undefined";
|
|
2024
2139
|
}
|
|
2025
|
-
function effect(compute, effect, error,
|
|
2140
|
+
function effect(compute, effect, error, options) {
|
|
2026
2141
|
let initialized = false;
|
|
2027
|
-
const
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
{
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
);
|
|
2040
|
-
node._prevValue = initialValue;
|
|
2142
|
+
const isUser = !!options?.user;
|
|
2143
|
+
const node = computed(isUser ? compute : p => staleValues(() => compute(p)), {
|
|
2144
|
+
...options,
|
|
2145
|
+
equals: () => {
|
|
2146
|
+
node._modified = !node._error;
|
|
2147
|
+
if (initialized) node._queue.enqueue(node._type, runEffect.bind(node));
|
|
2148
|
+
return false;
|
|
2149
|
+
},
|
|
2150
|
+
lazy: true
|
|
2151
|
+
});
|
|
2152
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
2153
|
+
node._prevValue = undefined;
|
|
2041
2154
|
node._effectFn = effect;
|
|
2042
2155
|
node._errorFn = error;
|
|
2043
2156
|
node._cleanup = undefined;
|
|
2044
|
-
node._type =
|
|
2157
|
+
node._type = isUser ? EFFECT_USER : EFFECT_RENDER;
|
|
2045
2158
|
node._notifyStatus = (status, error) => {
|
|
2046
2159
|
const actualStatus = status !== undefined ? status : node._statusFlags;
|
|
2047
2160
|
const actualError = error !== undefined ? error : node._error;
|
|
@@ -2065,28 +2178,32 @@ function effect(compute, effect, error, initialValue, options) {
|
|
|
2065
2178
|
node._queue.notify(node, STATUS_PENDING | STATUS_ERROR, actualStatus, actualError);
|
|
2066
2179
|
if (_hitUnhandledAsync) {
|
|
2067
2180
|
resetUnhandledAsync();
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2181
|
+
if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) {
|
|
2182
|
+
const message =
|
|
2183
|
+
"[ASYNC_OUTSIDE_LOADING_BOUNDARY] An async value was read outside a Loading boundary. The root mount will be deferred until all pending async settles.";
|
|
2184
|
+
emitDiagnostic({
|
|
2185
|
+
code: "ASYNC_OUTSIDE_LOADING_BOUNDARY",
|
|
2186
|
+
kind: "async",
|
|
2187
|
+
severity: "warn",
|
|
2188
|
+
message: message,
|
|
2189
|
+
ownerId: node.id,
|
|
2190
|
+
ownerName: node._name
|
|
2191
|
+
});
|
|
2192
|
+
console.warn(message);
|
|
2193
|
+
}
|
|
2078
2194
|
}
|
|
2079
2195
|
}
|
|
2080
2196
|
};
|
|
2081
2197
|
recompute(node, true);
|
|
2082
2198
|
!options?.defer &&
|
|
2083
|
-
(node._type === EFFECT_USER
|
|
2199
|
+
(node._type === EFFECT_USER || options?.schedule
|
|
2084
2200
|
? node._queue.enqueue(node._type, runEffect.bind(node))
|
|
2085
2201
|
: runEffect.call(node));
|
|
2086
2202
|
initialized = true;
|
|
2087
2203
|
cleanup(() => node._cleanup?.());
|
|
2088
2204
|
if (!node._parent) {
|
|
2089
|
-
const message =
|
|
2205
|
+
const message =
|
|
2206
|
+
"[NO_OWNER_EFFECT] Effects created outside a reactive context will never be disposed";
|
|
2090
2207
|
emitDiagnostic({
|
|
2091
2208
|
code: "NO_OWNER_EFFECT",
|
|
2092
2209
|
kind: "lifecycle",
|
|
@@ -2148,11 +2265,10 @@ function trackedEffect(fn, options) {
|
|
|
2148
2265
|
}
|
|
2149
2266
|
node._cleanup = cleanup;
|
|
2150
2267
|
},
|
|
2151
|
-
undefined,
|
|
2152
2268
|
{ ...options, lazy: true }
|
|
2153
2269
|
);
|
|
2154
2270
|
node._cleanup = undefined;
|
|
2155
|
-
node.
|
|
2271
|
+
node._config = (node._config & ~CONFIG_AUTO_DISPOSE) | CONFIG_CHILDREN_FORBIDDEN;
|
|
2156
2272
|
node._modified = true;
|
|
2157
2273
|
node._type = EFFECT_TRACKED;
|
|
2158
2274
|
node._notifyStatus = (status, error) => {
|
|
@@ -2167,7 +2283,8 @@ function trackedEffect(fn, options) {
|
|
|
2167
2283
|
node._queue.enqueue(EFFECT_USER, run);
|
|
2168
2284
|
cleanup(() => node._cleanup?.());
|
|
2169
2285
|
if (!node._parent) {
|
|
2170
|
-
const message =
|
|
2286
|
+
const message =
|
|
2287
|
+
"[NO_OWNER_EFFECT] Effects created outside a reactive context will never be disposed";
|
|
2171
2288
|
emitDiagnostic({
|
|
2172
2289
|
code: "NO_OWNER_EFFECT",
|
|
2173
2290
|
kind: "lifecycle",
|
|
@@ -2228,7 +2345,8 @@ function onCleanup(fn) {
|
|
|
2228
2345
|
{
|
|
2229
2346
|
const owner = getOwner();
|
|
2230
2347
|
if (!owner) {
|
|
2231
|
-
const message =
|
|
2348
|
+
const message =
|
|
2349
|
+
"[NO_OWNER_CLEANUP] onCleanup called outside a reactive context will never be run";
|
|
2232
2350
|
emitDiagnostic({
|
|
2233
2351
|
code: "NO_OWNER_CLEANUP",
|
|
2234
2352
|
kind: "lifecycle",
|
|
@@ -2236,9 +2354,9 @@ function onCleanup(fn) {
|
|
|
2236
2354
|
message: message
|
|
2237
2355
|
});
|
|
2238
2356
|
console.warn(message);
|
|
2239
|
-
} else if (owner.
|
|
2357
|
+
} else if (owner._config & CONFIG_CHILDREN_FORBIDDEN) {
|
|
2240
2358
|
const message =
|
|
2241
|
-
"Cannot use onCleanup inside createTrackedEffect or onSettled; return a cleanup function instead";
|
|
2359
|
+
"[CLEANUP_IN_FORBIDDEN_SCOPE] Cannot use onCleanup inside createTrackedEffect or onSettled; return a cleanup function instead";
|
|
2242
2360
|
emitDiagnostic({
|
|
2243
2361
|
code: "CLEANUP_IN_FORBIDDEN_SCOPE",
|
|
2244
2362
|
kind: "lifecycle",
|
|
@@ -2253,35 +2371,44 @@ function onCleanup(fn) {
|
|
|
2253
2371
|
return cleanup(fn);
|
|
2254
2372
|
}
|
|
2255
2373
|
function accessor(node) {
|
|
2256
|
-
|
|
2257
|
-
fn.$r = true;
|
|
2258
|
-
return fn;
|
|
2374
|
+
return read.bind(null, node);
|
|
2259
2375
|
}
|
|
2260
|
-
function createSignal(first, second
|
|
2376
|
+
function createSignal(first, second) {
|
|
2261
2377
|
if (typeof first === "function") {
|
|
2262
|
-
const node = computed(first, second
|
|
2378
|
+
const node = computed(first, second);
|
|
2379
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
2263
2380
|
return [accessor(node), setSignal.bind(null, node)];
|
|
2264
2381
|
}
|
|
2265
2382
|
const node = signal(first, second);
|
|
2266
2383
|
registerGraph(node, getOwner());
|
|
2267
2384
|
return [accessor(node), setSignal.bind(null, node)];
|
|
2268
2385
|
}
|
|
2269
|
-
function createMemo(compute,
|
|
2270
|
-
|
|
2271
|
-
return accessor(node);
|
|
2272
|
-
}
|
|
2273
|
-
function createEffect(compute, effectFn, value, options) {
|
|
2274
|
-
effect(compute, effectFn.effect || effectFn, effectFn.error, value, {
|
|
2275
|
-
...options,
|
|
2276
|
-
name: options?.name ?? "effect"
|
|
2277
|
-
});
|
|
2386
|
+
function createMemo(compute, options) {
|
|
2387
|
+
return accessor(computed(compute, options));
|
|
2278
2388
|
}
|
|
2279
|
-
function
|
|
2280
|
-
|
|
2281
|
-
|
|
2389
|
+
function createEffect(compute, effectFn, options) {
|
|
2390
|
+
if (effectFn === undefined) {
|
|
2391
|
+
const message =
|
|
2392
|
+
"[MISSING_EFFECT_FN] createEffect requires both a compute function and an effect function. " +
|
|
2393
|
+
"Use `createEffect(() => signal(), value => doWork(value))`. " +
|
|
2394
|
+
"If you want a derived value, use `createMemo`. " +
|
|
2395
|
+
"If you want a one-shot side effect, just call the function directly.";
|
|
2396
|
+
emitDiagnostic({
|
|
2397
|
+
code: "MISSING_EFFECT_FN",
|
|
2398
|
+
kind: "lifecycle",
|
|
2399
|
+
severity: "error",
|
|
2400
|
+
message: message
|
|
2401
|
+
});
|
|
2402
|
+
throw new Error(message);
|
|
2403
|
+
}
|
|
2404
|
+
effect(compute, effectFn.effect || effectFn, effectFn.error, {
|
|
2405
|
+
user: true,
|
|
2282
2406
|
...{ ...options, name: options?.name ?? "effect" }
|
|
2283
2407
|
});
|
|
2284
2408
|
}
|
|
2409
|
+
function createRenderEffect(compute, effectFn, options) {
|
|
2410
|
+
effect(compute, effectFn, undefined, { ...options, name: options?.name ?? "effect" });
|
|
2411
|
+
}
|
|
2285
2412
|
function createTrackedEffect(compute, options) {
|
|
2286
2413
|
trackedEffect(compute, { ...options, name: options?.name ?? "trackedEffect" });
|
|
2287
2414
|
}
|
|
@@ -2305,8 +2432,11 @@ function createReaction(effectFn, options) {
|
|
|
2305
2432
|
dispose(node);
|
|
2306
2433
|
},
|
|
2307
2434
|
effectFn.error,
|
|
2308
|
-
|
|
2309
|
-
|
|
2435
|
+
{
|
|
2436
|
+
...(true ? { ...options, name: options?.name ?? "effect" } : options),
|
|
2437
|
+
user: true,
|
|
2438
|
+
defer: true
|
|
2439
|
+
}
|
|
2310
2440
|
);
|
|
2311
2441
|
});
|
|
2312
2442
|
};
|
|
@@ -2331,9 +2461,10 @@ function resolve(fn) {
|
|
|
2331
2461
|
});
|
|
2332
2462
|
});
|
|
2333
2463
|
}
|
|
2334
|
-
function createOptimistic(first, second
|
|
2464
|
+
function createOptimistic(first, second) {
|
|
2335
2465
|
if (typeof first === "function") {
|
|
2336
|
-
const node = optimisticComputed(first, second
|
|
2466
|
+
const node = optimisticComputed(first, second);
|
|
2467
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
2337
2468
|
return [accessor(node), setSignal.bind(null, node)];
|
|
2338
2469
|
}
|
|
2339
2470
|
const node = optimisticSignal(first, second);
|
|
@@ -2342,7 +2473,7 @@ function createOptimistic(first, second, third) {
|
|
|
2342
2473
|
}
|
|
2343
2474
|
function onSettled(callback) {
|
|
2344
2475
|
const owner = getOwner();
|
|
2345
|
-
owner && !owner.
|
|
2476
|
+
owner && !(owner._config & CONFIG_CHILDREN_FORBIDDEN)
|
|
2346
2477
|
? createTrackedEffect(() => untrack(callback), { name: "onSettled" })
|
|
2347
2478
|
: globalQueue.enqueue(EFFECT_USER, () => {
|
|
2348
2479
|
const cleanup = callback();
|
|
@@ -2499,7 +2630,7 @@ function reconcile(value, key) {
|
|
|
2499
2630
|
applyState(value, state, keyFn);
|
|
2500
2631
|
};
|
|
2501
2632
|
}
|
|
2502
|
-
function createProjectionInternal(fn,
|
|
2633
|
+
function createProjectionInternal(fn, seed, options) {
|
|
2503
2634
|
let node;
|
|
2504
2635
|
const wrappedMap = new WeakMap();
|
|
2505
2636
|
const wrapper = s => {
|
|
@@ -2519,31 +2650,39 @@ function createProjectionInternal(fn, initialValue = {}, options) {
|
|
|
2519
2650
|
wrappedMap.set(source, wrapped);
|
|
2520
2651
|
return wrapped;
|
|
2521
2652
|
};
|
|
2522
|
-
const wrappedStore = wrapProjection(
|
|
2523
|
-
node = computed(
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
storeSetter(draft, s => {
|
|
2532
|
-
result = fn(s);
|
|
2533
|
-
settled = true;
|
|
2534
|
-
const value = handleAsync(owner, result, value => {
|
|
2535
|
-
value !== s &&
|
|
2536
|
-
value !== undefined &&
|
|
2537
|
-
storeSetter(wrappedStore, reconcile(value, options?.key || "id"));
|
|
2538
|
-
});
|
|
2539
|
-
value !== s && value !== undefined && reconcile(value, options?.key || "id")(wrappedStore);
|
|
2540
|
-
});
|
|
2541
|
-
});
|
|
2542
|
-
node._preventAutoDisposal = true;
|
|
2653
|
+
const wrappedStore = wrapProjection(seed);
|
|
2654
|
+
node = computed(
|
|
2655
|
+
() => {
|
|
2656
|
+
if (!node) node = getOwner();
|
|
2657
|
+
runProjectionComputed(wrappedStore, fn, options?.key || "id");
|
|
2658
|
+
},
|
|
2659
|
+
options?.name ? { name: options.name } : undefined
|
|
2660
|
+
);
|
|
2661
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
2543
2662
|
return { store: wrappedStore, node: node };
|
|
2544
2663
|
}
|
|
2545
|
-
function createProjection(fn,
|
|
2546
|
-
return createProjectionInternal(fn,
|
|
2664
|
+
function createProjection(fn, seed, options) {
|
|
2665
|
+
return createProjectionInternal(fn, seed, options).store;
|
|
2666
|
+
}
|
|
2667
|
+
function runProjectionComputed(wrappedStore, fn, key, wrapCommit) {
|
|
2668
|
+
const owner = getOwner();
|
|
2669
|
+
let settled = false;
|
|
2670
|
+
let result;
|
|
2671
|
+
const draft = new Proxy(
|
|
2672
|
+
wrappedStore,
|
|
2673
|
+
createWriteTraps(() => !settled || owner._inFlight === result)
|
|
2674
|
+
);
|
|
2675
|
+
storeSetter(draft, s => {
|
|
2676
|
+
result = fn(s);
|
|
2677
|
+
settled = true;
|
|
2678
|
+
const commit = v => {
|
|
2679
|
+
if (v === s || v === undefined) return;
|
|
2680
|
+
const write = () => storeSetter(wrappedStore, reconcile(v, key));
|
|
2681
|
+
wrapCommit ? wrapCommit(write) : write();
|
|
2682
|
+
};
|
|
2683
|
+
commit(handleAsync(owner, result, commit));
|
|
2684
|
+
});
|
|
2685
|
+
return owner;
|
|
2547
2686
|
}
|
|
2548
2687
|
function createWriteTraps(isActive) {
|
|
2549
2688
|
const traps = {
|
|
@@ -2607,6 +2746,7 @@ const STORE_VALUE = "v",
|
|
|
2607
2746
|
STORE_OPTIMISTIC_OVERRIDE = "x",
|
|
2608
2747
|
STORE_NODE = "n",
|
|
2609
2748
|
STORE_HAS = "h",
|
|
2749
|
+
STORE_CUSTOM_PROTO = "c",
|
|
2610
2750
|
STORE_WRAP = "w",
|
|
2611
2751
|
STORE_LOOKUP = "l",
|
|
2612
2752
|
STORE_FIREWALL = "f",
|
|
@@ -2617,6 +2757,7 @@ function createStoreProxy(value, traps = storeTraps, extend) {
|
|
|
2617
2757
|
newTarget = [];
|
|
2618
2758
|
newTarget.v = value;
|
|
2619
2759
|
} else newTarget = { v: value };
|
|
2760
|
+
newTarget[STORE_CUSTOM_PROTO] = hasCustomPrototype(unwrapStoreValue(value));
|
|
2620
2761
|
extend && extend(newTarget);
|
|
2621
2762
|
return (newTarget[$PROXY] = new Proxy(newTarget, traps));
|
|
2622
2763
|
}
|
|
@@ -2642,6 +2783,23 @@ function setWriteOverride(value) {
|
|
|
2642
2783
|
function writeOnly(proxy) {
|
|
2643
2784
|
return writeOverride || !!Writing?.has(proxy);
|
|
2644
2785
|
}
|
|
2786
|
+
function unwrapStoreValue(value) {
|
|
2787
|
+
return value?.[$TARGET]?.[STORE_VALUE] ?? value;
|
|
2788
|
+
}
|
|
2789
|
+
function hasCustomPrototype(value) {
|
|
2790
|
+
if (Array.isArray(value)) return false;
|
|
2791
|
+
const proto = Object.getPrototypeOf(value);
|
|
2792
|
+
return proto !== null && proto !== Object.prototype;
|
|
2793
|
+
}
|
|
2794
|
+
function hasInheritedAccessor(source, property) {
|
|
2795
|
+
let current = Object.getPrototypeOf(source);
|
|
2796
|
+
while (current && current !== Object.prototype) {
|
|
2797
|
+
const desc = Reflect.getOwnPropertyDescriptor(current, property);
|
|
2798
|
+
if (desc) return !!desc.get;
|
|
2799
|
+
current = Object.getPrototypeOf(current);
|
|
2800
|
+
}
|
|
2801
|
+
return false;
|
|
2802
|
+
}
|
|
2645
2803
|
function getNodes(target, type) {
|
|
2646
2804
|
let nodes = target[type];
|
|
2647
2805
|
if (!nodes) target[type] = nodes = Object.create(null);
|
|
@@ -2654,7 +2812,7 @@ function getNode(nodes, property, value, firewall, equals = isEqual, optimistic,
|
|
|
2654
2812
|
{
|
|
2655
2813
|
equals: equals,
|
|
2656
2814
|
unobserved() {
|
|
2657
|
-
delete nodes[property];
|
|
2815
|
+
if (nodes[property] === s) delete nodes[property];
|
|
2658
2816
|
}
|
|
2659
2817
|
},
|
|
2660
2818
|
firewall
|
|
@@ -2728,19 +2886,51 @@ function prepareStoreWrite(target, store, property) {
|
|
|
2728
2886
|
if (useOptimistic) trackOptimisticStore(store);
|
|
2729
2887
|
return { base: base, overrideKey: overrideKey, state: state };
|
|
2730
2888
|
}
|
|
2731
|
-
function
|
|
2732
|
-
if (
|
|
2889
|
+
function upsertStoreNode(target, nodes, property, prev, snapshotProps) {
|
|
2890
|
+
if (nodes[property]) return nodes[property];
|
|
2891
|
+
const initial = isWrappable(prev) ? wrap(prev, target) : prev;
|
|
2892
|
+
const node = getNode(
|
|
2893
|
+
nodes,
|
|
2894
|
+
property,
|
|
2895
|
+
initial,
|
|
2896
|
+
target[STORE_FIREWALL],
|
|
2897
|
+
isEqual,
|
|
2898
|
+
target[STORE_OPTIMISTIC],
|
|
2899
|
+
snapshotProps
|
|
2900
|
+
);
|
|
2901
|
+
registerTransientStoreNode(node);
|
|
2902
|
+
return node;
|
|
2903
|
+
}
|
|
2904
|
+
function notifyStoreProperty(target, property, mode, value, prev, prevHas) {
|
|
2905
|
+
const skipUpsert = projectionWriteActive || target[STORE_OPTIMISTIC];
|
|
2906
|
+
const newHas = mode !== "delete";
|
|
2907
|
+
const existingHas = target[STORE_HAS]?.[property];
|
|
2908
|
+
if (existingHas) {
|
|
2909
|
+
setSignal(existingHas, newHas);
|
|
2910
|
+
} else if (!skipUpsert && mode !== "invalidate" && prevHas !== newHas) {
|
|
2911
|
+
const hasNode = upsertStoreNode(target, getNodes(target, STORE_HAS), property, prevHas);
|
|
2912
|
+
setSignal(hasNode, newHas);
|
|
2913
|
+
}
|
|
2733
2914
|
const nodes = getNodes(target, STORE_NODE);
|
|
2734
2915
|
if (mode === "set") {
|
|
2735
|
-
nodes[property]
|
|
2916
|
+
if (nodes[property]) {
|
|
2736
2917
|
setSignal(nodes[property], () => (isWrappable(value) ? wrap(value, target) : value));
|
|
2918
|
+
} else if (!skipUpsert) {
|
|
2919
|
+
const node = upsertStoreNode(target, nodes, property, prev, target[STORE_SNAPSHOT_PROPS]);
|
|
2920
|
+
setSignal(node, () => (isWrappable(value) ? wrap(value, target) : value));
|
|
2921
|
+
}
|
|
2737
2922
|
} else if (mode === "invalidate") {
|
|
2738
2923
|
if (nodes[property]) {
|
|
2739
2924
|
setSignal(nodes[property], {});
|
|
2740
2925
|
delete nodes[property];
|
|
2741
2926
|
}
|
|
2742
2927
|
} else {
|
|
2743
|
-
|
|
2928
|
+
if (nodes[property]) {
|
|
2929
|
+
setSignal(nodes[property], undefined);
|
|
2930
|
+
} else if (!skipUpsert) {
|
|
2931
|
+
const node = upsertStoreNode(target, nodes, property, prev, target[STORE_SNAPSHOT_PROPS]);
|
|
2932
|
+
setSignal(node, undefined);
|
|
2933
|
+
}
|
|
2744
2934
|
}
|
|
2745
2935
|
nodes[$TRACK] && setSignal(nodes[$TRACK], undefined);
|
|
2746
2936
|
}
|
|
@@ -2769,6 +2959,12 @@ const storeTraps = {
|
|
|
2769
2959
|
if (!tracked) {
|
|
2770
2960
|
const desc = Object.getOwnPropertyDescriptor(storeValue, property);
|
|
2771
2961
|
if (desc && desc.get) return desc.get.call(receiver);
|
|
2962
|
+
if (!desc && !overridden && target[STORE_CUSTOM_PROTO]) {
|
|
2963
|
+
const source = unwrapStoreValue(storeValue);
|
|
2964
|
+
if (hasInheritedAccessor(source, property)) {
|
|
2965
|
+
return Reflect.get(storeValue, property, receiver);
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2772
2968
|
}
|
|
2773
2969
|
if (writeOnly(receiver)) {
|
|
2774
2970
|
let value =
|
|
@@ -2815,7 +3011,7 @@ const storeTraps = {
|
|
|
2815
3011
|
}
|
|
2816
3012
|
if (strictRead && typeof property === "string") {
|
|
2817
3013
|
const message =
|
|
2818
|
-
`Reactive value read directly in ${strictRead} will not update. ` +
|
|
3014
|
+
`[STRICT_READ_UNTRACKED] Reactive value read directly in ${strictRead} will not update. ` +
|
|
2819
3015
|
`Move it into a tracking scope (JSX, a memo, or an effect's compute function).`;
|
|
2820
3016
|
emitDiagnostic({
|
|
2821
3017
|
code: "STRICT_READ_UNTRACKED",
|
|
@@ -2837,18 +3033,13 @@ const storeTraps = {
|
|
|
2837
3033
|
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
2838
3034
|
? target[STORE_OVERRIDE][property] !== $DELETED
|
|
2839
3035
|
: property in target[STORE_VALUE];
|
|
2840
|
-
if (
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
target[STORE_FIREWALL],
|
|
2848
|
-
isEqual,
|
|
2849
|
-
target[STORE_OPTIMISTIC]
|
|
2850
|
-
)
|
|
2851
|
-
);
|
|
3036
|
+
if (writeOnly(target[$PROXY])) return has;
|
|
3037
|
+
const nodes = getNodes(target, STORE_HAS);
|
|
3038
|
+
if (nodes[property]) return read(nodes[property]);
|
|
3039
|
+
if (getObserver()) {
|
|
3040
|
+
return read(
|
|
3041
|
+
getNode(nodes, property, has, target[STORE_FIREWALL], isEqual, target[STORE_OPTIMISTIC])
|
|
3042
|
+
);
|
|
2852
3043
|
}
|
|
2853
3044
|
return has;
|
|
2854
3045
|
},
|
|
@@ -2867,7 +3058,13 @@ const storeTraps = {
|
|
|
2867
3058
|
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
2868
3059
|
? target[STORE_OVERRIDE][property]
|
|
2869
3060
|
: base;
|
|
2870
|
-
const
|
|
3061
|
+
const prevHas =
|
|
3062
|
+
target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]
|
|
3063
|
+
? target[STORE_OPTIMISTIC_OVERRIDE][property] !== $DELETED
|
|
3064
|
+
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
3065
|
+
? target[STORE_OVERRIDE][property] !== $DELETED
|
|
3066
|
+
: property in target[STORE_VALUE];
|
|
3067
|
+
const value = unwrapStoreValue(rawValue);
|
|
2871
3068
|
const isArrayIndexWrite = Array.isArray(state) && property !== "length";
|
|
2872
3069
|
const nextIndex = isArrayIndexWrite ? parseInt(property) + 1 : 0;
|
|
2873
3070
|
const len =
|
|
@@ -2886,11 +3083,21 @@ const storeTraps = {
|
|
|
2886
3083
|
override[property] = value;
|
|
2887
3084
|
if (nextLength !== undefined) override.length = nextLength;
|
|
2888
3085
|
}
|
|
2889
|
-
notifyStoreProperty(target, property, "set", value);
|
|
2890
|
-
if (Array.isArray(state)) {
|
|
3086
|
+
notifyStoreProperty(target, property, "set", value, prev, prevHas);
|
|
3087
|
+
if (Array.isArray(state) && property !== "length" && nextLength !== undefined) {
|
|
2891
3088
|
const nodes = getNodes(target, STORE_NODE);
|
|
2892
|
-
|
|
2893
|
-
|
|
3089
|
+
if (nodes.length) {
|
|
3090
|
+
setSignal(nodes.length, nextLength);
|
|
3091
|
+
} else if (!projectionWriteActive && !target[STORE_OPTIMISTIC]) {
|
|
3092
|
+
const node = upsertStoreNode(
|
|
3093
|
+
target,
|
|
3094
|
+
nodes,
|
|
3095
|
+
"length",
|
|
3096
|
+
len,
|
|
3097
|
+
target[STORE_SNAPSHOT_PROPS]
|
|
3098
|
+
);
|
|
3099
|
+
setSignal(node, nextLength);
|
|
3100
|
+
}
|
|
2894
3101
|
}
|
|
2895
3102
|
if (true) DEV$1.hooks.onStoreNodeUpdate?.(target[$PROXY], property, value, prev);
|
|
2896
3103
|
});
|
|
@@ -2904,10 +3111,7 @@ const storeTraps = {
|
|
|
2904
3111
|
const { base: base, overrideKey: overrideKey } = prepareStoreWrite(target, store, property);
|
|
2905
3112
|
const normalizedDescriptor =
|
|
2906
3113
|
"value" in descriptor
|
|
2907
|
-
? {
|
|
2908
|
-
...descriptor,
|
|
2909
|
-
value: descriptor.value?.[$TARGET]?.[STORE_VALUE] ?? descriptor.value
|
|
2910
|
-
}
|
|
3114
|
+
? { ...descriptor, value: unwrapStoreValue(descriptor.value) }
|
|
2911
3115
|
: descriptor;
|
|
2912
3116
|
Object.defineProperty(
|
|
2913
3117
|
target[overrideKey] || (target[overrideKey] = Object.create(null)),
|
|
@@ -2948,7 +3152,7 @@ const storeTraps = {
|
|
|
2948
3152
|
} else if (target[overrideKey] && property in target[overrideKey]) {
|
|
2949
3153
|
delete target[overrideKey][property];
|
|
2950
3154
|
} else return true;
|
|
2951
|
-
notifyStoreProperty(target, property, "delete");
|
|
3155
|
+
notifyStoreProperty(target, property, "delete", undefined, prev, true);
|
|
2952
3156
|
});
|
|
2953
3157
|
}
|
|
2954
3158
|
return true;
|
|
@@ -3021,7 +3225,7 @@ function createStore(first, second, options) {
|
|
|
3021
3225
|
function createOptimisticStore(first, second, options) {
|
|
3022
3226
|
GlobalQueue._clearOptimisticStore ||= clearOptimisticStore;
|
|
3023
3227
|
const derived = typeof first === "function";
|
|
3024
|
-
const initialValue =
|
|
3228
|
+
const initialValue = derived ? second : first;
|
|
3025
3229
|
const fn = derived ? first : undefined;
|
|
3026
3230
|
const { store: wrappedStore } = createOptimisticProjectionInternal(fn, initialValue, options);
|
|
3027
3231
|
return [wrappedStore, fn => storeSetter(wrappedStore, fn)];
|
|
@@ -3055,7 +3259,7 @@ function clearOptimisticStore(store) {
|
|
|
3055
3259
|
}
|
|
3056
3260
|
delete target[STORE_OPTIMISTIC_OVERRIDE];
|
|
3057
3261
|
}
|
|
3058
|
-
function createOptimisticProjectionInternal(fn, initialValue
|
|
3262
|
+
function createOptimisticProjectionInternal(fn, initialValue, options) {
|
|
3059
3263
|
let node;
|
|
3060
3264
|
const wrappedMap = new WeakMap();
|
|
3061
3265
|
const wrapper = s => {
|
|
@@ -3078,42 +3282,33 @@ function createOptimisticProjectionInternal(fn, initialValue = {}, options) {
|
|
|
3078
3282
|
};
|
|
3079
3283
|
const wrappedStore = wrapProjection(initialValue);
|
|
3080
3284
|
if (fn) {
|
|
3081
|
-
|
|
3082
|
-
const owner = getOwner();
|
|
3083
|
-
let settled = false;
|
|
3084
|
-
let result;
|
|
3085
|
-
const draft = new Proxy(
|
|
3086
|
-
wrappedStore,
|
|
3087
|
-
createWriteTraps(() => !settled || owner._inFlight === result)
|
|
3088
|
-
);
|
|
3285
|
+
const wrapCommit = write => {
|
|
3089
3286
|
setProjectionWriteActive(true);
|
|
3090
3287
|
try {
|
|
3091
|
-
|
|
3092
|
-
result = fn(s);
|
|
3093
|
-
settled = true;
|
|
3094
|
-
const value = handleAsync(owner, result, value => {
|
|
3095
|
-
setProjectionWriteActive(true);
|
|
3096
|
-
try {
|
|
3097
|
-
value !== s &&
|
|
3098
|
-
value !== undefined &&
|
|
3099
|
-
storeSetter(wrappedStore, reconcile(value, options?.key || "id"));
|
|
3100
|
-
} finally {
|
|
3101
|
-
setProjectionWriteActive(false);
|
|
3102
|
-
}
|
|
3103
|
-
});
|
|
3104
|
-
value !== s &&
|
|
3105
|
-
value !== undefined &&
|
|
3106
|
-
reconcile(value, options?.key || "id")(wrappedStore);
|
|
3107
|
-
});
|
|
3288
|
+
write();
|
|
3108
3289
|
} finally {
|
|
3109
3290
|
setProjectionWriteActive(false);
|
|
3110
3291
|
}
|
|
3111
|
-
}
|
|
3112
|
-
node
|
|
3292
|
+
};
|
|
3293
|
+
node = computed(
|
|
3294
|
+
() => {
|
|
3295
|
+
setProjectionWriteActive(true);
|
|
3296
|
+
try {
|
|
3297
|
+
runProjectionComputed(wrappedStore, fn, options?.key || "id", wrapCommit);
|
|
3298
|
+
} finally {
|
|
3299
|
+
setProjectionWriteActive(false);
|
|
3300
|
+
}
|
|
3301
|
+
},
|
|
3302
|
+
options?.name ? { name: options.name } : undefined
|
|
3303
|
+
);
|
|
3304
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
3113
3305
|
}
|
|
3114
3306
|
return { store: wrappedStore, node: node };
|
|
3115
3307
|
}
|
|
3116
3308
|
const DELETE = Symbol("STORE_PATH_DELETE");
|
|
3309
|
+
function isPrototypePollutionKey(part) {
|
|
3310
|
+
return part === "__proto__" || part === "constructor" || part === "prototype";
|
|
3311
|
+
}
|
|
3117
3312
|
function updatePath(current, args, i = 0) {
|
|
3118
3313
|
let part,
|
|
3119
3314
|
prev = current;
|
|
@@ -3121,6 +3316,7 @@ function updatePath(current, args, i = 0) {
|
|
|
3121
3316
|
part = args[i];
|
|
3122
3317
|
const partType = typeof part;
|
|
3123
3318
|
const isArray = Array.isArray(current);
|
|
3319
|
+
if (partType === "string" && isPrototypePollutionKey(part)) return;
|
|
3124
3320
|
if (Array.isArray(part)) {
|
|
3125
3321
|
for (let j = 0; j < part.length; j++) {
|
|
3126
3322
|
args[i] = part[j];
|
|
@@ -3167,6 +3363,7 @@ function updatePath(current, args, i = 0) {
|
|
|
3167
3363
|
const keys = Object.keys(value);
|
|
3168
3364
|
for (let i = 0; i < keys.length; i++) {
|
|
3169
3365
|
const key = keys[i];
|
|
3366
|
+
if (isPrototypePollutionKey(key)) continue;
|
|
3170
3367
|
const desc = Object.getOwnPropertyDescriptor(value, key);
|
|
3171
3368
|
if (desc.get || desc.set) Object.defineProperty(target, key, desc);
|
|
3172
3369
|
else target[key] = desc.value;
|
|
@@ -3386,23 +3583,25 @@ function mapArray(list, map, options) {
|
|
|
3386
3583
|
}
|
|
3387
3584
|
}
|
|
3388
3585
|
: map;
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3586
|
+
const data = {
|
|
3587
|
+
_owner: createOwner(),
|
|
3588
|
+
_len: 0,
|
|
3589
|
+
_list: list,
|
|
3590
|
+
_items: [],
|
|
3591
|
+
_map: wrappedMap,
|
|
3592
|
+
_mappings: [],
|
|
3593
|
+
_nodes: [],
|
|
3594
|
+
_key: keyFn,
|
|
3595
|
+
_rows: keyFn || options?.keyed === false ? [] : undefined,
|
|
3596
|
+
_indexes: indexes ? [] : undefined,
|
|
3597
|
+
_fallback: options?.fallback
|
|
3598
|
+
};
|
|
3599
|
+
const node = computed(updateKeyedMap.bind(data));
|
|
3600
|
+
data._owner._parentComputed = node;
|
|
3601
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
3602
|
+
return accessor(node);
|
|
3404
3603
|
}
|
|
3405
|
-
const pureOptions = {
|
|
3604
|
+
const pureOptions = { ownedWrite: true };
|
|
3406
3605
|
function updateKeyedMap() {
|
|
3407
3606
|
const newItems = this._list() || [],
|
|
3408
3607
|
newLen = newItems.length;
|
|
@@ -3539,17 +3738,21 @@ function repeat(count, map, options) {
|
|
|
3539
3738
|
}
|
|
3540
3739
|
}
|
|
3541
3740
|
: map;
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3741
|
+
const node = computed(
|
|
3742
|
+
updateRepeat.bind({
|
|
3743
|
+
_owner: createOwner(),
|
|
3744
|
+
_len: 0,
|
|
3745
|
+
_offset: 0,
|
|
3746
|
+
_count: count,
|
|
3747
|
+
_map: wrappedMap,
|
|
3748
|
+
_nodes: [],
|
|
3749
|
+
_mappings: [],
|
|
3750
|
+
_from: options?.from,
|
|
3751
|
+
_fallback: options?.fallback
|
|
3752
|
+
})
|
|
3753
|
+
);
|
|
3754
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
3755
|
+
return accessor(node);
|
|
3553
3756
|
}
|
|
3554
3757
|
function updateRepeat() {
|
|
3555
3758
|
const newLen = this._count();
|
|
@@ -3606,7 +3809,7 @@ function compare(key, a, b) {
|
|
|
3606
3809
|
return key ? key(a) === key(b) : true;
|
|
3607
3810
|
}
|
|
3608
3811
|
function boundaryComputed(fn, propagationMask) {
|
|
3609
|
-
const node = computed(fn,
|
|
3812
|
+
const node = computed(fn, { lazy: true });
|
|
3610
3813
|
node._notifyStatus = (status, error) => {
|
|
3611
3814
|
const flags = status !== undefined ? status : node._statusFlags;
|
|
3612
3815
|
const actualError = error !== undefined ? error : node._error;
|
|
@@ -3614,7 +3817,7 @@ function boundaryComputed(fn, propagationMask) {
|
|
|
3614
3817
|
node._queue.notify(node, node._propagationMask, flags, actualError);
|
|
3615
3818
|
};
|
|
3616
3819
|
node._propagationMask = propagationMask;
|
|
3617
|
-
node.
|
|
3820
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
3618
3821
|
recompute(node, true);
|
|
3619
3822
|
return node;
|
|
3620
3823
|
}
|
|
@@ -3631,12 +3834,16 @@ const ON_INIT = Symbol();
|
|
|
3631
3834
|
const RevealControllerContext = createContext(null);
|
|
3632
3835
|
let _revealUsed = false;
|
|
3633
3836
|
const FALSE_ACCESSOR = () => false;
|
|
3837
|
+
const SEQUENTIAL_ACCESSOR = () => "sequential";
|
|
3634
3838
|
function isRevealController(slot) {
|
|
3635
3839
|
return slot instanceof RevealController;
|
|
3636
3840
|
}
|
|
3637
3841
|
function isSlotReady(slot) {
|
|
3638
3842
|
return isRevealController(slot) ? slot.isReady() : slot._sources.size === 0 && !slot._pending;
|
|
3639
3843
|
}
|
|
3844
|
+
function isSlotMinimallyReady(slot) {
|
|
3845
|
+
return isRevealController(slot) ? slot.isMinimallyReady() : isSlotReady(slot);
|
|
3846
|
+
}
|
|
3640
3847
|
function setSlotState(slot, controller, disabled, collapsed) {
|
|
3641
3848
|
setSignal(slot._disabled, disabled);
|
|
3642
3849
|
setSignal(slot._collapsed, collapsed);
|
|
@@ -3648,16 +3855,17 @@ function setSlotState(slot, controller, disabled, collapsed) {
|
|
|
3648
3855
|
slot._revealController = undefined;
|
|
3649
3856
|
}
|
|
3650
3857
|
class RevealController {
|
|
3651
|
-
|
|
3858
|
+
_orderAccessor;
|
|
3652
3859
|
_collapsedAccessor;
|
|
3653
3860
|
_slots = [];
|
|
3654
3861
|
_parentController;
|
|
3655
|
-
_disabled = signal(false, {
|
|
3656
|
-
_collapsed = signal(false, {
|
|
3862
|
+
_disabled = signal(false, { ownedWrite: true, _noSnapshot: true });
|
|
3863
|
+
_collapsed = signal(false, { ownedWrite: true, _noSnapshot: true });
|
|
3657
3864
|
_ready = true;
|
|
3865
|
+
_minimallyReady = true;
|
|
3658
3866
|
_evaluating = false;
|
|
3659
|
-
constructor(
|
|
3660
|
-
this.
|
|
3867
|
+
constructor(order, collapsed) {
|
|
3868
|
+
this._orderAccessor = order;
|
|
3661
3869
|
this._collapsedAccessor = collapsed;
|
|
3662
3870
|
}
|
|
3663
3871
|
_forEachOwnedSlot(fn) {
|
|
@@ -3672,12 +3880,37 @@ class RevealController {
|
|
|
3672
3880
|
isReady() {
|
|
3673
3881
|
return this._forEachOwnedSlot(isSlotReady);
|
|
3674
3882
|
}
|
|
3883
|
+
isMinimallyReady() {
|
|
3884
|
+
const order = untrack(this._orderAccessor);
|
|
3885
|
+
if (order === "together") return this.isReady();
|
|
3886
|
+
if (order === "natural") {
|
|
3887
|
+
let hasSlot = false;
|
|
3888
|
+
let anyReady = false;
|
|
3889
|
+
this._forEachOwnedSlot(slot => {
|
|
3890
|
+
hasSlot = true;
|
|
3891
|
+
if (isSlotMinimallyReady(slot)) {
|
|
3892
|
+
anyReady = true;
|
|
3893
|
+
return false;
|
|
3894
|
+
}
|
|
3895
|
+
});
|
|
3896
|
+
return !hasSlot || anyReady;
|
|
3897
|
+
}
|
|
3898
|
+
let firstReady = true;
|
|
3899
|
+
this._forEachOwnedSlot(slot => {
|
|
3900
|
+
firstReady = isSlotMinimallyReady(slot);
|
|
3901
|
+
return false;
|
|
3902
|
+
});
|
|
3903
|
+
return firstReady;
|
|
3904
|
+
}
|
|
3675
3905
|
register(slot) {
|
|
3676
3906
|
if (this._slots.includes(slot)) return;
|
|
3677
3907
|
this._slots.push(slot);
|
|
3678
|
-
const
|
|
3679
|
-
setSignal(slot._disabled, true),
|
|
3680
|
-
setSignal(
|
|
3908
|
+
const order = untrack(this._orderAccessor);
|
|
3909
|
+
(setSignal(slot._disabled, true),
|
|
3910
|
+
setSignal(
|
|
3911
|
+
slot._collapsed,
|
|
3912
|
+
order === "sequential" ? !!untrack(this._collapsedAccessor) : false
|
|
3913
|
+
));
|
|
3681
3914
|
untrack(() => this.evaluate());
|
|
3682
3915
|
}
|
|
3683
3916
|
unregister(slot) {
|
|
@@ -3689,29 +3922,52 @@ class RevealController {
|
|
|
3689
3922
|
if (this._evaluating) return;
|
|
3690
3923
|
this._evaluating = true;
|
|
3691
3924
|
const wasReady = this._ready;
|
|
3925
|
+
const wasMinReady = this._minimallyReady;
|
|
3692
3926
|
try {
|
|
3693
3927
|
const disabled = disabledOverride ?? read(this._disabled),
|
|
3694
|
-
|
|
3928
|
+
order = untrack(this._orderAccessor),
|
|
3929
|
+
collapseTail = order === "sequential" && !!untrack(this._collapsedAccessor),
|
|
3695
3930
|
collapsed = collapsedOverride ?? collapseTail;
|
|
3696
|
-
if (disabled
|
|
3697
|
-
this._forEachOwnedSlot(slot => setSlotState(slot, this, true,
|
|
3698
|
-
else if (
|
|
3699
|
-
|
|
3700
|
-
|
|
3931
|
+
if (disabled) {
|
|
3932
|
+
this._forEachOwnedSlot(slot => setSlotState(slot, this, true, collapsed));
|
|
3933
|
+
} else if (order === "natural") {
|
|
3934
|
+
this._forEachOwnedSlot(slot => {
|
|
3935
|
+
if (isRevealController(slot)) {
|
|
3936
|
+
setSignal(slot._collapsed, false);
|
|
3937
|
+
setSignal(slot._disabled, false);
|
|
3938
|
+
slot.evaluate(false, false);
|
|
3939
|
+
} else {
|
|
3940
|
+
setSlotState(slot, this, !isSlotReady(slot), false);
|
|
3941
|
+
}
|
|
3942
|
+
});
|
|
3943
|
+
} else if (order === "together") {
|
|
3944
|
+
const minReady = this._forEachOwnedSlot(isSlotMinimallyReady);
|
|
3945
|
+
this._forEachOwnedSlot(slot => setSlotState(slot, this, !minReady, false));
|
|
3701
3946
|
} else {
|
|
3702
3947
|
let pendingSeen = false;
|
|
3703
3948
|
this._forEachOwnedSlot(slot => {
|
|
3704
3949
|
if (pendingSeen) return setSlotState(slot, this, true, collapseTail);
|
|
3705
3950
|
if (isSlotReady(slot)) return setSlotState(slot, this, false, false);
|
|
3706
3951
|
pendingSeen = true;
|
|
3707
|
-
|
|
3952
|
+
if (isRevealController(slot)) {
|
|
3953
|
+
setSignal(slot._collapsed, false);
|
|
3954
|
+
setSignal(slot._disabled, false);
|
|
3955
|
+
slot.evaluate(false, false);
|
|
3956
|
+
} else {
|
|
3957
|
+
setSlotState(slot, this, true, false);
|
|
3958
|
+
}
|
|
3708
3959
|
});
|
|
3709
3960
|
}
|
|
3710
3961
|
} finally {
|
|
3711
3962
|
this._ready = this.isReady();
|
|
3963
|
+
this._minimallyReady = this.isMinimallyReady();
|
|
3712
3964
|
this._evaluating = false;
|
|
3713
3965
|
}
|
|
3714
|
-
if (
|
|
3966
|
+
if (
|
|
3967
|
+
this._parentController &&
|
|
3968
|
+
(wasReady !== this._ready || wasMinReady !== this._minimallyReady)
|
|
3969
|
+
)
|
|
3970
|
+
this._parentController.evaluate();
|
|
3715
3971
|
}
|
|
3716
3972
|
}
|
|
3717
3973
|
class CollectionQueue extends Queue {
|
|
@@ -3719,8 +3975,8 @@ class CollectionQueue extends Queue {
|
|
|
3719
3975
|
_sources = new Set();
|
|
3720
3976
|
_tree;
|
|
3721
3977
|
_pending = true;
|
|
3722
|
-
_disabled = signal(false, {
|
|
3723
|
-
_collapsed = signal(false, {
|
|
3978
|
+
_disabled = signal(false, { ownedWrite: true, _noSnapshot: true });
|
|
3979
|
+
_collapsed = signal(false, { ownedWrite: true, _noSnapshot: true });
|
|
3724
3980
|
_revealController;
|
|
3725
3981
|
_initialized = false;
|
|
3726
3982
|
_onFn;
|
|
@@ -3800,7 +4056,8 @@ class CollectionQueue extends Queue {
|
|
|
3800
4056
|
}
|
|
3801
4057
|
function createCollectionBoundary(type, fn, fallback, onFn) {
|
|
3802
4058
|
if (!getOwner()) {
|
|
3803
|
-
const message =
|
|
4059
|
+
const message =
|
|
4060
|
+
"[NO_OWNER_BOUNDARY] Boundaries created outside a reactive context will never be disposed.";
|
|
3804
4061
|
emitDiagnostic({
|
|
3805
4062
|
code: "NO_OWNER_BOUNDARY",
|
|
3806
4063
|
kind: "lifecycle",
|
|
@@ -3833,15 +4090,16 @@ function createCollectionBoundary(type, fn, fallback, onFn) {
|
|
|
3833
4090
|
controller.register(queue);
|
|
3834
4091
|
cleanup(() => controller.unregister(queue));
|
|
3835
4092
|
}
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
4093
|
+
return accessor(
|
|
4094
|
+
computed(() => {
|
|
4095
|
+
if (!read(queue._disabled)) {
|
|
4096
|
+
const resolved = read(tree);
|
|
4097
|
+
if (!untrack(() => read(queue._disabled))) return ((queue._initialized = true), resolved);
|
|
4098
|
+
}
|
|
4099
|
+
if (_revealUsed && read(queue._collapsed)) return undefined;
|
|
4100
|
+
return fallback(queue);
|
|
4101
|
+
})
|
|
4102
|
+
);
|
|
3845
4103
|
}
|
|
3846
4104
|
function createLoadingBoundary(fn, fallback, options) {
|
|
3847
4105
|
return createCollectionBoundary(STATUS_PENDING, fn, () => fallback(), options?.on);
|
|
@@ -3860,14 +4118,14 @@ function createRevealOrder(fn, options) {
|
|
|
3860
4118
|
_revealUsed = true;
|
|
3861
4119
|
const owner = createOwner();
|
|
3862
4120
|
const parentController = getContext(RevealControllerContext);
|
|
3863
|
-
const
|
|
4121
|
+
const order = options?.order || SEQUENTIAL_ACCESSOR,
|
|
3864
4122
|
collapsed = options?.collapsed || FALSE_ACCESSOR;
|
|
3865
|
-
const controller = new RevealController(
|
|
4123
|
+
const controller = new RevealController(order, collapsed);
|
|
3866
4124
|
setContext(RevealControllerContext, controller, owner);
|
|
3867
4125
|
return runWithOwner(owner, () => {
|
|
3868
4126
|
const value = fn();
|
|
3869
4127
|
computed(() => {
|
|
3870
|
-
|
|
4128
|
+
order();
|
|
3871
4129
|
collapsed();
|
|
3872
4130
|
controller.evaluate();
|
|
3873
4131
|
});
|