@solidjs/signals 0.13.6 → 0.13.7

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.
Files changed (4) hide show
  1. package/dist/dev.js +255 -207
  2. package/dist/node.cjs +335 -305
  3. package/dist/prod.js +326 -296
  4. package/package.json +1 -1
package/dist/dev.js CHANGED
@@ -655,6 +655,209 @@ function assignOrMergeLane(el, sourceLane) {
655
655
  }
656
656
  el._optimisticLane = sourceLane;
657
657
  }
658
+ function unlinkSubs(link) {
659
+ const dep = link._dep;
660
+ const nextDep = link._nextDep;
661
+ const nextSub = link._nextSub;
662
+ const prevSub = link._prevSub;
663
+ if (nextSub !== null) nextSub._prevSub = prevSub;
664
+ else dep._subsTail = prevSub;
665
+ if (prevSub !== null) prevSub._nextSub = nextSub;
666
+ else {
667
+ dep._subs = nextSub;
668
+ if (nextSub === null) {
669
+ dep._unobserved?.();
670
+ dep._fn && !dep._preventAutoDisposal && !(dep._flags & REACTIVE_ZOMBIE) && unobserved(dep);
671
+ }
672
+ }
673
+ return nextDep;
674
+ }
675
+ function unobserved(el) {
676
+ deleteFromHeap(el, el._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
677
+ let dep = el._deps;
678
+ while (dep !== null) {
679
+ dep = unlinkSubs(dep);
680
+ }
681
+ el._deps = null;
682
+ disposeChildren(el, true);
683
+ }
684
+ function link(dep, sub) {
685
+ const prevDep = sub._depsTail;
686
+ if (prevDep !== null && prevDep._dep === dep) return;
687
+ let nextDep = null;
688
+ const isRecomputing = sub._flags & REACTIVE_RECOMPUTING_DEPS;
689
+ if (isRecomputing) {
690
+ nextDep = prevDep !== null ? prevDep._nextDep : sub._deps;
691
+ if (nextDep !== null && nextDep._dep === dep) {
692
+ sub._depsTail = nextDep;
693
+ return;
694
+ }
695
+ }
696
+ const prevSub = dep._subsTail;
697
+ if (prevSub !== null && prevSub._sub === sub && (!isRecomputing || isValidLink(prevSub, sub)))
698
+ return;
699
+ const newLink =
700
+ (sub._depsTail =
701
+ dep._subsTail =
702
+ { _dep: dep, _sub: sub, _nextDep: nextDep, _prevSub: prevSub, _nextSub: null });
703
+ if (prevDep !== null) prevDep._nextDep = newLink;
704
+ else sub._deps = newLink;
705
+ if (prevSub !== null) prevSub._nextSub = newLink;
706
+ else dep._subs = newLink;
707
+ }
708
+ function isValidLink(checkLink, sub) {
709
+ const depsTail = sub._depsTail;
710
+ if (depsTail !== null) {
711
+ let link = sub._deps;
712
+ do {
713
+ if (link === checkLink) return true;
714
+ if (link === depsTail) break;
715
+ link = link._nextDep;
716
+ } while (link !== null);
717
+ }
718
+ return false;
719
+ }
720
+ const PENDING_OWNER = {};
721
+ function markDisposal(el) {
722
+ let child = el._firstChild;
723
+ while (child) {
724
+ child._flags |= REACTIVE_ZOMBIE;
725
+ if (child._flags & REACTIVE_IN_HEAP) {
726
+ deleteFromHeap(child, dirtyQueue);
727
+ insertIntoHeap(child, zombieQueue);
728
+ }
729
+ markDisposal(child);
730
+ child = child._nextSibling;
731
+ }
732
+ }
733
+ function dispose(node) {
734
+ let toRemove = node._deps || null;
735
+ do {
736
+ toRemove = unlinkSubs(toRemove);
737
+ } while (toRemove !== null);
738
+ node._deps = null;
739
+ node._depsTail = null;
740
+ disposeChildren(node, true);
741
+ }
742
+ function disposeChildren(node, self = false, zombie) {
743
+ if (node._flags & REACTIVE_DISPOSED) return;
744
+ if (self) node._flags = REACTIVE_DISPOSED;
745
+ if (self && node._fn) node._inFlight = null;
746
+ let child = zombie ? node._pendingFirstChild : node._firstChild;
747
+ while (child) {
748
+ const nextChild = child._nextSibling;
749
+ if (child._deps) {
750
+ const n = child;
751
+ deleteFromHeap(n, n._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
752
+ let toRemove = n._deps;
753
+ do {
754
+ toRemove = unlinkSubs(toRemove);
755
+ } while (toRemove !== null);
756
+ n._deps = null;
757
+ n._depsTail = null;
758
+ }
759
+ disposeChildren(child, true);
760
+ child = nextChild;
761
+ }
762
+ if (zombie) {
763
+ node._pendingFirstChild = null;
764
+ } else {
765
+ node._firstChild = null;
766
+ node._childCount = 0;
767
+ }
768
+ runDisposal(node, zombie);
769
+ }
770
+ function runDisposal(node, zombie) {
771
+ let disposal = zombie ? node._pendingDisposal : node._disposal;
772
+ if (!disposal) return;
773
+ if (Array.isArray(disposal)) {
774
+ for (let i = 0; i < disposal.length; i++) {
775
+ const callable = disposal[i];
776
+ callable.call(callable);
777
+ }
778
+ } else {
779
+ disposal.call(disposal);
780
+ }
781
+ zombie ? (node._pendingDisposal = null) : (node._disposal = null);
782
+ }
783
+ function childId(owner, consume) {
784
+ let counter = owner;
785
+ while (counter._transparent && counter._parent) counter = counter._parent;
786
+ if (counter.id != null)
787
+ return formatId(counter.id, consume ? counter._childCount++ : counter._childCount);
788
+ throw new Error("Cannot get child id from owner without an id");
789
+ }
790
+ function getNextChildId(owner) {
791
+ return childId(owner, true);
792
+ }
793
+ function peekNextChildId(owner) {
794
+ return childId(owner, false);
795
+ }
796
+ function formatId(prefix, id) {
797
+ const num = id.toString(36),
798
+ len = num.length - 1;
799
+ return prefix + (len ? String.fromCharCode(64 + len) : "") + num;
800
+ }
801
+ function getObserver() {
802
+ if (pendingCheckActive || latestReadActive) return PENDING_OWNER;
803
+ return tracking ? context : null;
804
+ }
805
+ function getOwner() {
806
+ return context;
807
+ }
808
+ function cleanup(fn) {
809
+ if (!context) return fn;
810
+ if (!context._disposal) context._disposal = fn;
811
+ else if (Array.isArray(context._disposal)) context._disposal.push(fn);
812
+ else context._disposal = [context._disposal, fn];
813
+ return fn;
814
+ }
815
+ function isDisposed(node) {
816
+ return !!(node._flags & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE));
817
+ }
818
+ function createOwner(options) {
819
+ const parent = context;
820
+ const transparent = options?.transparent ?? false;
821
+ const owner = {
822
+ id:
823
+ options?.id ??
824
+ (transparent ? parent?.id : parent?.id != null ? getNextChildId(parent) : undefined),
825
+ _transparent: transparent || undefined,
826
+ _root: true,
827
+ _parentComputed: parent?._root ? parent._parentComputed : parent,
828
+ _firstChild: null,
829
+ _nextSibling: null,
830
+ _disposal: null,
831
+ _queue: parent?._queue ?? globalQueue,
832
+ _context: parent?._context || defaultContext,
833
+ _childCount: 0,
834
+ _pendingDisposal: null,
835
+ _pendingFirstChild: null,
836
+ _parent: parent,
837
+ dispose(self = true) {
838
+ disposeChildren(owner, self);
839
+ }
840
+ };
841
+ if (parent?._childrenForbidden) {
842
+ throw new Error(
843
+ "Cannot create reactive primitives inside createTrackedEffect or owner-backed onSettled"
844
+ );
845
+ }
846
+ if (parent) {
847
+ const lastChild = parent._firstChild;
848
+ if (lastChild === null) {
849
+ parent._firstChild = owner;
850
+ } else {
851
+ owner._nextSibling = lastChild;
852
+ parent._firstChild = owner;
853
+ }
854
+ }
855
+ return owner;
856
+ }
857
+ function createRoot(init, options) {
858
+ const owner = createOwner(options);
859
+ return runWithOwner(owner, () => init(owner.dispose));
860
+ }
658
861
  function addPendingSource(el, source) {
659
862
  if (el._pendingSource === source || el._pendingSources?.has(source)) return false;
660
863
  if (!el._pendingSource) {
@@ -819,6 +1022,17 @@ function handleAsync(el, result, setter) {
819
1022
  if (iterator) {
820
1023
  const it = result[Symbol.asyncIterator]();
821
1024
  let hadSyncValue = false;
1025
+ let completed = false;
1026
+ cleanup(() => {
1027
+ if (completed) return;
1028
+ completed = true;
1029
+ try {
1030
+ const returned = it.return?.();
1031
+ if (returned && typeof returned.then === "function") {
1032
+ returned.then(undefined, () => {});
1033
+ }
1034
+ } catch {}
1035
+ });
822
1036
  const iterate = () => {
823
1037
  let syncResult,
824
1038
  resolved = false,
@@ -828,14 +1042,21 @@ function handleAsync(el, result, setter) {
828
1042
  if (isSync) {
829
1043
  syncResult = r;
830
1044
  resolved = true;
1045
+ if (r.done) completed = true;
1046
+ } else if (el._inFlight !== result) {
1047
+ return;
831
1048
  } else if (!r.done) asyncWrite(r.value, iterate);
832
1049
  else {
1050
+ completed = true;
833
1051
  schedule();
834
1052
  flush();
835
1053
  }
836
1054
  },
837
1055
  e => {
838
- if (!isSync) handleError(e);
1056
+ if (!isSync && el._inFlight === result) {
1057
+ completed = true;
1058
+ handleError(e);
1059
+ }
839
1060
  }
840
1061
  );
841
1062
  isSync = false;
@@ -942,208 +1163,6 @@ function enableExternalSource(config) {
942
1163
  externalSourceConfig = { factory: factory, untrack: untrackFn };
943
1164
  }
944
1165
  }
945
- const PENDING_OWNER = {};
946
- function markDisposal(el) {
947
- let child = el._firstChild;
948
- while (child) {
949
- child._flags |= REACTIVE_ZOMBIE;
950
- if (child._flags & REACTIVE_IN_HEAP) {
951
- deleteFromHeap(child, dirtyQueue);
952
- insertIntoHeap(child, zombieQueue);
953
- }
954
- markDisposal(child);
955
- child = child._nextSibling;
956
- }
957
- }
958
- function dispose(node) {
959
- let toRemove = node._deps || null;
960
- do {
961
- toRemove = unlinkSubs(toRemove);
962
- } while (toRemove !== null);
963
- node._deps = null;
964
- node._depsTail = null;
965
- disposeChildren(node, true);
966
- }
967
- function disposeChildren(node, self = false, zombie) {
968
- if (node._flags & REACTIVE_DISPOSED) return;
969
- if (self) node._flags = REACTIVE_DISPOSED;
970
- let child = zombie ? node._pendingFirstChild : node._firstChild;
971
- while (child) {
972
- const nextChild = child._nextSibling;
973
- if (child._deps) {
974
- const n = child;
975
- deleteFromHeap(n, n._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
976
- let toRemove = n._deps;
977
- do {
978
- toRemove = unlinkSubs(toRemove);
979
- } while (toRemove !== null);
980
- n._deps = null;
981
- n._depsTail = null;
982
- }
983
- disposeChildren(child, true);
984
- child = nextChild;
985
- }
986
- if (zombie) {
987
- node._pendingFirstChild = null;
988
- } else {
989
- node._firstChild = null;
990
- node._childCount = 0;
991
- }
992
- runDisposal(node, zombie);
993
- }
994
- function runDisposal(node, zombie) {
995
- let disposal = zombie ? node._pendingDisposal : node._disposal;
996
- if (!disposal) return;
997
- if (Array.isArray(disposal)) {
998
- for (let i = 0; i < disposal.length; i++) {
999
- const callable = disposal[i];
1000
- callable.call(callable);
1001
- }
1002
- } else {
1003
- disposal.call(disposal);
1004
- }
1005
- zombie ? (node._pendingDisposal = null) : (node._disposal = null);
1006
- }
1007
- function childId(owner, consume) {
1008
- let counter = owner;
1009
- while (counter._transparent && counter._parent) counter = counter._parent;
1010
- if (counter.id != null)
1011
- return formatId(counter.id, consume ? counter._childCount++ : counter._childCount);
1012
- throw new Error("Cannot get child id from owner without an id");
1013
- }
1014
- function getNextChildId(owner) {
1015
- return childId(owner, true);
1016
- }
1017
- function peekNextChildId(owner) {
1018
- return childId(owner, false);
1019
- }
1020
- function formatId(prefix, id) {
1021
- const num = id.toString(36),
1022
- len = num.length - 1;
1023
- return prefix + (len ? String.fromCharCode(64 + len) : "") + num;
1024
- }
1025
- function getObserver() {
1026
- if (pendingCheckActive || latestReadActive) return PENDING_OWNER;
1027
- return tracking ? context : null;
1028
- }
1029
- function getOwner() {
1030
- return context;
1031
- }
1032
- function cleanup(fn) {
1033
- if (!context) return fn;
1034
- if (!context._disposal) context._disposal = fn;
1035
- else if (Array.isArray(context._disposal)) context._disposal.push(fn);
1036
- else context._disposal = [context._disposal, fn];
1037
- return fn;
1038
- }
1039
- function isDisposed(node) {
1040
- return !!(node._flags & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE));
1041
- }
1042
- function createOwner(options) {
1043
- const parent = context;
1044
- const transparent = options?.transparent ?? false;
1045
- const owner = {
1046
- id:
1047
- options?.id ??
1048
- (transparent ? parent?.id : parent?.id != null ? getNextChildId(parent) : undefined),
1049
- _transparent: transparent || undefined,
1050
- _root: true,
1051
- _parentComputed: parent?._root ? parent._parentComputed : parent,
1052
- _firstChild: null,
1053
- _nextSibling: null,
1054
- _disposal: null,
1055
- _queue: parent?._queue ?? globalQueue,
1056
- _context: parent?._context || defaultContext,
1057
- _childCount: 0,
1058
- _pendingDisposal: null,
1059
- _pendingFirstChild: null,
1060
- _parent: parent,
1061
- dispose(self = true) {
1062
- disposeChildren(owner, self);
1063
- }
1064
- };
1065
- if (parent?._childrenForbidden) {
1066
- throw new Error(
1067
- "Cannot create reactive primitives inside createTrackedEffect or owner-backed onSettled"
1068
- );
1069
- }
1070
- if (parent) {
1071
- const lastChild = parent._firstChild;
1072
- if (lastChild === null) {
1073
- parent._firstChild = owner;
1074
- } else {
1075
- owner._nextSibling = lastChild;
1076
- parent._firstChild = owner;
1077
- }
1078
- }
1079
- return owner;
1080
- }
1081
- function createRoot(init, options) {
1082
- const owner = createOwner(options);
1083
- return runWithOwner(owner, () => init(owner.dispose));
1084
- }
1085
- function unlinkSubs(link) {
1086
- const dep = link._dep;
1087
- const nextDep = link._nextDep;
1088
- const nextSub = link._nextSub;
1089
- const prevSub = link._prevSub;
1090
- if (nextSub !== null) nextSub._prevSub = prevSub;
1091
- else dep._subsTail = prevSub;
1092
- if (prevSub !== null) prevSub._nextSub = nextSub;
1093
- else {
1094
- dep._subs = nextSub;
1095
- if (nextSub === null) {
1096
- dep._unobserved?.();
1097
- dep._fn && !dep._preventAutoDisposal && !(dep._flags & REACTIVE_ZOMBIE) && unobserved(dep);
1098
- }
1099
- }
1100
- return nextDep;
1101
- }
1102
- function unobserved(el) {
1103
- deleteFromHeap(el, el._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
1104
- let dep = el._deps;
1105
- while (dep !== null) {
1106
- dep = unlinkSubs(dep);
1107
- }
1108
- el._deps = null;
1109
- disposeChildren(el, true);
1110
- }
1111
- function link(dep, sub) {
1112
- const prevDep = sub._depsTail;
1113
- if (prevDep !== null && prevDep._dep === dep) return;
1114
- let nextDep = null;
1115
- const isRecomputing = sub._flags & REACTIVE_RECOMPUTING_DEPS;
1116
- if (isRecomputing) {
1117
- nextDep = prevDep !== null ? prevDep._nextDep : sub._deps;
1118
- if (nextDep !== null && nextDep._dep === dep) {
1119
- sub._depsTail = nextDep;
1120
- return;
1121
- }
1122
- }
1123
- const prevSub = dep._subsTail;
1124
- if (prevSub !== null && prevSub._sub === sub && (!isRecomputing || isValidLink(prevSub, sub)))
1125
- return;
1126
- const newLink =
1127
- (sub._depsTail =
1128
- dep._subsTail =
1129
- { _dep: dep, _sub: sub, _nextDep: nextDep, _prevSub: prevSub, _nextSub: null });
1130
- if (prevDep !== null) prevDep._nextDep = newLink;
1131
- else sub._deps = newLink;
1132
- if (prevSub !== null) prevSub._nextSub = newLink;
1133
- else dep._subs = newLink;
1134
- }
1135
- function isValidLink(checkLink, sub) {
1136
- const depsTail = sub._depsTail;
1137
- if (depsTail !== null) {
1138
- let link = sub._deps;
1139
- do {
1140
- if (link === checkLink) return true;
1141
- if (link === depsTail) break;
1142
- link = link._nextDep;
1143
- } while (link !== null);
1144
- }
1145
- return false;
1146
- }
1147
1166
  GlobalQueue._update = recompute;
1148
1167
  GlobalQueue._dispose = disposeChildren;
1149
1168
  let tracking = false;
@@ -1212,6 +1231,7 @@ function recompute(el, create = false) {
1212
1231
  if (el._transition && (!isEffect || activeTransition) && activeTransition !== el._transition)
1213
1232
  globalQueue.initTransition(el._transition);
1214
1233
  deleteFromHeap(el, el._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
1234
+ el._inFlight = null;
1215
1235
  if (el._transition || isEffect === EFFECT_TRACKED) disposeChildren(el);
1216
1236
  else {
1217
1237
  markDisposal(el);
@@ -1516,6 +1536,11 @@ function read(el) {
1516
1536
  ) {
1517
1537
  foundPending = true;
1518
1538
  }
1539
+ let c = context;
1540
+ if (c?._root) c = c._parentComputed;
1541
+ if (c && tracking) link(el, c);
1542
+ read(getPendingSignal(el));
1543
+ read(getPendingSignal(firewall));
1519
1544
  } else {
1520
1545
  if (read(getPendingSignal(el))) foundPending = true;
1521
1546
  if (firewall && read(getPendingSignal(firewall))) foundPending = true;
@@ -1890,7 +1915,13 @@ function runEffect() {
1890
1915
  this._cleanup?.();
1891
1916
  this._cleanup = undefined;
1892
1917
  try {
1893
- this._cleanup = this._effectFn(this._value, this._prevValue);
1918
+ const cleanup = this._effectFn(this._value, this._prevValue);
1919
+ if (true && cleanup !== undefined && typeof cleanup !== "function") {
1920
+ throw new Error(
1921
+ `${this._name || "effect"} callback returned an invalid cleanup value. Return a cleanup function or undefined.`
1922
+ );
1923
+ }
1924
+ this._cleanup = cleanup;
1894
1925
  } catch (error) {
1895
1926
  this._error = new StatusError(this, error);
1896
1927
  this._statusFlags |= STATUS_ERROR;
@@ -1916,7 +1947,13 @@ function trackedEffect(fn, options) {
1916
1947
  () => {
1917
1948
  node._cleanup?.();
1918
1949
  node._cleanup = undefined;
1919
- node._cleanup = staleValues(fn) || undefined;
1950
+ const cleanup = staleValues(fn);
1951
+ if (cleanup !== undefined && typeof cleanup !== "function") {
1952
+ throw new Error(
1953
+ `${node._name || "trackedEffect"} callback returned an invalid cleanup value. Return a cleanup function or undefined.`
1954
+ );
1955
+ }
1956
+ node._cleanup = cleanup;
1920
1957
  },
1921
1958
  undefined,
1922
1959
  { ...options, lazy: true }
@@ -2036,7 +2073,13 @@ function createReaction(effectFn, options) {
2036
2073
  () => (tracking(), getOwner()),
2037
2074
  node => {
2038
2075
  cl?.();
2039
- cl = (effectFn.effect || effectFn)?.();
2076
+ const cleanup = (effectFn.effect || effectFn)?.();
2077
+ if (true && cleanup !== undefined && typeof cleanup !== "function") {
2078
+ throw new Error(
2079
+ "Reaction callback returned an invalid cleanup value. Return a cleanup function or undefined."
2080
+ );
2081
+ }
2082
+ cl = cleanup;
2040
2083
  dispose(node);
2041
2084
  },
2042
2085
  effectFn.error,
@@ -2076,9 +2119,14 @@ function createOptimistic(first, second, third) {
2076
2119
  function onSettled(callback) {
2077
2120
  const owner = getOwner();
2078
2121
  owner && !owner._childrenForbidden
2079
- ? createTrackedEffect(() => untrack(callback))
2122
+ ? createTrackedEffect(() => untrack(callback), { name: "onSettled" })
2080
2123
  : globalQueue.enqueue(EFFECT_USER, () => {
2081
2124
  const cleanup = callback();
2125
+ if (cleanup !== undefined && typeof cleanup !== "function") {
2126
+ throw new Error(
2127
+ "onSettled callback returned an invalid cleanup value. Return a cleanup function or undefined."
2128
+ );
2129
+ }
2082
2130
  cleanup?.();
2083
2131
  });
2084
2132
  }