@solidjs/signals 0.2.5 → 0.3.0

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
@@ -75,8 +75,8 @@ var Queue = class {
75
75
  for (let i = 0; i < this._children.length; i++) {
76
76
  rerun = this._children[i].run(type) || rerun;
77
77
  }
78
- if (type === EFFECT_PURE && this._queues[type].length)
79
- return true;
78
+ if (type === EFFECT_PURE)
79
+ return rerun || !!this._queues[type].length;
80
80
  }
81
81
  flush() {
82
82
  if (this._running)
@@ -138,6 +138,26 @@ function runEffectQueue(queue) {
138
138
  function isUndefined(value) {
139
139
  return typeof value === "undefined";
140
140
  }
141
+ function tryCatch(fn) {
142
+ try {
143
+ const v = fn();
144
+ if (v instanceof Promise) {
145
+ return v.then(
146
+ (v2) => [void 0, v2],
147
+ (e) => {
148
+ if (e instanceof NotReadyError)
149
+ throw e;
150
+ return [e];
151
+ }
152
+ );
153
+ }
154
+ return [void 0, v];
155
+ } catch (e) {
156
+ if (e instanceof NotReadyError)
157
+ throw e;
158
+ return [e];
159
+ }
160
+ }
141
161
 
142
162
  // src/core/owner.ts
143
163
  var currentOwner = null;
@@ -150,6 +170,10 @@ function setOwner(owner) {
150
170
  currentOwner = owner;
151
171
  return out;
152
172
  }
173
+ function formatId(prefix, id) {
174
+ const num = id.toString(36), len = num.length - 1;
175
+ return prefix + (len ? String.fromCharCode(64 + len) : "") + num;
176
+ }
153
177
  var Owner = class {
154
178
  // We flatten the owner tree into a linked list so that we don't need a pointer to .firstChild
155
179
  // However, the children are actually added in reverse creation order
@@ -162,13 +186,21 @@ var Owner = class {
162
186
  _context = defaultContext;
163
187
  _handlers = null;
164
188
  _queue = globalQueue;
165
- constructor(signal = false) {
166
- if (currentOwner && !signal)
189
+ _siblingCount = null;
190
+ _childCount = 0;
191
+ id = null;
192
+ constructor(id = null, skipAppend = false) {
193
+ this.id = id;
194
+ if (currentOwner && !skipAppend)
167
195
  currentOwner.append(this);
168
196
  }
169
197
  append(child) {
170
198
  child._parent = this;
171
199
  child._prevSibling = this;
200
+ if (this.id) {
201
+ child._siblingCount = this._nextSibling ? this._nextSibling._siblingCount + 1 : 0;
202
+ child.id = formatId(this.id, child._siblingCount);
203
+ }
172
204
  if (this._nextSibling)
173
205
  this._nextSibling._prevSibling = child;
174
206
  child._nextSibling = this._nextSibling;
@@ -223,6 +255,9 @@ var Owner = class {
223
255
  }
224
256
  this._disposal = null;
225
257
  }
258
+ addErrorHandler(handler) {
259
+ this._handlers = this._handlers ? [handler, ...this._handlers] : [handler];
260
+ }
226
261
  handleError(error) {
227
262
  if (!this._handlers)
228
263
  throw error;
@@ -238,6 +273,11 @@ var Owner = class {
238
273
  if (i === len)
239
274
  throw error;
240
275
  }
276
+ getNextChildId() {
277
+ if (this.id)
278
+ return formatId(this.id + "-", this._childCount++);
279
+ throw new Error("Cannot get child id from owner without an id");
280
+ }
241
281
  };
242
282
  function createContext(defaultValue, description) {
243
283
  return { id: Symbol(description), defaultValue };
@@ -316,11 +356,10 @@ var Computation = class extends Owner {
316
356
  _stateFlags = 0;
317
357
  /** Which flags raised by sources are handled, vs. being passed through. */
318
358
  _handlerMask = DEFAULT_FLAGS;
319
- _loading = null;
320
359
  _time = -1;
321
360
  _forceNotify = false;
322
361
  constructor(initialValue, compute2, options) {
323
- super(compute2 === null);
362
+ super(null, compute2 === null);
324
363
  this._compute = compute2;
325
364
  this._state = compute2 ? STATE_DIRTY : STATE_CLEAN;
326
365
  this._stateFlags = compute2 && initialValue === void 0 ? UNINITIALIZED_BIT : 0;
@@ -338,8 +377,7 @@ var Computation = class extends Owner {
338
377
  else
339
378
  this._updateIfNecessary();
340
379
  }
341
- if (!this._compute || this._sources?.length)
342
- track(this);
380
+ track(this);
343
381
  newFlags |= this._stateFlags & ~currentMask;
344
382
  if (this._stateFlags & ERROR_BIT) {
345
383
  throw this._error;
@@ -364,31 +402,22 @@ var Computation = class extends Owner {
364
402
  wait() {
365
403
  if (this._compute && this._stateFlags & ERROR_BIT && this._time <= getClock()) {
366
404
  update(this);
405
+ } else {
406
+ this._updateIfNecessary();
367
407
  }
368
- if ((notStale || this._stateFlags & UNINITIALIZED_BIT) && this.loading()) {
408
+ track(this);
409
+ if ((notStale || this._stateFlags & UNINITIALIZED_BIT) && this._stateFlags & LOADING_BIT) {
369
410
  throw new NotReadyError();
370
411
  }
371
- if (staleCheck && this.loading())
412
+ if (staleCheck && this._stateFlags & LOADING_BIT) {
372
413
  staleCheck._value = true;
373
- return this._read();
374
- }
375
- /**
376
- * Return true if the computation is the value is dependent on an unresolved promise
377
- * Triggers re-execution of the computation when the loading state changes
378
- *
379
- * This is useful especially when effects want to re-execute when a computation's
380
- * loading state changes
381
- */
382
- loading() {
383
- if (this._loading === null) {
384
- this._loading = loadingState(this);
385
414
  }
386
- return this._loading.read();
415
+ return this._read();
387
416
  }
388
417
  /** Update the computation with a new value. */
389
418
  write(value, flags = 0, raw = false) {
390
419
  const newValue = !raw && typeof value === "function" ? value(this._value) : value;
391
- const valueChanged = newValue !== UNCHANGED && (!!(this._stateFlags & UNINITIALIZED_BIT) || this._equals === false || !this._equals(this._value, newValue));
420
+ const valueChanged = newValue !== UNCHANGED && (!!(this._stateFlags & UNINITIALIZED_BIT) || this._stateFlags & LOADING_BIT & ~flags || this._equals === false || !this._equals(this._value, newValue));
392
421
  if (valueChanged) {
393
422
  this._value = newValue;
394
423
  this._error = void 0;
@@ -461,8 +490,11 @@ var Computation = class extends Owner {
461
490
  * This function will ensure that the value and states we read from the computation are up to date
462
491
  */
463
492
  _updateIfNecessary() {
493
+ if (!this._compute) {
494
+ return;
495
+ }
464
496
  if (this._state === STATE_DISPOSED) {
465
- throw new Error("Tried to read a disposed computation");
497
+ return;
466
498
  }
467
499
  if (this._state === STATE_CLEAN) {
468
500
  return;
@@ -495,22 +527,6 @@ var Computation = class extends Owner {
495
527
  super._disposeNode();
496
528
  }
497
529
  };
498
- function loadingState(node) {
499
- const prevOwner = setOwner(node._parent);
500
- const options = { name: node._name ? `loading ${node._name}` : "loading" } ;
501
- const computation = new Computation(
502
- void 0,
503
- () => {
504
- track(node);
505
- node._updateIfNecessary();
506
- return !!(node._stateFlags & LOADING_BIT);
507
- },
508
- options
509
- );
510
- computation._handlerMask = ERROR_BIT | LOADING_BIT;
511
- setOwner(prevOwner);
512
- return computation;
513
- }
514
530
  function track(computation) {
515
531
  if (currentObserver) {
516
532
  if (!newSources && currentObserver._sources && currentObserver._sources[newSourcesIndex] === computation) {
@@ -604,8 +620,7 @@ function hasUpdated(fn) {
604
620
  updateCheck = current;
605
621
  }
606
622
  }
607
- function isPending(fn, loadingValue) {
608
- const argLength = arguments.length;
623
+ function pendingCheck(fn, loadingValue) {
609
624
  const current = staleCheck;
610
625
  staleCheck = { _value: false };
611
626
  try {
@@ -614,13 +629,20 @@ function isPending(fn, loadingValue) {
614
629
  } catch (err) {
615
630
  if (!(err instanceof NotReadyError))
616
631
  return false;
617
- if (argLength > 1)
632
+ if (loadingValue !== void 0)
618
633
  return loadingValue;
619
634
  throw err;
620
635
  } finally {
621
636
  staleCheck = current;
622
637
  }
623
638
  }
639
+ function isPending(fn, loadingValue) {
640
+ if (!currentObserver)
641
+ return pendingCheck(fn, loadingValue);
642
+ const c = new Computation(void 0, () => pendingCheck(fn, loadingValue));
643
+ c._handlerMask |= LOADING_BIT;
644
+ return c.read();
645
+ }
624
646
  function latest(fn, fallback) {
625
647
  const argLength = arguments.length;
626
648
  const prevFlags = newFlags;
@@ -637,15 +659,6 @@ function latest(fn, fallback) {
637
659
  notStale = prevNotStale;
638
660
  }
639
661
  }
640
- function catchError(fn) {
641
- try {
642
- fn();
643
- } catch (e) {
644
- if (e instanceof NotReadyError)
645
- throw e;
646
- return e;
647
- }
648
- }
649
662
  function runWithObserver(observer, run) {
650
663
  const prevSources = newSources, prevSourcesIndex = newSourcesIndex, prevFlags = newFlags;
651
664
  newSources = null;
@@ -762,13 +775,6 @@ function flattenArray(children, results = [], options) {
762
775
  throw notReady;
763
776
  return needsUnwrap;
764
777
  }
765
- function createBoundary(fn, queue) {
766
- const owner = new Owner();
767
- const parentQueue = owner._queue;
768
- parentQueue.addChild(owner._queue = queue);
769
- onCleanup(() => parentQueue.removeChild(owner._queue));
770
- return compute(owner, fn, null);
771
- }
772
778
 
773
779
  // src/core/effect.ts
774
780
  var Effect = class extends Computation {
@@ -869,7 +875,7 @@ var EagerComputation = class extends Computation {
869
875
  };
870
876
  var ProjectionComputation = class extends Computation {
871
877
  constructor(compute2) {
872
- super(null, compute2);
878
+ super(void 0, compute2);
873
879
  if (!this._parent)
874
880
  console.warn("Eager Computations created outside a reactive context will never be disposed");
875
881
  }
@@ -882,52 +888,103 @@ var ProjectionComputation = class extends Computation {
882
888
  }
883
889
  };
884
890
 
885
- // src/core/suspense.ts
891
+ // src/core/boundaries.ts
892
+ function createBoundary(owner, fn, queue) {
893
+ if (queue) {
894
+ const parentQueue = owner._queue;
895
+ parentQueue.addChild(owner._queue = queue);
896
+ onCleanup(() => parentQueue.removeChild(owner._queue));
897
+ }
898
+ return compute(
899
+ owner,
900
+ () => {
901
+ const c = new Computation(void 0, fn);
902
+ return new EagerComputation(void 0, () => flatten(c.wait()), { defer: true });
903
+ },
904
+ null
905
+ );
906
+ }
907
+ function createDecision(main, condition, fallback) {
908
+ const decision = new Computation(void 0, () => {
909
+ if (!condition.read()) {
910
+ const resolved = main.read();
911
+ if (!condition.read())
912
+ return resolved;
913
+ }
914
+ return fallback();
915
+ });
916
+ return decision.read.bind(decision);
917
+ }
886
918
  var SuspenseQueue = class extends Queue {
887
919
  _nodes = /* @__PURE__ */ new Set();
888
- _fallback = false;
889
- _signal = new Computation(false, null);
920
+ _fallback = new Computation(false, null);
890
921
  run(type) {
891
- if (type && this._fallback)
922
+ if (type && this._fallback.read())
892
923
  return;
893
924
  return super.run(type);
894
925
  }
895
926
  _update(node) {
896
927
  if (node._stateFlags & LOADING_BIT) {
897
928
  this._nodes.add(node);
898
- if (!this._fallback) {
899
- this._fallback = true;
900
- this._signal.write(true);
901
- }
929
+ if (this._nodes.size === 1)
930
+ this._fallback.write(true);
902
931
  } else {
903
932
  this._nodes.delete(node);
904
- if (this._nodes.size === 0) {
905
- this._fallback = false;
906
- this._signal.write(false);
907
- }
933
+ if (this._nodes.size === 0)
934
+ this._fallback.write(false);
908
935
  }
909
936
  }
910
937
  };
911
- var LiveComputation = class extends EagerComputation {
912
- write(value, flags = 0) {
938
+ function createSuspense(fn, fallback) {
939
+ const owner = new Owner();
940
+ const queue = new SuspenseQueue();
941
+ const tree = createBoundary(owner, fn, queue);
942
+ const ogWrite = tree.write;
943
+ tree.write = function(value, flags = 0) {
913
944
  const currentFlags = this._stateFlags;
914
945
  const dirty = this._state === STATE_DIRTY;
915
- super.write(value, flags);
946
+ ogWrite.call(this, value, flags);
916
947
  if (dirty && (flags & LOADING_BIT) !== (currentFlags & LOADING_BIT)) {
917
948
  this._queue._update?.(this);
918
949
  }
919
950
  return this._value;
951
+ };
952
+ return createDecision(tree, queue._fallback, fallback);
953
+ }
954
+ function createErrorBoundary(fn, fallback) {
955
+ const owner = new Owner();
956
+ const error = new Computation(void 0, null);
957
+ const nodes = /* @__PURE__ */ new Set();
958
+ function handler(err, node) {
959
+ if (nodes.has(node))
960
+ return;
961
+ compute(
962
+ node,
963
+ () => onCleanup(() => {
964
+ nodes.delete(node);
965
+ if (!nodes.size)
966
+ error.write(void 0);
967
+ }),
968
+ null
969
+ );
970
+ nodes.add(node);
971
+ if (nodes.size === 1)
972
+ error.write({ _error: err });
920
973
  }
921
- };
922
- function createSuspense(fn, fallback) {
923
- const queue = new SuspenseQueue();
924
- const tree = createBoundary(() => {
925
- const child = new Computation(null, fn);
926
- return new LiveComputation(null, () => flatten(child.wait()));
927
- }, queue);
928
- const equality = new Computation(null, () => queue._signal.read() || queue._fallback);
929
- const comp = new Computation(null, () => equality.read() ? fallback() : tree.read());
930
- return comp.read.bind(comp);
974
+ owner.addErrorHandler(handler);
975
+ const tree = createBoundary(owner, fn);
976
+ tree._setError = tree.handleError;
977
+ return createDecision(
978
+ tree,
979
+ error,
980
+ () => fallback(error.read()._error, () => {
981
+ incrementClock();
982
+ for (let node of nodes) {
983
+ node._state = STATE_DIRTY;
984
+ node._queue?.enqueue(node._type, node);
985
+ }
986
+ })
987
+ );
931
988
  }
932
989
 
933
990
  // src/signals.ts
@@ -955,77 +1012,64 @@ function createMemo(compute2, value, options) {
955
1012
  let resolvedValue;
956
1013
  return () => {
957
1014
  if (node) {
1015
+ if (node._state === STATE_DISPOSED) {
1016
+ node = void 0;
1017
+ return resolvedValue;
1018
+ }
958
1019
  resolvedValue = node.wait();
959
1020
  if (!node._sources?.length && node._nextSibling?._parent !== node) {
960
1021
  node.dispose();
961
1022
  node = void 0;
962
- } else if (!node._parent && !node._observers?.length) {
963
- node.dispose();
964
- node._state = STATE_DIRTY;
965
1023
  }
966
1024
  }
967
1025
  return resolvedValue;
968
1026
  };
969
1027
  }
970
1028
  function createAsync(compute2, value, options) {
971
- let uninitialized = value === void 0;
972
- const lhs = new EagerComputation(
973
- {
974
- _value: value
975
- },
1029
+ const node = new EagerComputation(
1030
+ value,
976
1031
  (p) => {
977
- const value2 = p?._value;
978
- const source = compute2(value2);
1032
+ const source = compute2(p);
979
1033
  const isPromise = source instanceof Promise;
980
1034
  const iterator = source[Symbol.asyncIterator];
981
1035
  if (!isPromise && !iterator) {
982
- return {
983
- wait() {
984
- return source;
985
- },
986
- _value: source
987
- };
1036
+ return source;
988
1037
  }
989
- const signal = new Computation(value2, null, iterator ? { ...options, equals: false } : options);
990
- const w = signal.wait;
991
- signal.wait = function() {
992
- if (signal._stateFlags & ERROR_BIT && signal._time <= getClock()) {
993
- lhs._notify(STATE_DIRTY);
994
- throw new NotReadyError();
995
- }
996
- return w.call(this);
997
- };
998
- signal.write(UNCHANGED, LOADING_BIT | (uninitialized ? UNINITIALIZED_BIT : 0));
1038
+ let abort = false;
1039
+ onCleanup(() => abort = true);
999
1040
  if (isPromise) {
1000
1041
  source.then(
1001
1042
  (value3) => {
1002
- uninitialized = false;
1003
- signal.write(value3, 0, true);
1043
+ if (abort)
1044
+ return;
1045
+ node.write(value3, 0, true);
1004
1046
  },
1005
1047
  (error) => {
1006
- uninitialized = true;
1007
- signal._setError(error);
1048
+ if (abort)
1049
+ return;
1050
+ node._setError(error);
1008
1051
  }
1009
1052
  );
1010
1053
  } else {
1011
- let abort = false;
1012
- onCleanup(() => abort = true);
1013
1054
  (async () => {
1014
1055
  try {
1015
1056
  for await (let value3 of source) {
1016
1057
  if (abort)
1017
1058
  return;
1018
- signal.write(value3, 0, true);
1059
+ node.write(value3, 0, true);
1019
1060
  }
1020
1061
  } catch (error) {
1021
- signal.write(error, ERROR_BIT);
1062
+ if (abort)
1063
+ return;
1064
+ node.write(error, ERROR_BIT);
1022
1065
  }
1023
1066
  })();
1024
1067
  }
1025
- return signal;
1026
- }
1068
+ throw new NotReadyError();
1069
+ },
1070
+ options
1027
1071
  );
1028
- return () => lhs.wait().wait();
1072
+ return node.wait.bind(node);
1029
1073
  }
1030
1074
  function createEffect(compute2, effect, error, value, options) {
1031
1075
  void new Effect(
@@ -1042,62 +1086,13 @@ function createRenderEffect(compute2, effect, value, options) {
1042
1086
  ...{ ...options, name: options?.name ?? "effect" }
1043
1087
  });
1044
1088
  }
1045
- function createRoot(init) {
1046
- const owner = new Owner();
1089
+ function createRoot(init, options) {
1090
+ const owner = new Owner(options?.id);
1047
1091
  return compute(owner, !init.length ? init : () => init(() => owner.dispose()), null);
1048
1092
  }
1049
1093
  function runWithOwner(owner, run) {
1050
1094
  return compute(owner, run, null);
1051
1095
  }
1052
- function createErrorBoundary(fn, fallback) {
1053
- const owner = new Owner();
1054
- const error = new Computation(void 0, null);
1055
- const nodes = /* @__PURE__ */ new Set();
1056
- function handler(err, node) {
1057
- if (nodes.has(node))
1058
- return;
1059
- compute(
1060
- node,
1061
- () => onCleanup(() => {
1062
- nodes.delete(node);
1063
- if (!nodes.size)
1064
- error.write(void 0);
1065
- }),
1066
- null
1067
- );
1068
- nodes.add(node);
1069
- if (nodes.size === 1)
1070
- error.write({ _error: err });
1071
- }
1072
- owner._handlers = owner._handlers ? [handler, ...owner._handlers] : [handler];
1073
- const guarded = compute(
1074
- owner,
1075
- () => {
1076
- const c = new Computation(void 0, fn);
1077
- const f = new EagerComputation(void 0, () => flatten(c.read()), { defer: true });
1078
- f._setError = function(error2) {
1079
- this.handleError(error2);
1080
- };
1081
- return f;
1082
- },
1083
- null
1084
- );
1085
- const decision = new Computation(null, () => {
1086
- if (!error.read()) {
1087
- const resolved = guarded.read();
1088
- if (!error.read())
1089
- return resolved;
1090
- }
1091
- return fallback(error.read()._error, () => {
1092
- incrementClock();
1093
- for (let node of nodes) {
1094
- node._state = STATE_DIRTY;
1095
- node._queue?.enqueue(node._type, node);
1096
- }
1097
- });
1098
- });
1099
- return decision.read.bind(decision);
1100
- }
1101
1096
  function resolve(fn) {
1102
1097
  return new Promise((res, rej) => {
1103
1098
  createRoot((dispose) => {
@@ -1848,4 +1843,4 @@ function compare(key, a, b) {
1848
1843
  return key ? key(a) === key(b) : true;
1849
1844
  }
1850
1845
 
1851
- export { $PROXY, $RAW, $TARGET, $TRACK, Computation, ContextNotFoundError, NoOwnerError, NotReadyError, Owner, Queue, SUPPORTS_PROXY, catchError, createAsync, createBoundary, createContext, createEffect, createErrorBoundary, createMemo, createProjection, createRenderEffect, createRoot, createSignal, createStore, createSuspense, deep, flatten, flushSync, getContext, getObserver, getOwner, hasContext, hasUpdated, isEqual, isPending, isWrappable, latest, mapArray, merge, omit, onCleanup, reconcile, repeat, resolve, runWithObserver, runWithOwner, setContext, untrack, unwrap };
1846
+ export { $PROXY, $RAW, $TARGET, $TRACK, Computation, ContextNotFoundError, NoOwnerError, NotReadyError, Owner, Queue, SUPPORTS_PROXY, createAsync, createContext, createEffect, createErrorBoundary, createMemo, createProjection, createRenderEffect, createRoot, createSignal, createStore, createSuspense, deep, flatten, flushSync, getContext, getObserver, getOwner, hasContext, hasUpdated, isEqual, isPending, isWrappable, latest, mapArray, merge, omit, onCleanup, reconcile, repeat, resolve, runWithObserver, runWithOwner, setContext, tryCatch, untrack, unwrap };