@solidjs/signals 0.13.12 → 2.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -7
- package/dist/dev.js +590 -275
- package/dist/node.cjs +1549 -1320
- package/dist/prod.js +1217 -976
- package/dist/types/boundaries.d.ts +124 -3
- package/dist/types/core/action.d.ts +34 -0
- package/dist/types/core/constants.d.ts +24 -0
- package/dist/types/core/context.d.ts +10 -2
- package/dist/types/core/core.d.ts +108 -9
- package/dist/types/core/dev.d.ts +1 -1
- package/dist/types/core/effect.d.ts +3 -2
- package/dist/types/core/error.d.ts +24 -0
- package/dist/types/core/external.d.ts +19 -0
- package/dist/types/core/graph.d.ts +1 -0
- package/dist/types/core/owner.d.ts +93 -3
- package/dist/types/core/scheduler.d.ts +27 -2
- package/dist/types/core/types.d.ts +3 -6
- package/dist/types/index.d.ts +2 -2
- package/dist/types/map.d.ts +32 -3
- package/dist/types/signals.d.ts +338 -39
- package/dist/types/store/optimistic.d.ts +38 -12
- package/dist/types/store/projection.d.ts +55 -15
- package/dist/types/store/reconcile.d.ts +22 -0
- package/dist/types/store/store.d.ts +72 -15
- package/dist/types/store/storePath.d.ts +28 -0
- package/dist/types/store/utils.d.ts +78 -7
- package/dist/types-cjs/boundaries.d.cts +173 -0
- package/dist/types-cjs/core/action.d.cts +35 -0
- package/dist/types-cjs/core/async.d.cts +6 -0
- package/dist/types-cjs/core/constants.d.cts +49 -0
- package/dist/types-cjs/core/context.d.cts +36 -0
- package/dist/types-cjs/core/core.d.cts +153 -0
- package/dist/types-cjs/core/dev.d.cts +49 -0
- package/dist/types-cjs/core/effect.d.cts +31 -0
- package/dist/types-cjs/core/error.d.cts +38 -0
- package/dist/types-cjs/core/external.d.cts +45 -0
- package/dist/types-cjs/core/graph.d.cts +4 -0
- package/dist/types-cjs/core/heap.d.cts +14 -0
- package/dist/types-cjs/core/index.d.cts +12 -0
- package/dist/types-cjs/core/lanes.d.cts +54 -0
- package/dist/types-cjs/core/owner.d.cts +116 -0
- package/dist/types-cjs/core/scheduler.d.cts +106 -0
- package/dist/types-cjs/core/types.d.cts +83 -0
- package/dist/types-cjs/index.d.cts +9 -0
- package/dist/types-cjs/map.d.cts +53 -0
- package/dist/types-cjs/package.json +3 -0
- package/dist/types-cjs/signals.d.cts +491 -0
- package/dist/types-cjs/store/index.d.cts +9 -0
- package/dist/types-cjs/store/optimistic.d.cts +45 -0
- package/dist/types-cjs/store/projection.d.cts +66 -0
- package/dist/types-cjs/store/reconcile.d.cts +23 -0
- package/dist/types-cjs/store/store.d.cts +125 -0
- package/dist/types-cjs/store/storePath.d.cts +58 -0
- package/dist/types-cjs/store/utils.d.cts +114 -0
- package/package.json +32 -24
package/dist/dev.js
CHANGED
|
@@ -35,6 +35,12 @@ const REACTIVE_DISPOSED = 1 << 6;
|
|
|
35
35
|
const REACTIVE_OPTIMISTIC_DIRTY = 1 << 7;
|
|
36
36
|
const REACTIVE_SNAPSHOT_STALE = 1 << 8;
|
|
37
37
|
const REACTIVE_LAZY = 1 << 9;
|
|
38
|
+
const CONFIG_OWNED_WRITE = 1 << 0;
|
|
39
|
+
const CONFIG_NO_SNAPSHOT = 1 << 1;
|
|
40
|
+
const CONFIG_TRANSPARENT = 1 << 2;
|
|
41
|
+
const CONFIG_IN_SNAPSHOT_SCOPE = 1 << 3;
|
|
42
|
+
const CONFIG_CHILDREN_FORBIDDEN = 1 << 4;
|
|
43
|
+
const CONFIG_AUTO_DISPOSE = 1 << 5;
|
|
38
44
|
const STATUS_PENDING = 1 << 0;
|
|
39
45
|
const STATUS_ERROR = 1 << 1;
|
|
40
46
|
const STATUS_UNINITIALIZED = 1 << 2;
|
|
@@ -240,6 +246,23 @@ let inTrackedQueueCallback = false;
|
|
|
240
246
|
let _enforceLoadingBoundary = false;
|
|
241
247
|
let _hitUnhandledAsync = false;
|
|
242
248
|
let stashedOptimisticReads = null;
|
|
249
|
+
const transientStoreNodes = new Set();
|
|
250
|
+
function registerTransientStoreNode(node) {
|
|
251
|
+
transientStoreNodes.add(node);
|
|
252
|
+
}
|
|
253
|
+
function sweepTransientStoreNodes() {
|
|
254
|
+
if (transientStoreNodes.size === 0) return;
|
|
255
|
+
for (const node of transientStoreNodes) {
|
|
256
|
+
if (node._subs !== null) {
|
|
257
|
+
transientStoreNodes.delete(node);
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (node._pendingValue !== NOT_PENDING) continue;
|
|
261
|
+
if (node._overrideValue !== undefined && node._overrideValue !== NOT_PENDING) continue;
|
|
262
|
+
transientStoreNodes.delete(node);
|
|
263
|
+
node._unobserved?.();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
243
266
|
function resetUnhandledAsync() {
|
|
244
267
|
_hitUnhandledAsync = false;
|
|
245
268
|
}
|
|
@@ -292,6 +315,7 @@ function mergeTransitionState(target, outgoing) {
|
|
|
292
315
|
if (!targetReporters) target._asyncReporters.set(source, (targetReporters = new Set()));
|
|
293
316
|
for (const reporter of reporters) targetReporters.add(reporter);
|
|
294
317
|
}
|
|
318
|
+
for (const sub of outgoing._gatedSubs) target._gatedSubs.add(sub);
|
|
295
319
|
}
|
|
296
320
|
function resolveOptimisticNodes(nodes) {
|
|
297
321
|
for (let i = 0; i < nodes.length; i++) {
|
|
@@ -422,11 +446,15 @@ class GlobalQueue extends Queue {
|
|
|
422
446
|
scheduled = dirtyQueue._max >= dirtyQueue._min;
|
|
423
447
|
reassignPendingTransition(stashedTransition._pendingNodes);
|
|
424
448
|
activeTransition = null;
|
|
425
|
-
if (
|
|
449
|
+
if (
|
|
450
|
+
!stashedTransition._actions.length &&
|
|
451
|
+
!stashedTransition._asyncReporters.size &&
|
|
452
|
+
stashedTransition._optimisticNodes.length
|
|
453
|
+
) {
|
|
426
454
|
stashedOptimisticReads = new Set();
|
|
427
455
|
for (let i = 0; i < stashedTransition._optimisticNodes.length; i++) {
|
|
428
456
|
const node = stashedTransition._optimisticNodes[i];
|
|
429
|
-
if (node._fn || node.
|
|
457
|
+
if (node._fn || node._config & CONFIG_OWNED_WRITE) continue;
|
|
430
458
|
stashedOptimisticReads.add(node);
|
|
431
459
|
queueStashedOptimisticEffects(node);
|
|
432
460
|
}
|
|
@@ -492,7 +520,8 @@ class GlobalQueue extends Queue {
|
|
|
492
520
|
_optimisticStores: new Set(),
|
|
493
521
|
_actions: [],
|
|
494
522
|
_queueStash: { _queues: [[], []], _children: [] },
|
|
495
|
-
_done: false
|
|
523
|
+
_done: false,
|
|
524
|
+
_gatedSubs: new Set()
|
|
496
525
|
};
|
|
497
526
|
} else if (transition) {
|
|
498
527
|
const outgoing = activeTransition;
|
|
@@ -531,7 +560,7 @@ function insertSubs(node, optimistic = false) {
|
|
|
531
560
|
const sourceLane = node._optimisticLane || currentOptimisticLane;
|
|
532
561
|
const hasSnapshot = node._snapshotValue !== undefined;
|
|
533
562
|
for (let s = node._subs; s !== null; s = s._nextSub) {
|
|
534
|
-
if (hasSnapshot && s._sub.
|
|
563
|
+
if (hasSnapshot && s._sub._config & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
535
564
|
s._sub._flags |= REACTIVE_SNAPSHOT_STALE;
|
|
536
565
|
continue;
|
|
537
566
|
}
|
|
@@ -579,6 +608,22 @@ function finalizePureQueue(completingTransition = null, incomplete = false) {
|
|
|
579
608
|
resolveOptimisticNodes(
|
|
580
609
|
completingTransition ? completingTransition._optimisticNodes : globalQueue._optimisticNodes
|
|
581
610
|
);
|
|
611
|
+
if (completingTransition && completingTransition._gatedSubs.size) {
|
|
612
|
+
for (const sub of completingTransition._gatedSubs) {
|
|
613
|
+
if (sub._flags & REACTIVE_DISPOSED) continue;
|
|
614
|
+
if (sub._type === EFFECT_TRACKED) {
|
|
615
|
+
if (!sub._modified) {
|
|
616
|
+
sub._modified = true;
|
|
617
|
+
sub._queue.enqueue(EFFECT_USER, sub._run);
|
|
618
|
+
}
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
const queue = sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
|
|
622
|
+
if (queue._min > sub._height) queue._min = sub._height;
|
|
623
|
+
insertIntoHeap(sub, queue);
|
|
624
|
+
}
|
|
625
|
+
completingTransition._gatedSubs.clear();
|
|
626
|
+
}
|
|
582
627
|
const optimisticStores = completingTransition
|
|
583
628
|
? completingTransition._optimisticStores
|
|
584
629
|
: globalQueue._optimisticStores;
|
|
@@ -589,6 +634,7 @@ function finalizePureQueue(completingTransition = null, incomplete = false) {
|
|
|
589
634
|
optimisticStores.clear();
|
|
590
635
|
schedule();
|
|
591
636
|
}
|
|
637
|
+
sweepTransientStoreNodes();
|
|
592
638
|
cleanupCompletedLanes(completingTransition);
|
|
593
639
|
}
|
|
594
640
|
}
|
|
@@ -778,7 +824,8 @@ function unlinkSubs(link) {
|
|
|
778
824
|
dep._subs = nextSub;
|
|
779
825
|
if (nextSub === null) {
|
|
780
826
|
dep._unobserved?.();
|
|
781
|
-
|
|
827
|
+
const c = dep;
|
|
828
|
+
c._fn && c._config & CONFIG_AUTO_DISPOSE && !(c._flags & REACTIVE_ZOMBIE) && unobserved(c);
|
|
782
829
|
}
|
|
783
830
|
}
|
|
784
831
|
return nextDep;
|
|
@@ -790,6 +837,7 @@ function unobserved(el) {
|
|
|
790
837
|
dep = unlinkSubs(dep);
|
|
791
838
|
}
|
|
792
839
|
el._deps = null;
|
|
840
|
+
el._depsTail = null;
|
|
793
841
|
disposeChildren(el, true);
|
|
794
842
|
}
|
|
795
843
|
function link(dep, sub) {
|
|
@@ -894,7 +942,7 @@ function runDisposal(node, zombie) {
|
|
|
894
942
|
}
|
|
895
943
|
function childId(owner, consume) {
|
|
896
944
|
let counter = owner;
|
|
897
|
-
while (counter.
|
|
945
|
+
while (counter._config & CONFIG_TRANSPARENT && counter._parent) counter = counter._parent;
|
|
898
946
|
if (counter.id != null)
|
|
899
947
|
return formatId(counter.id, consume ? counter._childCount++ : counter._childCount);
|
|
900
948
|
throw new Error("Cannot get child id from owner without an id");
|
|
@@ -934,7 +982,7 @@ function createOwner(options) {
|
|
|
934
982
|
id:
|
|
935
983
|
options?.id ??
|
|
936
984
|
(transparent ? parent?.id : parent?.id != null ? getNextChildId(parent) : undefined),
|
|
937
|
-
|
|
985
|
+
_config: transparent ? CONFIG_TRANSPARENT : 0,
|
|
938
986
|
_root: true,
|
|
939
987
|
_parentComputed: parent?._root ? parent._parentComputed : parent,
|
|
940
988
|
_firstChild: null,
|
|
@@ -950,10 +998,16 @@ function createOwner(options) {
|
|
|
950
998
|
disposeChildren(owner, self);
|
|
951
999
|
}
|
|
952
1000
|
};
|
|
953
|
-
if (parent
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
1001
|
+
if (parent && parent._config & CONFIG_CHILDREN_FORBIDDEN) {
|
|
1002
|
+
emitDiagnostic({
|
|
1003
|
+
code: "PRIMITIVE_IN_FORBIDDEN_SCOPE",
|
|
1004
|
+
kind: "lifecycle",
|
|
1005
|
+
severity: "error",
|
|
1006
|
+
message: PRIMITIVE_IN_FORBIDDEN_SCOPE_MESSAGE,
|
|
1007
|
+
ownerId: parent.id,
|
|
1008
|
+
ownerName: parent._name
|
|
1009
|
+
});
|
|
1010
|
+
throw new Error(PRIMITIVE_IN_FORBIDDEN_SCOPE_MESSAGE);
|
|
957
1011
|
}
|
|
958
1012
|
if (parent) {
|
|
959
1013
|
const lastChild = parent._firstChild;
|
|
@@ -1081,6 +1135,7 @@ function handleAsync(el, result, setter) {
|
|
|
1081
1135
|
if (el._inFlight !== result) return;
|
|
1082
1136
|
if (el._flags & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
1083
1137
|
globalQueue.initTransition(resolveTransition(el));
|
|
1138
|
+
const wasUninitialized = !!(el._statusFlags & STATUS_UNINITIALIZED);
|
|
1084
1139
|
clearStatus(el);
|
|
1085
1140
|
const lane = resolveLane(el);
|
|
1086
1141
|
if (lane) lane._pendingAsync.delete(el);
|
|
@@ -1094,9 +1149,10 @@ function handleAsync(el, result, setter) {
|
|
|
1094
1149
|
}
|
|
1095
1150
|
el._time = clock;
|
|
1096
1151
|
} else if (lane) {
|
|
1152
|
+
const isEffect = el._type;
|
|
1097
1153
|
const prevValue = el._value;
|
|
1098
1154
|
const equals = el._equals;
|
|
1099
|
-
if (!equals || !equals(value, prevValue)) {
|
|
1155
|
+
if ((!isEffect && wasUninitialized) || !equals || !equals(value, prevValue)) {
|
|
1100
1156
|
el._value = value;
|
|
1101
1157
|
el._time = clock;
|
|
1102
1158
|
if (el._latestValueComputed) {
|
|
@@ -1278,6 +1334,8 @@ function enableExternalSource(config) {
|
|
|
1278
1334
|
}
|
|
1279
1335
|
GlobalQueue._update = recompute;
|
|
1280
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";
|
|
1281
1339
|
let tracking = false;
|
|
1282
1340
|
let stale = false;
|
|
1283
1341
|
let refreshing = false;
|
|
@@ -1316,7 +1374,7 @@ function releaseSubtree(owner) {
|
|
|
1316
1374
|
}
|
|
1317
1375
|
if (child._fn) {
|
|
1318
1376
|
const comp = child;
|
|
1319
|
-
comp.
|
|
1377
|
+
comp._config &= ~CONFIG_IN_SNAPSHOT_SCOPE;
|
|
1320
1378
|
if (comp._flags & REACTIVE_SNAPSHOT_STALE) {
|
|
1321
1379
|
comp._flags &= ~REACTIVE_SNAPSHOT_STALE;
|
|
1322
1380
|
comp._flags |= REACTIVE_DIRTY;
|
|
@@ -1356,9 +1414,10 @@ function recompute(el, create = false) {
|
|
|
1356
1414
|
clearSignals(el);
|
|
1357
1415
|
}
|
|
1358
1416
|
}
|
|
1359
|
-
|
|
1417
|
+
let isOptimisticDirty = !!(el._flags & REACTIVE_OPTIMISTIC_DIRTY);
|
|
1360
1418
|
const hasOverride = el._overrideValue !== undefined && el._overrideValue !== NOT_PENDING;
|
|
1361
1419
|
const wasPending = !!(el._statusFlags & STATUS_PENDING);
|
|
1420
|
+
const wasUninitialized = !!(el._statusFlags & STATUS_UNINITIALIZED);
|
|
1362
1421
|
const oldcontext = context;
|
|
1363
1422
|
context = el;
|
|
1364
1423
|
el._depsTail = null;
|
|
@@ -1377,9 +1436,25 @@ function recompute(el, create = false) {
|
|
|
1377
1436
|
if (isOptimisticDirty) {
|
|
1378
1437
|
const lane = resolveLane(el);
|
|
1379
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
|
+
}
|
|
1380
1453
|
}
|
|
1381
1454
|
try {
|
|
1382
|
-
|
|
1455
|
+
const prevInFlight = el._inFlight;
|
|
1456
|
+
const fnResult = el._fn(value);
|
|
1457
|
+
value = el._inFlight !== prevInFlight ? fnResult : handleAsync(el, fnResult);
|
|
1383
1458
|
clearStatus(el, create);
|
|
1384
1459
|
const resolvedLane = resolveLane(el);
|
|
1385
1460
|
if (resolvedLane) {
|
|
@@ -1424,7 +1499,8 @@ function recompute(el, create = false) {
|
|
|
1424
1499
|
: el._pendingValue === NOT_PENDING
|
|
1425
1500
|
? el._value
|
|
1426
1501
|
: el._pendingValue;
|
|
1427
|
-
const valueChanged =
|
|
1502
|
+
const valueChanged =
|
|
1503
|
+
(!isEffect && wasUninitialized) || !el._equals || !el._equals(compareValue, value);
|
|
1428
1504
|
if (valueChanged) {
|
|
1429
1505
|
const prevVisible = hasOverride ? el._overrideValue : undefined;
|
|
1430
1506
|
if (create || (isEffect && activeTransition !== el._transition) || isOptimisticDirty) {
|
|
@@ -1477,22 +1553,25 @@ function updateIfNecessary(el) {
|
|
|
1477
1553
|
}
|
|
1478
1554
|
el._flags = el._flags & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
1479
1555
|
}
|
|
1480
|
-
function computed(fn,
|
|
1556
|
+
function computed(fn, options) {
|
|
1481
1557
|
const transparent = options?.transparent ?? false;
|
|
1482
1558
|
const self = {
|
|
1483
1559
|
id:
|
|
1484
1560
|
options?.id ??
|
|
1485
1561
|
(transparent ? context?.id : context?.id != null ? getNextChildId(context) : undefined),
|
|
1486
|
-
|
|
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),
|
|
1487
1567
|
_equals: options?.equals != null ? options.equals : isEqual,
|
|
1488
|
-
_pureWrite: !!options?.pureWrite,
|
|
1489
1568
|
_unobserved: options?.unobserved,
|
|
1490
1569
|
_disposal: null,
|
|
1491
1570
|
_queue: context?._queue ?? globalQueue,
|
|
1492
1571
|
_context: context?._context ?? defaultContext,
|
|
1493
1572
|
_childCount: 0,
|
|
1494
1573
|
_fn: fn,
|
|
1495
|
-
_value:
|
|
1574
|
+
_value: undefined,
|
|
1496
1575
|
_height: 0,
|
|
1497
1576
|
_child: null,
|
|
1498
1577
|
_nextHeap: undefined,
|
|
@@ -1516,10 +1595,16 @@ function computed(fn, initialValue, options) {
|
|
|
1516
1595
|
self._name = options?.name ?? "computed";
|
|
1517
1596
|
self._prevHeap = self;
|
|
1518
1597
|
const parent = context?._root ? context._parentComputed : context;
|
|
1519
|
-
if (context
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
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);
|
|
1523
1608
|
}
|
|
1524
1609
|
if (context) {
|
|
1525
1610
|
const lastChild = context._firstChild;
|
|
@@ -1532,9 +1617,8 @@ function computed(fn, initialValue, options) {
|
|
|
1532
1617
|
}
|
|
1533
1618
|
DEV$1.hooks.onOwner?.(self);
|
|
1534
1619
|
if (parent) self._height = parent._height + 1;
|
|
1535
|
-
if (snapshotCaptureActive && ownerInSnapshotScope(context)) self._inSnapshotScope = true;
|
|
1536
1620
|
if (externalSourceConfig) {
|
|
1537
|
-
const bridgeSignal = signal(undefined, { equals: false,
|
|
1621
|
+
const bridgeSignal = signal(undefined, { equals: false, ownedWrite: true });
|
|
1538
1622
|
const source = externalSourceConfig.factory(self._fn, () => {
|
|
1539
1623
|
setSignal(bridgeSignal, undefined);
|
|
1540
1624
|
});
|
|
@@ -1556,8 +1640,9 @@ function computed(fn, initialValue, options) {
|
|
|
1556
1640
|
function signal(v, options, firewall = null) {
|
|
1557
1641
|
const s = {
|
|
1558
1642
|
_equals: options?.equals != null ? options.equals : isEqual,
|
|
1559
|
-
|
|
1560
|
-
|
|
1643
|
+
_config:
|
|
1644
|
+
(options?.ownedWrite ? CONFIG_OWNED_WRITE : 0) |
|
|
1645
|
+
(options?._noSnapshot ? CONFIG_NO_SNAPSHOT : 0),
|
|
1561
1646
|
_unobserved: options?.unobserved,
|
|
1562
1647
|
_value: v,
|
|
1563
1648
|
_subs: null,
|
|
@@ -1574,7 +1659,7 @@ function signal(v, options, firewall = null) {
|
|
|
1574
1659
|
firewall && (firewall._child = s);
|
|
1575
1660
|
if (
|
|
1576
1661
|
snapshotCaptureActive &&
|
|
1577
|
-
!s.
|
|
1662
|
+
!(s._config & CONFIG_NO_SNAPSHOT) &&
|
|
1578
1663
|
!((firewall?._statusFlags ?? 0) & STATUS_PENDING)
|
|
1579
1664
|
) {
|
|
1580
1665
|
s._snapshotValue = v === undefined ? NO_SNAPSHOT : v;
|
|
@@ -1587,8 +1672,8 @@ function optimisticSignal(v, options) {
|
|
|
1587
1672
|
s._overrideValue = NOT_PENDING;
|
|
1588
1673
|
return s;
|
|
1589
1674
|
}
|
|
1590
|
-
function optimisticComputed(fn,
|
|
1591
|
-
const c = computed(fn,
|
|
1675
|
+
function optimisticComputed(fn, options) {
|
|
1676
|
+
const c = computed(fn, options);
|
|
1592
1677
|
c._overrideValue = NOT_PENDING;
|
|
1593
1678
|
return c;
|
|
1594
1679
|
}
|
|
@@ -1668,15 +1753,21 @@ function read(el) {
|
|
|
1668
1753
|
}
|
|
1669
1754
|
let c = context;
|
|
1670
1755
|
if (c?._root) c = c._parentComputed;
|
|
1671
|
-
|
|
1672
|
-
if (
|
|
1673
|
-
|
|
1674
|
-
|
|
1756
|
+
const computed = el;
|
|
1757
|
+
if (typeof computed._fn === "function") {
|
|
1758
|
+
const comp = el;
|
|
1759
|
+
if (refreshing && !(comp._flags & REACTIVE_DISPOSED)) recompute(comp);
|
|
1760
|
+
if (comp._flags & REACTIVE_LAZY) {
|
|
1761
|
+
comp._flags &= ~REACTIVE_LAZY;
|
|
1762
|
+
recompute(comp, true);
|
|
1763
|
+
} else if (comp._flags & REACTIVE_DISPOSED) {
|
|
1764
|
+
recompute(comp, true);
|
|
1765
|
+
}
|
|
1675
1766
|
}
|
|
1676
1767
|
const owner = el._firewall || el;
|
|
1677
1768
|
if (strictRead && owner._statusFlags & STATUS_PENDING) {
|
|
1678
1769
|
const message =
|
|
1679
|
-
`Reading a pending async value directly in ${strictRead}. ` +
|
|
1770
|
+
`[PENDING_ASYNC_UNTRACKED_READ] Reading a pending async value directly in ${strictRead}. ` +
|
|
1680
1771
|
`Async values must be read within a tracking scope (JSX, a memo, or an effect's compute function).`;
|
|
1681
1772
|
emitDiagnostic({
|
|
1682
1773
|
code: "PENDING_ASYNC_UNTRACKED_READ",
|
|
@@ -1691,7 +1782,6 @@ function read(el) {
|
|
|
1691
1782
|
throw new Error(message);
|
|
1692
1783
|
}
|
|
1693
1784
|
if (c && tracking) {
|
|
1694
|
-
if (el._fn && el._flags & REACTIVE_DISPOSED) recompute(el);
|
|
1695
1785
|
link(el, c);
|
|
1696
1786
|
if (owner._fn) {
|
|
1697
1787
|
const isZombie = el._flags & REACTIVE_ZOMBIE;
|
|
@@ -1708,9 +1798,9 @@ function read(el) {
|
|
|
1708
1798
|
}
|
|
1709
1799
|
if (owner._statusFlags & STATUS_PENDING) {
|
|
1710
1800
|
if (c && !(stale && owner._transition && activeTransition !== owner._transition)) {
|
|
1711
|
-
if (c
|
|
1801
|
+
if (c && c._config & CONFIG_CHILDREN_FORBIDDEN) {
|
|
1712
1802
|
const message =
|
|
1713
|
-
"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. " +
|
|
1714
1804
|
"Use createEffect instead which supports async-aware reactivity.";
|
|
1715
1805
|
emitDiagnostic({
|
|
1716
1806
|
code: "PENDING_ASYNC_FORBIDDEN_SCOPE",
|
|
@@ -1747,7 +1837,7 @@ function read(el) {
|
|
|
1747
1837
|
return read(el);
|
|
1748
1838
|
} else throw el._error;
|
|
1749
1839
|
}
|
|
1750
|
-
if (snapshotCaptureActive && c && c.
|
|
1840
|
+
if (snapshotCaptureActive && c && c._config & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
1751
1841
|
const sv = el._snapshotValue;
|
|
1752
1842
|
if (sv !== undefined) {
|
|
1753
1843
|
const snapshot = sv === NO_SNAPSHOT ? undefined : sv;
|
|
@@ -1758,7 +1848,7 @@ function read(el) {
|
|
|
1758
1848
|
}
|
|
1759
1849
|
if (strictRead) {
|
|
1760
1850
|
const message =
|
|
1761
|
-
`Reactive value read directly in ${strictRead} will not update. ` +
|
|
1851
|
+
`[STRICT_READ_UNTRACKED] Reactive value read directly in ${strictRead} will not update. ` +
|
|
1762
1852
|
`Move it into a tracking scope (JSX, a memo, or an effect's compute function).`;
|
|
1763
1853
|
emitDiagnostic({
|
|
1764
1854
|
code: "STRICT_READ_UNTRACKED",
|
|
@@ -1776,7 +1866,20 @@ function read(el) {
|
|
|
1776
1866
|
if (c && stale && shouldReadStashedOptimisticValue(el)) return el._value;
|
|
1777
1867
|
return el._overrideValue;
|
|
1778
1868
|
}
|
|
1779
|
-
|
|
1869
|
+
if (
|
|
1870
|
+
activeTransition !== null &&
|
|
1871
|
+
currentOptimisticLane !== null &&
|
|
1872
|
+
!latestReadActive &&
|
|
1873
|
+
el._pendingValue !== NOT_PENDING &&
|
|
1874
|
+
owner === el &&
|
|
1875
|
+
!el._fn &&
|
|
1876
|
+
c
|
|
1877
|
+
) {
|
|
1878
|
+
activeTransition._gatedSubs.add(c);
|
|
1879
|
+
return el._value;
|
|
1880
|
+
}
|
|
1881
|
+
const value =
|
|
1882
|
+
!c ||
|
|
1780
1883
|
(currentOptimisticLane !== null &&
|
|
1781
1884
|
(el._overrideValue !== undefined ||
|
|
1782
1885
|
el._optimisticLane ||
|
|
@@ -1784,14 +1887,30 @@ function read(el) {
|
|
|
1784
1887
|
!!(owner._statusFlags & STATUS_PENDING))) ||
|
|
1785
1888
|
el._pendingValue === NOT_PENDING ||
|
|
1786
1889
|
(stale && el._transition && activeTransition !== el._transition)
|
|
1787
|
-
|
|
1788
|
-
|
|
1890
|
+
? el._value
|
|
1891
|
+
: el._pendingValue;
|
|
1892
|
+
if (
|
|
1893
|
+
!c &&
|
|
1894
|
+
owner === el &&
|
|
1895
|
+
typeof computed._fn === "function" &&
|
|
1896
|
+
el._config & CONFIG_AUTO_DISPOSE &&
|
|
1897
|
+
!(owner._statusFlags & STATUS_PENDING) &&
|
|
1898
|
+
!el._subs
|
|
1899
|
+
) {
|
|
1900
|
+
unobserved(el);
|
|
1901
|
+
}
|
|
1902
|
+
return value;
|
|
1789
1903
|
}
|
|
1790
1904
|
function setSignal(el, v) {
|
|
1791
|
-
if (
|
|
1905
|
+
if (
|
|
1906
|
+
!(el._config & CONFIG_OWNED_WRITE) &&
|
|
1907
|
+
!(context && context._config & CONFIG_CHILDREN_FORBIDDEN) &&
|
|
1908
|
+
context &&
|
|
1909
|
+
el._firewall !== context
|
|
1910
|
+
) {
|
|
1792
1911
|
const message =
|
|
1793
|
-
"Writing to a Signal inside an owned scope (component, computation) is not allowed. " +
|
|
1794
|
-
"Move the write outside or set the `
|
|
1912
|
+
"[SIGNAL_WRITE_IN_OWNED_SCOPE] Writing to a Signal inside an owned scope (component, computation) is not allowed. " +
|
|
1913
|
+
"Move the write outside or set the `ownedWrite` option if this is intentional.";
|
|
1795
1914
|
emitDiagnostic({
|
|
1796
1915
|
code: "SIGNAL_WRITE_IN_OWNED_SCOPE",
|
|
1797
1916
|
kind: "write",
|
|
@@ -1851,7 +1970,7 @@ function setSignal(el, v) {
|
|
|
1851
1970
|
function runWithOwner(owner, fn) {
|
|
1852
1971
|
if (owner && owner._flags & REACTIVE_DISPOSED) {
|
|
1853
1972
|
const message =
|
|
1854
|
-
"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.";
|
|
1855
1974
|
emitDiagnostic({
|
|
1856
1975
|
code: "RUN_WITH_DISPOSED_OWNER",
|
|
1857
1976
|
kind: "owner",
|
|
@@ -1875,7 +1994,7 @@ function runWithOwner(owner, fn) {
|
|
|
1875
1994
|
}
|
|
1876
1995
|
function getPendingSignal(el) {
|
|
1877
1996
|
if (!el._pendingSignal) {
|
|
1878
|
-
el._pendingSignal = optimisticSignal(false, {
|
|
1997
|
+
el._pendingSignal = optimisticSignal(false, { ownedWrite: true });
|
|
1879
1998
|
if (el._parentSource) {
|
|
1880
1999
|
el._pendingSignal._parentSource = el;
|
|
1881
2000
|
}
|
|
@@ -2018,26 +2137,24 @@ function hasContext(context, owner) {
|
|
|
2018
2137
|
function isUndefined(value) {
|
|
2019
2138
|
return typeof value === "undefined";
|
|
2020
2139
|
}
|
|
2021
|
-
function effect(compute, effect, error,
|
|
2140
|
+
function effect(compute, effect, error, options) {
|
|
2022
2141
|
let initialized = false;
|
|
2023
|
-
const
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
{
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
);
|
|
2036
|
-
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;
|
|
2037
2154
|
node._effectFn = effect;
|
|
2038
2155
|
node._errorFn = error;
|
|
2039
2156
|
node._cleanup = undefined;
|
|
2040
|
-
node._type =
|
|
2157
|
+
node._type = isUser ? EFFECT_USER : EFFECT_RENDER;
|
|
2041
2158
|
node._notifyStatus = (status, error) => {
|
|
2042
2159
|
const actualStatus = status !== undefined ? status : node._statusFlags;
|
|
2043
2160
|
const actualError = error !== undefined ? error : node._error;
|
|
@@ -2061,28 +2178,32 @@ function effect(compute, effect, error, initialValue, options) {
|
|
|
2061
2178
|
node._queue.notify(node, STATUS_PENDING | STATUS_ERROR, actualStatus, actualError);
|
|
2062
2179
|
if (_hitUnhandledAsync) {
|
|
2063
2180
|
resetUnhandledAsync();
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2181
|
+
if (!node._queue.notify(node, STATUS_ERROR, STATUS_ERROR)) {
|
|
2182
|
+
const message =
|
|
2183
|
+
"[ASYNC_OUTSIDE_LOADING_BOUNDARY] An async value was read outside a Loading boundary. The root mount will be deferred until all pending async settles.";
|
|
2184
|
+
emitDiagnostic({
|
|
2185
|
+
code: "ASYNC_OUTSIDE_LOADING_BOUNDARY",
|
|
2186
|
+
kind: "async",
|
|
2187
|
+
severity: "warn",
|
|
2188
|
+
message: message,
|
|
2189
|
+
ownerId: node.id,
|
|
2190
|
+
ownerName: node._name
|
|
2191
|
+
});
|
|
2192
|
+
console.warn(message);
|
|
2193
|
+
}
|
|
2074
2194
|
}
|
|
2075
2195
|
}
|
|
2076
2196
|
};
|
|
2077
2197
|
recompute(node, true);
|
|
2078
2198
|
!options?.defer &&
|
|
2079
|
-
(node._type === EFFECT_USER
|
|
2199
|
+
(node._type === EFFECT_USER || options?.schedule
|
|
2080
2200
|
? node._queue.enqueue(node._type, runEffect.bind(node))
|
|
2081
2201
|
: runEffect.call(node));
|
|
2082
2202
|
initialized = true;
|
|
2083
2203
|
cleanup(() => node._cleanup?.());
|
|
2084
2204
|
if (!node._parent) {
|
|
2085
|
-
const message =
|
|
2205
|
+
const message =
|
|
2206
|
+
"[NO_OWNER_EFFECT] Effects created outside a reactive context will never be disposed";
|
|
2086
2207
|
emitDiagnostic({
|
|
2087
2208
|
code: "NO_OWNER_EFFECT",
|
|
2088
2209
|
kind: "lifecycle",
|
|
@@ -2144,11 +2265,10 @@ function trackedEffect(fn, options) {
|
|
|
2144
2265
|
}
|
|
2145
2266
|
node._cleanup = cleanup;
|
|
2146
2267
|
},
|
|
2147
|
-
undefined,
|
|
2148
2268
|
{ ...options, lazy: true }
|
|
2149
2269
|
);
|
|
2150
2270
|
node._cleanup = undefined;
|
|
2151
|
-
node.
|
|
2271
|
+
node._config = (node._config & ~CONFIG_AUTO_DISPOSE) | CONFIG_CHILDREN_FORBIDDEN;
|
|
2152
2272
|
node._modified = true;
|
|
2153
2273
|
node._type = EFFECT_TRACKED;
|
|
2154
2274
|
node._notifyStatus = (status, error) => {
|
|
@@ -2163,7 +2283,8 @@ function trackedEffect(fn, options) {
|
|
|
2163
2283
|
node._queue.enqueue(EFFECT_USER, run);
|
|
2164
2284
|
cleanup(() => node._cleanup?.());
|
|
2165
2285
|
if (!node._parent) {
|
|
2166
|
-
const message =
|
|
2286
|
+
const message =
|
|
2287
|
+
"[NO_OWNER_EFFECT] Effects created outside a reactive context will never be disposed";
|
|
2167
2288
|
emitDiagnostic({
|
|
2168
2289
|
code: "NO_OWNER_EFFECT",
|
|
2169
2290
|
kind: "lifecycle",
|
|
@@ -2224,7 +2345,8 @@ function onCleanup(fn) {
|
|
|
2224
2345
|
{
|
|
2225
2346
|
const owner = getOwner();
|
|
2226
2347
|
if (!owner) {
|
|
2227
|
-
const message =
|
|
2348
|
+
const message =
|
|
2349
|
+
"[NO_OWNER_CLEANUP] onCleanup called outside a reactive context will never be run";
|
|
2228
2350
|
emitDiagnostic({
|
|
2229
2351
|
code: "NO_OWNER_CLEANUP",
|
|
2230
2352
|
kind: "lifecycle",
|
|
@@ -2232,9 +2354,9 @@ function onCleanup(fn) {
|
|
|
2232
2354
|
message: message
|
|
2233
2355
|
});
|
|
2234
2356
|
console.warn(message);
|
|
2235
|
-
} else if (owner.
|
|
2357
|
+
} else if (owner._config & CONFIG_CHILDREN_FORBIDDEN) {
|
|
2236
2358
|
const message =
|
|
2237
|
-
"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";
|
|
2238
2360
|
emitDiagnostic({
|
|
2239
2361
|
code: "CLEANUP_IN_FORBIDDEN_SCOPE",
|
|
2240
2362
|
kind: "lifecycle",
|
|
@@ -2249,35 +2371,44 @@ function onCleanup(fn) {
|
|
|
2249
2371
|
return cleanup(fn);
|
|
2250
2372
|
}
|
|
2251
2373
|
function accessor(node) {
|
|
2252
|
-
|
|
2253
|
-
fn.$r = true;
|
|
2254
|
-
return fn;
|
|
2374
|
+
return read.bind(null, node);
|
|
2255
2375
|
}
|
|
2256
|
-
function createSignal(first, second
|
|
2376
|
+
function createSignal(first, second) {
|
|
2257
2377
|
if (typeof first === "function") {
|
|
2258
|
-
const node = computed(first, second
|
|
2378
|
+
const node = computed(first, second);
|
|
2379
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
2259
2380
|
return [accessor(node), setSignal.bind(null, node)];
|
|
2260
2381
|
}
|
|
2261
2382
|
const node = signal(first, second);
|
|
2262
2383
|
registerGraph(node, getOwner());
|
|
2263
2384
|
return [accessor(node), setSignal.bind(null, node)];
|
|
2264
2385
|
}
|
|
2265
|
-
function createMemo(compute,
|
|
2266
|
-
|
|
2267
|
-
return accessor(node);
|
|
2386
|
+
function createMemo(compute, options) {
|
|
2387
|
+
return accessor(computed(compute, options));
|
|
2268
2388
|
}
|
|
2269
|
-
function createEffect(compute, effectFn,
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2389
|
+
function createEffect(compute, effectFn, options) {
|
|
2390
|
+
if (effectFn === undefined) {
|
|
2391
|
+
const message =
|
|
2392
|
+
"[MISSING_EFFECT_FN] createEffect requires both a compute function and an effect function. " +
|
|
2393
|
+
"Use `createEffect(() => signal(), value => doWork(value))`. " +
|
|
2394
|
+
"If you want a derived value, use `createMemo`. " +
|
|
2395
|
+
"If you want a one-shot side effect, just call the function directly.";
|
|
2396
|
+
emitDiagnostic({
|
|
2397
|
+
code: "MISSING_EFFECT_FN",
|
|
2398
|
+
kind: "lifecycle",
|
|
2399
|
+
severity: "error",
|
|
2400
|
+
message: message
|
|
2401
|
+
});
|
|
2402
|
+
throw new Error(message);
|
|
2403
|
+
}
|
|
2404
|
+
effect(compute, effectFn.effect || effectFn, effectFn.error, {
|
|
2405
|
+
user: true,
|
|
2278
2406
|
...{ ...options, name: options?.name ?? "effect" }
|
|
2279
2407
|
});
|
|
2280
2408
|
}
|
|
2409
|
+
function createRenderEffect(compute, effectFn, options) {
|
|
2410
|
+
effect(compute, effectFn, undefined, { ...options, name: options?.name ?? "effect" });
|
|
2411
|
+
}
|
|
2281
2412
|
function createTrackedEffect(compute, options) {
|
|
2282
2413
|
trackedEffect(compute, { ...options, name: options?.name ?? "trackedEffect" });
|
|
2283
2414
|
}
|
|
@@ -2301,8 +2432,11 @@ function createReaction(effectFn, options) {
|
|
|
2301
2432
|
dispose(node);
|
|
2302
2433
|
},
|
|
2303
2434
|
effectFn.error,
|
|
2304
|
-
|
|
2305
|
-
|
|
2435
|
+
{
|
|
2436
|
+
...(true ? { ...options, name: options?.name ?? "effect" } : options),
|
|
2437
|
+
user: true,
|
|
2438
|
+
defer: true
|
|
2439
|
+
}
|
|
2306
2440
|
);
|
|
2307
2441
|
});
|
|
2308
2442
|
};
|
|
@@ -2327,9 +2461,10 @@ function resolve(fn) {
|
|
|
2327
2461
|
});
|
|
2328
2462
|
});
|
|
2329
2463
|
}
|
|
2330
|
-
function createOptimistic(first, second
|
|
2464
|
+
function createOptimistic(first, second) {
|
|
2331
2465
|
if (typeof first === "function") {
|
|
2332
|
-
const node = optimisticComputed(first, second
|
|
2466
|
+
const node = optimisticComputed(first, second);
|
|
2467
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
2333
2468
|
return [accessor(node), setSignal.bind(null, node)];
|
|
2334
2469
|
}
|
|
2335
2470
|
const node = optimisticSignal(first, second);
|
|
@@ -2338,7 +2473,7 @@ function createOptimistic(first, second, third) {
|
|
|
2338
2473
|
}
|
|
2339
2474
|
function onSettled(callback) {
|
|
2340
2475
|
const owner = getOwner();
|
|
2341
|
-
owner && !owner.
|
|
2476
|
+
owner && !(owner._config & CONFIG_CHILDREN_FORBIDDEN)
|
|
2342
2477
|
? createTrackedEffect(() => untrack(callback), { name: "onSettled" })
|
|
2343
2478
|
: globalQueue.enqueue(EFFECT_USER, () => {
|
|
2344
2479
|
const cleanup = callback();
|
|
@@ -2495,7 +2630,7 @@ function reconcile(value, key) {
|
|
|
2495
2630
|
applyState(value, state, keyFn);
|
|
2496
2631
|
};
|
|
2497
2632
|
}
|
|
2498
|
-
function createProjectionInternal(fn,
|
|
2633
|
+
function createProjectionInternal(fn, seed, options) {
|
|
2499
2634
|
let node;
|
|
2500
2635
|
const wrappedMap = new WeakMap();
|
|
2501
2636
|
const wrapper = s => {
|
|
@@ -2515,31 +2650,39 @@ function createProjectionInternal(fn, initialValue = {}, options) {
|
|
|
2515
2650
|
wrappedMap.set(source, wrapped);
|
|
2516
2651
|
return wrapped;
|
|
2517
2652
|
};
|
|
2518
|
-
const wrappedStore = wrapProjection(
|
|
2519
|
-
node = computed(
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
storeSetter(draft, s => {
|
|
2528
|
-
result = fn(s);
|
|
2529
|
-
settled = true;
|
|
2530
|
-
const value = handleAsync(owner, result, value => {
|
|
2531
|
-
value !== s &&
|
|
2532
|
-
value !== undefined &&
|
|
2533
|
-
storeSetter(wrappedStore, reconcile(value, options?.key || "id"));
|
|
2534
|
-
});
|
|
2535
|
-
value !== s && value !== undefined && reconcile(value, options?.key || "id")(wrappedStore);
|
|
2536
|
-
});
|
|
2537
|
-
});
|
|
2538
|
-
node._preventAutoDisposal = true;
|
|
2653
|
+
const wrappedStore = wrapProjection(seed);
|
|
2654
|
+
node = computed(
|
|
2655
|
+
() => {
|
|
2656
|
+
if (!node) node = getOwner();
|
|
2657
|
+
runProjectionComputed(wrappedStore, fn, options?.key || "id");
|
|
2658
|
+
},
|
|
2659
|
+
options?.name ? { name: options.name } : undefined
|
|
2660
|
+
);
|
|
2661
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
2539
2662
|
return { store: wrappedStore, node: node };
|
|
2540
2663
|
}
|
|
2541
|
-
function createProjection(fn,
|
|
2542
|
-
return createProjectionInternal(fn,
|
|
2664
|
+
function createProjection(fn, seed, options) {
|
|
2665
|
+
return createProjectionInternal(fn, seed, options).store;
|
|
2666
|
+
}
|
|
2667
|
+
function runProjectionComputed(wrappedStore, fn, key, wrapCommit) {
|
|
2668
|
+
const owner = getOwner();
|
|
2669
|
+
let settled = false;
|
|
2670
|
+
let result;
|
|
2671
|
+
const draft = new Proxy(
|
|
2672
|
+
wrappedStore,
|
|
2673
|
+
createWriteTraps(() => !settled || owner._inFlight === result)
|
|
2674
|
+
);
|
|
2675
|
+
storeSetter(draft, s => {
|
|
2676
|
+
result = fn(s);
|
|
2677
|
+
settled = true;
|
|
2678
|
+
const commit = v => {
|
|
2679
|
+
if (v === s || v === undefined) return;
|
|
2680
|
+
const write = () => storeSetter(wrappedStore, reconcile(v, key));
|
|
2681
|
+
wrapCommit ? wrapCommit(write) : write();
|
|
2682
|
+
};
|
|
2683
|
+
commit(handleAsync(owner, result, commit));
|
|
2684
|
+
});
|
|
2685
|
+
return owner;
|
|
2543
2686
|
}
|
|
2544
2687
|
function createWriteTraps(isActive) {
|
|
2545
2688
|
const traps = {
|
|
@@ -2603,6 +2746,7 @@ const STORE_VALUE = "v",
|
|
|
2603
2746
|
STORE_OPTIMISTIC_OVERRIDE = "x",
|
|
2604
2747
|
STORE_NODE = "n",
|
|
2605
2748
|
STORE_HAS = "h",
|
|
2749
|
+
STORE_CUSTOM_PROTO = "c",
|
|
2606
2750
|
STORE_WRAP = "w",
|
|
2607
2751
|
STORE_LOOKUP = "l",
|
|
2608
2752
|
STORE_FIREWALL = "f",
|
|
@@ -2613,6 +2757,7 @@ function createStoreProxy(value, traps = storeTraps, extend) {
|
|
|
2613
2757
|
newTarget = [];
|
|
2614
2758
|
newTarget.v = value;
|
|
2615
2759
|
} else newTarget = { v: value };
|
|
2760
|
+
newTarget[STORE_CUSTOM_PROTO] = hasCustomPrototype(unwrapStoreValue(value));
|
|
2616
2761
|
extend && extend(newTarget);
|
|
2617
2762
|
return (newTarget[$PROXY] = new Proxy(newTarget, traps));
|
|
2618
2763
|
}
|
|
@@ -2638,6 +2783,23 @@ function setWriteOverride(value) {
|
|
|
2638
2783
|
function writeOnly(proxy) {
|
|
2639
2784
|
return writeOverride || !!Writing?.has(proxy);
|
|
2640
2785
|
}
|
|
2786
|
+
function unwrapStoreValue(value) {
|
|
2787
|
+
return value?.[$TARGET]?.[STORE_VALUE] ?? value;
|
|
2788
|
+
}
|
|
2789
|
+
function hasCustomPrototype(value) {
|
|
2790
|
+
if (Array.isArray(value)) return false;
|
|
2791
|
+
const proto = Object.getPrototypeOf(value);
|
|
2792
|
+
return proto !== null && proto !== Object.prototype;
|
|
2793
|
+
}
|
|
2794
|
+
function hasInheritedAccessor(source, property) {
|
|
2795
|
+
let current = Object.getPrototypeOf(source);
|
|
2796
|
+
while (current && current !== Object.prototype) {
|
|
2797
|
+
const desc = Reflect.getOwnPropertyDescriptor(current, property);
|
|
2798
|
+
if (desc) return !!desc.get;
|
|
2799
|
+
current = Object.getPrototypeOf(current);
|
|
2800
|
+
}
|
|
2801
|
+
return false;
|
|
2802
|
+
}
|
|
2641
2803
|
function getNodes(target, type) {
|
|
2642
2804
|
let nodes = target[type];
|
|
2643
2805
|
if (!nodes) target[type] = nodes = Object.create(null);
|
|
@@ -2650,7 +2812,7 @@ function getNode(nodes, property, value, firewall, equals = isEqual, optimistic,
|
|
|
2650
2812
|
{
|
|
2651
2813
|
equals: equals,
|
|
2652
2814
|
unobserved() {
|
|
2653
|
-
delete nodes[property];
|
|
2815
|
+
if (nodes[property] === s) delete nodes[property];
|
|
2654
2816
|
}
|
|
2655
2817
|
},
|
|
2656
2818
|
firewall
|
|
@@ -2690,12 +2852,87 @@ function getKeys(source, override, enumerable = true) {
|
|
|
2690
2852
|
return Array.from(keys);
|
|
2691
2853
|
}
|
|
2692
2854
|
function getPropertyDescriptor(source, override, property) {
|
|
2693
|
-
let value = source;
|
|
2694
2855
|
if (override && property in override) {
|
|
2695
|
-
if (
|
|
2696
|
-
|
|
2856
|
+
if (override[property] === $DELETED) return void 0;
|
|
2857
|
+
const overrideDesc = Reflect.getOwnPropertyDescriptor(override, property);
|
|
2858
|
+
if (overrideDesc?.get || overrideDesc?.set || !(property in source)) return overrideDesc;
|
|
2697
2859
|
}
|
|
2698
|
-
return Reflect.getOwnPropertyDescriptor(
|
|
2860
|
+
return Reflect.getOwnPropertyDescriptor(source, property);
|
|
2861
|
+
}
|
|
2862
|
+
function prepareStoreWrite(target, store, property) {
|
|
2863
|
+
if (target[STORE_OPTIMISTIC]) {
|
|
2864
|
+
const firewall = target[STORE_FIREWALL];
|
|
2865
|
+
if (firewall?._transition) {
|
|
2866
|
+
globalQueue.initTransition(firewall._transition);
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
const state = target[STORE_VALUE];
|
|
2870
|
+
const base = state[property];
|
|
2871
|
+
if (
|
|
2872
|
+
snapshotCaptureActive &&
|
|
2873
|
+
typeof property !== "symbol" &&
|
|
2874
|
+
!((target[STORE_FIREWALL]?._statusFlags ?? 0) & STATUS_PENDING)
|
|
2875
|
+
) {
|
|
2876
|
+
if (!target[STORE_SNAPSHOT_PROPS]) {
|
|
2877
|
+
target[STORE_SNAPSHOT_PROPS] = Object.create(null);
|
|
2878
|
+
snapshotSources?.add(target);
|
|
2879
|
+
}
|
|
2880
|
+
if (!(property in target[STORE_SNAPSHOT_PROPS])) {
|
|
2881
|
+
target[STORE_SNAPSHOT_PROPS][property] = base;
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
const useOptimistic = target[STORE_OPTIMISTIC] && !projectionWriteActive;
|
|
2885
|
+
const overrideKey = useOptimistic ? STORE_OPTIMISTIC_OVERRIDE : STORE_OVERRIDE;
|
|
2886
|
+
if (useOptimistic) trackOptimisticStore(store);
|
|
2887
|
+
return { base: base, overrideKey: overrideKey, state: state };
|
|
2888
|
+
}
|
|
2889
|
+
function upsertStoreNode(target, nodes, property, prev, snapshotProps) {
|
|
2890
|
+
if (nodes[property]) return nodes[property];
|
|
2891
|
+
const initial = isWrappable(prev) ? wrap(prev, target) : prev;
|
|
2892
|
+
const node = getNode(
|
|
2893
|
+
nodes,
|
|
2894
|
+
property,
|
|
2895
|
+
initial,
|
|
2896
|
+
target[STORE_FIREWALL],
|
|
2897
|
+
isEqual,
|
|
2898
|
+
target[STORE_OPTIMISTIC],
|
|
2899
|
+
snapshotProps
|
|
2900
|
+
);
|
|
2901
|
+
registerTransientStoreNode(node);
|
|
2902
|
+
return node;
|
|
2903
|
+
}
|
|
2904
|
+
function notifyStoreProperty(target, property, mode, value, prev, prevHas) {
|
|
2905
|
+
const skipUpsert = projectionWriteActive || target[STORE_OPTIMISTIC];
|
|
2906
|
+
const newHas = mode !== "delete";
|
|
2907
|
+
const existingHas = target[STORE_HAS]?.[property];
|
|
2908
|
+
if (existingHas) {
|
|
2909
|
+
setSignal(existingHas, newHas);
|
|
2910
|
+
} else if (!skipUpsert && mode !== "invalidate" && prevHas !== newHas) {
|
|
2911
|
+
const hasNode = upsertStoreNode(target, getNodes(target, STORE_HAS), property, prevHas);
|
|
2912
|
+
setSignal(hasNode, newHas);
|
|
2913
|
+
}
|
|
2914
|
+
const nodes = getNodes(target, STORE_NODE);
|
|
2915
|
+
if (mode === "set") {
|
|
2916
|
+
if (nodes[property]) {
|
|
2917
|
+
setSignal(nodes[property], () => (isWrappable(value) ? wrap(value, target) : value));
|
|
2918
|
+
} else if (!skipUpsert) {
|
|
2919
|
+
const node = upsertStoreNode(target, nodes, property, prev, target[STORE_SNAPSHOT_PROPS]);
|
|
2920
|
+
setSignal(node, () => (isWrappable(value) ? wrap(value, target) : value));
|
|
2921
|
+
}
|
|
2922
|
+
} else if (mode === "invalidate") {
|
|
2923
|
+
if (nodes[property]) {
|
|
2924
|
+
setSignal(nodes[property], {});
|
|
2925
|
+
delete nodes[property];
|
|
2926
|
+
}
|
|
2927
|
+
} else {
|
|
2928
|
+
if (nodes[property]) {
|
|
2929
|
+
setSignal(nodes[property], undefined);
|
|
2930
|
+
} else if (!skipUpsert) {
|
|
2931
|
+
const node = upsertStoreNode(target, nodes, property, prev, target[STORE_SNAPSHOT_PROPS]);
|
|
2932
|
+
setSignal(node, undefined);
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
nodes[$TRACK] && setSignal(nodes[$TRACK], undefined);
|
|
2699
2936
|
}
|
|
2700
2937
|
let Writing = null;
|
|
2701
2938
|
const storeTraps = {
|
|
@@ -2722,6 +2959,12 @@ const storeTraps = {
|
|
|
2722
2959
|
if (!tracked) {
|
|
2723
2960
|
const desc = Object.getOwnPropertyDescriptor(storeValue, property);
|
|
2724
2961
|
if (desc && desc.get) return desc.get.call(receiver);
|
|
2962
|
+
if (!desc && !overridden && target[STORE_CUSTOM_PROTO]) {
|
|
2963
|
+
const source = unwrapStoreValue(storeValue);
|
|
2964
|
+
if (hasInheritedAccessor(source, property)) {
|
|
2965
|
+
return Reflect.get(storeValue, property, receiver);
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2725
2968
|
}
|
|
2726
2969
|
if (writeOnly(receiver)) {
|
|
2727
2970
|
let value =
|
|
@@ -2768,7 +3011,7 @@ const storeTraps = {
|
|
|
2768
3011
|
}
|
|
2769
3012
|
if (strictRead && typeof property === "string") {
|
|
2770
3013
|
const message =
|
|
2771
|
-
`Reactive value read directly in ${strictRead} will not update. ` +
|
|
3014
|
+
`[STRICT_READ_UNTRACKED] Reactive value read directly in ${strictRead} will not update. ` +
|
|
2772
3015
|
`Move it into a tracking scope (JSX, a memo, or an effect's compute function).`;
|
|
2773
3016
|
emitDiagnostic({
|
|
2774
3017
|
code: "STRICT_READ_UNTRACKED",
|
|
@@ -2790,56 +3033,38 @@ const storeTraps = {
|
|
|
2790
3033
|
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
2791
3034
|
? target[STORE_OVERRIDE][property] !== $DELETED
|
|
2792
3035
|
: property in target[STORE_VALUE];
|
|
2793
|
-
if (
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
target[STORE_FIREWALL],
|
|
2801
|
-
isEqual,
|
|
2802
|
-
target[STORE_OPTIMISTIC]
|
|
2803
|
-
)
|
|
2804
|
-
);
|
|
3036
|
+
if (writeOnly(target[$PROXY])) return has;
|
|
3037
|
+
const nodes = getNodes(target, STORE_HAS);
|
|
3038
|
+
if (nodes[property]) return read(nodes[property]);
|
|
3039
|
+
if (getObserver()) {
|
|
3040
|
+
return read(
|
|
3041
|
+
getNode(nodes, property, has, target[STORE_FIREWALL], isEqual, target[STORE_OPTIMISTIC])
|
|
3042
|
+
);
|
|
2805
3043
|
}
|
|
2806
3044
|
return has;
|
|
2807
3045
|
},
|
|
2808
3046
|
set(target, property, rawValue) {
|
|
2809
3047
|
const store = target[$PROXY];
|
|
2810
3048
|
if (writeOnly(store)) {
|
|
2811
|
-
if (target[STORE_OPTIMISTIC]) {
|
|
2812
|
-
const firewall = target[STORE_FIREWALL];
|
|
2813
|
-
if (firewall?._transition) {
|
|
2814
|
-
globalQueue.initTransition(firewall._transition);
|
|
2815
|
-
}
|
|
2816
|
-
}
|
|
2817
3049
|
untrack(() => {
|
|
2818
|
-
const
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
!((target[STORE_FIREWALL]?._statusFlags ?? 0) & STATUS_PENDING)
|
|
2824
|
-
) {
|
|
2825
|
-
if (!target[STORE_SNAPSHOT_PROPS]) {
|
|
2826
|
-
target[STORE_SNAPSHOT_PROPS] = Object.create(null);
|
|
2827
|
-
snapshotSources?.add(target);
|
|
2828
|
-
}
|
|
2829
|
-
if (!(property in target[STORE_SNAPSHOT_PROPS])) {
|
|
2830
|
-
target[STORE_SNAPSHOT_PROPS][property] = base;
|
|
2831
|
-
}
|
|
2832
|
-
}
|
|
2833
|
-
const useOptimistic = target[STORE_OPTIMISTIC] && !projectionWriteActive;
|
|
2834
|
-
const overrideKey = useOptimistic ? STORE_OPTIMISTIC_OVERRIDE : STORE_OVERRIDE;
|
|
2835
|
-
if (useOptimistic) trackOptimisticStore(store);
|
|
3050
|
+
const {
|
|
3051
|
+
base: base,
|
|
3052
|
+
overrideKey: overrideKey,
|
|
3053
|
+
state: state
|
|
3054
|
+
} = prepareStoreWrite(target, store, property);
|
|
2836
3055
|
const prev =
|
|
2837
3056
|
target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]
|
|
2838
3057
|
? target[STORE_OPTIMISTIC_OVERRIDE][property]
|
|
2839
3058
|
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
2840
3059
|
? target[STORE_OVERRIDE][property]
|
|
2841
3060
|
: base;
|
|
2842
|
-
const
|
|
3061
|
+
const prevHas =
|
|
3062
|
+
target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]
|
|
3063
|
+
? target[STORE_OPTIMISTIC_OVERRIDE][property] !== $DELETED
|
|
3064
|
+
: target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
|
|
3065
|
+
? target[STORE_OVERRIDE][property] !== $DELETED
|
|
3066
|
+
: property in target[STORE_VALUE];
|
|
3067
|
+
const value = unwrapStoreValue(rawValue);
|
|
2843
3068
|
const isArrayIndexWrite = Array.isArray(state) && property !== "length";
|
|
2844
3069
|
const nextIndex = isArrayIndexWrite ? parseInt(property) + 1 : 0;
|
|
2845
3070
|
const len =
|
|
@@ -2858,21 +3083,53 @@ const storeTraps = {
|
|
|
2858
3083
|
override[property] = value;
|
|
2859
3084
|
if (nextLength !== undefined) override.length = nextLength;
|
|
2860
3085
|
}
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
3086
|
+
notifyStoreProperty(target, property, "set", value, prev, prevHas);
|
|
3087
|
+
if (Array.isArray(state) && property !== "length" && nextLength !== undefined) {
|
|
3088
|
+
const nodes = getNodes(target, STORE_NODE);
|
|
3089
|
+
if (nodes.length) {
|
|
3090
|
+
setSignal(nodes.length, nextLength);
|
|
3091
|
+
} else if (!projectionWriteActive && !target[STORE_OPTIMISTIC]) {
|
|
3092
|
+
const node = upsertStoreNode(
|
|
3093
|
+
target,
|
|
3094
|
+
nodes,
|
|
3095
|
+
"length",
|
|
3096
|
+
len,
|
|
3097
|
+
target[STORE_SNAPSHOT_PROPS]
|
|
3098
|
+
);
|
|
3099
|
+
setSignal(node, nextLength);
|
|
3100
|
+
}
|
|
2869
3101
|
}
|
|
2870
|
-
nodes[$TRACK] && setSignal(nodes[$TRACK], undefined);
|
|
2871
3102
|
if (true) DEV$1.hooks.onStoreNodeUpdate?.(target[$PROXY], property, value, prev);
|
|
2872
3103
|
});
|
|
2873
3104
|
}
|
|
2874
3105
|
return true;
|
|
2875
3106
|
},
|
|
3107
|
+
defineProperty(target, property, descriptor) {
|
|
3108
|
+
const store = target[$PROXY];
|
|
3109
|
+
if (writeOnly(store)) {
|
|
3110
|
+
untrack(() => {
|
|
3111
|
+
const { base: base, overrideKey: overrideKey } = prepareStoreWrite(target, store, property);
|
|
3112
|
+
const normalizedDescriptor =
|
|
3113
|
+
"value" in descriptor
|
|
3114
|
+
? { ...descriptor, value: unwrapStoreValue(descriptor.value) }
|
|
3115
|
+
: descriptor;
|
|
3116
|
+
Object.defineProperty(
|
|
3117
|
+
target[overrideKey] || (target[overrideKey] = Object.create(null)),
|
|
3118
|
+
property,
|
|
3119
|
+
normalizedDescriptor
|
|
3120
|
+
);
|
|
3121
|
+
notifyStoreProperty(target, property, "invalidate");
|
|
3122
|
+
if (true) {
|
|
3123
|
+
const next =
|
|
3124
|
+
"value" in normalizedDescriptor
|
|
3125
|
+
? normalizedDescriptor.value
|
|
3126
|
+
: normalizedDescriptor.get?.call(store);
|
|
3127
|
+
DEV$1.hooks.onStoreNodeUpdate?.(target[$PROXY], property, next, base);
|
|
3128
|
+
}
|
|
3129
|
+
});
|
|
3130
|
+
}
|
|
3131
|
+
return true;
|
|
3132
|
+
},
|
|
2876
3133
|
deleteProperty(target, property) {
|
|
2877
3134
|
const optDeleted = target[STORE_OPTIMISTIC_OVERRIDE]?.[property] === $DELETED;
|
|
2878
3135
|
const regDeleted = target[STORE_OVERRIDE]?.[property] === $DELETED;
|
|
@@ -2895,10 +3152,7 @@ const storeTraps = {
|
|
|
2895
3152
|
} else if (target[overrideKey] && property in target[overrideKey]) {
|
|
2896
3153
|
delete target[overrideKey][property];
|
|
2897
3154
|
} else return true;
|
|
2898
|
-
|
|
2899
|
-
const nodes = getNodes(target, STORE_NODE);
|
|
2900
|
-
nodes[property] && setSignal(nodes[property], undefined);
|
|
2901
|
-
nodes[$TRACK] && setSignal(nodes[$TRACK], undefined);
|
|
3155
|
+
notifyStoreProperty(target, property, "delete", undefined, prev, true);
|
|
2902
3156
|
});
|
|
2903
3157
|
}
|
|
2904
3158
|
return true;
|
|
@@ -2920,6 +3174,8 @@ const storeTraps = {
|
|
|
2920
3174
|
if (property === $PROXY) return { value: target[$PROXY], writable: true, configurable: true };
|
|
2921
3175
|
if (target[STORE_OPTIMISTIC_OVERRIDE] && property in target[STORE_OPTIMISTIC_OVERRIDE]) {
|
|
2922
3176
|
if (target[STORE_OPTIMISTIC_OVERRIDE][property] === $DELETED) return undefined;
|
|
3177
|
+
const optDesc = Reflect.getOwnPropertyDescriptor(target[STORE_OPTIMISTIC_OVERRIDE], property);
|
|
3178
|
+
if (optDesc?.get || optDesc?.set || !(property in target[STORE_VALUE])) return optDesc;
|
|
2923
3179
|
const baseDesc = getPropertyDescriptor(target[STORE_VALUE], target[STORE_OVERRIDE], property);
|
|
2924
3180
|
if (baseDesc) {
|
|
2925
3181
|
return { ...baseDesc, value: target[STORE_OPTIMISTIC_OVERRIDE][property] };
|
|
@@ -2969,7 +3225,7 @@ function createStore(first, second, options) {
|
|
|
2969
3225
|
function createOptimisticStore(first, second, options) {
|
|
2970
3226
|
GlobalQueue._clearOptimisticStore ||= clearOptimisticStore;
|
|
2971
3227
|
const derived = typeof first === "function";
|
|
2972
|
-
const initialValue =
|
|
3228
|
+
const initialValue = derived ? second : first;
|
|
2973
3229
|
const fn = derived ? first : undefined;
|
|
2974
3230
|
const { store: wrappedStore } = createOptimisticProjectionInternal(fn, initialValue, options);
|
|
2975
3231
|
return [wrappedStore, fn => storeSetter(wrappedStore, fn)];
|
|
@@ -3003,7 +3259,7 @@ function clearOptimisticStore(store) {
|
|
|
3003
3259
|
}
|
|
3004
3260
|
delete target[STORE_OPTIMISTIC_OVERRIDE];
|
|
3005
3261
|
}
|
|
3006
|
-
function createOptimisticProjectionInternal(fn, initialValue
|
|
3262
|
+
function createOptimisticProjectionInternal(fn, initialValue, options) {
|
|
3007
3263
|
let node;
|
|
3008
3264
|
const wrappedMap = new WeakMap();
|
|
3009
3265
|
const wrapper = s => {
|
|
@@ -3026,42 +3282,33 @@ function createOptimisticProjectionInternal(fn, initialValue = {}, options) {
|
|
|
3026
3282
|
};
|
|
3027
3283
|
const wrappedStore = wrapProjection(initialValue);
|
|
3028
3284
|
if (fn) {
|
|
3029
|
-
|
|
3030
|
-
const owner = getOwner();
|
|
3031
|
-
let settled = false;
|
|
3032
|
-
let result;
|
|
3033
|
-
const draft = new Proxy(
|
|
3034
|
-
wrappedStore,
|
|
3035
|
-
createWriteTraps(() => !settled || owner._inFlight === result)
|
|
3036
|
-
);
|
|
3285
|
+
const wrapCommit = write => {
|
|
3037
3286
|
setProjectionWriteActive(true);
|
|
3038
3287
|
try {
|
|
3039
|
-
|
|
3040
|
-
result = fn(s);
|
|
3041
|
-
settled = true;
|
|
3042
|
-
const value = handleAsync(owner, result, value => {
|
|
3043
|
-
setProjectionWriteActive(true);
|
|
3044
|
-
try {
|
|
3045
|
-
value !== s &&
|
|
3046
|
-
value !== undefined &&
|
|
3047
|
-
storeSetter(wrappedStore, reconcile(value, options?.key || "id"));
|
|
3048
|
-
} finally {
|
|
3049
|
-
setProjectionWriteActive(false);
|
|
3050
|
-
}
|
|
3051
|
-
});
|
|
3052
|
-
value !== s &&
|
|
3053
|
-
value !== undefined &&
|
|
3054
|
-
reconcile(value, options?.key || "id")(wrappedStore);
|
|
3055
|
-
});
|
|
3288
|
+
write();
|
|
3056
3289
|
} finally {
|
|
3057
3290
|
setProjectionWriteActive(false);
|
|
3058
3291
|
}
|
|
3059
|
-
}
|
|
3060
|
-
node
|
|
3292
|
+
};
|
|
3293
|
+
node = computed(
|
|
3294
|
+
() => {
|
|
3295
|
+
setProjectionWriteActive(true);
|
|
3296
|
+
try {
|
|
3297
|
+
runProjectionComputed(wrappedStore, fn, options?.key || "id", wrapCommit);
|
|
3298
|
+
} finally {
|
|
3299
|
+
setProjectionWriteActive(false);
|
|
3300
|
+
}
|
|
3301
|
+
},
|
|
3302
|
+
options?.name ? { name: options.name } : undefined
|
|
3303
|
+
);
|
|
3304
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
3061
3305
|
}
|
|
3062
3306
|
return { store: wrappedStore, node: node };
|
|
3063
3307
|
}
|
|
3064
3308
|
const DELETE = Symbol("STORE_PATH_DELETE");
|
|
3309
|
+
function isPrototypePollutionKey(part) {
|
|
3310
|
+
return part === "__proto__" || part === "constructor" || part === "prototype";
|
|
3311
|
+
}
|
|
3065
3312
|
function updatePath(current, args, i = 0) {
|
|
3066
3313
|
let part,
|
|
3067
3314
|
prev = current;
|
|
@@ -3069,6 +3316,7 @@ function updatePath(current, args, i = 0) {
|
|
|
3069
3316
|
part = args[i];
|
|
3070
3317
|
const partType = typeof part;
|
|
3071
3318
|
const isArray = Array.isArray(current);
|
|
3319
|
+
if (partType === "string" && isPrototypePollutionKey(part)) return;
|
|
3072
3320
|
if (Array.isArray(part)) {
|
|
3073
3321
|
for (let j = 0; j < part.length; j++) {
|
|
3074
3322
|
args[i] = part[j];
|
|
@@ -3113,7 +3361,13 @@ function updatePath(current, args, i = 0) {
|
|
|
3113
3361
|
) {
|
|
3114
3362
|
const target = part !== undefined ? current[part] : current;
|
|
3115
3363
|
const keys = Object.keys(value);
|
|
3116
|
-
for (let i = 0; i < keys.length; i++)
|
|
3364
|
+
for (let i = 0; i < keys.length; i++) {
|
|
3365
|
+
const key = keys[i];
|
|
3366
|
+
if (isPrototypePollutionKey(key)) continue;
|
|
3367
|
+
const desc = Object.getOwnPropertyDescriptor(value, key);
|
|
3368
|
+
if (desc.get || desc.set) Object.defineProperty(target, key, desc);
|
|
3369
|
+
else target[key] = desc.value;
|
|
3370
|
+
}
|
|
3117
3371
|
} else {
|
|
3118
3372
|
current[part] = value;
|
|
3119
3373
|
}
|
|
@@ -3329,23 +3583,25 @@ function mapArray(list, map, options) {
|
|
|
3329
3583
|
}
|
|
3330
3584
|
}
|
|
3331
3585
|
: map;
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3586
|
+
const data = {
|
|
3587
|
+
_owner: createOwner(),
|
|
3588
|
+
_len: 0,
|
|
3589
|
+
_list: list,
|
|
3590
|
+
_items: [],
|
|
3591
|
+
_map: wrappedMap,
|
|
3592
|
+
_mappings: [],
|
|
3593
|
+
_nodes: [],
|
|
3594
|
+
_key: keyFn,
|
|
3595
|
+
_rows: keyFn || options?.keyed === false ? [] : undefined,
|
|
3596
|
+
_indexes: indexes ? [] : undefined,
|
|
3597
|
+
_fallback: options?.fallback
|
|
3598
|
+
};
|
|
3599
|
+
const node = computed(updateKeyedMap.bind(data));
|
|
3600
|
+
data._owner._parentComputed = node;
|
|
3601
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
3602
|
+
return accessor(node);
|
|
3347
3603
|
}
|
|
3348
|
-
const pureOptions = {
|
|
3604
|
+
const pureOptions = { ownedWrite: true };
|
|
3349
3605
|
function updateKeyedMap() {
|
|
3350
3606
|
const newItems = this._list() || [],
|
|
3351
3607
|
newLen = newItems.length;
|
|
@@ -3482,17 +3738,21 @@ function repeat(count, map, options) {
|
|
|
3482
3738
|
}
|
|
3483
3739
|
}
|
|
3484
3740
|
: map;
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3741
|
+
const node = computed(
|
|
3742
|
+
updateRepeat.bind({
|
|
3743
|
+
_owner: createOwner(),
|
|
3744
|
+
_len: 0,
|
|
3745
|
+
_offset: 0,
|
|
3746
|
+
_count: count,
|
|
3747
|
+
_map: wrappedMap,
|
|
3748
|
+
_nodes: [],
|
|
3749
|
+
_mappings: [],
|
|
3750
|
+
_from: options?.from,
|
|
3751
|
+
_fallback: options?.fallback
|
|
3752
|
+
})
|
|
3753
|
+
);
|
|
3754
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
3755
|
+
return accessor(node);
|
|
3496
3756
|
}
|
|
3497
3757
|
function updateRepeat() {
|
|
3498
3758
|
const newLen = this._count();
|
|
@@ -3549,7 +3809,7 @@ function compare(key, a, b) {
|
|
|
3549
3809
|
return key ? key(a) === key(b) : true;
|
|
3550
3810
|
}
|
|
3551
3811
|
function boundaryComputed(fn, propagationMask) {
|
|
3552
|
-
const node = computed(fn,
|
|
3812
|
+
const node = computed(fn, { lazy: true });
|
|
3553
3813
|
node._notifyStatus = (status, error) => {
|
|
3554
3814
|
const flags = status !== undefined ? status : node._statusFlags;
|
|
3555
3815
|
const actualError = error !== undefined ? error : node._error;
|
|
@@ -3557,7 +3817,7 @@ function boundaryComputed(fn, propagationMask) {
|
|
|
3557
3817
|
node._queue.notify(node, node._propagationMask, flags, actualError);
|
|
3558
3818
|
};
|
|
3559
3819
|
node._propagationMask = propagationMask;
|
|
3560
|
-
node.
|
|
3820
|
+
node._config &= ~CONFIG_AUTO_DISPOSE;
|
|
3561
3821
|
recompute(node, true);
|
|
3562
3822
|
return node;
|
|
3563
3823
|
}
|
|
@@ -3574,12 +3834,16 @@ const ON_INIT = Symbol();
|
|
|
3574
3834
|
const RevealControllerContext = createContext(null);
|
|
3575
3835
|
let _revealUsed = false;
|
|
3576
3836
|
const FALSE_ACCESSOR = () => false;
|
|
3837
|
+
const SEQUENTIAL_ACCESSOR = () => "sequential";
|
|
3577
3838
|
function isRevealController(slot) {
|
|
3578
3839
|
return slot instanceof RevealController;
|
|
3579
3840
|
}
|
|
3580
3841
|
function isSlotReady(slot) {
|
|
3581
3842
|
return isRevealController(slot) ? slot.isReady() : slot._sources.size === 0 && !slot._pending;
|
|
3582
3843
|
}
|
|
3844
|
+
function isSlotMinimallyReady(slot) {
|
|
3845
|
+
return isRevealController(slot) ? slot.isMinimallyReady() : isSlotReady(slot);
|
|
3846
|
+
}
|
|
3583
3847
|
function setSlotState(slot, controller, disabled, collapsed) {
|
|
3584
3848
|
setSignal(slot._disabled, disabled);
|
|
3585
3849
|
setSignal(slot._collapsed, collapsed);
|
|
@@ -3591,16 +3855,17 @@ function setSlotState(slot, controller, disabled, collapsed) {
|
|
|
3591
3855
|
slot._revealController = undefined;
|
|
3592
3856
|
}
|
|
3593
3857
|
class RevealController {
|
|
3594
|
-
|
|
3858
|
+
_orderAccessor;
|
|
3595
3859
|
_collapsedAccessor;
|
|
3596
3860
|
_slots = [];
|
|
3597
3861
|
_parentController;
|
|
3598
|
-
_disabled = signal(false, {
|
|
3599
|
-
_collapsed = signal(false, {
|
|
3862
|
+
_disabled = signal(false, { ownedWrite: true, _noSnapshot: true });
|
|
3863
|
+
_collapsed = signal(false, { ownedWrite: true, _noSnapshot: true });
|
|
3600
3864
|
_ready = true;
|
|
3865
|
+
_minimallyReady = true;
|
|
3601
3866
|
_evaluating = false;
|
|
3602
|
-
constructor(
|
|
3603
|
-
this.
|
|
3867
|
+
constructor(order, collapsed) {
|
|
3868
|
+
this._orderAccessor = order;
|
|
3604
3869
|
this._collapsedAccessor = collapsed;
|
|
3605
3870
|
}
|
|
3606
3871
|
_forEachOwnedSlot(fn) {
|
|
@@ -3615,12 +3880,37 @@ class RevealController {
|
|
|
3615
3880
|
isReady() {
|
|
3616
3881
|
return this._forEachOwnedSlot(isSlotReady);
|
|
3617
3882
|
}
|
|
3883
|
+
isMinimallyReady() {
|
|
3884
|
+
const order = untrack(this._orderAccessor);
|
|
3885
|
+
if (order === "together") return this.isReady();
|
|
3886
|
+
if (order === "natural") {
|
|
3887
|
+
let hasSlot = false;
|
|
3888
|
+
let anyReady = false;
|
|
3889
|
+
this._forEachOwnedSlot(slot => {
|
|
3890
|
+
hasSlot = true;
|
|
3891
|
+
if (isSlotMinimallyReady(slot)) {
|
|
3892
|
+
anyReady = true;
|
|
3893
|
+
return false;
|
|
3894
|
+
}
|
|
3895
|
+
});
|
|
3896
|
+
return !hasSlot || anyReady;
|
|
3897
|
+
}
|
|
3898
|
+
let firstReady = true;
|
|
3899
|
+
this._forEachOwnedSlot(slot => {
|
|
3900
|
+
firstReady = isSlotMinimallyReady(slot);
|
|
3901
|
+
return false;
|
|
3902
|
+
});
|
|
3903
|
+
return firstReady;
|
|
3904
|
+
}
|
|
3618
3905
|
register(slot) {
|
|
3619
3906
|
if (this._slots.includes(slot)) return;
|
|
3620
3907
|
this._slots.push(slot);
|
|
3621
|
-
const
|
|
3622
|
-
setSignal(slot._disabled, true),
|
|
3623
|
-
setSignal(
|
|
3908
|
+
const order = untrack(this._orderAccessor);
|
|
3909
|
+
(setSignal(slot._disabled, true),
|
|
3910
|
+
setSignal(
|
|
3911
|
+
slot._collapsed,
|
|
3912
|
+
order === "sequential" ? !!untrack(this._collapsedAccessor) : false
|
|
3913
|
+
));
|
|
3624
3914
|
untrack(() => this.evaluate());
|
|
3625
3915
|
}
|
|
3626
3916
|
unregister(slot) {
|
|
@@ -3632,29 +3922,52 @@ class RevealController {
|
|
|
3632
3922
|
if (this._evaluating) return;
|
|
3633
3923
|
this._evaluating = true;
|
|
3634
3924
|
const wasReady = this._ready;
|
|
3925
|
+
const wasMinReady = this._minimallyReady;
|
|
3635
3926
|
try {
|
|
3636
3927
|
const disabled = disabledOverride ?? read(this._disabled),
|
|
3637
|
-
|
|
3928
|
+
order = untrack(this._orderAccessor),
|
|
3929
|
+
collapseTail = order === "sequential" && !!untrack(this._collapsedAccessor),
|
|
3638
3930
|
collapsed = collapsedOverride ?? collapseTail;
|
|
3639
|
-
if (disabled
|
|
3640
|
-
this._forEachOwnedSlot(slot => setSlotState(slot, this, true,
|
|
3641
|
-
else if (
|
|
3642
|
-
|
|
3643
|
-
|
|
3931
|
+
if (disabled) {
|
|
3932
|
+
this._forEachOwnedSlot(slot => setSlotState(slot, this, true, collapsed));
|
|
3933
|
+
} else if (order === "natural") {
|
|
3934
|
+
this._forEachOwnedSlot(slot => {
|
|
3935
|
+
if (isRevealController(slot)) {
|
|
3936
|
+
setSignal(slot._collapsed, false);
|
|
3937
|
+
setSignal(slot._disabled, false);
|
|
3938
|
+
slot.evaluate(false, false);
|
|
3939
|
+
} else {
|
|
3940
|
+
setSlotState(slot, this, !isSlotReady(slot), false);
|
|
3941
|
+
}
|
|
3942
|
+
});
|
|
3943
|
+
} else if (order === "together") {
|
|
3944
|
+
const minReady = this._forEachOwnedSlot(isSlotMinimallyReady);
|
|
3945
|
+
this._forEachOwnedSlot(slot => setSlotState(slot, this, !minReady, false));
|
|
3644
3946
|
} else {
|
|
3645
3947
|
let pendingSeen = false;
|
|
3646
3948
|
this._forEachOwnedSlot(slot => {
|
|
3647
3949
|
if (pendingSeen) return setSlotState(slot, this, true, collapseTail);
|
|
3648
3950
|
if (isSlotReady(slot)) return setSlotState(slot, this, false, false);
|
|
3649
3951
|
pendingSeen = true;
|
|
3650
|
-
|
|
3952
|
+
if (isRevealController(slot)) {
|
|
3953
|
+
setSignal(slot._collapsed, false);
|
|
3954
|
+
setSignal(slot._disabled, false);
|
|
3955
|
+
slot.evaluate(false, false);
|
|
3956
|
+
} else {
|
|
3957
|
+
setSlotState(slot, this, true, false);
|
|
3958
|
+
}
|
|
3651
3959
|
});
|
|
3652
3960
|
}
|
|
3653
3961
|
} finally {
|
|
3654
3962
|
this._ready = this.isReady();
|
|
3963
|
+
this._minimallyReady = this.isMinimallyReady();
|
|
3655
3964
|
this._evaluating = false;
|
|
3656
3965
|
}
|
|
3657
|
-
if (
|
|
3966
|
+
if (
|
|
3967
|
+
this._parentController &&
|
|
3968
|
+
(wasReady !== this._ready || wasMinReady !== this._minimallyReady)
|
|
3969
|
+
)
|
|
3970
|
+
this._parentController.evaluate();
|
|
3658
3971
|
}
|
|
3659
3972
|
}
|
|
3660
3973
|
class CollectionQueue extends Queue {
|
|
@@ -3662,8 +3975,8 @@ class CollectionQueue extends Queue {
|
|
|
3662
3975
|
_sources = new Set();
|
|
3663
3976
|
_tree;
|
|
3664
3977
|
_pending = true;
|
|
3665
|
-
_disabled = signal(false, {
|
|
3666
|
-
_collapsed = signal(false, {
|
|
3978
|
+
_disabled = signal(false, { ownedWrite: true, _noSnapshot: true });
|
|
3979
|
+
_collapsed = signal(false, { ownedWrite: true, _noSnapshot: true });
|
|
3667
3980
|
_revealController;
|
|
3668
3981
|
_initialized = false;
|
|
3669
3982
|
_onFn;
|
|
@@ -3743,7 +4056,8 @@ class CollectionQueue extends Queue {
|
|
|
3743
4056
|
}
|
|
3744
4057
|
function createCollectionBoundary(type, fn, fallback, onFn) {
|
|
3745
4058
|
if (!getOwner()) {
|
|
3746
|
-
const message =
|
|
4059
|
+
const message =
|
|
4060
|
+
"[NO_OWNER_BOUNDARY] Boundaries created outside a reactive context will never be disposed.";
|
|
3747
4061
|
emitDiagnostic({
|
|
3748
4062
|
code: "NO_OWNER_BOUNDARY",
|
|
3749
4063
|
kind: "lifecycle",
|
|
@@ -3776,15 +4090,16 @@ function createCollectionBoundary(type, fn, fallback, onFn) {
|
|
|
3776
4090
|
controller.register(queue);
|
|
3777
4091
|
cleanup(() => controller.unregister(queue));
|
|
3778
4092
|
}
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
4093
|
+
return accessor(
|
|
4094
|
+
computed(() => {
|
|
4095
|
+
if (!read(queue._disabled)) {
|
|
4096
|
+
const resolved = read(tree);
|
|
4097
|
+
if (!untrack(() => read(queue._disabled))) return ((queue._initialized = true), resolved);
|
|
4098
|
+
}
|
|
4099
|
+
if (_revealUsed && read(queue._collapsed)) return undefined;
|
|
4100
|
+
return fallback(queue);
|
|
4101
|
+
})
|
|
4102
|
+
);
|
|
3788
4103
|
}
|
|
3789
4104
|
function createLoadingBoundary(fn, fallback, options) {
|
|
3790
4105
|
return createCollectionBoundary(STATUS_PENDING, fn, () => fallback(), options?.on);
|
|
@@ -3803,14 +4118,14 @@ function createRevealOrder(fn, options) {
|
|
|
3803
4118
|
_revealUsed = true;
|
|
3804
4119
|
const owner = createOwner();
|
|
3805
4120
|
const parentController = getContext(RevealControllerContext);
|
|
3806
|
-
const
|
|
4121
|
+
const order = options?.order || SEQUENTIAL_ACCESSOR,
|
|
3807
4122
|
collapsed = options?.collapsed || FALSE_ACCESSOR;
|
|
3808
|
-
const controller = new RevealController(
|
|
4123
|
+
const controller = new RevealController(order, collapsed);
|
|
3809
4124
|
setContext(RevealControllerContext, controller, owner);
|
|
3810
4125
|
return runWithOwner(owner, () => {
|
|
3811
4126
|
const value = fn();
|
|
3812
4127
|
computed(() => {
|
|
3813
|
-
|
|
4128
|
+
order();
|
|
3814
4129
|
collapsed();
|
|
3815
4130
|
controller.evaluate();
|
|
3816
4131
|
});
|