@solidjs/signals 0.9.2 → 0.9.4

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
@@ -34,6 +34,7 @@ const EFFECT_USER = 2;
34
34
  const NOT_PENDING = {};
35
35
  const SUPPORTS_PROXY = typeof Proxy === "function";
36
36
  const defaultContext = {};
37
+ const $REFRESH = Symbol("refresh");
37
38
  function actualInsertIntoHeap(n, heap) {
38
39
  const parentHeight =
39
40
  (n._parent?._root ? n._parent._parentComputed?._height : n._parent?._height) ?? -1;
@@ -141,7 +142,7 @@ let scheduled = false;
141
142
  function schedule() {
142
143
  if (scheduled) return;
143
144
  scheduled = true;
144
- if (!globalQueue._running) queueMicrotask(flush);
145
+ if (!globalQueue._running) Promise.resolve().then(() => queueMicrotask(flush));
145
146
  }
146
147
  class Queue {
147
148
  _parent = null;
@@ -226,6 +227,8 @@ class GlobalQueue extends Queue {
226
227
  return;
227
228
  }
228
229
  this._pendingNodes.push(...activeTransition.pendingNodes);
230
+ this._optimisticNodes !== activeTransition.optimisticNodes &&
231
+ this._optimisticNodes.push(...activeTransition.optimisticNodes);
229
232
  this.restoreQueues(activeTransition.queueStash);
230
233
  transitions.delete(activeTransition);
231
234
  activeTransition = null;
@@ -255,11 +258,12 @@ class GlobalQueue extends Queue {
255
258
  initTransition(node) {
256
259
  if (activeTransition && activeTransition.time === clock) return;
257
260
  if (!activeTransition) {
258
- activeTransition = node._transition ?? {
261
+ activeTransition = node?._transition ?? {
259
262
  time: clock,
260
263
  pendingNodes: [],
261
264
  asyncNodes: [],
262
265
  optimisticNodes: [],
266
+ actions: [],
263
267
  queueStash: { _queues: [[], []], _children: [] },
264
268
  done: false
265
269
  };
@@ -345,6 +349,7 @@ function runQueue(queue, type) {
345
349
  }
346
350
  function transitionComplete(transition) {
347
351
  if (transition.done) return true;
352
+ if (transition.actions.length) return false;
348
353
  let done = true;
349
354
  for (let i = 0; i < transition.asyncNodes.length; i++) {
350
355
  if (transition.asyncNodes[i]._statusFlags & STATUS_PENDING) {
@@ -355,11 +360,40 @@ function transitionComplete(transition) {
355
360
  done && (transition.done = true);
356
361
  return done;
357
362
  }
358
- function runInTransition(el, recompute) {
363
+ function runInTransition(transition, fn) {
359
364
  const prevTransition = activeTransition;
360
- activeTransition = el._transition;
361
- recompute(el);
362
- activeTransition = prevTransition;
365
+ try {
366
+ activeTransition = transition;
367
+ return fn();
368
+ } finally {
369
+ activeTransition = prevTransition;
370
+ }
371
+ }
372
+ function action(genFn) {
373
+ return (...args) => {
374
+ const iterator = genFn(...args);
375
+ globalQueue.initTransition();
376
+ let ctx = activeTransition;
377
+ ctx.actions.push(iterator);
378
+ const step = input => {
379
+ let nextValue = iterator.next(input);
380
+ if (nextValue instanceof Promise) return nextValue.then(process);
381
+ process(nextValue);
382
+ };
383
+ const process = result => {
384
+ if (result.done) {
385
+ ctx.actions.splice(ctx.actions.indexOf(iterator), 1);
386
+ activeTransition = ctx;
387
+ schedule();
388
+ flush();
389
+ return;
390
+ }
391
+ const yielded = result.value;
392
+ if (yielded instanceof Promise) return yielded.then(step);
393
+ runInTransition(ctx, () => step(yielded));
394
+ };
395
+ runInTransition(ctx, () => step());
396
+ };
363
397
  }
364
398
  GlobalQueue._update = recompute;
365
399
  GlobalQueue._dispose = disposeChildren;
@@ -426,7 +460,7 @@ function recompute(el, create = false) {
426
460
  const valueChanged =
427
461
  !el._equals ||
428
462
  !el._equals(
429
- el._pendingValue === NOT_PENDING || el._optimistic || honoraryOptimistic
463
+ el._pendingValue === NOT_PENDING || (el._optimistic && el._transition) || honoraryOptimistic
430
464
  ? el._value
431
465
  : el._pendingValue,
432
466
  value
@@ -449,7 +483,7 @@ function recompute(el, create = false) {
449
483
  (!create || el._statusFlags & STATUS_PENDING) &&
450
484
  !el._transition &&
451
485
  globalQueue._pendingNodes.push(el);
452
- el._transition && honoraryOptimistic && runInTransition(el, recompute);
486
+ el._transition && honoraryOptimistic && runInTransition(el._transition, () => recompute(el));
453
487
  }
454
488
  function handleAsync(el, result, setter) {
455
489
  const isObject = typeof result === "object" && result !== null;
@@ -755,17 +789,6 @@ function read(el) {
755
789
  }
756
790
  }
757
791
  }
758
- if (pendingCheck) {
759
- if (!el._pendingCheck) {
760
- el._pendingCheck = signal(false);
761
- el._pendingCheck._optimistic = true;
762
- el._pendingCheck._set = v => setSignal(el._pendingCheck, v);
763
- }
764
- const prev = pendingCheck;
765
- pendingCheck = null;
766
- prev._value = read(el._pendingCheck) || prev._value;
767
- pendingCheck = prev;
768
- }
769
792
  if (pendingValueCheck) {
770
793
  if (!el._pendingSignal) {
771
794
  el._pendingSignal = signal(el._value);
@@ -778,10 +801,23 @@ function read(el) {
778
801
  pendingValueCheck = true;
779
802
  }
780
803
  }
781
- if (el._statusFlags & STATUS_PENDING && !pendingCheck) {
782
- if ((c && !stale) || el._statusFlags & STATUS_UNINITIALIZED) throw el._error;
804
+ const asyncCompute = el._firewall || el;
805
+ if (pendingCheck) {
806
+ if (!asyncCompute._pendingCheck) {
807
+ asyncCompute._pendingCheck = signal(false);
808
+ asyncCompute._pendingCheck._optimistic = true;
809
+ asyncCompute._pendingCheck._set = v => setSignal(asyncCompute._pendingCheck, v);
810
+ }
811
+ const prev = pendingCheck;
812
+ pendingCheck = null;
813
+ prev._value = read(asyncCompute._pendingCheck) || prev._value;
814
+ pendingCheck = prev;
815
+ }
816
+ if (!pendingCheck && asyncCompute._statusFlags & STATUS_PENDING) {
817
+ if ((c && !stale) || asyncCompute._statusFlags & STATUS_UNINITIALIZED || el._firewall)
818
+ throw asyncCompute._error;
783
819
  else if (c && stale) {
784
- setStatusFlags(c, c._statusFlags | 1, el._error);
820
+ setStatusFlags(c, c._statusFlags | STATUS_PENDING, asyncCompute._error);
785
821
  }
786
822
  }
787
823
  if (el._statusFlags & STATUS_ERROR) {
@@ -814,7 +850,9 @@ function setSignal(el, v) {
814
850
  const valueChanged =
815
851
  !el._equals ||
816
852
  !el._equals(
817
- el._pendingValue === NOT_PENDING || el._optimistic ? el._value : el._pendingValue,
853
+ el._pendingValue === NOT_PENDING || (el._optimistic && el._transition)
854
+ ? el._value
855
+ : el._pendingValue,
818
856
  v
819
857
  );
820
858
  if (!valueChanged && !el._statusFlags) return v;
@@ -928,6 +966,10 @@ function refresh(fn) {
928
966
  let prevRefreshing = refreshing;
929
967
  refreshing = true;
930
968
  try {
969
+ if (typeof fn !== "function") {
970
+ recompute(fn[$REFRESH]);
971
+ return fn;
972
+ }
931
973
  return untrack(fn);
932
974
  } finally {
933
975
  refreshing = prevRefreshing;
@@ -1040,9 +1082,7 @@ function createSignal(first, second, third) {
1040
1082
  const node = computed(first, second, third);
1041
1083
  return [read.bind(null, node), setSignal.bind(null, node)];
1042
1084
  }
1043
- const o = getOwner();
1044
- const needsId = o?.id != null;
1045
- const node = signal(first, needsId ? { id: getNextChildId(o), ...second } : second);
1085
+ const node = signal(first, second);
1046
1086
  return [read.bind(null, node), setSignal.bind(null, node)];
1047
1087
  }
1048
1088
  function createMemo(compute, value, options) {
@@ -1101,8 +1141,10 @@ function createOptimistic(first, second, third) {
1101
1141
  if (typeof first === "function") {
1102
1142
  const node = computed(
1103
1143
  prev => {
1104
- let n = node || getOwner();
1105
- n._pendingValue = first(prev);
1144
+ const n = getOwner();
1145
+ const value = first(prev);
1146
+ if (n._statusFlags & STATUS_UNINITIALIZED) return value;
1147
+ n._pendingValue = value;
1106
1148
  return prev;
1107
1149
  },
1108
1150
  second,
@@ -1111,9 +1153,7 @@ function createOptimistic(first, second, third) {
1111
1153
  node._optimistic = true;
1112
1154
  return [read.bind(null, node), setSignal.bind(null, node)];
1113
1155
  }
1114
- const o = getOwner();
1115
- const needsId = o?.id != null;
1116
- const node = signal(first, needsId ? { id: getNextChildId(o), ...second } : second);
1156
+ const node = signal(first, second);
1117
1157
  node._optimistic = true;
1118
1158
  return [
1119
1159
  read.bind(null, node),
@@ -1136,11 +1176,7 @@ function unwrap(value) {
1136
1176
  return value?.[$TARGET]?.[STORE_NODE] ?? value;
1137
1177
  }
1138
1178
  function getOverrideValue(value, override, nodes, key) {
1139
- return nodes && key in nodes
1140
- ? read(nodes[key])
1141
- : override && key in override
1142
- ? override[key]
1143
- : value[key];
1179
+ return override && key in override ? override[key] : value[key];
1144
1180
  }
1145
1181
  function getAllKeys(value, override, next) {
1146
1182
  const keys = getKeys(value, override);
@@ -1226,10 +1262,12 @@ function applyState(next, state, keyFn, all) {
1226
1262
  } else target[STORE_NODE][j] && setSignal(target[STORE_NODE][j], wrap(next[j], target));
1227
1263
  }
1228
1264
  if (start < next.length) changed = true;
1229
- } else if (prevLength && next.length) {
1265
+ } else if (next.length) {
1230
1266
  for (let i = 0, len = next.length; i < len; i++) {
1231
1267
  const item = getOverrideValue(previous, override, nodes, i);
1232
- isWrappable(item) && applyState(next[i], wrap(item, target), keyFn, all);
1268
+ isWrappable(item)
1269
+ ? applyState(next[i], wrap(item, target), keyFn, all)
1270
+ : target[STORE_NODE][i] && setSignal(target[STORE_NODE][i], next[i]);
1233
1271
  }
1234
1272
  }
1235
1273
  if (prevLength !== next.length) {
@@ -1279,36 +1317,74 @@ function reconcile(value, key, all = false) {
1279
1317
  function createProjectionInternal(fn, initialValue = {}, options) {
1280
1318
  let node;
1281
1319
  const wrappedMap = new WeakMap();
1320
+ const wrapper = s => {
1321
+ s[STORE_WRAP] = wrapProjection;
1322
+ s[STORE_LOOKUP] = wrappedMap;
1323
+ Object.defineProperty(s, STORE_FIREWALL, {
1324
+ get() {
1325
+ return node;
1326
+ },
1327
+ configurable: true
1328
+ });
1329
+ };
1282
1330
  const wrapProjection = source => {
1283
1331
  if (wrappedMap.has(source)) return wrappedMap.get(source);
1284
1332
  if (source[$TARGET]?.[STORE_WRAP] === wrapProjection) return source;
1285
- const wrapped = createStoreProxy(source, storeTraps, {
1286
- [STORE_WRAP]: wrapProjection,
1287
- [STORE_LOOKUP]: wrappedMap,
1288
- [STORE_FIREWALL]() {
1289
- return node;
1290
- }
1291
- });
1333
+ const wrapped = createStoreProxy(source, storeTraps, wrapper);
1292
1334
  wrappedMap.set(source, wrapped);
1293
1335
  return wrapped;
1294
1336
  };
1295
1337
  const wrappedStore = wrapProjection(initialValue);
1296
1338
  node = computed(() => {
1297
- const owner = node || getOwner();
1298
- storeSetter(wrappedStore, s => {
1339
+ const owner = getOwner();
1340
+ storeSetter(new Proxy(wrappedStore, writeTraps), s => {
1299
1341
  const value = handleAsync(owner, fn(s), value => {
1300
- value !== s &&
1342
+ value !== wrappedStore &&
1301
1343
  value !== undefined &&
1302
1344
  storeSetter(wrappedStore, reconcile(value, options?.key || "id", options?.all));
1345
+ setSignal(owner, undefined);
1303
1346
  });
1304
- value !== s && value !== undefined && reconcile(value, options?.key || "id", options?.all)(s);
1347
+ value !== wrappedStore &&
1348
+ value !== undefined &&
1349
+ reconcile(value, options?.key || "id", options?.all)(wrappedStore);
1305
1350
  });
1306
1351
  });
1352
+ node._preventAutoDisposal = true;
1307
1353
  return { store: wrappedStore, node: node };
1308
1354
  }
1309
1355
  function createProjection(fn, initialValue = {}, options) {
1310
1356
  return createProjectionInternal(fn, initialValue, options).store;
1311
1357
  }
1358
+ const writeTraps = {
1359
+ get(_, prop) {
1360
+ let value;
1361
+ setWriteOverride(true);
1362
+ try {
1363
+ value = _[prop];
1364
+ } finally {
1365
+ setWriteOverride(false);
1366
+ }
1367
+ return typeof value === "object" && value !== null ? new Proxy(value, writeTraps) : value;
1368
+ },
1369
+ set(_, prop, value) {
1370
+ setWriteOverride(true);
1371
+ try {
1372
+ _[prop] = value;
1373
+ } finally {
1374
+ setWriteOverride(false);
1375
+ }
1376
+ return true;
1377
+ },
1378
+ deleteProperty(_, prop) {
1379
+ setWriteOverride(true);
1380
+ try {
1381
+ delete _[prop];
1382
+ } finally {
1383
+ setWriteOverride(false);
1384
+ }
1385
+ return true;
1386
+ }
1387
+ };
1312
1388
  const $TRACK = Symbol("STORE_TRACK"),
1313
1389
  $DEEP = Symbol("STORE_DEEP"),
1314
1390
  $TARGET = Symbol("STORE_TARGET"),
@@ -1328,7 +1404,7 @@ function createStoreProxy(value, traps = storeTraps, extend) {
1328
1404
  newTarget = [];
1329
1405
  newTarget.v = value;
1330
1406
  } else newTarget = { v: value };
1331
- extend && Object.assign(newTarget, extend);
1407
+ extend && extend(newTarget);
1332
1408
  return (newTarget[$PROXY] = new Proxy(newTarget, traps));
1333
1409
  }
1334
1410
  const storeLookup = new WeakMap();
@@ -1341,6 +1417,13 @@ function wrap(value, target) {
1341
1417
  function isWrappable(obj) {
1342
1418
  return obj != null && typeof obj === "object" && !Object.isFrozen(obj);
1343
1419
  }
1420
+ let writeOverride = false;
1421
+ function setWriteOverride(value) {
1422
+ writeOverride = value;
1423
+ }
1424
+ function writeOnly(proxy) {
1425
+ return writeOverride || !!Writing?.has(proxy);
1426
+ }
1344
1427
  function getNodes(target, type) {
1345
1428
  let nodes = target[type];
1346
1429
  if (!nodes) target[type] = nodes = Object.create(null);
@@ -1361,9 +1444,7 @@ function getNode(nodes, property, value, firewall, equals = isEqual) {
1361
1444
  }
1362
1445
  function trackSelf(target, symbol = $TRACK) {
1363
1446
  getObserver() &&
1364
- read(
1365
- getNode(getNodes(target, STORE_NODE), symbol, undefined, target[STORE_FIREWALL]?.(), false)
1366
- );
1447
+ read(getNode(getNodes(target, STORE_NODE), symbol, undefined, target[STORE_FIREWALL], false));
1367
1448
  }
1368
1449
  function getKeys(source, override, enumerable = true) {
1369
1450
  const baseKeys = untrack(() => (enumerable ? Object.keys(source) : Reflect.ownKeys(source)));
@@ -1389,6 +1470,7 @@ const storeTraps = {
1389
1470
  get(target, property, receiver) {
1390
1471
  if (property === $TARGET) return target;
1391
1472
  if (property === $PROXY) return receiver;
1473
+ if (property === $REFRESH) return target[STORE_FIREWALL];
1392
1474
  if (property === $TRACK || property === $DEEP) {
1393
1475
  trackSelf(target, property);
1394
1476
  return receiver;
@@ -1402,7 +1484,7 @@ const storeTraps = {
1402
1484
  const desc = Object.getOwnPropertyDescriptor(storeValue, property);
1403
1485
  if (desc && desc.get) return desc.get.call(receiver);
1404
1486
  }
1405
- if (Writing?.has(receiver)) {
1487
+ if (writeOnly(receiver)) {
1406
1488
  let value =
1407
1489
  tracked && (overridden || !proxySource)
1408
1490
  ? tracked._pendingValue !== NOT_PENDING
@@ -1412,7 +1494,7 @@ const storeTraps = {
1412
1494
  value === $DELETED && (value = undefined);
1413
1495
  if (!isWrappable(value)) return value;
1414
1496
  const wrapped = wrap(value, target);
1415
- Writing.add(wrapped);
1497
+ Writing?.add(wrapped);
1416
1498
  return wrapped;
1417
1499
  }
1418
1500
  let value = tracked
@@ -1435,7 +1517,7 @@ const storeTraps = {
1435
1517
  nodes,
1436
1518
  property,
1437
1519
  isWrappable(value) ? wrap(value, target) : value,
1438
- target[STORE_FIREWALL]?.()
1520
+ target[STORE_FIREWALL]
1439
1521
  )
1440
1522
  );
1441
1523
  }
@@ -1449,12 +1531,12 @@ const storeTraps = {
1449
1531
  ? target[STORE_OVERRIDE][property] !== $DELETED
1450
1532
  : property in target[STORE_VALUE];
1451
1533
  getObserver() &&
1452
- read(getNode(getNodes(target, STORE_HAS), property, has, target[STORE_FIREWALL]?.()));
1534
+ read(getNode(getNodes(target, STORE_HAS), property, has, target[STORE_FIREWALL]));
1453
1535
  return has;
1454
1536
  },
1455
1537
  set(target, property, rawValue) {
1456
1538
  const store = target[$PROXY];
1457
- if (Writing?.has(target[$PROXY])) {
1539
+ if (writeOnly(store)) {
1458
1540
  untrack(() => {
1459
1541
  const state = target[STORE_VALUE];
1460
1542
  const base = state[property];
@@ -1489,7 +1571,7 @@ const storeTraps = {
1489
1571
  return true;
1490
1572
  },
1491
1573
  deleteProperty(target, property) {
1492
- if (Writing?.has(target[$PROXY]) && target[STORE_OVERRIDE]?.[property] !== $DELETED) {
1574
+ if (writeOnly(target[$PROXY]) && target[STORE_OVERRIDE]?.[property] !== $DELETED) {
1493
1575
  untrack(() => {
1494
1576
  const prev =
1495
1577
  target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
@@ -2214,6 +2296,7 @@ export {
2214
2296
  NoOwnerError,
2215
2297
  NotReadyError,
2216
2298
  SUPPORTS_PROXY,
2299
+ action,
2217
2300
  createBoundary,
2218
2301
  createContext,
2219
2302
  createEffect,