@solidjs/signals 0.10.4 → 0.10.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/dev.js CHANGED
@@ -33,6 +33,7 @@ const REACTIVE_IN_HEAP_HEIGHT = 1 << 4;
33
33
  const REACTIVE_ZOMBIE = 1 << 5;
34
34
  const REACTIVE_DISPOSED = 1 << 6;
35
35
  const REACTIVE_OPTIMISTIC_DIRTY = 1 << 7;
36
+ const REACTIVE_SNAPSHOT_STALE = 1 << 8;
36
37
  const STATUS_PENDING = 1 << 0;
37
38
  const STATUS_ERROR = 1 << 1;
38
39
  const STATUS_UNINITIALIZED = 1 << 2;
@@ -40,6 +41,8 @@ const EFFECT_RENDER = 1;
40
41
  const EFFECT_USER = 2;
41
42
  const EFFECT_TRACKED = 3;
42
43
  const NOT_PENDING = {};
44
+ const NO_SNAPSHOT = {};
45
+ const STORE_SNAPSHOT_PROPS = "sp";
43
46
  const SUPPORTS_PROXY = typeof Proxy === "function";
44
47
  const defaultContext = {};
45
48
  const $REFRESH = Symbol("refresh");
@@ -350,7 +353,12 @@ class GlobalQueue extends Queue {
350
353
  }
351
354
  function insertSubs(node, optimistic = false) {
352
355
  const sourceLane = node._optimisticLane || currentOptimisticLane;
356
+ const hasSnapshot = node._snapshotValue !== undefined;
353
357
  for (let s = node._subs; s !== null; s = s._nextSub) {
358
+ if (hasSnapshot && s._sub._inSnapshotScope) {
359
+ s._sub._flags |= REACTIVE_SNAPSHOT_STALE;
360
+ continue;
361
+ }
354
362
  if (optimistic && sourceLane) {
355
363
  s._sub._flags |= REACTIVE_OPTIMISTIC_DIRTY;
356
364
  assignOrMergeLane(s._sub, sourceLane);
@@ -729,7 +737,7 @@ function unlinkSubs(link) {
729
737
  dep._subs = nextSub;
730
738
  if (nextSub === null) {
731
739
  dep._unobserved?.();
732
- dep._fn && !dep._preventAutoDisposal && unobserved(dep);
740
+ dep._fn && !dep._preventAutoDisposal && !(dep._flags & REACTIVE_ZOMBIE) && unobserved(dep);
733
741
  }
734
742
  }
735
743
  return nextDep;
@@ -874,6 +882,9 @@ function onCleanup(fn) {
874
882
  else context._disposal = [context._disposal, fn];
875
883
  return fn;
876
884
  }
885
+ function isDisposed(node) {
886
+ return !!(node._flags & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE));
887
+ }
877
888
  function createOwner(options) {
878
889
  const parent = context;
879
890
  const transparent = options?.transparent ?? false;
@@ -1020,6 +1031,58 @@ let foundPending = false;
1020
1031
  let pendingReadActive = false;
1021
1032
  let context = null;
1022
1033
  let currentOptimisticLane = null;
1034
+ let snapshotCaptureActive = false;
1035
+ let snapshotSources = null;
1036
+ function ownerInSnapshotScope(owner) {
1037
+ while (owner) {
1038
+ if (owner._snapshotScope) return true;
1039
+ owner = owner._parent;
1040
+ }
1041
+ return false;
1042
+ }
1043
+ function setSnapshotCapture(active) {
1044
+ snapshotCaptureActive = active;
1045
+ if (active && !snapshotSources) snapshotSources = new Set();
1046
+ }
1047
+ function markSnapshotScope(owner) {
1048
+ owner._snapshotScope = true;
1049
+ }
1050
+ function releaseSnapshotScope(owner) {
1051
+ owner._snapshotScope = false;
1052
+ releaseSubtree(owner);
1053
+ schedule();
1054
+ }
1055
+ function releaseSubtree(owner) {
1056
+ let child = owner._firstChild;
1057
+ while (child) {
1058
+ if (child._snapshotScope) {
1059
+ child = child._nextSibling;
1060
+ continue;
1061
+ }
1062
+ if (child._fn) {
1063
+ const comp = child;
1064
+ comp._inSnapshotScope = false;
1065
+ if (comp._flags & REACTIVE_SNAPSHOT_STALE) {
1066
+ comp._flags &= ~REACTIVE_SNAPSHOT_STALE;
1067
+ comp._flags |= REACTIVE_DIRTY;
1068
+ if (dirtyQueue._min > comp._height) dirtyQueue._min = comp._height;
1069
+ insertIntoHeap(comp, dirtyQueue);
1070
+ }
1071
+ }
1072
+ releaseSubtree(child);
1073
+ child = child._nextSibling;
1074
+ }
1075
+ }
1076
+ function clearSnapshots() {
1077
+ if (snapshotSources) {
1078
+ for (const source of snapshotSources) {
1079
+ delete source._snapshotValue;
1080
+ delete source[STORE_SNAPSHOT_PROPS];
1081
+ }
1082
+ snapshotSources = null;
1083
+ }
1084
+ snapshotCaptureActive = false;
1085
+ }
1023
1086
  function recompute(el, create = false) {
1024
1087
  const isEffect = el._type;
1025
1088
  if (!create) {
@@ -1079,7 +1142,7 @@ function recompute(el, create = false) {
1079
1142
  );
1080
1143
  } finally {
1081
1144
  tracking = prevTracking;
1082
- el._flags = REACTIVE_NONE;
1145
+ el._flags = REACTIVE_NONE | (create ? el._flags & REACTIVE_SNAPSHOT_STALE : 0);
1083
1146
  context = oldcontext;
1084
1147
  }
1085
1148
  if (!el._error) {
@@ -1145,7 +1208,7 @@ function updateIfNecessary(el) {
1145
1208
  if (el._flags & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || (el._error && el._time < clock)) {
1146
1209
  recompute(el);
1147
1210
  }
1148
- el._flags = REACTIVE_NONE;
1211
+ el._flags = REACTIVE_NONE | (el._flags & REACTIVE_SNAPSHOT_STALE);
1149
1212
  }
1150
1213
  function computed(fn, initialValue, options) {
1151
1214
  const transparent = options?.transparent ?? false;
@@ -1199,7 +1262,14 @@ function computed(fn, initialValue, options) {
1199
1262
  }
1200
1263
  }
1201
1264
  if (parent) self._height = parent._height + 1;
1265
+ if (snapshotCaptureActive && ownerInSnapshotScope(context)) self._inSnapshotScope = true;
1202
1266
  !options?.lazy && recompute(self, true);
1267
+ if (snapshotCaptureActive && !options?.lazy) {
1268
+ if (!(self._statusFlags & STATUS_PENDING)) {
1269
+ self._snapshotValue = self._value === undefined ? NO_SNAPSHOT : self._value;
1270
+ snapshotSources.add(self);
1271
+ }
1272
+ }
1203
1273
  return self;
1204
1274
  }
1205
1275
  function signal(v, options, firewall = null) {
@@ -1217,6 +1287,10 @@ function signal(v, options, firewall = null) {
1217
1287
  };
1218
1288
  s._name = options?.name ?? "signal";
1219
1289
  firewall && (firewall._child = s);
1290
+ if (snapshotCaptureActive) {
1291
+ s._snapshotValue = v === undefined ? NO_SNAPSHOT : v;
1292
+ snapshotSources.add(s);
1293
+ }
1220
1294
  return s;
1221
1295
  }
1222
1296
  function optimisticSignal(v, options) {
@@ -1246,8 +1320,15 @@ function read(el) {
1246
1320
  const pendingComputed = getPendingValueComputed(el);
1247
1321
  const prevPending = pendingReadActive;
1248
1322
  pendingReadActive = false;
1249
- const value = read(pendingComputed);
1250
- pendingReadActive = prevPending;
1323
+ let value;
1324
+ try {
1325
+ value = read(pendingComputed);
1326
+ } catch (e) {
1327
+ if (!context && e instanceof NotReadyError) return el._value;
1328
+ throw e;
1329
+ } finally {
1330
+ pendingReadActive = prevPending;
1331
+ }
1251
1332
  if (pendingComputed._statusFlags & STATUS_PENDING) return el._value;
1252
1333
  if (stale && currentOptimisticLane && pendingComputed._optimisticLane) {
1253
1334
  const pcLane = findLane(pendingComputed._optimisticLane);
@@ -1290,20 +1371,23 @@ function read(el) {
1290
1371
  }
1291
1372
  }
1292
1373
  const asyncCompute = el._firewall || el;
1293
- if (
1294
- c &&
1295
- asyncCompute._statusFlags & STATUS_PENDING &&
1296
- !(stale && asyncCompute._transition && activeTransition !== asyncCompute._transition)
1297
- ) {
1298
- if (currentOptimisticLane) {
1299
- const pendingLane = asyncCompute._optimisticLane;
1300
- const lane = findLane(currentOptimisticLane);
1301
- if (pendingLane && findLane(pendingLane) === lane && !hasActiveOverride(asyncCompute)) {
1374
+ if (asyncCompute._statusFlags & STATUS_PENDING) {
1375
+ if (
1376
+ c &&
1377
+ !(stale && asyncCompute._transition && activeTransition !== asyncCompute._transition)
1378
+ ) {
1379
+ if (currentOptimisticLane) {
1380
+ const pendingLane = asyncCompute._optimisticLane;
1381
+ const lane = findLane(currentOptimisticLane);
1382
+ if (pendingLane && findLane(pendingLane) === lane && !hasActiveOverride(asyncCompute)) {
1383
+ if (!tracking) link(el, c);
1384
+ throw asyncCompute._error;
1385
+ }
1386
+ } else {
1302
1387
  if (!tracking) link(el, c);
1303
1388
  throw asyncCompute._error;
1304
1389
  }
1305
- } else {
1306
- if (!tracking) link(el, c);
1390
+ } else if (!c && asyncCompute._statusFlags & STATUS_UNINITIALIZED) {
1307
1391
  throw asyncCompute._error;
1308
1392
  }
1309
1393
  }
@@ -1313,6 +1397,15 @@ function read(el) {
1313
1397
  return read(el);
1314
1398
  } else throw el._error;
1315
1399
  }
1400
+ if (snapshotCaptureActive && c && c._inSnapshotScope) {
1401
+ const sv = el._snapshotValue;
1402
+ if (sv !== undefined) {
1403
+ const snapshot = sv === NO_SNAPSHOT ? undefined : sv;
1404
+ const current = el._pendingValue !== NOT_PENDING ? el._pendingValue : el._value;
1405
+ if (current !== snapshot) c._flags |= REACTIVE_SNAPSHOT_STALE;
1406
+ return snapshot;
1407
+ }
1408
+ }
1316
1409
  return !c ||
1317
1410
  currentOptimisticLane !== null ||
1318
1411
  el._pendingValue === NOT_PENDING ||
@@ -1907,7 +2000,7 @@ function getNodes(target, type) {
1907
2000
  if (!nodes) target[type] = nodes = Object.create(null);
1908
2001
  return nodes;
1909
2002
  }
1910
- function getNode(nodes, property, value, firewall, equals = isEqual, optimistic) {
2003
+ function getNode(nodes, property, value, firewall, equals = isEqual, optimistic, snapshotProps) {
1911
2004
  if (nodes[property]) return nodes[property];
1912
2005
  const s = signal(
1913
2006
  value,
@@ -1920,6 +2013,11 @@ function getNode(nodes, property, value, firewall, equals = isEqual, optimistic)
1920
2013
  firewall
1921
2014
  );
1922
2015
  if (optimistic) s._optimistic = true;
2016
+ if (snapshotProps && property in snapshotProps) {
2017
+ const sv = snapshotProps[property];
2018
+ s._snapshotValue = sv === undefined ? NO_SNAPSHOT : sv;
2019
+ snapshotSources?.add(s);
2020
+ }
1923
2021
  return (nodes[property] = s);
1924
2022
  }
1925
2023
  function trackSelf(target, symbol = $TRACK) {
@@ -2017,7 +2115,8 @@ const storeTraps = {
2017
2115
  isWrappable(value) ? wrap(value, target) : value,
2018
2116
  target[STORE_FIREWALL],
2019
2117
  isEqual,
2020
- target[STORE_OPTIMISTIC]
2118
+ target[STORE_OPTIMISTIC],
2119
+ target[STORE_SNAPSHOT_PROPS]
2021
2120
  )
2022
2121
  );
2023
2122
  }
@@ -2057,6 +2156,15 @@ const storeTraps = {
2057
2156
  untrack(() => {
2058
2157
  const state = target[STORE_VALUE];
2059
2158
  const base = state[property];
2159
+ if (snapshotCaptureActive && typeof property !== "symbol") {
2160
+ if (!target[STORE_SNAPSHOT_PROPS]) {
2161
+ target[STORE_SNAPSHOT_PROPS] = Object.create(null);
2162
+ snapshotSources?.add(target);
2163
+ }
2164
+ if (!(property in target[STORE_SNAPSHOT_PROPS])) {
2165
+ target[STORE_SNAPSHOT_PROPS][property] = base;
2166
+ }
2167
+ }
2060
2168
  const useOptimistic = target[STORE_OPTIMISTIC] && !projectionWriteActive;
2061
2169
  const overrideKey = useOptimistic ? STORE_OPTIMISTIC_OVERRIDE : STORE_OVERRIDE;
2062
2170
  if (useOptimistic) trackOptimisticStore(store);
@@ -2878,6 +2986,7 @@ export {
2878
2986
  NotReadyError,
2879
2987
  SUPPORTS_PROXY,
2880
2988
  action,
2989
+ clearSnapshots,
2881
2990
  createContext,
2882
2991
  createEffect,
2883
2992
  createErrorBoundary,
@@ -2900,11 +3009,13 @@ export {
2900
3009
  getNextChildId,
2901
3010
  getObserver,
2902
3011
  getOwner,
3012
+ isDisposed,
2903
3013
  isEqual,
2904
3014
  isPending,
2905
3015
  isRefreshing,
2906
3016
  isWrappable,
2907
3017
  mapArray,
3018
+ markSnapshotScope,
2908
3019
  merge,
2909
3020
  omit,
2910
3021
  onCleanup,
@@ -2913,10 +3024,12 @@ export {
2913
3024
  pending,
2914
3025
  reconcile,
2915
3026
  refresh,
3027
+ releaseSnapshotScope,
2916
3028
  repeat,
2917
3029
  resolve,
2918
3030
  runWithOwner,
2919
3031
  setContext,
3032
+ setSnapshotCapture,
2920
3033
  snapshot,
2921
3034
  untrack
2922
3035
  };