@solidjs/signals 2.0.0-beta.7 → 2.0.0-beta.9
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 +401 -199
- package/dist/node.cjs +1403 -1259
- package/dist/prod.js +1053 -905
- package/dist/types/boundaries.d.ts +79 -3
- package/dist/types/core/action.d.ts +34 -0
- package/dist/types/core/constants.d.ts +17 -0
- 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/owner.d.ts +54 -3
- package/dist/types/core/scheduler.d.ts +19 -2
- package/dist/types/core/types.d.ts +2 -5
- package/dist/types/index.d.ts +2 -2
- package/dist/types/map.d.ts +32 -3
- package/dist/types/signals.d.ts +283 -16
- package/dist/types/store/optimistic.d.ts +38 -12
- package/dist/types/store/projection.d.ts +54 -14
- package/dist/types/store/reconcile.d.ts +22 -0
- package/dist/types/store/store.d.ts +64 -14
- 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 +79 -3
- package/dist/types-cjs/core/action.d.cts +34 -0
- package/dist/types-cjs/core/constants.d.cts +17 -0
- package/dist/types-cjs/core/core.d.cts +108 -9
- package/dist/types-cjs/core/dev.d.cts +1 -1
- package/dist/types-cjs/core/effect.d.cts +3 -2
- package/dist/types-cjs/core/owner.d.cts +54 -3
- package/dist/types-cjs/core/scheduler.d.cts +19 -2
- package/dist/types-cjs/core/types.d.cts +2 -5
- package/dist/types-cjs/index.d.cts +2 -2
- package/dist/types-cjs/map.d.cts +32 -3
- package/dist/types-cjs/signals.d.cts +283 -16
- package/dist/types-cjs/store/optimistic.d.cts +38 -12
- package/dist/types-cjs/store/projection.d.cts +54 -14
- package/dist/types-cjs/store/reconcile.d.cts +22 -0
- package/dist/types-cjs/store/store.d.cts +64 -14
- package/dist/types-cjs/store/storePath.d.cts +28 -0
- package/dist/types-cjs/store/utils.d.cts +78 -7
- package/package.json +4 -3
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;
|
|
@@ -895,7 +942,7 @@ function runDisposal(node, zombie) {
|
|
|
895
942
|
}
|
|
896
943
|
function childId(owner, consume) {
|
|
897
944
|
let counter = owner;
|
|
898
|
-
while (counter.
|
|
945
|
+
while (counter._config & CONFIG_TRANSPARENT && counter._parent) counter = counter._parent;
|
|
899
946
|
if (counter.id != null)
|
|
900
947
|
return formatId(counter.id, consume ? counter._childCount++ : counter._childCount);
|
|
901
948
|
throw new Error("Cannot get child id from owner without an id");
|
|
@@ -935,7 +982,7 @@ function createOwner(options) {
|
|
|
935
982
|
id:
|
|
936
983
|
options?.id ??
|
|
937
984
|
(transparent ? parent?.id : parent?.id != null ? getNextChildId(parent) : undefined),
|
|
938
|
-
|
|
985
|
+
_config: transparent ? CONFIG_TRANSPARENT : 0,
|
|
939
986
|
_root: true,
|
|
940
987
|
_parentComputed: parent?._root ? parent._parentComputed : parent,
|
|
941
988
|
_firstChild: null,
|
|
@@ -951,10 +998,16 @@ function createOwner(options) {
|
|
|
951
998
|
disposeChildren(owner, self);
|
|
952
999
|
}
|
|
953
1000
|
};
|
|
954
|
-
if (parent
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
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);
|
|
958
1011
|
}
|
|
959
1012
|
if (parent) {
|
|
960
1013
|
const lastChild = parent._firstChild;
|
|
@@ -1281,6 +1334,8 @@ function enableExternalSource(config) {
|
|
|
1281
1334
|
}
|
|
1282
1335
|
GlobalQueue._update = recompute;
|
|
1283
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";
|
|
1284
1339
|
let tracking = false;
|
|
1285
1340
|
let stale = false;
|
|
1286
1341
|
let refreshing = false;
|
|
@@ -1319,7 +1374,7 @@ function releaseSubtree(owner) {
|
|
|
1319
1374
|
}
|
|
1320
1375
|
if (child._fn) {
|
|
1321
1376
|
const comp = child;
|
|
1322
|
-
comp.
|
|
1377
|
+
comp._config &= ~CONFIG_IN_SNAPSHOT_SCOPE;
|
|
1323
1378
|
if (comp._flags & REACTIVE_SNAPSHOT_STALE) {
|
|
1324
1379
|
comp._flags &= ~REACTIVE_SNAPSHOT_STALE;
|
|
1325
1380
|
comp._flags |= REACTIVE_DIRTY;
|
|
@@ -1359,7 +1414,7 @@ function recompute(el, create = false) {
|
|
|
1359
1414
|
clearSignals(el);
|
|
1360
1415
|
}
|
|
1361
1416
|
}
|
|
1362
|
-
|
|
1417
|
+
let isOptimisticDirty = !!(el._flags & REACTIVE_OPTIMISTIC_DIRTY);
|
|
1363
1418
|
const hasOverride = el._overrideValue !== undefined && el._overrideValue !== NOT_PENDING;
|
|
1364
1419
|
const wasPending = !!(el._statusFlags & STATUS_PENDING);
|
|
1365
1420
|
const wasUninitialized = !!(el._statusFlags & STATUS_UNINITIALIZED);
|
|
@@ -1381,9 +1436,25 @@ function recompute(el, create = false) {
|
|
|
1381
1436
|
if (isOptimisticDirty) {
|
|
1382
1437
|
const lane = resolveLane(el);
|
|
1383
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
|
+
}
|
|
1384
1453
|
}
|
|
1385
1454
|
try {
|
|
1386
|
-
|
|
1455
|
+
const prevInFlight = el._inFlight;
|
|
1456
|
+
const fnResult = el._fn(value);
|
|
1457
|
+
value = el._inFlight !== prevInFlight ? fnResult : handleAsync(el, fnResult);
|
|
1387
1458
|
clearStatus(el, create);
|
|
1388
1459
|
const resolvedLane = resolveLane(el);
|
|
1389
1460
|
if (resolvedLane) {
|
|
@@ -1482,22 +1553,25 @@ function updateIfNecessary(el) {
|
|
|
1482
1553
|
}
|
|
1483
1554
|
el._flags = el._flags & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
1484
1555
|
}
|
|
1485
|
-
function computed(fn,
|
|
1556
|
+
function computed(fn, options) {
|
|
1486
1557
|
const transparent = options?.transparent ?? false;
|
|
1487
1558
|
const self = {
|
|
1488
1559
|
id:
|
|
1489
1560
|
options?.id ??
|
|
1490
1561
|
(transparent ? context?.id : context?.id != null ? getNextChildId(context) : undefined),
|
|
1491
|
-
|
|
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),
|
|
1492
1567
|
_equals: options?.equals != null ? options.equals : isEqual,
|
|
1493
|
-
_ownedWrite: !!options?.ownedWrite,
|
|
1494
1568
|
_unobserved: options?.unobserved,
|
|
1495
1569
|
_disposal: null,
|
|
1496
1570
|
_queue: context?._queue ?? globalQueue,
|
|
1497
1571
|
_context: context?._context ?? defaultContext,
|
|
1498
1572
|
_childCount: 0,
|
|
1499
1573
|
_fn: fn,
|
|
1500
|
-
_value:
|
|
1574
|
+
_value: undefined,
|
|
1501
1575
|
_height: 0,
|
|
1502
1576
|
_child: null,
|
|
1503
1577
|
_nextHeap: undefined,
|
|
@@ -1521,10 +1595,16 @@ function computed(fn, initialValue, options) {
|
|
|
1521
1595
|
self._name = options?.name ?? "computed";
|
|
1522
1596
|
self._prevHeap = self;
|
|
1523
1597
|
const parent = context?._root ? context._parentComputed : context;
|
|
1524
|
-
if (context
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
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);
|
|
1528
1608
|
}
|
|
1529
1609
|
if (context) {
|
|
1530
1610
|
const lastChild = context._firstChild;
|
|
@@ -1537,7 +1617,6 @@ function computed(fn, initialValue, options) {
|
|
|
1537
1617
|
}
|
|
1538
1618
|
DEV$1.hooks.onOwner?.(self);
|
|
1539
1619
|
if (parent) self._height = parent._height + 1;
|
|
1540
|
-
if (snapshotCaptureActive && ownerInSnapshotScope(context)) self._inSnapshotScope = true;
|
|
1541
1620
|
if (externalSourceConfig) {
|
|
1542
1621
|
const bridgeSignal = signal(undefined, { equals: false, ownedWrite: true });
|
|
1543
1622
|
const source = externalSourceConfig.factory(self._fn, () => {
|
|
@@ -1561,8 +1640,9 @@ function computed(fn, initialValue, options) {
|
|
|
1561
1640
|
function signal(v, options, firewall = null) {
|
|
1562
1641
|
const s = {
|
|
1563
1642
|
_equals: options?.equals != null ? options.equals : isEqual,
|
|
1564
|
-
|
|
1565
|
-
|
|
1643
|
+
_config:
|
|
1644
|
+
(options?.ownedWrite ? CONFIG_OWNED_WRITE : 0) |
|
|
1645
|
+
(options?._noSnapshot ? CONFIG_NO_SNAPSHOT : 0),
|
|
1566
1646
|
_unobserved: options?.unobserved,
|
|
1567
1647
|
_value: v,
|
|
1568
1648
|
_subs: null,
|
|
@@ -1579,7 +1659,7 @@ function signal(v, options, firewall = null) {
|
|
|
1579
1659
|
firewall && (firewall._child = s);
|
|
1580
1660
|
if (
|
|
1581
1661
|
snapshotCaptureActive &&
|
|
1582
|
-
!s.
|
|
1662
|
+
!(s._config & CONFIG_NO_SNAPSHOT) &&
|
|
1583
1663
|
!((firewall?._statusFlags ?? 0) & STATUS_PENDING)
|
|
1584
1664
|
) {
|
|
1585
1665
|
s._snapshotValue = v === undefined ? NO_SNAPSHOT : v;
|
|
@@ -1592,8 +1672,8 @@ function optimisticSignal(v, options) {
|
|
|
1592
1672
|
s._overrideValue = NOT_PENDING;
|
|
1593
1673
|
return s;
|
|
1594
1674
|
}
|
|
1595
|
-
function optimisticComputed(fn,
|
|
1596
|
-
const c = computed(fn,
|
|
1675
|
+
function optimisticComputed(fn, options) {
|
|
1676
|
+
const c = computed(fn, options);
|
|
1597
1677
|
c._overrideValue = NOT_PENDING;
|
|
1598
1678
|
return c;
|
|
1599
1679
|
}
|
|
@@ -1687,7 +1767,7 @@ function read(el) {
|
|
|
1687
1767
|
const owner = el._firewall || el;
|
|
1688
1768
|
if (strictRead && owner._statusFlags & STATUS_PENDING) {
|
|
1689
1769
|
const message =
|
|
1690
|
-
`Reading a pending async value directly in ${strictRead}. ` +
|
|
1770
|
+
`[PENDING_ASYNC_UNTRACKED_READ] Reading a pending async value directly in ${strictRead}. ` +
|
|
1691
1771
|
`Async values must be read within a tracking scope (JSX, a memo, or an effect's compute function).`;
|
|
1692
1772
|
emitDiagnostic({
|
|
1693
1773
|
code: "PENDING_ASYNC_UNTRACKED_READ",
|
|
@@ -1718,9 +1798,9 @@ function read(el) {
|
|
|
1718
1798
|
}
|
|
1719
1799
|
if (owner._statusFlags & STATUS_PENDING) {
|
|
1720
1800
|
if (c && !(stale && owner._transition && activeTransition !== owner._transition)) {
|
|
1721
|
-
if (c
|
|
1801
|
+
if (c && c._config & CONFIG_CHILDREN_FORBIDDEN) {
|
|
1722
1802
|
const message =
|
|
1723
|
-
"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. " +
|
|
1724
1804
|
"Use createEffect instead which supports async-aware reactivity.";
|
|
1725
1805
|
emitDiagnostic({
|
|
1726
1806
|
code: "PENDING_ASYNC_FORBIDDEN_SCOPE",
|
|
@@ -1757,7 +1837,7 @@ function read(el) {
|
|
|
1757
1837
|
return read(el);
|
|
1758
1838
|
} else throw el._error;
|
|
1759
1839
|
}
|
|
1760
|
-
if (snapshotCaptureActive && c && c.
|
|
1840
|
+
if (snapshotCaptureActive && c && c._config & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
1761
1841
|
const sv = el._snapshotValue;
|
|
1762
1842
|
if (sv !== undefined) {
|
|
1763
1843
|
const snapshot = sv === NO_SNAPSHOT ? undefined : sv;
|
|
@@ -1768,7 +1848,7 @@ function read(el) {
|
|
|
1768
1848
|
}
|
|
1769
1849
|
if (strictRead) {
|
|
1770
1850
|
const message =
|
|
1771
|
-
`Reactive value read directly in ${strictRead} will not update. ` +
|
|
1851
|
+
`[STRICT_READ_UNTRACKED] Reactive value read directly in ${strictRead} will not update. ` +
|
|
1772
1852
|
`Move it into a tracking scope (JSX, a memo, or an effect's compute function).`;
|
|
1773
1853
|
emitDiagnostic({
|
|
1774
1854
|
code: "STRICT_READ_UNTRACKED",
|
|
@@ -1786,6 +1866,18 @@ function read(el) {
|
|
|
1786
1866
|
if (c && stale && shouldReadStashedOptimisticValue(el)) return el._value;
|
|
1787
1867
|
return el._overrideValue;
|
|
1788
1868
|
}
|
|
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
|
+
}
|
|
1789
1881
|
const value =
|
|
1790
1882
|
!c ||
|
|
1791
1883
|
(currentOptimisticLane !== null &&
|
|
@@ -1801,9 +1893,8 @@ function read(el) {
|
|
|
1801
1893
|
!c &&
|
|
1802
1894
|
owner === el &&
|
|
1803
1895
|
typeof computed._fn === "function" &&
|
|
1804
|
-
|
|
1896
|
+
el._config & CONFIG_AUTO_DISPOSE &&
|
|
1805
1897
|
!(owner._statusFlags & STATUS_PENDING) &&
|
|
1806
|
-
!computed._parent &&
|
|
1807
1898
|
!el._subs
|
|
1808
1899
|
) {
|
|
1809
1900
|
unobserved(el);
|
|
@@ -1811,9 +1902,14 @@ function read(el) {
|
|
|
1811
1902
|
return value;
|
|
1812
1903
|
}
|
|
1813
1904
|
function setSignal(el, v) {
|
|
1814
|
-
if (
|
|
1905
|
+
if (
|
|
1906
|
+
!(el._config & CONFIG_OWNED_WRITE) &&
|
|
1907
|
+
!(context && context._config & CONFIG_CHILDREN_FORBIDDEN) &&
|
|
1908
|
+
context &&
|
|
1909
|
+
el._firewall !== context
|
|
1910
|
+
) {
|
|
1815
1911
|
const message =
|
|
1816
|
-
"Writing to a Signal inside an owned scope (component, computation) is not allowed. " +
|
|
1912
|
+
"[SIGNAL_WRITE_IN_OWNED_SCOPE] Writing to a Signal inside an owned scope (component, computation) is not allowed. " +
|
|
1817
1913
|
"Move the write outside or set the `ownedWrite` option if this is intentional.";
|
|
1818
1914
|
emitDiagnostic({
|
|
1819
1915
|
code: "SIGNAL_WRITE_IN_OWNED_SCOPE",
|
|
@@ -1874,7 +1970,7 @@ function setSignal(el, v) {
|
|
|
1874
1970
|
function runWithOwner(owner, fn) {
|
|
1875
1971
|
if (owner && owner._flags & REACTIVE_DISPOSED) {
|
|
1876
1972
|
const message =
|
|
1877
|
-
"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.";
|
|
1878
1974
|
emitDiagnostic({
|
|
1879
1975
|
code: "RUN_WITH_DISPOSED_OWNER",
|
|
1880
1976
|
kind: "owner",
|
|
@@ -2041,26 +2137,24 @@ function hasContext(context, owner) {
|
|
|
2041
2137
|
function isUndefined(value) {
|
|
2042
2138
|
return typeof value === "undefined";
|
|
2043
2139
|
}
|
|
2044
|
-
function effect(compute, effect, error,
|
|
2140
|
+
function effect(compute, effect, error, options) {
|
|
2045
2141
|
let initialized = false;
|
|
2046
|
-
const
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
{
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
);
|
|
2059
|
-
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;
|
|
2060
2154
|
node._effectFn = effect;
|
|
2061
2155
|
node._errorFn = error;
|
|
2062
2156
|
node._cleanup = undefined;
|
|
2063
|
-
node._type =
|
|
2157
|
+
node._type = isUser ? EFFECT_USER : EFFECT_RENDER;
|
|
2064
2158
|
node._notifyStatus = (status, error) => {
|
|
2065
2159
|
const actualStatus = status !== undefined ? status : node._statusFlags;
|
|
2066
2160
|
const actualError = error !== undefined ? error : node._error;
|
|
@@ -2085,29 +2179,31 @@ function effect(compute, effect, error, initialValue, options) {
|
|
|
2085
2179
|
if (_hitUnhandledAsync) {
|
|
2086
2180
|
resetUnhandledAsync();
|
|
2087
2181
|
if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) {
|
|
2088
|
-
const message =
|
|
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.";
|
|
2089
2184
|
emitDiagnostic({
|
|
2090
2185
|
code: "ASYNC_OUTSIDE_LOADING_BOUNDARY",
|
|
2091
2186
|
kind: "async",
|
|
2092
|
-
severity: "
|
|
2187
|
+
severity: "warn",
|
|
2093
2188
|
message: message,
|
|
2094
2189
|
ownerId: node.id,
|
|
2095
2190
|
ownerName: node._name
|
|
2096
2191
|
});
|
|
2097
|
-
|
|
2192
|
+
console.warn(message);
|
|
2098
2193
|
}
|
|
2099
2194
|
}
|
|
2100
2195
|
}
|
|
2101
2196
|
};
|
|
2102
2197
|
recompute(node, true);
|
|
2103
2198
|
!options?.defer &&
|
|
2104
|
-
(node._type === EFFECT_USER
|
|
2199
|
+
(node._type === EFFECT_USER || options?.schedule
|
|
2105
2200
|
? node._queue.enqueue(node._type, runEffect.bind(node))
|
|
2106
2201
|
: runEffect.call(node));
|
|
2107
2202
|
initialized = true;
|
|
2108
2203
|
cleanup(() => node._cleanup?.());
|
|
2109
2204
|
if (!node._parent) {
|
|
2110
|
-
const message =
|
|
2205
|
+
const message =
|
|
2206
|
+
"[NO_OWNER_EFFECT] Effects created outside a reactive context will never be disposed";
|
|
2111
2207
|
emitDiagnostic({
|
|
2112
2208
|
code: "NO_OWNER_EFFECT",
|
|
2113
2209
|
kind: "lifecycle",
|
|
@@ -2169,11 +2265,10 @@ function trackedEffect(fn, options) {
|
|
|
2169
2265
|
}
|
|
2170
2266
|
node._cleanup = cleanup;
|
|
2171
2267
|
},
|
|
2172
|
-
undefined,
|
|
2173
2268
|
{ ...options, lazy: true }
|
|
2174
2269
|
);
|
|
2175
2270
|
node._cleanup = undefined;
|
|
2176
|
-
node.
|
|
2271
|
+
node._config = (node._config & ~CONFIG_AUTO_DISPOSE) | CONFIG_CHILDREN_FORBIDDEN;
|
|
2177
2272
|
node._modified = true;
|
|
2178
2273
|
node._type = EFFECT_TRACKED;
|
|
2179
2274
|
node._notifyStatus = (status, error) => {
|
|
@@ -2188,7 +2283,8 @@ function trackedEffect(fn, options) {
|
|
|
2188
2283
|
node._queue.enqueue(EFFECT_USER, run);
|
|
2189
2284
|
cleanup(() => node._cleanup?.());
|
|
2190
2285
|
if (!node._parent) {
|
|
2191
|
-
const message =
|
|
2286
|
+
const message =
|
|
2287
|
+
"[NO_OWNER_EFFECT] Effects created outside a reactive context will never be disposed";
|
|
2192
2288
|
emitDiagnostic({
|
|
2193
2289
|
code: "NO_OWNER_EFFECT",
|
|
2194
2290
|
kind: "lifecycle",
|
|
@@ -2249,7 +2345,8 @@ function onCleanup(fn) {
|
|
|
2249
2345
|
{
|
|
2250
2346
|
const owner = getOwner();
|
|
2251
2347
|
if (!owner) {
|
|
2252
|
-
const message =
|
|
2348
|
+
const message =
|
|
2349
|
+
"[NO_OWNER_CLEANUP] onCleanup called outside a reactive context will never be run";
|
|
2253
2350
|
emitDiagnostic({
|
|
2254
2351
|
code: "NO_OWNER_CLEANUP",
|
|
2255
2352
|
kind: "lifecycle",
|
|
@@ -2257,9 +2354,9 @@ function onCleanup(fn) {
|
|
|
2257
2354
|
message: message
|
|
2258
2355
|
});
|
|
2259
2356
|
console.warn(message);
|
|
2260
|
-
} else if (owner.
|
|
2357
|
+
} else if (owner._config & CONFIG_CHILDREN_FORBIDDEN) {
|
|
2261
2358
|
const message =
|
|
2262
|
-
"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";
|
|
2263
2360
|
emitDiagnostic({
|
|
2264
2361
|
code: "CLEANUP_IN_FORBIDDEN_SCOPE",
|
|
2265
2362
|
kind: "lifecycle",
|
|
@@ -2274,14 +2371,12 @@ function onCleanup(fn) {
|
|
|
2274
2371
|
return cleanup(fn);
|
|
2275
2372
|
}
|
|
2276
2373
|
function accessor(node) {
|
|
2277
|
-
|
|
2278
|
-
fn.$r = true;
|
|
2279
|
-
return fn;
|
|
2374
|
+
return read.bind(null, node);
|
|
2280
2375
|
}
|
|
2281
2376
|
function createSignal(first, second) {
|
|
2282
2377
|
if (typeof first === "function") {
|
|
2283
|
-
const node = computed(first,
|
|
2284
|
-
node.
|
|
2378
|
+
const node = computed(first, second);
|
|
2379
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
2285
2380
|
return [accessor(node), setSignal.bind(null, node)];
|
|
2286
2381
|
}
|
|
2287
2382
|
const node = signal(first, second);
|
|
@@ -2289,20 +2384,30 @@ function createSignal(first, second) {
|
|
|
2289
2384
|
return [accessor(node), setSignal.bind(null, node)];
|
|
2290
2385
|
}
|
|
2291
2386
|
function createMemo(compute, options) {
|
|
2292
|
-
|
|
2293
|
-
return accessor(node);
|
|
2387
|
+
return accessor(computed(compute, options));
|
|
2294
2388
|
}
|
|
2295
2389
|
function createEffect(compute, effectFn, options) {
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
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,
|
|
2406
|
+
...{ ...options, name: options?.name ?? "effect" }
|
|
2299
2407
|
});
|
|
2300
2408
|
}
|
|
2301
2409
|
function createRenderEffect(compute, effectFn, options) {
|
|
2302
|
-
effect(compute, effectFn, undefined,
|
|
2303
|
-
render: true,
|
|
2304
|
-
...{ ...options, name: options?.name ?? "effect" }
|
|
2305
|
-
});
|
|
2410
|
+
effect(compute, effectFn, undefined, { ...options, name: options?.name ?? "effect" });
|
|
2306
2411
|
}
|
|
2307
2412
|
function createTrackedEffect(compute, options) {
|
|
2308
2413
|
trackedEffect(compute, { ...options, name: options?.name ?? "trackedEffect" });
|
|
@@ -2327,8 +2432,11 @@ function createReaction(effectFn, options) {
|
|
|
2327
2432
|
dispose(node);
|
|
2328
2433
|
},
|
|
2329
2434
|
effectFn.error,
|
|
2330
|
-
|
|
2331
|
-
|
|
2435
|
+
{
|
|
2436
|
+
...(true ? { ...options, name: options?.name ?? "effect" } : options),
|
|
2437
|
+
user: true,
|
|
2438
|
+
defer: true
|
|
2439
|
+
}
|
|
2332
2440
|
);
|
|
2333
2441
|
});
|
|
2334
2442
|
};
|
|
@@ -2355,8 +2463,8 @@ function resolve(fn) {
|
|
|
2355
2463
|
}
|
|
2356
2464
|
function createOptimistic(first, second) {
|
|
2357
2465
|
if (typeof first === "function") {
|
|
2358
|
-
const node = optimisticComputed(first,
|
|
2359
|
-
node.
|
|
2466
|
+
const node = optimisticComputed(first, second);
|
|
2467
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
2360
2468
|
return [accessor(node), setSignal.bind(null, node)];
|
|
2361
2469
|
}
|
|
2362
2470
|
const node = optimisticSignal(first, second);
|
|
@@ -2365,7 +2473,7 @@ function createOptimistic(first, second) {
|
|
|
2365
2473
|
}
|
|
2366
2474
|
function onSettled(callback) {
|
|
2367
2475
|
const owner = getOwner();
|
|
2368
|
-
owner && !owner.
|
|
2476
|
+
owner && !(owner._config & CONFIG_CHILDREN_FORBIDDEN)
|
|
2369
2477
|
? createTrackedEffect(() => untrack(callback), { name: "onSettled" })
|
|
2370
2478
|
: globalQueue.enqueue(EFFECT_USER, () => {
|
|
2371
2479
|
const cleanup = callback();
|
|
@@ -2543,31 +2651,39 @@ function createProjectionInternal(fn, seed, options) {
|
|
|
2543
2651
|
return wrapped;
|
|
2544
2652
|
};
|
|
2545
2653
|
const wrappedStore = wrapProjection(seed);
|
|
2546
|
-
node = computed(
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
storeSetter(draft, s => {
|
|
2555
|
-
result = fn(s);
|
|
2556
|
-
settled = true;
|
|
2557
|
-
const value = handleAsync(owner, result, value => {
|
|
2558
|
-
value !== s &&
|
|
2559
|
-
value !== undefined &&
|
|
2560
|
-
storeSetter(wrappedStore, reconcile(value, options?.key || "id"));
|
|
2561
|
-
});
|
|
2562
|
-
value !== s && value !== undefined && reconcile(value, options?.key || "id")(wrappedStore);
|
|
2563
|
-
});
|
|
2564
|
-
});
|
|
2565
|
-
node._preventAutoDisposal = true;
|
|
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;
|
|
2566
2662
|
return { store: wrappedStore, node: node };
|
|
2567
2663
|
}
|
|
2568
2664
|
function createProjection(fn, seed, options) {
|
|
2569
2665
|
return createProjectionInternal(fn, seed, options).store;
|
|
2570
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;
|
|
2686
|
+
}
|
|
2571
2687
|
function createWriteTraps(isActive) {
|
|
2572
2688
|
const traps = {
|
|
2573
2689
|
get(_, prop) {
|
|
@@ -2677,7 +2793,7 @@ function getNode(nodes, property, value, firewall, equals = isEqual, optimistic,
|
|
|
2677
2793
|
{
|
|
2678
2794
|
equals: equals,
|
|
2679
2795
|
unobserved() {
|
|
2680
|
-
delete nodes[property];
|
|
2796
|
+
if (nodes[property] === s) delete nodes[property];
|
|
2681
2797
|
}
|
|
2682
2798
|
},
|
|
2683
2799
|
firewall
|
|
@@ -2751,19 +2867,51 @@ function prepareStoreWrite(target, store, property) {
|
|
|
2751
2867
|
if (useOptimistic) trackOptimisticStore(store);
|
|
2752
2868
|
return { base: base, overrideKey: overrideKey, state: state };
|
|
2753
2869
|
}
|
|
2754
|
-
function
|
|
2755
|
-
if (
|
|
2870
|
+
function upsertStoreNode(target, nodes, property, prev, snapshotProps) {
|
|
2871
|
+
if (nodes[property]) return nodes[property];
|
|
2872
|
+
const initial = isWrappable(prev) ? wrap(prev, target) : prev;
|
|
2873
|
+
const node = getNode(
|
|
2874
|
+
nodes,
|
|
2875
|
+
property,
|
|
2876
|
+
initial,
|
|
2877
|
+
target[STORE_FIREWALL],
|
|
2878
|
+
isEqual,
|
|
2879
|
+
target[STORE_OPTIMISTIC],
|
|
2880
|
+
snapshotProps
|
|
2881
|
+
);
|
|
2882
|
+
registerTransientStoreNode(node);
|
|
2883
|
+
return node;
|
|
2884
|
+
}
|
|
2885
|
+
function notifyStoreProperty(target, property, mode, value, prev, prevHas) {
|
|
2886
|
+
const skipUpsert = projectionWriteActive || target[STORE_OPTIMISTIC];
|
|
2887
|
+
const newHas = mode !== "delete";
|
|
2888
|
+
const existingHas = target[STORE_HAS]?.[property];
|
|
2889
|
+
if (existingHas) {
|
|
2890
|
+
setSignal(existingHas, newHas);
|
|
2891
|
+
} else if (!skipUpsert && mode !== "invalidate" && prevHas !== newHas) {
|
|
2892
|
+
const hasNode = upsertStoreNode(target, getNodes(target, STORE_HAS), property, prevHas);
|
|
2893
|
+
setSignal(hasNode, newHas);
|
|
2894
|
+
}
|
|
2756
2895
|
const nodes = getNodes(target, STORE_NODE);
|
|
2757
2896
|
if (mode === "set") {
|
|
2758
|
-
nodes[property]
|
|
2897
|
+
if (nodes[property]) {
|
|
2759
2898
|
setSignal(nodes[property], () => (isWrappable(value) ? wrap(value, target) : value));
|
|
2899
|
+
} else if (!skipUpsert) {
|
|
2900
|
+
const node = upsertStoreNode(target, nodes, property, prev, target[STORE_SNAPSHOT_PROPS]);
|
|
2901
|
+
setSignal(node, () => (isWrappable(value) ? wrap(value, target) : value));
|
|
2902
|
+
}
|
|
2760
2903
|
} else if (mode === "invalidate") {
|
|
2761
2904
|
if (nodes[property]) {
|
|
2762
2905
|
setSignal(nodes[property], {});
|
|
2763
2906
|
delete nodes[property];
|
|
2764
2907
|
}
|
|
2765
2908
|
} else {
|
|
2766
|
-
|
|
2909
|
+
if (nodes[property]) {
|
|
2910
|
+
setSignal(nodes[property], undefined);
|
|
2911
|
+
} else if (!skipUpsert) {
|
|
2912
|
+
const node = upsertStoreNode(target, nodes, property, prev, target[STORE_SNAPSHOT_PROPS]);
|
|
2913
|
+
setSignal(node, undefined);
|
|
2914
|
+
}
|
|
2767
2915
|
}
|
|
2768
2916
|
nodes[$TRACK] && setSignal(nodes[$TRACK], undefined);
|
|
2769
2917
|
}
|
|
@@ -2838,7 +2986,7 @@ const storeTraps = {
|
|
|
2838
2986
|
}
|
|
2839
2987
|
if (strictRead && typeof property === "string") {
|
|
2840
2988
|
const message =
|
|
2841
|
-
`Reactive value read directly in ${strictRead} will not update. ` +
|
|
2989
|
+
`[STRICT_READ_UNTRACKED] Reactive value read directly in ${strictRead} will not update. ` +
|
|
2842
2990
|
`Move it into a tracking scope (JSX, a memo, or an effect's compute function).`;
|
|
2843
2991
|
emitDiagnostic({
|
|
2844
2992
|
code: "STRICT_READ_UNTRACKED",
|
|
@@ -2860,18 +3008,13 @@ const storeTraps = {
|
|
|
2860
3008
|
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
2861
3009
|
? target[STORE_OVERRIDE][property] !== $DELETED
|
|
2862
3010
|
: property in target[STORE_VALUE];
|
|
2863
|
-
if (
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
target[STORE_FIREWALL],
|
|
2871
|
-
isEqual,
|
|
2872
|
-
target[STORE_OPTIMISTIC]
|
|
2873
|
-
)
|
|
2874
|
-
);
|
|
3011
|
+
if (writeOnly(target[$PROXY])) return has;
|
|
3012
|
+
const nodes = getNodes(target, STORE_HAS);
|
|
3013
|
+
if (nodes[property]) return read(nodes[property]);
|
|
3014
|
+
if (getObserver()) {
|
|
3015
|
+
return read(
|
|
3016
|
+
getNode(nodes, property, has, target[STORE_FIREWALL], isEqual, target[STORE_OPTIMISTIC])
|
|
3017
|
+
);
|
|
2875
3018
|
}
|
|
2876
3019
|
return has;
|
|
2877
3020
|
},
|
|
@@ -2890,6 +3033,12 @@ const storeTraps = {
|
|
|
2890
3033
|
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
2891
3034
|
? target[STORE_OVERRIDE][property]
|
|
2892
3035
|
: base;
|
|
3036
|
+
const prevHas =
|
|
3037
|
+
target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]
|
|
3038
|
+
? target[STORE_OPTIMISTIC_OVERRIDE][property] !== $DELETED
|
|
3039
|
+
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
3040
|
+
? target[STORE_OVERRIDE][property] !== $DELETED
|
|
3041
|
+
: property in target[STORE_VALUE];
|
|
2893
3042
|
const value = rawValue?.[$TARGET]?.[STORE_VALUE] ?? rawValue;
|
|
2894
3043
|
const isArrayIndexWrite = Array.isArray(state) && property !== "length";
|
|
2895
3044
|
const nextIndex = isArrayIndexWrite ? parseInt(property) + 1 : 0;
|
|
@@ -2909,11 +3058,21 @@ const storeTraps = {
|
|
|
2909
3058
|
override[property] = value;
|
|
2910
3059
|
if (nextLength !== undefined) override.length = nextLength;
|
|
2911
3060
|
}
|
|
2912
|
-
notifyStoreProperty(target, property, "set", value);
|
|
2913
|
-
if (Array.isArray(state)) {
|
|
3061
|
+
notifyStoreProperty(target, property, "set", value, prev, prevHas);
|
|
3062
|
+
if (Array.isArray(state) && property !== "length" && nextLength !== undefined) {
|
|
2914
3063
|
const nodes = getNodes(target, STORE_NODE);
|
|
2915
|
-
|
|
2916
|
-
|
|
3064
|
+
if (nodes.length) {
|
|
3065
|
+
setSignal(nodes.length, nextLength);
|
|
3066
|
+
} else if (!projectionWriteActive && !target[STORE_OPTIMISTIC]) {
|
|
3067
|
+
const node = upsertStoreNode(
|
|
3068
|
+
target,
|
|
3069
|
+
nodes,
|
|
3070
|
+
"length",
|
|
3071
|
+
len,
|
|
3072
|
+
target[STORE_SNAPSHOT_PROPS]
|
|
3073
|
+
);
|
|
3074
|
+
setSignal(node, nextLength);
|
|
3075
|
+
}
|
|
2917
3076
|
}
|
|
2918
3077
|
if (true) DEV$1.hooks.onStoreNodeUpdate?.(target[$PROXY], property, value, prev);
|
|
2919
3078
|
});
|
|
@@ -2971,7 +3130,7 @@ const storeTraps = {
|
|
|
2971
3130
|
} else if (target[overrideKey] && property in target[overrideKey]) {
|
|
2972
3131
|
delete target[overrideKey][property];
|
|
2973
3132
|
} else return true;
|
|
2974
|
-
notifyStoreProperty(target, property, "delete");
|
|
3133
|
+
notifyStoreProperty(target, property, "delete", undefined, prev, true);
|
|
2975
3134
|
});
|
|
2976
3135
|
}
|
|
2977
3136
|
return true;
|
|
@@ -3101,38 +3260,26 @@ function createOptimisticProjectionInternal(fn, initialValue, options) {
|
|
|
3101
3260
|
};
|
|
3102
3261
|
const wrappedStore = wrapProjection(initialValue);
|
|
3103
3262
|
if (fn) {
|
|
3104
|
-
|
|
3105
|
-
const owner = getOwner();
|
|
3106
|
-
let settled = false;
|
|
3107
|
-
let result;
|
|
3108
|
-
const draft = new Proxy(
|
|
3109
|
-
wrappedStore,
|
|
3110
|
-
createWriteTraps(() => !settled || owner._inFlight === result)
|
|
3111
|
-
);
|
|
3263
|
+
const wrapCommit = write => {
|
|
3112
3264
|
setProjectionWriteActive(true);
|
|
3113
3265
|
try {
|
|
3114
|
-
|
|
3115
|
-
result = fn(s);
|
|
3116
|
-
settled = true;
|
|
3117
|
-
const value = handleAsync(owner, result, value => {
|
|
3118
|
-
setProjectionWriteActive(true);
|
|
3119
|
-
try {
|
|
3120
|
-
value !== s &&
|
|
3121
|
-
value !== undefined &&
|
|
3122
|
-
storeSetter(wrappedStore, reconcile(value, options?.key || "id"));
|
|
3123
|
-
} finally {
|
|
3124
|
-
setProjectionWriteActive(false);
|
|
3125
|
-
}
|
|
3126
|
-
});
|
|
3127
|
-
value !== s &&
|
|
3128
|
-
value !== undefined &&
|
|
3129
|
-
reconcile(value, options?.key || "id")(wrappedStore);
|
|
3130
|
-
});
|
|
3266
|
+
write();
|
|
3131
3267
|
} finally {
|
|
3132
3268
|
setProjectionWriteActive(false);
|
|
3133
3269
|
}
|
|
3134
|
-
}
|
|
3135
|
-
node
|
|
3270
|
+
};
|
|
3271
|
+
node = computed(
|
|
3272
|
+
() => {
|
|
3273
|
+
setProjectionWriteActive(true);
|
|
3274
|
+
try {
|
|
3275
|
+
runProjectionComputed(wrappedStore, fn, options?.key || "id", wrapCommit);
|
|
3276
|
+
} finally {
|
|
3277
|
+
setProjectionWriteActive(false);
|
|
3278
|
+
}
|
|
3279
|
+
},
|
|
3280
|
+
options?.name ? { name: options.name } : undefined
|
|
3281
|
+
);
|
|
3282
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
3136
3283
|
}
|
|
3137
3284
|
return { store: wrappedStore, node: node };
|
|
3138
3285
|
}
|
|
@@ -3409,22 +3556,22 @@ function mapArray(list, map, options) {
|
|
|
3409
3556
|
}
|
|
3410
3557
|
}
|
|
3411
3558
|
: map;
|
|
3412
|
-
const
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
node.
|
|
3559
|
+
const data = {
|
|
3560
|
+
_owner: createOwner(),
|
|
3561
|
+
_len: 0,
|
|
3562
|
+
_list: list,
|
|
3563
|
+
_items: [],
|
|
3564
|
+
_map: wrappedMap,
|
|
3565
|
+
_mappings: [],
|
|
3566
|
+
_nodes: [],
|
|
3567
|
+
_key: keyFn,
|
|
3568
|
+
_rows: keyFn || options?.keyed === false ? [] : undefined,
|
|
3569
|
+
_indexes: indexes ? [] : undefined,
|
|
3570
|
+
_fallback: options?.fallback
|
|
3571
|
+
};
|
|
3572
|
+
const node = computed(updateKeyedMap.bind(data));
|
|
3573
|
+
data._owner._parentComputed = node;
|
|
3574
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
3428
3575
|
return accessor(node);
|
|
3429
3576
|
}
|
|
3430
3577
|
const pureOptions = { ownedWrite: true };
|
|
@@ -3577,7 +3724,7 @@ function repeat(count, map, options) {
|
|
|
3577
3724
|
_fallback: options?.fallback
|
|
3578
3725
|
})
|
|
3579
3726
|
);
|
|
3580
|
-
node.
|
|
3727
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
3581
3728
|
return accessor(node);
|
|
3582
3729
|
}
|
|
3583
3730
|
function updateRepeat() {
|
|
@@ -3635,7 +3782,7 @@ function compare(key, a, b) {
|
|
|
3635
3782
|
return key ? key(a) === key(b) : true;
|
|
3636
3783
|
}
|
|
3637
3784
|
function boundaryComputed(fn, propagationMask) {
|
|
3638
|
-
const node = computed(fn,
|
|
3785
|
+
const node = computed(fn, { lazy: true });
|
|
3639
3786
|
node._notifyStatus = (status, error) => {
|
|
3640
3787
|
const flags = status !== undefined ? status : node._statusFlags;
|
|
3641
3788
|
const actualError = error !== undefined ? error : node._error;
|
|
@@ -3643,7 +3790,7 @@ function boundaryComputed(fn, propagationMask) {
|
|
|
3643
3790
|
node._queue.notify(node, node._propagationMask, flags, actualError);
|
|
3644
3791
|
};
|
|
3645
3792
|
node._propagationMask = propagationMask;
|
|
3646
|
-
node.
|
|
3793
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
3647
3794
|
recompute(node, true);
|
|
3648
3795
|
return node;
|
|
3649
3796
|
}
|
|
@@ -3660,12 +3807,16 @@ const ON_INIT = Symbol();
|
|
|
3660
3807
|
const RevealControllerContext = createContext(null);
|
|
3661
3808
|
let _revealUsed = false;
|
|
3662
3809
|
const FALSE_ACCESSOR = () => false;
|
|
3810
|
+
const SEQUENTIAL_ACCESSOR = () => "sequential";
|
|
3663
3811
|
function isRevealController(slot) {
|
|
3664
3812
|
return slot instanceof RevealController;
|
|
3665
3813
|
}
|
|
3666
3814
|
function isSlotReady(slot) {
|
|
3667
3815
|
return isRevealController(slot) ? slot.isReady() : slot._sources.size === 0 && !slot._pending;
|
|
3668
3816
|
}
|
|
3817
|
+
function isSlotMinimallyReady(slot) {
|
|
3818
|
+
return isRevealController(slot) ? slot.isMinimallyReady() : isSlotReady(slot);
|
|
3819
|
+
}
|
|
3669
3820
|
function setSlotState(slot, controller, disabled, collapsed) {
|
|
3670
3821
|
setSignal(slot._disabled, disabled);
|
|
3671
3822
|
setSignal(slot._collapsed, collapsed);
|
|
@@ -3677,16 +3828,17 @@ function setSlotState(slot, controller, disabled, collapsed) {
|
|
|
3677
3828
|
slot._revealController = undefined;
|
|
3678
3829
|
}
|
|
3679
3830
|
class RevealController {
|
|
3680
|
-
|
|
3831
|
+
_orderAccessor;
|
|
3681
3832
|
_collapsedAccessor;
|
|
3682
3833
|
_slots = [];
|
|
3683
3834
|
_parentController;
|
|
3684
3835
|
_disabled = signal(false, { ownedWrite: true, _noSnapshot: true });
|
|
3685
3836
|
_collapsed = signal(false, { ownedWrite: true, _noSnapshot: true });
|
|
3686
3837
|
_ready = true;
|
|
3838
|
+
_minimallyReady = true;
|
|
3687
3839
|
_evaluating = false;
|
|
3688
|
-
constructor(
|
|
3689
|
-
this.
|
|
3840
|
+
constructor(order, collapsed) {
|
|
3841
|
+
this._orderAccessor = order;
|
|
3690
3842
|
this._collapsedAccessor = collapsed;
|
|
3691
3843
|
}
|
|
3692
3844
|
_forEachOwnedSlot(fn) {
|
|
@@ -3701,12 +3853,37 @@ class RevealController {
|
|
|
3701
3853
|
isReady() {
|
|
3702
3854
|
return this._forEachOwnedSlot(isSlotReady);
|
|
3703
3855
|
}
|
|
3856
|
+
isMinimallyReady() {
|
|
3857
|
+
const order = untrack(this._orderAccessor);
|
|
3858
|
+
if (order === "together") return this.isReady();
|
|
3859
|
+
if (order === "natural") {
|
|
3860
|
+
let hasSlot = false;
|
|
3861
|
+
let anyReady = false;
|
|
3862
|
+
this._forEachOwnedSlot(slot => {
|
|
3863
|
+
hasSlot = true;
|
|
3864
|
+
if (isSlotMinimallyReady(slot)) {
|
|
3865
|
+
anyReady = true;
|
|
3866
|
+
return false;
|
|
3867
|
+
}
|
|
3868
|
+
});
|
|
3869
|
+
return !hasSlot || anyReady;
|
|
3870
|
+
}
|
|
3871
|
+
let firstReady = true;
|
|
3872
|
+
this._forEachOwnedSlot(slot => {
|
|
3873
|
+
firstReady = isSlotMinimallyReady(slot);
|
|
3874
|
+
return false;
|
|
3875
|
+
});
|
|
3876
|
+
return firstReady;
|
|
3877
|
+
}
|
|
3704
3878
|
register(slot) {
|
|
3705
3879
|
if (this._slots.includes(slot)) return;
|
|
3706
3880
|
this._slots.push(slot);
|
|
3707
|
-
const
|
|
3881
|
+
const order = untrack(this._orderAccessor);
|
|
3708
3882
|
(setSignal(slot._disabled, true),
|
|
3709
|
-
setSignal(
|
|
3883
|
+
setSignal(
|
|
3884
|
+
slot._collapsed,
|
|
3885
|
+
order === "sequential" ? !!untrack(this._collapsedAccessor) : false
|
|
3886
|
+
));
|
|
3710
3887
|
untrack(() => this.evaluate());
|
|
3711
3888
|
}
|
|
3712
3889
|
unregister(slot) {
|
|
@@ -3718,29 +3895,52 @@ class RevealController {
|
|
|
3718
3895
|
if (this._evaluating) return;
|
|
3719
3896
|
this._evaluating = true;
|
|
3720
3897
|
const wasReady = this._ready;
|
|
3898
|
+
const wasMinReady = this._minimallyReady;
|
|
3721
3899
|
try {
|
|
3722
3900
|
const disabled = disabledOverride ?? read(this._disabled),
|
|
3723
|
-
|
|
3901
|
+
order = untrack(this._orderAccessor),
|
|
3902
|
+
collapseTail = order === "sequential" && !!untrack(this._collapsedAccessor),
|
|
3724
3903
|
collapsed = collapsedOverride ?? collapseTail;
|
|
3725
|
-
if (disabled
|
|
3726
|
-
this._forEachOwnedSlot(slot => setSlotState(slot, this, true,
|
|
3727
|
-
else if (
|
|
3728
|
-
|
|
3729
|
-
|
|
3904
|
+
if (disabled) {
|
|
3905
|
+
this._forEachOwnedSlot(slot => setSlotState(slot, this, true, collapsed));
|
|
3906
|
+
} else if (order === "natural") {
|
|
3907
|
+
this._forEachOwnedSlot(slot => {
|
|
3908
|
+
if (isRevealController(slot)) {
|
|
3909
|
+
setSignal(slot._collapsed, false);
|
|
3910
|
+
setSignal(slot._disabled, false);
|
|
3911
|
+
slot.evaluate(false, false);
|
|
3912
|
+
} else {
|
|
3913
|
+
setSlotState(slot, this, !isSlotReady(slot), false);
|
|
3914
|
+
}
|
|
3915
|
+
});
|
|
3916
|
+
} else if (order === "together") {
|
|
3917
|
+
const minReady = this._forEachOwnedSlot(isSlotMinimallyReady);
|
|
3918
|
+
this._forEachOwnedSlot(slot => setSlotState(slot, this, !minReady, false));
|
|
3730
3919
|
} else {
|
|
3731
3920
|
let pendingSeen = false;
|
|
3732
3921
|
this._forEachOwnedSlot(slot => {
|
|
3733
3922
|
if (pendingSeen) return setSlotState(slot, this, true, collapseTail);
|
|
3734
3923
|
if (isSlotReady(slot)) return setSlotState(slot, this, false, false);
|
|
3735
3924
|
pendingSeen = true;
|
|
3736
|
-
|
|
3925
|
+
if (isRevealController(slot)) {
|
|
3926
|
+
setSignal(slot._collapsed, false);
|
|
3927
|
+
setSignal(slot._disabled, false);
|
|
3928
|
+
slot.evaluate(false, false);
|
|
3929
|
+
} else {
|
|
3930
|
+
setSlotState(slot, this, true, false);
|
|
3931
|
+
}
|
|
3737
3932
|
});
|
|
3738
3933
|
}
|
|
3739
3934
|
} finally {
|
|
3740
3935
|
this._ready = this.isReady();
|
|
3936
|
+
this._minimallyReady = this.isMinimallyReady();
|
|
3741
3937
|
this._evaluating = false;
|
|
3742
3938
|
}
|
|
3743
|
-
if (
|
|
3939
|
+
if (
|
|
3940
|
+
this._parentController &&
|
|
3941
|
+
(wasReady !== this._ready || wasMinReady !== this._minimallyReady)
|
|
3942
|
+
)
|
|
3943
|
+
this._parentController.evaluate();
|
|
3744
3944
|
}
|
|
3745
3945
|
}
|
|
3746
3946
|
class CollectionQueue extends Queue {
|
|
@@ -3829,7 +4029,8 @@ class CollectionQueue extends Queue {
|
|
|
3829
4029
|
}
|
|
3830
4030
|
function createCollectionBoundary(type, fn, fallback, onFn) {
|
|
3831
4031
|
if (!getOwner()) {
|
|
3832
|
-
const message =
|
|
4032
|
+
const message =
|
|
4033
|
+
"[NO_OWNER_BOUNDARY] Boundaries created outside a reactive context will never be disposed.";
|
|
3833
4034
|
emitDiagnostic({
|
|
3834
4035
|
code: "NO_OWNER_BOUNDARY",
|
|
3835
4036
|
kind: "lifecycle",
|
|
@@ -3862,15 +4063,16 @@ function createCollectionBoundary(type, fn, fallback, onFn) {
|
|
|
3862
4063
|
controller.register(queue);
|
|
3863
4064
|
cleanup(() => controller.unregister(queue));
|
|
3864
4065
|
}
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
4066
|
+
return accessor(
|
|
4067
|
+
computed(() => {
|
|
4068
|
+
if (!read(queue._disabled)) {
|
|
4069
|
+
const resolved = read(tree);
|
|
4070
|
+
if (!untrack(() => read(queue._disabled))) return ((queue._initialized = true), resolved);
|
|
4071
|
+
}
|
|
4072
|
+
if (_revealUsed && read(queue._collapsed)) return undefined;
|
|
4073
|
+
return fallback(queue);
|
|
4074
|
+
})
|
|
4075
|
+
);
|
|
3874
4076
|
}
|
|
3875
4077
|
function createLoadingBoundary(fn, fallback, options) {
|
|
3876
4078
|
return createCollectionBoundary(STATUS_PENDING, fn, () => fallback(), options?.on);
|
|
@@ -3889,14 +4091,14 @@ function createRevealOrder(fn, options) {
|
|
|
3889
4091
|
_revealUsed = true;
|
|
3890
4092
|
const owner = createOwner();
|
|
3891
4093
|
const parentController = getContext(RevealControllerContext);
|
|
3892
|
-
const
|
|
4094
|
+
const order = options?.order || SEQUENTIAL_ACCESSOR,
|
|
3893
4095
|
collapsed = options?.collapsed || FALSE_ACCESSOR;
|
|
3894
|
-
const controller = new RevealController(
|
|
4096
|
+
const controller = new RevealController(order, collapsed);
|
|
3895
4097
|
setContext(RevealControllerContext, controller, owner);
|
|
3896
4098
|
return runWithOwner(owner, () => {
|
|
3897
4099
|
const value = fn();
|
|
3898
4100
|
computed(() => {
|
|
3899
|
-
|
|
4101
|
+
order();
|
|
3900
4102
|
collapsed();
|
|
3901
4103
|
controller.evaluate();
|
|
3902
4104
|
});
|