@solidjs/signals 2.0.0-beta.16 → 2.0.0-beta.18
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 +4 -3
- package/dist/dev.js +421 -106
- package/dist/node.cjs +1908 -1642
- package/dist/prod.js +1719 -1454
- package/dist/types/affects.d.ts +47 -0
- package/dist/types/boundaries.d.ts +2 -2
- package/dist/types/core/async.d.ts +39 -2
- package/dist/types/core/constants.d.ts +8 -0
- package/dist/types/core/core.d.ts +9 -0
- package/dist/types/core/dev.d.ts +1 -1
- package/dist/types/core/error.d.ts +2 -0
- package/dist/types/core/index.d.ts +1 -1
- package/dist/types/core/invariants.d.ts +10 -0
- package/dist/types/core/scheduler.d.ts +43 -0
- package/dist/types/core/types.d.ts +22 -5
- package/dist/types/index.d.ts +1 -0
- package/dist/types/store/store.d.ts +32 -14
- package/dist/types-cjs/affects.d.cts +47 -0
- package/dist/types-cjs/boundaries.d.cts +2 -2
- package/dist/types-cjs/core/async.d.cts +39 -2
- package/dist/types-cjs/core/constants.d.cts +8 -0
- package/dist/types-cjs/core/core.d.cts +9 -0
- package/dist/types-cjs/core/dev.d.cts +1 -1
- package/dist/types-cjs/core/error.d.cts +2 -0
- package/dist/types-cjs/core/index.d.cts +1 -1
- package/dist/types-cjs/core/invariants.d.cts +10 -0
- package/dist/types-cjs/core/scheduler.d.cts +43 -0
- package/dist/types-cjs/core/types.d.cts +22 -5
- package/dist/types-cjs/index.d.cts +1 -0
- package/dist/types-cjs/store/store.d.cts +32 -14
- package/package.json +1 -1
package/dist/dev.js
CHANGED
|
@@ -12,6 +12,9 @@ class StatusError extends Error {
|
|
|
12
12
|
this.source = source;
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
+
function unwrapStatusError(error) {
|
|
16
|
+
return error instanceof StatusError ? error.cause : error;
|
|
17
|
+
}
|
|
15
18
|
class NoOwnerError extends Error {
|
|
16
19
|
constructor() {
|
|
17
20
|
super("Context can only be accessed under a reactive root.");
|
|
@@ -36,6 +39,7 @@ const REACTIVE_OPTIMISTIC_DIRTY = 1 << 7;
|
|
|
36
39
|
const REACTIVE_SNAPSHOT_STALE = 1 << 8;
|
|
37
40
|
const REACTIVE_LAZY = 1 << 9;
|
|
38
41
|
const REACTIVE_MANUAL_WRITE = 1 << 10;
|
|
42
|
+
const REACTIVE_REASK = 1 << 11;
|
|
39
43
|
const CONFIG_OWNED_WRITE = 1 << 0;
|
|
40
44
|
const CONFIG_NO_SNAPSHOT = 1 << 1;
|
|
41
45
|
const CONFIG_TRANSPARENT = 1 << 2;
|
|
@@ -253,6 +257,7 @@ function canUseSimpleSyncFlush(queue) {
|
|
|
253
257
|
activeLanes.size === 0 &&
|
|
254
258
|
queue._children.length === 0 &&
|
|
255
259
|
queue._optimisticNodes.length === 0 &&
|
|
260
|
+
queue._affectsNodes.length === 0 &&
|
|
256
261
|
queue._optimisticStores.size === 0 &&
|
|
257
262
|
transientStoreNodes.size === 0
|
|
258
263
|
);
|
|
@@ -266,6 +271,7 @@ function sweepTransientStoreNodes() {
|
|
|
266
271
|
}
|
|
267
272
|
if (node._pendingValue !== NOT_PENDING) continue;
|
|
268
273
|
if (node._overrideValue !== undefined && node._overrideValue !== NOT_PENDING) continue;
|
|
274
|
+
if (node._affectsCount) continue;
|
|
269
275
|
transientStoreNodes.delete(node);
|
|
270
276
|
node._unobserved?.();
|
|
271
277
|
}
|
|
@@ -316,6 +322,10 @@ function mergeTransitionState(target, outgoing) {
|
|
|
316
322
|
target._actions.push(...outgoing._actions);
|
|
317
323
|
for (const lane of activeLanes) if (lane._transition === outgoing) lane._transition = target;
|
|
318
324
|
target._optimisticNodes.push(...outgoing._optimisticNodes);
|
|
325
|
+
if (outgoing._affectsNodes.length) {
|
|
326
|
+
target._affectsNodes.push(...outgoing._affectsNodes);
|
|
327
|
+
outgoing._affectsNodes.length = 0;
|
|
328
|
+
}
|
|
319
329
|
for (const store of outgoing._optimisticStores) target._optimisticStores.add(store);
|
|
320
330
|
for (const [source, reporters] of outgoing._asyncReporters) {
|
|
321
331
|
let targetReporters = target._asyncReporters.get(source);
|
|
@@ -466,11 +476,15 @@ class GlobalQueue extends Queue {
|
|
|
466
476
|
_pendingNode = null;
|
|
467
477
|
_pendingNodes = [];
|
|
468
478
|
_optimisticNodes = [];
|
|
479
|
+
_affectsNodes = [];
|
|
469
480
|
_optimisticStores = new Set();
|
|
470
481
|
static _update;
|
|
471
482
|
static _dispose;
|
|
472
483
|
static _runEffect;
|
|
473
484
|
static _clearOptimisticStore = null;
|
|
485
|
+
static _releaseAffectsScope = null;
|
|
486
|
+
static _propagateAffects = null;
|
|
487
|
+
static _settleAffects = null;
|
|
474
488
|
flush() {
|
|
475
489
|
if (this._running) return;
|
|
476
490
|
this._running = true;
|
|
@@ -485,6 +499,7 @@ class GlobalQueue extends Queue {
|
|
|
485
499
|
this._pendingNode = null;
|
|
486
500
|
this._pendingNodes = [];
|
|
487
501
|
this._optimisticNodes = [];
|
|
502
|
+
this._affectsNodes = [];
|
|
488
503
|
this._optimisticStores = new Set();
|
|
489
504
|
runLaneEffects(EFFECT_RENDER);
|
|
490
505
|
runLaneEffects(EFFECT_USER);
|
|
@@ -590,6 +605,7 @@ class GlobalQueue extends Queue {
|
|
|
590
605
|
_pendingNodes: [],
|
|
591
606
|
_asyncReporters: createAsyncReporters(),
|
|
592
607
|
_optimisticNodes: [],
|
|
608
|
+
_affectsNodes: [],
|
|
593
609
|
_optimisticStores: new Set(),
|
|
594
610
|
_actions: [],
|
|
595
611
|
_queueStash: { _queues: [[], []], _children: [] },
|
|
@@ -625,6 +641,10 @@ class GlobalQueue extends Queue {
|
|
|
625
641
|
}
|
|
626
642
|
this._optimisticNodes = activeTransition._optimisticNodes;
|
|
627
643
|
}
|
|
644
|
+
if (this._affectsNodes !== activeTransition._affectsNodes) {
|
|
645
|
+
activeTransition._affectsNodes.push(...this._affectsNodes);
|
|
646
|
+
this._affectsNodes = activeTransition._affectsNodes;
|
|
647
|
+
}
|
|
628
648
|
for (const lane of activeLanes) {
|
|
629
649
|
if (!lane._transition) lane._transition = activeTransition;
|
|
630
650
|
}
|
|
@@ -649,10 +669,16 @@ function queuePendingNode(node) {
|
|
|
649
669
|
}
|
|
650
670
|
globalQueue._pendingNodes.push(node);
|
|
651
671
|
}
|
|
672
|
+
let reaskArmed = false;
|
|
673
|
+
function armReaskClear() {
|
|
674
|
+
reaskArmed = true;
|
|
675
|
+
}
|
|
652
676
|
function insertSubs(node, optimistic = false) {
|
|
653
677
|
const sourceLane = node._optimisticLane || currentOptimisticLane;
|
|
654
678
|
const hasSnapshot = node._snapshotValue !== undefined;
|
|
679
|
+
const clearReask = reaskArmed;
|
|
655
680
|
for (let s = node._subs; s !== null; s = s._nextSub) {
|
|
681
|
+
if (clearReask) s._sub._flags &= ~REACTIVE_REASK;
|
|
656
682
|
if (hasSnapshot && s._sub._config & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
657
683
|
s._sub._flags |= REACTIVE_SNAPSHOT_STALE;
|
|
658
684
|
continue;
|
|
@@ -736,6 +762,9 @@ function finalizePureQueue(completingTransition = null, incomplete = false) {
|
|
|
736
762
|
}
|
|
737
763
|
completingTransition._gatedSubs.clear();
|
|
738
764
|
}
|
|
765
|
+
releaseAffectsMarks(
|
|
766
|
+
completingTransition ? completingTransition._affectsNodes : globalQueue._affectsNodes
|
|
767
|
+
);
|
|
739
768
|
const optimisticStores = completingTransition
|
|
740
769
|
? completingTransition._optimisticStores
|
|
741
770
|
: globalQueue._optimisticStores;
|
|
@@ -760,6 +789,32 @@ function trackOptimisticStore(store) {
|
|
|
760
789
|
globalQueue._optimisticStores.add(store);
|
|
761
790
|
schedule();
|
|
762
791
|
}
|
|
792
|
+
let activeAffectsMarks = 0;
|
|
793
|
+
function markAffects(node) {
|
|
794
|
+
node._affectsCount = (node._affectsCount || 0) + 1;
|
|
795
|
+
activeAffectsMarks++;
|
|
796
|
+
if (node._affectsCount === 1) updatePendingSignal(node);
|
|
797
|
+
}
|
|
798
|
+
function registerAffectsMark(node) {
|
|
799
|
+
markAffects(node);
|
|
800
|
+
globalQueue._affectsNodes.push(node);
|
|
801
|
+
GlobalQueue._propagateAffects?.(node);
|
|
802
|
+
schedule();
|
|
803
|
+
}
|
|
804
|
+
function releaseAffectsMark(node) {
|
|
805
|
+
activeAffectsMarks--;
|
|
806
|
+
node._affectsCount--;
|
|
807
|
+
if (!node._affectsCount) {
|
|
808
|
+
GlobalQueue._settleAffects?.(node);
|
|
809
|
+
snapCompanionsToState(node);
|
|
810
|
+
GlobalQueue._releaseAffectsScope?.(node);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
function releaseAffectsMarks(nodes) {
|
|
814
|
+
if (!nodes.length) return;
|
|
815
|
+
for (let i = 0; i < nodes.length; i++) releaseAffectsMark(nodes[i]);
|
|
816
|
+
nodes.length = 0;
|
|
817
|
+
}
|
|
763
818
|
function reassignPendingTransition(pendingNodes) {
|
|
764
819
|
for (let i = 0; i < pendingNodes.length; i++) {
|
|
765
820
|
pendingNodes[i]._transition = activeTransition;
|
|
@@ -839,7 +894,8 @@ function transitionComplete(transition) {
|
|
|
839
894
|
hasActiveOverride(node) &&
|
|
840
895
|
"_statusFlags" in node &&
|
|
841
896
|
node._statusFlags & STATUS_PENDING &&
|
|
842
|
-
node._error instanceof NotReadyError
|
|
897
|
+
node._error instanceof NotReadyError &&
|
|
898
|
+
!node._error.source?._affectsFor
|
|
843
899
|
) {
|
|
844
900
|
done = false;
|
|
845
901
|
break;
|
|
@@ -1276,7 +1332,7 @@ function setPendingError(el, source, error) {
|
|
|
1276
1332
|
}
|
|
1277
1333
|
function forEachDependent(el, fn) {
|
|
1278
1334
|
for (let s = el._subs; s !== null; s = s._nextSub) fn(s._sub, s);
|
|
1279
|
-
for (let child = el._child; child !== null; child = child._nextChild) {
|
|
1335
|
+
for (let child = el._child ?? null; child !== null; child = child._nextChild) {
|
|
1280
1336
|
for (let s = child._subs; s !== null; s = s._nextSub) fn(s._sub, s);
|
|
1281
1337
|
}
|
|
1282
1338
|
}
|
|
@@ -1293,21 +1349,22 @@ function enqueueForRerun(node) {
|
|
|
1293
1349
|
insertIntoHeap(node, queue);
|
|
1294
1350
|
}
|
|
1295
1351
|
}
|
|
1296
|
-
function settlePendingSource(el) {
|
|
1352
|
+
function settlePendingSource(el, source = el, snap = false) {
|
|
1297
1353
|
let scheduled = false;
|
|
1298
1354
|
const visited = new Set();
|
|
1355
|
+
const updateCompanions = snap ? snapCompanionsToState : updatePendingSignal;
|
|
1299
1356
|
const settle = node => {
|
|
1300
|
-
if (visited.has(node) || !removePendingSource(node,
|
|
1357
|
+
if (visited.has(node) || !removePendingSource(node, source)) return;
|
|
1301
1358
|
visited.add(node);
|
|
1302
1359
|
node._time = clock;
|
|
1303
|
-
const
|
|
1304
|
-
if (
|
|
1305
|
-
setPendingError(node,
|
|
1306
|
-
|
|
1360
|
+
const remaining = node._pendingSource ?? node._pendingSources?.values().next().value;
|
|
1361
|
+
if (remaining) {
|
|
1362
|
+
setPendingError(node, remaining);
|
|
1363
|
+
updateCompanions(node);
|
|
1307
1364
|
} else {
|
|
1308
1365
|
node._statusFlags &= ~STATUS_PENDING;
|
|
1309
1366
|
setPendingError(node);
|
|
1310
|
-
|
|
1367
|
+
updateCompanions(node);
|
|
1311
1368
|
if (node._blocked) {
|
|
1312
1369
|
enqueueForRerun(node);
|
|
1313
1370
|
scheduled = true;
|
|
@@ -1433,8 +1490,9 @@ function handleAsync(el, result, setter) {
|
|
|
1433
1490
|
}
|
|
1434
1491
|
if (iterator) {
|
|
1435
1492
|
const it = result[Symbol.asyncIterator]();
|
|
1436
|
-
let
|
|
1493
|
+
let hadValue = false;
|
|
1437
1494
|
let completed = false;
|
|
1495
|
+
let initialRead = true;
|
|
1438
1496
|
cleanup(() => {
|
|
1439
1497
|
if (completed) return;
|
|
1440
1498
|
completed = true;
|
|
@@ -1445,7 +1503,9 @@ function handleAsync(el, result, setter) {
|
|
|
1445
1503
|
});
|
|
1446
1504
|
const iterate = () => {
|
|
1447
1505
|
let syncResult,
|
|
1506
|
+
syncError,
|
|
1448
1507
|
resolved = false,
|
|
1508
|
+
rejected = false,
|
|
1449
1509
|
isSync = true;
|
|
1450
1510
|
it.next().then(
|
|
1451
1511
|
r => {
|
|
@@ -1455,30 +1515,46 @@ function handleAsync(el, result, setter) {
|
|
|
1455
1515
|
if (r.done) completed = true;
|
|
1456
1516
|
} else if (el._inFlight !== result) {
|
|
1457
1517
|
return;
|
|
1458
|
-
} else if (!r.done)
|
|
1459
|
-
|
|
1518
|
+
} else if (!r.done) {
|
|
1519
|
+
hadValue = true;
|
|
1520
|
+
asyncWrite(r.value, iterate);
|
|
1521
|
+
} else {
|
|
1460
1522
|
completed = true;
|
|
1461
|
-
|
|
1462
|
-
|
|
1523
|
+
if (hadValue) {
|
|
1524
|
+
schedule();
|
|
1525
|
+
flush();
|
|
1526
|
+
} else {
|
|
1527
|
+
asyncWrite(undefined);
|
|
1528
|
+
}
|
|
1463
1529
|
}
|
|
1464
1530
|
},
|
|
1465
1531
|
e => {
|
|
1466
|
-
if (
|
|
1532
|
+
if (isSync) {
|
|
1533
|
+
syncError = e;
|
|
1534
|
+
rejected = true;
|
|
1535
|
+
} else if (el._inFlight === result) {
|
|
1467
1536
|
completed = true;
|
|
1468
1537
|
handleError(e);
|
|
1469
1538
|
}
|
|
1470
1539
|
}
|
|
1471
1540
|
);
|
|
1472
1541
|
isSync = false;
|
|
1542
|
+
if (rejected) {
|
|
1543
|
+
completed = true;
|
|
1544
|
+
handleError(syncError);
|
|
1545
|
+
if (initialRead) throw syncError;
|
|
1546
|
+
return true;
|
|
1547
|
+
}
|
|
1473
1548
|
if (resolved && !syncResult.done) {
|
|
1474
1549
|
syncValue = syncResult.value;
|
|
1475
|
-
|
|
1550
|
+
hadValue = true;
|
|
1476
1551
|
return iterate();
|
|
1477
1552
|
}
|
|
1478
1553
|
return resolved && syncResult.done;
|
|
1479
1554
|
};
|
|
1480
1555
|
const immediatelyDone = iterate();
|
|
1481
|
-
|
|
1556
|
+
initialRead = false;
|
|
1557
|
+
if (!hadValue && !immediatelyDone) {
|
|
1482
1558
|
globalQueue.initTransition(resolveTransition(el));
|
|
1483
1559
|
throw new NotReadyError(context);
|
|
1484
1560
|
}
|
|
@@ -1488,6 +1564,7 @@ function handleAsync(el, result, setter) {
|
|
|
1488
1564
|
function clearStatus(el, clearUninitialized = false) {
|
|
1489
1565
|
if (el._pendingSource || el._pendingSources) clearPendingSources(el);
|
|
1490
1566
|
if (el._blocked) el._blocked = false;
|
|
1567
|
+
el._reask = false;
|
|
1491
1568
|
el._statusFlags = clearUninitialized ? 0 : el._statusFlags & STATUS_UNINITIALIZED;
|
|
1492
1569
|
if (el._error) setPendingError(el);
|
|
1493
1570
|
if (el._pendingSignal || el._latestValueComputed) updatePendingSignal(el);
|
|
@@ -1557,6 +1634,48 @@ function notifyStatus(el, status, error, blockStatus, lane) {
|
|
|
1557
1634
|
}
|
|
1558
1635
|
});
|
|
1559
1636
|
}
|
|
1637
|
+
function getAffectsSentinel(node) {
|
|
1638
|
+
return (node._affectsSentinel ??= {
|
|
1639
|
+
_name: "affects-sentinel",
|
|
1640
|
+
_affectsFor: node,
|
|
1641
|
+
_flags: 0,
|
|
1642
|
+
_statusFlags: 0,
|
|
1643
|
+
_reask: false,
|
|
1644
|
+
_error: undefined,
|
|
1645
|
+
_subs: null,
|
|
1646
|
+
_deps: null
|
|
1647
|
+
});
|
|
1648
|
+
}
|
|
1649
|
+
function propagateAffectsMark(node) {
|
|
1650
|
+
if (!node._subs && !node._child) return;
|
|
1651
|
+
const sentinel = getAffectsSentinel(node);
|
|
1652
|
+
const error = new NotReadyError(sentinel);
|
|
1653
|
+
forEachDependent(node, sub => {
|
|
1654
|
+
if (sub._pendingSource !== sentinel && !sub._pendingSources?.has(sentinel)) {
|
|
1655
|
+
if (!sub._transition) queuePendingNode(sub);
|
|
1656
|
+
notifyStatus(sub, STATUS_PENDING, error);
|
|
1657
|
+
}
|
|
1658
|
+
});
|
|
1659
|
+
}
|
|
1660
|
+
function applyAffectsReads(el, sources) {
|
|
1661
|
+
let applied = false;
|
|
1662
|
+
for (let i = 0; i < sources.length; i++) {
|
|
1663
|
+
const src = sources[i];
|
|
1664
|
+
if (!src._affectsCount) continue;
|
|
1665
|
+
const sentinel = getAffectsSentinel(src);
|
|
1666
|
+
if (addPendingSource(el, sentinel)) {
|
|
1667
|
+
el._statusFlags |= STATUS_PENDING;
|
|
1668
|
+
setPendingError(el, sentinel);
|
|
1669
|
+
applied = true;
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
if (applied) updatePendingSignal(el);
|
|
1673
|
+
}
|
|
1674
|
+
GlobalQueue._propagateAffects = propagateAffectsMark;
|
|
1675
|
+
GlobalQueue._settleAffects = node => {
|
|
1676
|
+
const sentinel = node._affectsSentinel;
|
|
1677
|
+
if (sentinel) settlePendingSource(node, sentinel, true);
|
|
1678
|
+
};
|
|
1560
1679
|
let externalSourceConfig = null;
|
|
1561
1680
|
function enableExternalSource(config) {
|
|
1562
1681
|
const { factory: factory, untrack: untrackFn = fn => fn() } = config;
|
|
@@ -1597,6 +1716,7 @@ let latestReadActive = false;
|
|
|
1597
1716
|
let context = null;
|
|
1598
1717
|
let currentOptimisticLane = null;
|
|
1599
1718
|
let pendingProbe = null;
|
|
1719
|
+
let affectsReads = null;
|
|
1600
1720
|
let snapshotCaptureActive = false;
|
|
1601
1721
|
let snapshotSources = null;
|
|
1602
1722
|
function ownerInSnapshotScope(owner) {
|
|
@@ -1669,8 +1789,9 @@ function recompute(el, create = false) {
|
|
|
1669
1789
|
}
|
|
1670
1790
|
let isOptimisticDirty = !!(el._flags & REACTIVE_OPTIMISTIC_DIRTY);
|
|
1671
1791
|
const hasOverride = el._overrideValue !== undefined && el._overrideValue !== NOT_PENDING;
|
|
1672
|
-
!!(el._statusFlags & STATUS_PENDING);
|
|
1792
|
+
const wasPending = !!(el._statusFlags & STATUS_PENDING);
|
|
1673
1793
|
const wasUninitialized = !!(el._statusFlags & STATUS_UNINITIALIZED);
|
|
1794
|
+
const isReask = !!(el._flags & REACTIVE_REASK) && !(wasPending && !el._reask);
|
|
1674
1795
|
const oldcontext = context;
|
|
1675
1796
|
context = el;
|
|
1676
1797
|
el._depsTail = null;
|
|
@@ -1680,6 +1801,9 @@ function recompute(el, create = false) {
|
|
|
1680
1801
|
let value = el._pendingValue === NOT_PENDING ? el._value : el._pendingValue;
|
|
1681
1802
|
let oldHeight = el._height;
|
|
1682
1803
|
let prevTracking = tracking;
|
|
1804
|
+
const prevAffectsReads = affectsReads;
|
|
1805
|
+
affectsReads = null;
|
|
1806
|
+
let markedReads = null;
|
|
1683
1807
|
let prevLane = currentOptimisticLane;
|
|
1684
1808
|
let prevStrictRead = false;
|
|
1685
1809
|
{
|
|
@@ -1735,7 +1859,12 @@ function recompute(el, create = false) {
|
|
|
1735
1859
|
updatePendingSignal(lane._source);
|
|
1736
1860
|
}
|
|
1737
1861
|
}
|
|
1738
|
-
|
|
1862
|
+
let reaskChanged = false;
|
|
1863
|
+
if (e instanceof NotReadyError) {
|
|
1864
|
+
el._blocked = true;
|
|
1865
|
+
reaskChanged = wasPending && el._reask !== isReask;
|
|
1866
|
+
el._reask = isReask;
|
|
1867
|
+
}
|
|
1739
1868
|
notifyStatus(
|
|
1740
1869
|
el,
|
|
1741
1870
|
e instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR,
|
|
@@ -1743,12 +1872,15 @@ function recompute(el, create = false) {
|
|
|
1743
1872
|
undefined,
|
|
1744
1873
|
e instanceof NotReadyError ? el._optimisticLane : undefined
|
|
1745
1874
|
);
|
|
1875
|
+
if (reaskChanged) repollDownstreamVerdicts(el);
|
|
1746
1876
|
} finally {
|
|
1747
1877
|
tracking = prevTracking;
|
|
1748
1878
|
strictRead = prevStrictRead;
|
|
1749
1879
|
if (isStaleEffect) stale = prevStale;
|
|
1750
1880
|
el._flags = REACTIVE_NONE | (create ? el._flags & REACTIVE_SNAPSHOT_STALE : 0);
|
|
1751
1881
|
context = oldcontext;
|
|
1882
|
+
markedReads = affectsReads;
|
|
1883
|
+
affectsReads = prevAffectsReads;
|
|
1752
1884
|
}
|
|
1753
1885
|
if (!el._error) {
|
|
1754
1886
|
trimStaleDeps(el);
|
|
@@ -1794,6 +1926,7 @@ function recompute(el, create = false) {
|
|
|
1794
1926
|
}
|
|
1795
1927
|
}
|
|
1796
1928
|
currentOptimisticLane = prevLane;
|
|
1929
|
+
if (markedReads) applyAffectsReads(el, markedReads);
|
|
1797
1930
|
const needsPendingCommit =
|
|
1798
1931
|
el._pendingValue !== NOT_PENDING ||
|
|
1799
1932
|
el._pendingFirstChild !== null ||
|
|
@@ -1870,7 +2003,8 @@ function computed(fn, options) {
|
|
|
1870
2003
|
_pendingDisposal: null,
|
|
1871
2004
|
_pendingFirstChild: null,
|
|
1872
2005
|
_inFlight: null,
|
|
1873
|
-
_transition: null
|
|
2006
|
+
_transition: null,
|
|
2007
|
+
_reask: false
|
|
1874
2008
|
};
|
|
1875
2009
|
self._name = options?.name ?? "computed";
|
|
1876
2010
|
setupComputedNode(self, options);
|
|
@@ -1916,6 +2050,7 @@ function createEffectNode(fn, effectFn, errorFn, type, notifyStatus, options) {
|
|
|
1916
2050
|
_pendingFirstChild: null,
|
|
1917
2051
|
_inFlight: null,
|
|
1918
2052
|
_transition: null,
|
|
2053
|
+
_reask: false,
|
|
1919
2054
|
_modified: false,
|
|
1920
2055
|
_prevValue: undefined,
|
|
1921
2056
|
_effectFn: effectFn,
|
|
@@ -2105,7 +2240,11 @@ function read(el) {
|
|
|
2105
2240
|
!snapshotCaptureActive &&
|
|
2106
2241
|
!strictRead
|
|
2107
2242
|
) {
|
|
2108
|
-
if (c && tracking)
|
|
2243
|
+
if (c && tracking) {
|
|
2244
|
+
link(el, c);
|
|
2245
|
+
if (activeAffectsMarks !== 0 && el._affectsCount && !pendingCheckActive)
|
|
2246
|
+
(affectsReads ??= []).push(el);
|
|
2247
|
+
}
|
|
2109
2248
|
return !c || el._pendingValue === NOT_PENDING ? el._value : el._pendingValue;
|
|
2110
2249
|
}
|
|
2111
2250
|
if (strictRead && owner._statusFlags & STATUS_PENDING) {
|
|
@@ -2126,6 +2265,8 @@ function read(el) {
|
|
|
2126
2265
|
}
|
|
2127
2266
|
if (c && tracking) {
|
|
2128
2267
|
link(el, c, pendingCheckActive);
|
|
2268
|
+
if (activeAffectsMarks !== 0 && el._affectsCount && !pendingCheckActive)
|
|
2269
|
+
(affectsReads ??= []).push(el);
|
|
2129
2270
|
if (owner._fn) {
|
|
2130
2271
|
const isZombie = el._flags & REACTIVE_ZOMBIE;
|
|
2131
2272
|
if (owner._height >= (isZombie ? zombieQueue._min : dirtyQueue._min)) {
|
|
@@ -2360,29 +2501,48 @@ function collectPendingSources(el) {
|
|
|
2360
2501
|
const owner = el._firewall || el;
|
|
2361
2502
|
if (owner !== el) pendingProbe.sources.add(owner);
|
|
2362
2503
|
}
|
|
2504
|
+
function witnessAffects(node) {
|
|
2505
|
+
pendingProbe?.sources.add(node);
|
|
2506
|
+
}
|
|
2507
|
+
function quietPending(el) {
|
|
2508
|
+
if (el._pendingSources) {
|
|
2509
|
+
for (const source of el._pendingSources) if (!source._reask) return false;
|
|
2510
|
+
return true;
|
|
2511
|
+
}
|
|
2512
|
+
if (el._pendingSource) return el._pendingSource._reask;
|
|
2513
|
+
return el._reask;
|
|
2514
|
+
}
|
|
2515
|
+
function newQuestionInFlight(comp) {
|
|
2516
|
+
return (
|
|
2517
|
+
!!(comp._statusFlags & STATUS_PENDING) &&
|
|
2518
|
+
!(comp._statusFlags & STATUS_UNINITIALIZED) &&
|
|
2519
|
+
!quietPending(comp)
|
|
2520
|
+
);
|
|
2521
|
+
}
|
|
2363
2522
|
function computePendingState(el) {
|
|
2364
2523
|
const comp = el;
|
|
2365
2524
|
if (comp._flags & REACTIVE_DISPOSED) return false;
|
|
2525
|
+
if (el._affectsCount) return true;
|
|
2366
2526
|
const firewall = el._firewall;
|
|
2367
|
-
if ((firewall || comp)._optimisticMask) return false;
|
|
2368
2527
|
if (el._parentSource) {
|
|
2369
2528
|
const parentNode = el._parentSource;
|
|
2370
|
-
if (
|
|
2529
|
+
if (parentNode._affectsCount) return true;
|
|
2371
2530
|
const parent = parentNode._firewall || parentNode;
|
|
2372
|
-
|
|
2373
|
-
return !!(
|
|
2374
|
-
parent._statusFlags & STATUS_PENDING && !(parent._statusFlags & STATUS_UNINITIALIZED)
|
|
2375
|
-
);
|
|
2531
|
+
return newQuestionInFlight(parent);
|
|
2376
2532
|
}
|
|
2377
|
-
if (hasActiveOverride(el))
|
|
2378
|
-
if (firewall && el._pendingValue !== NOT_PENDING) {
|
|
2533
|
+
if (firewall && el._pendingValue !== NOT_PENDING && !hasActiveOverride(el)) {
|
|
2379
2534
|
return (
|
|
2380
2535
|
!!(firewall._flags & REACTIVE_MANUAL_WRITE) ||
|
|
2381
|
-
(!firewall._inFlight && !(firewall._statusFlags & STATUS_PENDING))
|
|
2536
|
+
(!firewall._inFlight && !(firewall._statusFlags & STATUS_PENDING)) ||
|
|
2537
|
+
(!!(firewall._statusFlags & STATUS_PENDING) && quietPending(firewall))
|
|
2382
2538
|
);
|
|
2383
2539
|
}
|
|
2384
|
-
if (el._pendingValue !== NOT_PENDING && !(comp._statusFlags & STATUS_UNINITIALIZED))
|
|
2385
|
-
|
|
2540
|
+
if (el._pendingValue !== NOT_PENDING && !(comp._statusFlags & STATUS_UNINITIALIZED)) {
|
|
2541
|
+
if (hasActiveOverride(el))
|
|
2542
|
+
return !el._equals || !el._equals(el._pendingValue, el._overrideValue);
|
|
2543
|
+
return true;
|
|
2544
|
+
}
|
|
2545
|
+
return newQuestionInFlight(comp);
|
|
2386
2546
|
}
|
|
2387
2547
|
function syncCompanions(el, value) {
|
|
2388
2548
|
if (el._pendingSignal) updatePendingSignal(el);
|
|
@@ -2399,6 +2559,19 @@ function updateChildCompanions(el) {
|
|
|
2399
2559
|
if (child._pendingSignal || child._latestValueComputed) updatePendingSignal(child);
|
|
2400
2560
|
}
|
|
2401
2561
|
}
|
|
2562
|
+
function repollDownstreamVerdicts(el) {
|
|
2563
|
+
const visited = new Set();
|
|
2564
|
+
const visit = node => {
|
|
2565
|
+
if (visited.has(node)) return;
|
|
2566
|
+
visited.add(node);
|
|
2567
|
+
if (node._pendingSignal || node._latestValueComputed) updatePendingSignal(node);
|
|
2568
|
+
for (let s = node._subs; s !== null; s = s._nextSub) visit(s._sub);
|
|
2569
|
+
for (let child = node._child ?? null; child !== null; child = child._nextChild) {
|
|
2570
|
+
visit(child);
|
|
2571
|
+
}
|
|
2572
|
+
};
|
|
2573
|
+
visit(el);
|
|
2574
|
+
}
|
|
2402
2575
|
function snapCompanionsToState(owner) {
|
|
2403
2576
|
const sig = owner._pendingSignal;
|
|
2404
2577
|
if (sig && (sig._overrideValue === undefined || sig._overrideValue === NOT_PENDING)) {
|
|
@@ -2486,8 +2659,9 @@ function isPending(fn) {
|
|
|
2486
2659
|
} catch (e) {
|
|
2487
2660
|
collectPending();
|
|
2488
2661
|
if (e instanceof NotReadyError) {
|
|
2489
|
-
|
|
2490
|
-
if (
|
|
2662
|
+
const uninitialized = !!(e.source?._statusFlags & STATUS_UNINITIALIZED);
|
|
2663
|
+
if (probe.found && !uninitialized) return true;
|
|
2664
|
+
if (context && uninitialized) throw e;
|
|
2491
2665
|
}
|
|
2492
2666
|
return probe.found;
|
|
2493
2667
|
} finally {
|
|
@@ -2532,6 +2706,10 @@ function refresh(target) {
|
|
|
2532
2706
|
typeof node._fn === "function" &&
|
|
2533
2707
|
!(node._flags & (REACTIVE_DISPOSED | REACTIVE_MANUAL_WRITE))
|
|
2534
2708
|
) {
|
|
2709
|
+
if (!(node._flags & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP))) {
|
|
2710
|
+
node._flags |= REACTIVE_REASK;
|
|
2711
|
+
armReaskClear();
|
|
2712
|
+
}
|
|
2535
2713
|
node._flags = (node._flags & ~REACTIVE_CHECK) | REACTIVE_DIRTY;
|
|
2536
2714
|
insertIntoHeap(node, node._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
|
|
2537
2715
|
schedule();
|
|
@@ -2632,8 +2810,7 @@ function notifyEffectStatus(status, error) {
|
|
|
2632
2810
|
function runEffect(node) {
|
|
2633
2811
|
if (!node._modified || node._flags & REACTIVE_DISPOSED) return;
|
|
2634
2812
|
if (node._statusFlags & STATUS_ERROR && node._type === EFFECT_USER) {
|
|
2635
|
-
const err =
|
|
2636
|
-
node._error instanceof StatusError ? (node._error.cause ?? node._error) : node._error;
|
|
2813
|
+
const err = unwrapStatusError(node._error);
|
|
2637
2814
|
node._prevValue = node._value;
|
|
2638
2815
|
node._modified = false;
|
|
2639
2816
|
try {
|
|
@@ -2739,6 +2916,9 @@ function trackedEffect(fn, options) {
|
|
|
2739
2916
|
console.warn(message);
|
|
2740
2917
|
}
|
|
2741
2918
|
}
|
|
2919
|
+
const ACTION_CALLED_IN_OWNED_SCOPE_MESSAGE =
|
|
2920
|
+
"[ACTION_CALLED_IN_OWNED_SCOPE] Calling an action inside an owned scope (component, computation) is not allowed. " +
|
|
2921
|
+
"Call it from an event handler or another imperative scope.";
|
|
2742
2922
|
function restoreTransition(transition, fn) {
|
|
2743
2923
|
globalQueue.initTransition(transition);
|
|
2744
2924
|
const result = fn();
|
|
@@ -2746,28 +2926,42 @@ function restoreTransition(transition, fn) {
|
|
|
2746
2926
|
return result;
|
|
2747
2927
|
}
|
|
2748
2928
|
function action(genFn) {
|
|
2749
|
-
return (...args) =>
|
|
2750
|
-
|
|
2929
|
+
return (...args) => {
|
|
2930
|
+
{
|
|
2931
|
+
const owner = getOwner();
|
|
2932
|
+
if (owner && !(owner._config & CONFIG_CHILDREN_FORBIDDEN)) {
|
|
2933
|
+
emitDiagnostic({
|
|
2934
|
+
code: "ACTION_CALLED_IN_OWNED_SCOPE",
|
|
2935
|
+
kind: "write",
|
|
2936
|
+
severity: "error",
|
|
2937
|
+
message: ACTION_CALLED_IN_OWNED_SCOPE_MESSAGE,
|
|
2938
|
+
ownerId: owner.id,
|
|
2939
|
+
ownerName: owner._name
|
|
2940
|
+
});
|
|
2941
|
+
throw new Error(ACTION_CALLED_IN_OWNED_SCOPE_MESSAGE);
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2944
|
+
return new Promise((resolve, reject) => {
|
|
2751
2945
|
const it = genFn(...args);
|
|
2752
2946
|
globalQueue.initTransition();
|
|
2753
2947
|
let ctx = activeTransition;
|
|
2754
2948
|
ctx._actions.push(it);
|
|
2755
|
-
const done = (v, e) => {
|
|
2949
|
+
const done = (v, e, failed = false) => {
|
|
2756
2950
|
ctx = currentTransition(ctx);
|
|
2757
2951
|
const i = ctx._actions.indexOf(it);
|
|
2758
2952
|
if (i >= 0) ctx._actions.splice(i, 1);
|
|
2759
2953
|
setActiveTransition(ctx);
|
|
2760
2954
|
schedule();
|
|
2761
|
-
|
|
2955
|
+
failed ? reject(e) : resolve(v);
|
|
2762
2956
|
};
|
|
2763
2957
|
const step = (v, err) => {
|
|
2764
2958
|
let r;
|
|
2765
2959
|
try {
|
|
2766
2960
|
r = err ? it.throw(v) : it.next(v);
|
|
2767
2961
|
} catch (e) {
|
|
2768
|
-
return done(undefined, e);
|
|
2962
|
+
return done(undefined, e, true);
|
|
2769
2963
|
}
|
|
2770
|
-
if (isThenable(r)) return void r.then(run, e => done(undefined, e));
|
|
2964
|
+
if (isThenable(r)) return void r.then(run, e => done(undefined, e, true));
|
|
2771
2965
|
run(r);
|
|
2772
2966
|
};
|
|
2773
2967
|
const run = r => {
|
|
@@ -2781,6 +2975,7 @@ function action(genFn) {
|
|
|
2781
2975
|
};
|
|
2782
2976
|
step();
|
|
2783
2977
|
});
|
|
2978
|
+
};
|
|
2784
2979
|
}
|
|
2785
2980
|
function onCleanup(fn) {
|
|
2786
2981
|
{
|
|
@@ -2859,11 +3054,17 @@ function createReaction(effectFn, options) {
|
|
|
2859
3054
|
let cl = undefined;
|
|
2860
3055
|
cleanup(() => cl?.());
|
|
2861
3056
|
const owner = getOwner();
|
|
3057
|
+
let arm;
|
|
2862
3058
|
return tracking => {
|
|
3059
|
+
if (arm) {
|
|
3060
|
+
dispose(arm);
|
|
3061
|
+
arm = undefined;
|
|
3062
|
+
}
|
|
2863
3063
|
runWithOwner(owner, () => {
|
|
2864
3064
|
effect(
|
|
2865
|
-
() => (tracking(), getOwner()),
|
|
3065
|
+
() => (tracking(), (arm = getOwner())),
|
|
2866
3066
|
node => {
|
|
3067
|
+
arm = undefined;
|
|
2867
3068
|
cl?.();
|
|
2868
3069
|
const cleanup = (effectFn.effect || effectFn)?.();
|
|
2869
3070
|
if (true && cleanup !== undefined && typeof cleanup !== "function") {
|
|
@@ -3406,7 +3607,8 @@ function createWriteTraps(isActive, onDraftWrite) {
|
|
|
3406
3607
|
const $TRACK = Symbol("STORE_TRACK"),
|
|
3407
3608
|
$TARGET = Symbol("STORE_TARGET"),
|
|
3408
3609
|
$PROXY = Symbol("STORE_PROXY"),
|
|
3409
|
-
$DELETED = Symbol("STORE_DELETED")
|
|
3610
|
+
$DELETED = Symbol("STORE_DELETED"),
|
|
3611
|
+
$AFFECTS = Symbol("STORE_AFFECTS");
|
|
3410
3612
|
const STORE_VALUE = "v",
|
|
3411
3613
|
STORE_OVERRIDE = "o",
|
|
3412
3614
|
STORE_OPTIMISTIC_OVERRIDE = "x",
|
|
@@ -3416,8 +3618,7 @@ const STORE_VALUE = "v",
|
|
|
3416
3618
|
STORE_WRAP = "w",
|
|
3417
3619
|
STORE_LOOKUP = "l",
|
|
3418
3620
|
STORE_FIREWALL = "f",
|
|
3419
|
-
STORE_OPTIMISTIC = "p"
|
|
3420
|
-
STORE_MASKED = "m";
|
|
3621
|
+
STORE_OPTIMISTIC = "p";
|
|
3421
3622
|
const STORE_SELF_PENDING = Symbol("STORE_SELF_PENDING");
|
|
3422
3623
|
function createStoreProxy(value, traps = storeTraps, extend) {
|
|
3423
3624
|
let newTarget;
|
|
@@ -3513,7 +3714,7 @@ function getNodes(target, type) {
|
|
|
3513
3714
|
if (!nodes) target[type] = nodes = Object.create(null);
|
|
3514
3715
|
return nodes;
|
|
3515
3716
|
}
|
|
3516
|
-
function getNode(nodes, property, value,
|
|
3717
|
+
function getNode(target, nodes, property, value, equals = isEqual, snapshotProps) {
|
|
3517
3718
|
if (nodes[property]) return nodes[property];
|
|
3518
3719
|
const s = signal(
|
|
3519
3720
|
value,
|
|
@@ -3525,12 +3726,13 @@ function getNode(nodes, property, value, firewall, equals = isEqual, optimistic,
|
|
|
3525
3726
|
if (
|
|
3526
3727
|
typeof property === "symbol" &&
|
|
3527
3728
|
property !== $TRACK &&
|
|
3729
|
+
property !== $AFFECTS &&
|
|
3528
3730
|
symbolKeyedRecords.has(nodes)
|
|
3529
3731
|
) {
|
|
3530
3732
|
const syms = Object.getOwnPropertySymbols(nodes);
|
|
3531
3733
|
let hasUserSymbol = false;
|
|
3532
3734
|
for (let i = 0, len = syms.length; i < len; i++) {
|
|
3533
|
-
if (syms[i] !== $TRACK) {
|
|
3735
|
+
if (syms[i] !== $TRACK && syms[i] !== $AFFECTS) {
|
|
3534
3736
|
hasUserSymbol = true;
|
|
3535
3737
|
break;
|
|
3536
3738
|
}
|
|
@@ -3540,9 +3742,9 @@ function getNode(nodes, property, value, firewall, equals = isEqual, optimistic,
|
|
|
3540
3742
|
}
|
|
3541
3743
|
}
|
|
3542
3744
|
},
|
|
3543
|
-
|
|
3745
|
+
target[STORE_FIREWALL]
|
|
3544
3746
|
);
|
|
3545
|
-
if (
|
|
3747
|
+
if (target[STORE_OPTIMISTIC]) {
|
|
3546
3748
|
s._overrideValue = NOT_PENDING;
|
|
3547
3749
|
}
|
|
3548
3750
|
if (snapshotProps && property in snapshotProps) {
|
|
@@ -3550,21 +3752,99 @@ function getNode(nodes, property, value, firewall, equals = isEqual, optimistic,
|
|
|
3550
3752
|
s._snapshotValue = sv === undefined ? NO_SNAPSHOT : sv;
|
|
3551
3753
|
snapshotSources?.add(s);
|
|
3552
3754
|
}
|
|
3553
|
-
if (typeof property === "symbol" && property !== $TRACK
|
|
3755
|
+
if (typeof property === "symbol" && property !== $TRACK && property !== $AFFECTS)
|
|
3756
|
+
symbolKeyedRecords.add(nodes);
|
|
3757
|
+
if (property !== $AFFECTS && affectsScopes.size) inheritAffectsMarks(s, target[STORE_VALUE]);
|
|
3554
3758
|
return (nodes[property] = s);
|
|
3555
3759
|
}
|
|
3760
|
+
function inheritAffectsMarks(node, raw) {
|
|
3761
|
+
for (const [carrier, entry] of affectsScopes) {
|
|
3762
|
+
if (carrier._affectsCount && entry.scope.has(raw)) {
|
|
3763
|
+
markAffects(node);
|
|
3764
|
+
entry.inherited.push(node);
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3767
|
+
}
|
|
3768
|
+
const affectsScopes = new Map();
|
|
3769
|
+
function walkAffectsScope(value, entry, found, lookup, visited) {
|
|
3770
|
+
if (!isWrappable(value)) return;
|
|
3771
|
+
const target = value[$TARGET] || (lookup ?? storeLookup).get(value)?.[$TARGET];
|
|
3772
|
+
const raw = target ? target[STORE_VALUE] : value;
|
|
3773
|
+
if (visited.has(raw)) return;
|
|
3774
|
+
visited.add(raw);
|
|
3775
|
+
entry.scope.add(raw);
|
|
3776
|
+
let override;
|
|
3777
|
+
if (target) {
|
|
3778
|
+
collectRecordNodes(target[STORE_NODE], found);
|
|
3779
|
+
collectRecordNodes(target[STORE_HAS], found);
|
|
3780
|
+
override = mergedOverlay(target);
|
|
3781
|
+
lookup = target[STORE_LOOKUP] ?? lookup;
|
|
3782
|
+
}
|
|
3783
|
+
if (Array.isArray(raw)) {
|
|
3784
|
+
const len = override?.length ?? raw.length;
|
|
3785
|
+
for (let i = 0; i < len; i++) {
|
|
3786
|
+
const v = override && i in override ? override[i] : raw[i];
|
|
3787
|
+
if (v !== $DELETED) walkAffectsScope(v, entry, found, lookup, visited);
|
|
3788
|
+
}
|
|
3789
|
+
} else {
|
|
3790
|
+
const keys = getKeys(raw, override);
|
|
3791
|
+
for (let i = 0, l = keys.length; i < l; i++) {
|
|
3792
|
+
const desc = getPropertyDescriptor(raw, override, keys[i]);
|
|
3793
|
+
if (!desc || desc.get) continue;
|
|
3794
|
+
walkAffectsScope(desc.value, entry, found, lookup, visited);
|
|
3795
|
+
}
|
|
3796
|
+
}
|
|
3797
|
+
}
|
|
3798
|
+
function collectRecordNodes(nodes, found) {
|
|
3799
|
+
if (!nodes) return;
|
|
3800
|
+
for (const key of Object.keys(nodes)) found.push(nodes[key]);
|
|
3801
|
+
const syms = Object.getOwnPropertySymbols(nodes);
|
|
3802
|
+
for (let i = 0, l = syms.length; i < l; i++) {
|
|
3803
|
+
if (syms[i] !== $AFFECTS) found.push(nodes[syms[i]]);
|
|
3804
|
+
}
|
|
3805
|
+
}
|
|
3806
|
+
function witnessAffectsMark(target) {
|
|
3807
|
+
const own = target[STORE_NODE]?.[$AFFECTS];
|
|
3808
|
+
if (own?._affectsCount) witnessAffects(own);
|
|
3809
|
+
if (affectsScopes.size) {
|
|
3810
|
+
const raw = target[STORE_VALUE];
|
|
3811
|
+
for (const [carrier, entry] of affectsScopes) {
|
|
3812
|
+
if (carrier !== own && carrier._affectsCount && entry.scope.has(raw)) witnessAffects(carrier);
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3816
|
+
function getStoreAffectsNodes(target, key) {
|
|
3817
|
+
const nodes = getNodes(target, STORE_NODE);
|
|
3818
|
+
if (key === undefined) {
|
|
3819
|
+
const carrier = getNode(target, nodes, $AFFECTS, undefined, false);
|
|
3820
|
+
GlobalQueue._releaseAffectsScope ||= node => {
|
|
3821
|
+
const entry = affectsScopes.get(node);
|
|
3822
|
+
if (!entry) return;
|
|
3823
|
+
affectsScopes.delete(node);
|
|
3824
|
+
for (let i = 0; i < entry.inherited.length; i++) releaseAffectsMark(entry.inherited[i]);
|
|
3825
|
+
};
|
|
3826
|
+
let entry = affectsScopes.get(carrier);
|
|
3827
|
+
if (!entry) affectsScopes.set(carrier, (entry = { scope: new Set(), inherited: [] }));
|
|
3828
|
+
const result = [carrier];
|
|
3829
|
+
walkAffectsScope(target[$PROXY], entry, result, target[STORE_LOOKUP], new Set());
|
|
3830
|
+
return result;
|
|
3831
|
+
}
|
|
3832
|
+
if (nodes[key]) return [nodes[key]];
|
|
3833
|
+
const layer = getOverlayLayer(target, key);
|
|
3834
|
+
const raw = layer ? layer[key] : target[STORE_VALUE][key];
|
|
3835
|
+
const prev = raw === $DELETED ? undefined : raw;
|
|
3836
|
+
return [upsertStoreNode(target, nodes, key, prev, target[STORE_SNAPSHOT_PROPS])];
|
|
3837
|
+
}
|
|
3556
3838
|
function trackSelf(target, symbol = $TRACK) {
|
|
3557
|
-
getObserver()
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
)
|
|
3567
|
-
);
|
|
3839
|
+
if (!getObserver()) return;
|
|
3840
|
+
read(getNode(target, getNodes(target, STORE_NODE), symbol, undefined, false));
|
|
3841
|
+
if (
|
|
3842
|
+
symbol === $TRACK &&
|
|
3843
|
+
!target[STORE_OVERRIDE] &&
|
|
3844
|
+
!target[STORE_OPTIMISTIC_OVERRIDE] &&
|
|
3845
|
+
target[STORE_VALUE][$TARGET]
|
|
3846
|
+
)
|
|
3847
|
+
target[STORE_VALUE][$TRACK];
|
|
3568
3848
|
}
|
|
3569
3849
|
function notifySelf(target) {
|
|
3570
3850
|
const node = target[STORE_NODE]?.[$TRACK];
|
|
@@ -3574,6 +3854,11 @@ function notifySelf(target) {
|
|
|
3574
3854
|
target[STORE_OPTIMISTIC] && !projectionWriteActive ? STORE_SELF_PENDING : undefined
|
|
3575
3855
|
);
|
|
3576
3856
|
}
|
|
3857
|
+
function mergedOverlay(target) {
|
|
3858
|
+
const override = target[STORE_OVERRIDE];
|
|
3859
|
+
const opt = target[STORE_OPTIMISTIC_OVERRIDE];
|
|
3860
|
+
return override && opt ? { ...override, ...opt } : (opt ?? override);
|
|
3861
|
+
}
|
|
3577
3862
|
function getKeys(source, override, enumerable = true) {
|
|
3578
3863
|
const baseKeys = source[$TARGET]
|
|
3579
3864
|
? untrack(() => (enumerable ? Object.keys(source) : Reflect.ownKeys(source)))
|
|
@@ -3602,17 +3887,6 @@ function getPropertyDescriptor(source, override, property) {
|
|
|
3602
3887
|
}
|
|
3603
3888
|
return Reflect.getOwnPropertyDescriptor(source, property);
|
|
3604
3889
|
}
|
|
3605
|
-
function maskStoreTarget(target, on) {
|
|
3606
|
-
const firewall = target[STORE_FIREWALL];
|
|
3607
|
-
if (!firewall) return;
|
|
3608
|
-
if (!!target[STORE_MASKED] === on) return;
|
|
3609
|
-
target[STORE_MASKED] = on;
|
|
3610
|
-
const count = (firewall._optimisticMask = (firewall._optimisticMask || 0) + (on ? 1 : -1));
|
|
3611
|
-
if ((on && count === 1) || (!on && count === 0)) {
|
|
3612
|
-
updatePendingSignal(firewall);
|
|
3613
|
-
updateChildCompanions(firewall);
|
|
3614
|
-
}
|
|
3615
|
-
}
|
|
3616
3890
|
function prepareStoreWrite(target, store, property) {
|
|
3617
3891
|
if (target[STORE_OPTIMISTIC]) {
|
|
3618
3892
|
const firewall = target[STORE_FIREWALL];
|
|
@@ -3642,21 +3916,12 @@ function prepareStoreWrite(target, store, property) {
|
|
|
3642
3916
|
function armOptimisticStoreWrite(target, store) {
|
|
3643
3917
|
if (target[STORE_OPTIMISTIC] && !projectionWriteActive) {
|
|
3644
3918
|
trackOptimisticStore(store);
|
|
3645
|
-
maskStoreTarget(target, true);
|
|
3646
3919
|
}
|
|
3647
3920
|
}
|
|
3648
3921
|
function upsertStoreNode(target, nodes, property, prev, snapshotProps) {
|
|
3649
3922
|
if (nodes[property]) return nodes[property];
|
|
3650
3923
|
const initial = isWrappable(prev) ? wrap(prev, target) : prev;
|
|
3651
|
-
const node = getNode(
|
|
3652
|
-
nodes,
|
|
3653
|
-
property,
|
|
3654
|
-
initial,
|
|
3655
|
-
target[STORE_FIREWALL],
|
|
3656
|
-
isEqual,
|
|
3657
|
-
target[STORE_OPTIMISTIC],
|
|
3658
|
-
snapshotProps
|
|
3659
|
-
);
|
|
3924
|
+
const node = getNode(target, nodes, property, initial, isEqual, snapshotProps);
|
|
3660
3925
|
registerTransientStoreNode(node);
|
|
3661
3926
|
return node;
|
|
3662
3927
|
}
|
|
@@ -3699,6 +3964,7 @@ const storeTraps = {
|
|
|
3699
3964
|
if (property === $TARGET) return target;
|
|
3700
3965
|
if (property === $PROXY) return receiver;
|
|
3701
3966
|
if (property === $REFRESH) return target[STORE_FIREWALL];
|
|
3967
|
+
if (pendingCheckActive) witnessAffectsMark(target);
|
|
3702
3968
|
if (property === $TRACK) {
|
|
3703
3969
|
trackSelf(target);
|
|
3704
3970
|
return receiver;
|
|
@@ -3720,7 +3986,7 @@ const storeTraps = {
|
|
|
3720
3986
|
!selfRead &&
|
|
3721
3987
|
!writeOnly(receiver)
|
|
3722
3988
|
) {
|
|
3723
|
-
return read(getNode(nodes, property, undefined
|
|
3989
|
+
return read(getNode(target, nodes, property, undefined));
|
|
3724
3990
|
}
|
|
3725
3991
|
const overlay = getOverlayLayer(target, property);
|
|
3726
3992
|
const overridden = !!overlay;
|
|
@@ -3768,12 +4034,11 @@ const storeTraps = {
|
|
|
3768
4034
|
} else if (getObserver() && !selfRead) {
|
|
3769
4035
|
return read(
|
|
3770
4036
|
getNode(
|
|
4037
|
+
target,
|
|
3771
4038
|
nodes,
|
|
3772
4039
|
property,
|
|
3773
4040
|
isWrappable(value) ? wrap(value, target) : value,
|
|
3774
|
-
target[STORE_FIREWALL],
|
|
3775
4041
|
isEqual,
|
|
3776
|
-
target[STORE_OPTIMISTIC],
|
|
3777
4042
|
target[STORE_SNAPSHOT_PROPS]
|
|
3778
4043
|
)
|
|
3779
4044
|
);
|
|
@@ -3797,15 +4062,14 @@ const storeTraps = {
|
|
|
3797
4062
|
},
|
|
3798
4063
|
has(target, property) {
|
|
3799
4064
|
if (property === $PROXY || property === $TRACK || property === "__proto__") return true;
|
|
4065
|
+
if (pendingCheckActive) witnessAffectsMark(target);
|
|
3800
4066
|
const hasLayer = getOverlayLayer(target, property);
|
|
3801
4067
|
const has = hasLayer ? hasLayer[property] !== $DELETED : property in target[STORE_VALUE];
|
|
3802
4068
|
if (writeOnly(target[$PROXY]) || getObserver() === target[STORE_FIREWALL]) return has;
|
|
3803
4069
|
const nodes = getNodes(target, STORE_HAS);
|
|
3804
4070
|
if (nodes[property]) return read(nodes[property]);
|
|
3805
4071
|
if (getObserver()) {
|
|
3806
|
-
return read(
|
|
3807
|
-
getNode(nodes, property, has, target[STORE_FIREWALL], isEqual, target[STORE_OPTIMISTIC])
|
|
3808
|
-
);
|
|
4072
|
+
return read(getNode(target, nodes, property, has));
|
|
3809
4073
|
}
|
|
3810
4074
|
return has;
|
|
3811
4075
|
},
|
|
@@ -3825,9 +4089,14 @@ const storeTraps = {
|
|
|
3825
4089
|
? prevLayer[property] !== $DELETED
|
|
3826
4090
|
: property in target[STORE_VALUE];
|
|
3827
4091
|
const value = unwrapStoreValue(rawValue);
|
|
4092
|
+
const index = typeof property === "string" ? Number(property) : -1;
|
|
3828
4093
|
const isArrayIndexWrite =
|
|
3829
|
-
Array.isArray(state) &&
|
|
3830
|
-
|
|
4094
|
+
Array.isArray(state) &&
|
|
4095
|
+
Number.isInteger(index) &&
|
|
4096
|
+
index >= 0 &&
|
|
4097
|
+
index < 4294967295 &&
|
|
4098
|
+
String(index) === property;
|
|
4099
|
+
const nextIndex = isArrayIndexWrite ? index + 1 : 0;
|
|
3831
4100
|
const len = isArrayIndexWrite && (getOverlayLayer(target, "length") ?? state).length;
|
|
3832
4101
|
const nextLength = isArrayIndexWrite && nextIndex > len ? nextIndex : undefined;
|
|
3833
4102
|
if (prev === value && nextLength === undefined) return true;
|
|
@@ -3930,6 +4199,7 @@ const storeTraps = {
|
|
|
3930
4199
|
return true;
|
|
3931
4200
|
},
|
|
3932
4201
|
ownKeys(target) {
|
|
4202
|
+
if (pendingCheckActive) witnessAffectsMark(target);
|
|
3933
4203
|
if (getObserver() !== target[STORE_FIREWALL]) trackSelf(target);
|
|
3934
4204
|
let keys = getKeys(target[STORE_VALUE], target[STORE_OVERRIDE], false);
|
|
3935
4205
|
if (target[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
@@ -4013,6 +4283,58 @@ function createStore(first, second, options) {
|
|
|
4013
4283
|
: fn => storeSetter(wrappedStore, fn)
|
|
4014
4284
|
];
|
|
4015
4285
|
}
|
|
4286
|
+
function affects(target, key) {
|
|
4287
|
+
if (arguments.length > 2) {
|
|
4288
|
+
const message =
|
|
4289
|
+
"[INVALID_AFFECTS_TARGET] affects() takes a single optional key — extra keys are " +
|
|
4290
|
+
"not a path. Mark each slot with its own affects(record, key) call, or pass the " +
|
|
4291
|
+
'nested record itself: affects(state.user, "name").';
|
|
4292
|
+
emitDiagnostic({
|
|
4293
|
+
code: "INVALID_AFFECTS_TARGET",
|
|
4294
|
+
kind: "write",
|
|
4295
|
+
severity: "error",
|
|
4296
|
+
message: message
|
|
4297
|
+
});
|
|
4298
|
+
throw new Error(message);
|
|
4299
|
+
}
|
|
4300
|
+
const storeTarget = target?.[$TARGET];
|
|
4301
|
+
if (storeTarget) {
|
|
4302
|
+
const nodes = getStoreAffectsNodes(storeTarget, key);
|
|
4303
|
+
for (let i = 0; i < nodes.length; i++) registerAffectsMark(nodes[i]);
|
|
4304
|
+
return;
|
|
4305
|
+
}
|
|
4306
|
+
const node = target?.[$REFRESH];
|
|
4307
|
+
if (node) {
|
|
4308
|
+
if (key !== undefined) {
|
|
4309
|
+
const message =
|
|
4310
|
+
"[INVALID_AFFECTS_TARGET] affects() keys are only valid on store targets. " +
|
|
4311
|
+
"An accessor is a single slot — pass it alone, or target the store record that owns the property.";
|
|
4312
|
+
emitDiagnostic({
|
|
4313
|
+
code: "INVALID_AFFECTS_TARGET",
|
|
4314
|
+
kind: "write",
|
|
4315
|
+
severity: "error",
|
|
4316
|
+
message: message,
|
|
4317
|
+
nodeName: node._name
|
|
4318
|
+
});
|
|
4319
|
+
throw new Error(message);
|
|
4320
|
+
}
|
|
4321
|
+
registerAffectsMark(node);
|
|
4322
|
+
return;
|
|
4323
|
+
}
|
|
4324
|
+
{
|
|
4325
|
+
const message =
|
|
4326
|
+
"[INVALID_AFFECTS_TARGET] affects() expects a Solid source accessor or a store node. " +
|
|
4327
|
+
"Pass the store proxy (optionally with a property key) or the original accessor, " +
|
|
4328
|
+
"not a wrapper function or an already-read value.";
|
|
4329
|
+
emitDiagnostic({
|
|
4330
|
+
code: "INVALID_AFFECTS_TARGET",
|
|
4331
|
+
kind: "write",
|
|
4332
|
+
severity: "error",
|
|
4333
|
+
message: message
|
|
4334
|
+
});
|
|
4335
|
+
throw new Error(message);
|
|
4336
|
+
}
|
|
4337
|
+
}
|
|
4016
4338
|
function createOptimisticStore(first, second, options) {
|
|
4017
4339
|
GlobalQueue._clearOptimisticStore ||= clearOptimisticStore;
|
|
4018
4340
|
const derived = typeof first === "function";
|
|
@@ -4023,15 +4345,12 @@ function createOptimisticStore(first, second, options) {
|
|
|
4023
4345
|
}
|
|
4024
4346
|
function clearOptimisticStore(store) {
|
|
4025
4347
|
const target = store[$TARGET];
|
|
4026
|
-
if (!target) return;
|
|
4027
|
-
maskStoreTarget(target, false);
|
|
4028
|
-
if (!target[STORE_OPTIMISTIC_OVERRIDE]) return;
|
|
4348
|
+
if (!target?.[STORE_OPTIMISTIC_OVERRIDE]) return;
|
|
4029
4349
|
clearOptimisticOverride(target);
|
|
4030
4350
|
}
|
|
4031
4351
|
function clearOptimisticOverride(target) {
|
|
4032
4352
|
const override = target[STORE_OPTIMISTIC_OVERRIDE];
|
|
4033
4353
|
if (!override) return;
|
|
4034
|
-
maskStoreTarget(target, false);
|
|
4035
4354
|
const nodes = target[STORE_NODE];
|
|
4036
4355
|
delete target[STORE_OPTIMISTIC_OVERRIDE];
|
|
4037
4356
|
const wasProjectionWriteActive = projectionWriteActive;
|
|
@@ -4198,18 +4517,16 @@ const storePath = Object.assign(
|
|
|
4198
4517
|
},
|
|
4199
4518
|
{ DELETE: DELETE }
|
|
4200
4519
|
);
|
|
4201
|
-
function mergedOverlay(target) {
|
|
4202
|
-
const override = target[STORE_OVERRIDE];
|
|
4203
|
-
const opt = target[STORE_OPTIMISTIC_OVERRIDE];
|
|
4204
|
-
return override && opt ? { ...override, ...opt } : (opt ?? override);
|
|
4205
|
-
}
|
|
4206
4520
|
function snapshotImpl(item, track, map, lookup) {
|
|
4207
4521
|
let target, isArray, override, result, unwrapped, v;
|
|
4208
4522
|
if (!isWrappable(item)) return item;
|
|
4209
4523
|
if (map && map.has(item)) return map.get(item);
|
|
4210
4524
|
if (!map) map = new Map();
|
|
4211
4525
|
if ((target = item[$TARGET] || lookup?.get(item)?.[$TARGET])) {
|
|
4212
|
-
if (track)
|
|
4526
|
+
if (track) {
|
|
4527
|
+
trackSelf(target, $TRACK);
|
|
4528
|
+
if (pendingCheckActive) witnessAffectsMark(target);
|
|
4529
|
+
}
|
|
4213
4530
|
override = mergedOverlay(target);
|
|
4214
4531
|
isArray = Array.isArray(target[STORE_VALUE]);
|
|
4215
4532
|
map.set(
|
|
@@ -4751,7 +5068,7 @@ class RevealController {
|
|
|
4751
5068
|
}
|
|
4752
5069
|
isMinimallyReady() {
|
|
4753
5070
|
const order = untrack(this._orderAccessor);
|
|
4754
|
-
if (order === "together") return this.
|
|
5071
|
+
if (order === "together") return this._forEachOwnedSlot(isSlotMinimallyReady);
|
|
4755
5072
|
if (order === "natural") {
|
|
4756
5073
|
let hasSlot = false;
|
|
4757
5074
|
let anyReady = false;
|
|
@@ -4875,9 +5192,6 @@ class CollectionQueue extends Queue {
|
|
|
4875
5192
|
this._sources.clear();
|
|
4876
5193
|
}
|
|
4877
5194
|
}
|
|
4878
|
-
if (this._collectionType & STATUS_PENDING && flags & STATUS_ERROR) {
|
|
4879
|
-
return super.notify(node, STATUS_ERROR, flags, error);
|
|
4880
|
-
}
|
|
4881
5195
|
if (this._collectionType & STATUS_PENDING && this._initialized)
|
|
4882
5196
|
return super.notify(node, type, flags, error);
|
|
4883
5197
|
if (flags & this._collectionType) {
|
|
@@ -4888,7 +5202,7 @@ class CollectionQueue extends Queue {
|
|
|
4888
5202
|
this._sources.add(source);
|
|
4889
5203
|
if (wasEmpty) setSignal(this._disabled, true);
|
|
4890
5204
|
if (this._collectionType & STATUS_ERROR) {
|
|
4891
|
-
setSignal(this._error, source._error
|
|
5205
|
+
setSignal(this._error, unwrapStatusError(source._error));
|
|
4892
5206
|
}
|
|
4893
5207
|
}
|
|
4894
5208
|
}
|
|
@@ -5081,6 +5395,7 @@ export {
|
|
|
5081
5395
|
NotReadyError,
|
|
5082
5396
|
SUPPORTS_PROXY,
|
|
5083
5397
|
action,
|
|
5398
|
+
affects,
|
|
5084
5399
|
clearSnapshots,
|
|
5085
5400
|
createContext,
|
|
5086
5401
|
createEffect,
|