valdres 1.0.0-beta.4 → 1.0.0-beta.5
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/index.js +210 -54
- package/dist/types/lib/IS_PROD.d.ts +1 -0
- package/dist/types/lib/atomFamilyIndex.d.ts +1 -0
- package/dist/types/lib/propagateUpdatedAtoms.d.ts +4 -4
- package/dist/types/lib/transaction.d.ts +1 -0
- package/dist/types/lib/writeAtoms.d.ts +21 -0
- package/dist/types/types/Subscription.d.ts +7 -0
- package/dist/types/utils/deepFreeze.d.ts +1 -1
- package/package.json +1 -1
- package/dist/types/lib/isProd.d.ts +0 -1
package/dist/index.js
CHANGED
|
@@ -123,17 +123,18 @@ var isPromiseLike = (object) => {
|
|
|
123
123
|
};
|
|
124
124
|
|
|
125
125
|
// src/utils/deepFreeze.ts
|
|
126
|
-
var deepFreeze = (obj, seen
|
|
126
|
+
var deepFreeze = (obj, seen) => {
|
|
127
127
|
if (obj === null || obj === undefined)
|
|
128
128
|
return obj;
|
|
129
129
|
if (typeof obj !== "object" && typeof obj !== "function")
|
|
130
130
|
return obj;
|
|
131
|
-
if (
|
|
131
|
+
if (Object.isFrozen(obj) || seen?.has(obj))
|
|
132
132
|
return obj;
|
|
133
|
-
seen.add(obj);
|
|
134
133
|
if (Array.isArray(obj)) {
|
|
135
134
|
for (const item of obj) {
|
|
136
135
|
if (item && typeof item === "object") {
|
|
136
|
+
seen ??= new WeakSet;
|
|
137
|
+
seen.add(obj);
|
|
137
138
|
deepFreeze(item, seen);
|
|
138
139
|
}
|
|
139
140
|
}
|
|
@@ -142,6 +143,8 @@ var deepFreeze = (obj, seen = new WeakSet) => {
|
|
|
142
143
|
for (const name of propNames) {
|
|
143
144
|
const value = obj[name];
|
|
144
145
|
if (value && typeof value === "object") {
|
|
146
|
+
seen ??= new WeakSet;
|
|
147
|
+
seen.add(obj);
|
|
145
148
|
deepFreeze(value, seen);
|
|
146
149
|
}
|
|
147
150
|
}
|
|
@@ -149,10 +152,8 @@ var deepFreeze = (obj, seen = new WeakSet) => {
|
|
|
149
152
|
return Object.freeze(obj);
|
|
150
153
|
};
|
|
151
154
|
|
|
152
|
-
// src/lib/
|
|
153
|
-
var
|
|
154
|
-
return false;
|
|
155
|
-
};
|
|
155
|
+
// src/lib/IS_PROD.ts
|
|
156
|
+
var IS_PROD = typeof process !== "undefined" && process.env != null && process.env.NODE_ENV === "production";
|
|
156
157
|
|
|
157
158
|
// src/lib/setValueInData.ts
|
|
158
159
|
var trackScopeValue = (key, data) => {
|
|
@@ -172,7 +173,7 @@ var trackScopeValue = (key, data) => {
|
|
|
172
173
|
var setValueInData = (atom, value, data) => {
|
|
173
174
|
const isNewAtomInScope = data.parent && Object.hasOwn(atom, "defaultValue") && !data.values.has(atom);
|
|
174
175
|
let written;
|
|
175
|
-
if (atom.mutable ||
|
|
176
|
+
if (atom.mutable || IS_PROD) {
|
|
176
177
|
data.values.set(atom, value);
|
|
177
178
|
written = value;
|
|
178
179
|
} else {
|
|
@@ -180,8 +181,14 @@ var setValueInData = (atom, value, data) => {
|
|
|
180
181
|
data.values.set(atom, frozenValue);
|
|
181
182
|
written = frozenValue;
|
|
182
183
|
}
|
|
183
|
-
if (isNewAtomInScope)
|
|
184
|
+
if (isNewAtomInScope) {
|
|
184
185
|
trackScopeValue(atom, data);
|
|
186
|
+
const subs = data.subscriptions.get(atom);
|
|
187
|
+
if (subs) {
|
|
188
|
+
for (const sub of subs)
|
|
189
|
+
sub.reRoot?.();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
185
192
|
if (atom.maxAge !== undefined) {
|
|
186
193
|
data.lastValueWriteAt.set(atom, Date.now());
|
|
187
194
|
}
|
|
@@ -275,8 +282,10 @@ var recursivelyUpdateIndexes = (data, family) => {
|
|
|
275
282
|
const childScopesWithFamily = data.scopeValueIndex.get(family);
|
|
276
283
|
if (!childScopesWithFamily || childScopesWithFamily.size === 0)
|
|
277
284
|
return;
|
|
285
|
+
const parentIndex = data.values.get(family).__index;
|
|
278
286
|
for (const scopedData of childScopesWithFamily) {
|
|
279
287
|
const index = scopedData.values.get(family).__index;
|
|
288
|
+
index.parentIndex = parentIndex;
|
|
280
289
|
index.rendered = null;
|
|
281
290
|
index.renderedArray = null;
|
|
282
291
|
scopedData.values.set(family, renderAtomFamilyIndex(index));
|
|
@@ -672,7 +681,7 @@ var addSetToSet = (fromSet, toSet) => {
|
|
|
672
681
|
}
|
|
673
682
|
}
|
|
674
683
|
};
|
|
675
|
-
var propagateDeletedAtoms = (atoms, data, subscriptions = new Set, families = new Map, timestamp = performance.now()) => {
|
|
684
|
+
var propagateDeletedAtoms = (atoms, data, subscriptions = new Set, families = new Map, timestamp = performance.now(), evaluatedSelectors) => {
|
|
676
685
|
const selectors = new Set;
|
|
677
686
|
for (const atom of atoms) {
|
|
678
687
|
addSetToSet(data.stateDependents.get(atom), selectors);
|
|
@@ -693,7 +702,7 @@ var propagateDeletedAtoms = (atoms, data, subscriptions = new Set, families = ne
|
|
|
693
702
|
deleteFamilyAtomsFromSet(family, familyAtoms, data, timestamp);
|
|
694
703
|
}
|
|
695
704
|
}
|
|
696
|
-
propagateDirtySelectors(atoms, selectors, data, subscriptions, families);
|
|
705
|
+
propagateDirtySelectors(atoms, selectors, data, subscriptions, families, false, evaluatedSelectors);
|
|
697
706
|
if (families.size > 0 && data.scopes && data.scopes.size > 0) {
|
|
698
707
|
const scopeFamilies = new Map;
|
|
699
708
|
for (const family of families.keys()) {
|
|
@@ -710,11 +719,11 @@ var propagateDeletedAtoms = (atoms, data, subscriptions = new Set, families = ne
|
|
|
710
719
|
}
|
|
711
720
|
}
|
|
712
721
|
for (const [scope, familiesInScope] of scopeFamilies) {
|
|
713
|
-
propagateInScope(familiesInScope, scope);
|
|
722
|
+
propagateInScope(familiesInScope, scope, false, evaluatedSelectors);
|
|
714
723
|
}
|
|
715
724
|
}
|
|
716
725
|
};
|
|
717
|
-
var propagateAtomUpdate = (atoms, data, isInitOnly = false) => {
|
|
726
|
+
var propagateAtomUpdate = (atoms, data, isInitOnly = false, evaluatedSelectors) => {
|
|
718
727
|
if (atoms.length === 1) {
|
|
719
728
|
const atom = atoms[0];
|
|
720
729
|
if (!isFamilyAtom(atom) && !isAtomFamily(atom)) {
|
|
@@ -751,30 +760,37 @@ var propagateAtomUpdate = (atoms, data, isInitOnly = false) => {
|
|
|
751
760
|
addFamilyAtomsToSet(family, familyAtoms, data, timestamp);
|
|
752
761
|
}
|
|
753
762
|
}
|
|
754
|
-
propagateDirtySelectors(atoms, selectors, data, subscriptions, families, isInitOnly);
|
|
755
763
|
if (data.scopes && data.scopes.size > 0) {
|
|
756
|
-
|
|
764
|
+
for (const atom of atoms) {
|
|
765
|
+
if (isAtomFamily(atom) && !families.has(atom)) {
|
|
766
|
+
recursivelyUpdateIndexes(data, atom);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
propagateDirtySelectors(atoms, selectors, data, subscriptions, families, isInitOnly, evaluatedSelectors);
|
|
771
|
+
if (data.scopes && data.scopes.size > 0) {
|
|
772
|
+
propagateToScopes(atoms, data, isInitOnly, evaluatedSelectors);
|
|
757
773
|
}
|
|
758
774
|
};
|
|
759
|
-
var propagateInScope = (atoms, data, isInitOnly = false) => {
|
|
775
|
+
var propagateInScope = (atoms, data, isInitOnly = false, evaluatedSelectors) => {
|
|
760
776
|
const subscriptions = new Set;
|
|
761
777
|
const families = new Map;
|
|
762
778
|
const selectors = new Set;
|
|
763
779
|
for (const atom of atoms) {
|
|
764
780
|
addSetToSet(data.stateDependents.get(atom), selectors);
|
|
765
781
|
}
|
|
766
|
-
propagateDirtySelectors(atoms, selectors, data, subscriptions, families, isInitOnly);
|
|
782
|
+
propagateDirtySelectors(atoms, selectors, data, subscriptions, families, isInitOnly, evaluatedSelectors);
|
|
767
783
|
if (data.scopes && data.scopes.size > 0) {
|
|
768
|
-
propagateToScopes(atoms, data, isInitOnly);
|
|
784
|
+
propagateToScopes(atoms, data, isInitOnly, evaluatedSelectors);
|
|
769
785
|
}
|
|
770
786
|
};
|
|
771
|
-
var propagateToScopes = (atoms, data, isInitOnly) => {
|
|
787
|
+
var propagateToScopes = (atoms, data, isInitOnly, evaluatedSelectors) => {
|
|
772
788
|
if (atoms.length === 1) {
|
|
773
789
|
const atom = atoms[0];
|
|
774
790
|
const shadowingScopes = isAtomFamily(atom) ? undefined : data.scopeValueIndex.get(atom);
|
|
775
791
|
for (const [, scope] of data.scopes) {
|
|
776
792
|
if (!shadowingScopes || !shadowingScopes.has(scope)) {
|
|
777
|
-
propagateInScope(atoms, scope, isInitOnly);
|
|
793
|
+
propagateInScope(atoms, scope, isInitOnly, evaluatedSelectors);
|
|
778
794
|
}
|
|
779
795
|
}
|
|
780
796
|
return;
|
|
@@ -794,7 +810,7 @@ var propagateToScopes = (atoms, data, isInitOnly) => {
|
|
|
794
810
|
}
|
|
795
811
|
if (!anyShadowed) {
|
|
796
812
|
for (const [, scope] of data.scopes) {
|
|
797
|
-
propagateInScope(atoms, scope, isInitOnly);
|
|
813
|
+
propagateInScope(atoms, scope, isInitOnly, evaluatedSelectors);
|
|
798
814
|
}
|
|
799
815
|
return;
|
|
800
816
|
}
|
|
@@ -811,20 +827,20 @@ var propagateToScopes = (atoms, data, isInitOnly) => {
|
|
|
811
827
|
}
|
|
812
828
|
}
|
|
813
829
|
if (atomsToUpdateInScope.length > 0) {
|
|
814
|
-
propagateInScope(atomsToUpdateInScope, scope, isInitOnly);
|
|
830
|
+
propagateInScope(atomsToUpdateInScope, scope, isInitOnly, evaluatedSelectors);
|
|
815
831
|
}
|
|
816
832
|
}
|
|
817
833
|
};
|
|
818
|
-
var propagateDirtySelectors = (updatedAtoms, selectors, data, subscriptions, families, isInitOnly = false) => {
|
|
834
|
+
var propagateDirtySelectors = (updatedAtoms, selectors, data, subscriptions, families, isInitOnly = false, evaluatedSelectors) => {
|
|
819
835
|
const updatedInitializedAtoms = new Set(updatedAtoms);
|
|
820
836
|
if (selectors.size > 0) {
|
|
821
|
-
propagateSelectorUpdates(selectors, data, subscriptions, updatedInitializedAtoms, isInitOnly);
|
|
837
|
+
propagateSelectorUpdates(selectors, data, subscriptions, updatedInitializedAtoms, isInitOnly, evaluatedSelectors);
|
|
822
838
|
}
|
|
823
839
|
if (subscriptions.size > 0) {
|
|
824
840
|
callSubscribers(subscriptions, families);
|
|
825
841
|
}
|
|
826
842
|
};
|
|
827
|
-
var propagateDownstreamTopo = (seeds, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly) => {
|
|
843
|
+
var propagateDownstreamTopo = (seeds, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly, evaluatedSelectors) => {
|
|
828
844
|
const closure = new Set(seeds);
|
|
829
845
|
{
|
|
830
846
|
const stack = [...seeds];
|
|
@@ -857,13 +873,22 @@ var propagateDownstreamTopo = (seeds, data, collectedSubscribers, updatedInitial
|
|
|
857
873
|
ready.push(s);
|
|
858
874
|
}
|
|
859
875
|
const needsEval = new Set(seeds);
|
|
876
|
+
let graphMutated = false;
|
|
860
877
|
const advance = (selector, propagateChange) => {
|
|
861
878
|
const downstream = data.stateDependents.get(selector);
|
|
862
879
|
if (!downstream)
|
|
863
880
|
return;
|
|
864
881
|
for (const d of downstream) {
|
|
865
|
-
if (!closure.has(d))
|
|
882
|
+
if (!closure.has(d)) {
|
|
883
|
+
if (propagateChange) {
|
|
884
|
+
graphMutated = true;
|
|
885
|
+
closure.add(d);
|
|
886
|
+
pending.set(d, 0);
|
|
887
|
+
needsEval.add(d);
|
|
888
|
+
ready.push(d);
|
|
889
|
+
}
|
|
866
890
|
continue;
|
|
891
|
+
}
|
|
867
892
|
const c = (pending.get(d) ?? 0) - 1;
|
|
868
893
|
pending.set(d, c);
|
|
869
894
|
if (propagateChange)
|
|
@@ -876,6 +901,10 @@ var propagateDownstreamTopo = (seeds, data, collectedSubscribers, updatedInitial
|
|
|
876
901
|
let head = 0;
|
|
877
902
|
while (head < ready.length) {
|
|
878
903
|
const selector = ready[head++];
|
|
904
|
+
if (evaluatedSelectors !== undefined && evaluatedSelectors.has(selector)) {
|
|
905
|
+
advance(selector, false);
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
879
908
|
const currentValue = data.values.get(selector);
|
|
880
909
|
if (isPromiseLike(currentValue) && isInitOnly) {
|
|
881
910
|
advance(selector, false);
|
|
@@ -895,19 +924,24 @@ var propagateDownstreamTopo = (seeds, data, collectedSubscribers, updatedInitial
|
|
|
895
924
|
depsChange.added = undefined;
|
|
896
925
|
depsChange.removed = undefined;
|
|
897
926
|
const wasValueUpdated = reEvaluateSelector(selector, data, updatedInitializedAtoms, depsChange, currentValue);
|
|
927
|
+
if (evaluatedSelectors !== undefined)
|
|
928
|
+
evaluatedSelectors.add(selector);
|
|
898
929
|
const added = depsChange.added;
|
|
899
930
|
const removed = depsChange.removed;
|
|
900
|
-
if (
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
931
|
+
if (added || removed) {
|
|
932
|
+
graphMutated = true;
|
|
933
|
+
if (isLive(selector, data)) {
|
|
934
|
+
if (added) {
|
|
935
|
+
for (const dep of added) {
|
|
936
|
+
onLiveDependencyAdded(dep, data);
|
|
937
|
+
mountTransitiveDeps(dep, data);
|
|
938
|
+
}
|
|
905
939
|
}
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
940
|
+
if (removed) {
|
|
941
|
+
for (const dep of removed) {
|
|
942
|
+
onLiveDependencyRemoved(dep, data);
|
|
943
|
+
unmountOrphanedDeps(dep, data);
|
|
944
|
+
}
|
|
911
945
|
}
|
|
912
946
|
}
|
|
913
947
|
}
|
|
@@ -916,13 +950,74 @@ var propagateDownstreamTopo = (seeds, data, collectedSubscribers, updatedInitial
|
|
|
916
950
|
addSetToSet(subscribers, collectedSubscribers);
|
|
917
951
|
}
|
|
918
952
|
}
|
|
953
|
+
if (!graphMutated)
|
|
954
|
+
return;
|
|
955
|
+
let stranded;
|
|
956
|
+
for (const s of closure) {
|
|
957
|
+
if (needsEval.has(s) && (pending.get(s) ?? 0) > 0) {
|
|
958
|
+
if (!stranded)
|
|
959
|
+
stranded = new Set;
|
|
960
|
+
stranded.add(s);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
if (!stranded)
|
|
964
|
+
return;
|
|
965
|
+
let work = stranded;
|
|
966
|
+
while (work.size > 0) {
|
|
967
|
+
const next = new Set;
|
|
968
|
+
for (const selector of work) {
|
|
969
|
+
const currentValue = data.values.get(selector);
|
|
970
|
+
if (isPromiseLike(currentValue) && isInitOnly)
|
|
971
|
+
continue;
|
|
972
|
+
const dependents = data.stateDependents.get(selector);
|
|
973
|
+
const subscribers = data.subscriptions.get(selector);
|
|
974
|
+
if (!isPromiseLike(currentValue) && (!dependents || dependents.size === 0) && (!subscribers || subscribers.size === 0)) {
|
|
975
|
+
data.values.delete(selector);
|
|
976
|
+
continue;
|
|
977
|
+
}
|
|
978
|
+
depsChange.added = undefined;
|
|
979
|
+
depsChange.removed = undefined;
|
|
980
|
+
const wasValueUpdated = reEvaluateSelector(selector, data, updatedInitializedAtoms, depsChange, currentValue);
|
|
981
|
+
if (evaluatedSelectors !== undefined)
|
|
982
|
+
evaluatedSelectors.add(selector);
|
|
983
|
+
const added = depsChange.added;
|
|
984
|
+
const removed = depsChange.removed;
|
|
985
|
+
if ((added || removed) && isLive(selector, data)) {
|
|
986
|
+
if (added) {
|
|
987
|
+
for (const dep of added) {
|
|
988
|
+
onLiveDependencyAdded(dep, data);
|
|
989
|
+
mountTransitiveDeps(dep, data);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
if (removed) {
|
|
993
|
+
for (const dep of removed) {
|
|
994
|
+
onLiveDependencyRemoved(dep, data);
|
|
995
|
+
unmountOrphanedDeps(dep, data);
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
if (wasValueUpdated) {
|
|
1000
|
+
if (subscribers)
|
|
1001
|
+
addSetToSet(subscribers, collectedSubscribers);
|
|
1002
|
+
const downstream = data.stateDependents.get(selector);
|
|
1003
|
+
if (downstream) {
|
|
1004
|
+
for (const d of downstream)
|
|
1005
|
+
next.add(d);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
work = next;
|
|
1010
|
+
}
|
|
919
1011
|
};
|
|
920
|
-
var propagateSelectorUpdates = (selectors, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly = false) => {
|
|
1012
|
+
var propagateSelectorUpdates = (selectors, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly = false, evaluatedSelectors) => {
|
|
921
1013
|
if (selectors.size === 0)
|
|
922
1014
|
return;
|
|
923
1015
|
let downstreamSeeds;
|
|
924
1016
|
const depsChange = {};
|
|
925
1017
|
for (const selector of selectors) {
|
|
1018
|
+
if (evaluatedSelectors !== undefined && evaluatedSelectors.has(selector)) {
|
|
1019
|
+
continue;
|
|
1020
|
+
}
|
|
926
1021
|
const currentValue = data.values.get(selector);
|
|
927
1022
|
if (isPromiseLike(currentValue) && isInitOnly)
|
|
928
1023
|
continue;
|
|
@@ -935,6 +1030,8 @@ var propagateSelectorUpdates = (selectors, data, collectedSubscribers, updatedIn
|
|
|
935
1030
|
depsChange.added = undefined;
|
|
936
1031
|
depsChange.removed = undefined;
|
|
937
1032
|
const wasValueUpdated = reEvaluateSelector(selector, data, updatedInitializedAtoms, depsChange, currentValue);
|
|
1033
|
+
if (evaluatedSelectors !== undefined)
|
|
1034
|
+
evaluatedSelectors.add(selector);
|
|
938
1035
|
const added = depsChange.added;
|
|
939
1036
|
const removed = depsChange.removed;
|
|
940
1037
|
if ((added || removed) && isLive(selector, data)) {
|
|
@@ -964,7 +1061,7 @@ var propagateSelectorUpdates = (selectors, data, collectedSubscribers, updatedIn
|
|
|
964
1061
|
}
|
|
965
1062
|
}
|
|
966
1063
|
if (downstreamSeeds && downstreamSeeds.size > 0) {
|
|
967
|
-
propagateDownstreamTopo(downstreamSeeds, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly);
|
|
1064
|
+
propagateDownstreamTopo(downstreamSeeds, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly, evaluatedSelectors);
|
|
968
1065
|
}
|
|
969
1066
|
};
|
|
970
1067
|
|
|
@@ -1504,14 +1601,18 @@ var installMaxAgeTimer = (state, data) => {
|
|
|
1504
1601
|
};
|
|
1505
1602
|
var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) => {
|
|
1506
1603
|
let parentUnsubscribe;
|
|
1604
|
+
let dropDelegate;
|
|
1507
1605
|
if (data.parent && (!data.values.has(state) && isAtom(state) || isAtomFamily(state))) {
|
|
1508
1606
|
const originalCallback = callback;
|
|
1509
1607
|
parentUnsubscribe = subscribe(state, originalCallback, requireDeepEqualCheckBeforeCallback, data.parent);
|
|
1510
|
-
|
|
1608
|
+
dropDelegate = () => {
|
|
1511
1609
|
if (parentUnsubscribe) {
|
|
1512
1610
|
parentUnsubscribe();
|
|
1513
1611
|
parentUnsubscribe = undefined;
|
|
1514
1612
|
}
|
|
1613
|
+
};
|
|
1614
|
+
callback = (arg) => {
|
|
1615
|
+
dropDelegate();
|
|
1515
1616
|
originalCallback(arg);
|
|
1516
1617
|
};
|
|
1517
1618
|
} else if (!data.values.has(state) && isAtom(state)) {
|
|
@@ -1533,12 +1634,14 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
|
|
|
1533
1634
|
subscription = {
|
|
1534
1635
|
callback,
|
|
1535
1636
|
state,
|
|
1536
|
-
requireDeepEqualCheckBeforeCallback
|
|
1637
|
+
requireDeepEqualCheckBeforeCallback,
|
|
1638
|
+
reRoot: dropDelegate
|
|
1537
1639
|
};
|
|
1538
1640
|
} else {
|
|
1539
1641
|
subscription = {
|
|
1540
1642
|
callback,
|
|
1541
|
-
requireDeepEqualCheckBeforeCallback
|
|
1643
|
+
requireDeepEqualCheckBeforeCallback,
|
|
1644
|
+
reRoot: dropDelegate
|
|
1542
1645
|
};
|
|
1543
1646
|
}
|
|
1544
1647
|
subscribers.add(subscription);
|
|
@@ -1562,8 +1665,8 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
|
|
|
1562
1665
|
};
|
|
1563
1666
|
};
|
|
1564
1667
|
|
|
1565
|
-
// src/lib/
|
|
1566
|
-
var
|
|
1668
|
+
// src/lib/writeAtoms.ts
|
|
1669
|
+
var writeAtoms = (pairs, data, initializedAtomsSet, skipOnSet = false, onSetQueue) => {
|
|
1567
1670
|
const updatedAtoms = [];
|
|
1568
1671
|
for (let [atom, value] of pairs) {
|
|
1569
1672
|
const currentValue = getState(atom, data, initializedAtomsSet);
|
|
@@ -1571,8 +1674,12 @@ var setAtoms = (pairs, data, initializedAtomsSet, skipOnSet = false) => {
|
|
|
1571
1674
|
if (!areEqual) {
|
|
1572
1675
|
updatedAtoms.push(atom);
|
|
1573
1676
|
value = setValueInData(atom, value, data);
|
|
1574
|
-
if (atom.onSet && !skipOnSet)
|
|
1575
|
-
|
|
1677
|
+
if (atom.onSet && !skipOnSet) {
|
|
1678
|
+
if (onSetQueue)
|
|
1679
|
+
onSetQueue.push([atom, value, data]);
|
|
1680
|
+
else
|
|
1681
|
+
atom.onSet(value, data);
|
|
1682
|
+
}
|
|
1576
1683
|
} else {
|
|
1577
1684
|
setValueInData(atom, value, data);
|
|
1578
1685
|
}
|
|
@@ -1582,6 +1689,12 @@ var setAtoms = (pairs, data, initializedAtomsSet, skipOnSet = false) => {
|
|
|
1582
1689
|
updatedAtoms.push(atom);
|
|
1583
1690
|
}
|
|
1584
1691
|
}
|
|
1692
|
+
return updatedAtoms;
|
|
1693
|
+
};
|
|
1694
|
+
|
|
1695
|
+
// src/lib/setAtoms.ts
|
|
1696
|
+
var setAtoms = (pairs, data, initializedAtomsSet, skipOnSet = false) => {
|
|
1697
|
+
const updatedAtoms = writeAtoms(pairs, data, initializedAtomsSet, skipOnSet);
|
|
1585
1698
|
if (updatedAtoms.length > 0) {
|
|
1586
1699
|
propagateAtomUpdate(updatedAtoms, data);
|
|
1587
1700
|
}
|
|
@@ -1671,7 +1784,7 @@ class Transaction {
|
|
|
1671
1784
|
} else {
|
|
1672
1785
|
resolved = value;
|
|
1673
1786
|
}
|
|
1674
|
-
if (!atom.mutable && !
|
|
1787
|
+
if (!atom.mutable && !IS_PROD && resolved !== null && (typeof resolved === "object" || typeof resolved === "function")) {
|
|
1675
1788
|
resolved = deepFreeze(resolved);
|
|
1676
1789
|
}
|
|
1677
1790
|
this._atomMap.set(atom, resolved);
|
|
@@ -1761,15 +1874,58 @@ class Transaction {
|
|
|
1761
1874
|
}
|
|
1762
1875
|
};
|
|
1763
1876
|
commit = () => {
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1877
|
+
if (!this._scopedTransactions) {
|
|
1878
|
+
const initializedAtomsSet = new Set;
|
|
1879
|
+
if (this._deleteSet?.size) {
|
|
1880
|
+
const evaluatedSelectors2 = new Set;
|
|
1881
|
+
const updatedAtoms = writeAtoms(this._atomMap, this.data, initializedAtomsSet);
|
|
1882
|
+
if (updatedAtoms.length > 0) {
|
|
1883
|
+
propagateAtomUpdate(updatedAtoms, this.data, false, evaluatedSelectors2);
|
|
1884
|
+
}
|
|
1885
|
+
deleteAtomFamilyAtoms(this._deleteSet, this.data);
|
|
1886
|
+
propagateDeletedAtoms([...this._deleteSet], this.data, undefined, undefined, undefined, evaluatedSelectors2);
|
|
1887
|
+
} else {
|
|
1888
|
+
setAtoms(this._atomMap, this.data, initializedAtomsSet);
|
|
1889
|
+
}
|
|
1890
|
+
return;
|
|
1891
|
+
}
|
|
1892
|
+
const plan = [];
|
|
1893
|
+
this.collectStores(plan);
|
|
1894
|
+
for (let i = plan.length - 1;i >= 0; i--) {
|
|
1895
|
+
const entry = plan[i];
|
|
1896
|
+
const txn = entry.txn;
|
|
1897
|
+
entry.updatedAtoms = writeAtoms(txn._atomMap, entry.data, new Set, false, entry.onSets);
|
|
1898
|
+
if (txn._deleteSet?.size) {
|
|
1899
|
+
deleteAtomFamilyAtoms(txn._deleteSet, entry.data);
|
|
1900
|
+
entry.deleted = [...txn._deleteSet];
|
|
1901
|
+
}
|
|
1769
1902
|
}
|
|
1903
|
+
for (const entry of plan) {
|
|
1904
|
+
for (const [atom, value, data] of entry.onSets) {
|
|
1905
|
+
atom.onSet(value, data);
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
const evaluatedSelectors = new Set;
|
|
1909
|
+
for (const { data, updatedAtoms, deleted } of plan) {
|
|
1910
|
+
if (updatedAtoms.length > 0) {
|
|
1911
|
+
propagateAtomUpdate(updatedAtoms, data, false, evaluatedSelectors);
|
|
1912
|
+
}
|
|
1913
|
+
if (deleted) {
|
|
1914
|
+
propagateDeletedAtoms(deleted, data, undefined, undefined, undefined, evaluatedSelectors);
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
};
|
|
1918
|
+
collectStores = (plan) => {
|
|
1919
|
+
plan.push({
|
|
1920
|
+
txn: this,
|
|
1921
|
+
data: this.data,
|
|
1922
|
+
updatedAtoms: [],
|
|
1923
|
+
deleted: undefined,
|
|
1924
|
+
onSets: []
|
|
1925
|
+
});
|
|
1770
1926
|
if (this._scopedTransactions) {
|
|
1771
1927
|
for (const [, scopedTxn] of this._scopedTransactions) {
|
|
1772
|
-
scopedTxn.
|
|
1928
|
+
scopedTxn.collectStores(plan);
|
|
1773
1929
|
}
|
|
1774
1930
|
}
|
|
1775
1931
|
};
|
|
@@ -2592,9 +2748,9 @@ var isFamilySelector = (state) => isFamilyState(state) && isSelector(state);
|
|
|
2592
2748
|
|
|
2593
2749
|
// src/index.ts
|
|
2594
2750
|
if (globalThis.__valdres__) {
|
|
2595
|
-
throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${"1.0.0-beta.
|
|
2751
|
+
throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${"1.0.0-beta.5"}`);
|
|
2596
2752
|
} else {
|
|
2597
|
-
globalThis.__valdres__ = "1.0.0-beta.
|
|
2753
|
+
globalThis.__valdres__ = "1.0.0-beta.5";
|
|
2598
2754
|
}
|
|
2599
2755
|
export {
|
|
2600
2756
|
store,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const IS_PROD: boolean;
|
|
@@ -14,4 +14,5 @@ export type AtomFamilyIndex = {
|
|
|
14
14
|
export declare const cloneAtomFamilyIndex: (index: AtomFamilyIndex, parentIndexOverride?: AtomFamilyIndex) => AtomFamilyIndex;
|
|
15
15
|
export declare const createAtomFamilyIndex: (parentIndex?: AtomFamilyIndex) => AtomFamilyIndex;
|
|
16
16
|
export declare const deleteFamilyAtomsFromSet: (family: Family<any>, familyAtoms: Set<AtomFamilyAtom<any>>, data: StoreData, timestamp: number) => void;
|
|
17
|
+
export declare const recursivelyUpdateIndexes: (data: StoreData, family: Family<any>) => void;
|
|
17
18
|
export declare const addFamilyAtomsToSet: (family: Family<any>, familyAtoms: Set<AtomFamilyAtom<any>>, data: StoreData, timestamp: number) => void;
|
|
@@ -7,7 +7,7 @@ import type { Subscription } from "../types/Subscription";
|
|
|
7
7
|
export type { AtomFamilyIndex, } from "./atomFamilyIndex";
|
|
8
8
|
export { cloneAtomFamilyIndex, createAtomFamilyIndex, renderAtomFamilyIndex, } from "./atomFamilyIndex";
|
|
9
9
|
type AtomInput = Atom<any> | AtomFamilyAtom<any, any> | AtomFamily<any, any>;
|
|
10
|
-
export declare const propagateDeletedAtoms: (atoms: AtomFamilyAtom<any, any>[], data: StoreData, subscriptions?: Set<Subscription>, families?: Map<AtomFamily<any>, Set<AtomFamilyAtom<any>>>, timestamp?: number) => void;
|
|
11
|
-
export declare const propagateAtomUpdate: (atoms: AtomInput[], data: StoreData, isInitOnly?: boolean) => void;
|
|
12
|
-
export declare const propagateInScope: (atoms: AtomInput[], data: StoreData, isInitOnly?: boolean) => void;
|
|
13
|
-
export declare const propagateDirtySelectors: (updatedAtoms: Atom[], selectors: Set<Selector>, data: StoreData, subscriptions: Set<Subscription>, families: Map<AtomFamily<any>, Set<AtomFamilyAtom<any>>>, isInitOnly?: boolean) => void;
|
|
10
|
+
export declare const propagateDeletedAtoms: (atoms: AtomFamilyAtom<any, any>[], data: StoreData, subscriptions?: Set<Subscription>, families?: Map<AtomFamily<any>, Set<AtomFamilyAtom<any>>>, timestamp?: number, evaluatedSelectors?: Set<Selector>) => void;
|
|
11
|
+
export declare const propagateAtomUpdate: (atoms: AtomInput[], data: StoreData, isInitOnly?: boolean, evaluatedSelectors?: Set<Selector>) => void;
|
|
12
|
+
export declare const propagateInScope: (atoms: AtomInput[], data: StoreData, isInitOnly?: boolean, evaluatedSelectors?: Set<Selector>) => void;
|
|
13
|
+
export declare const propagateDirtySelectors: (updatedAtoms: Atom[], selectors: Set<Selector>, data: StoreData, subscriptions: Set<Subscription>, families: Map<AtomFamily<any>, Set<AtomFamilyAtom<any>>>, isInitOnly?: boolean, evaluatedSelectors?: Set<Selector>) => void;
|
|
@@ -26,6 +26,7 @@ export declare class Transaction {
|
|
|
26
26
|
execute: (callback: TransactionFn, autoCommit?: boolean) => any;
|
|
27
27
|
private txnCommit;
|
|
28
28
|
commit: () => void;
|
|
29
|
+
private collectStores;
|
|
29
30
|
private get selectorCache();
|
|
30
31
|
private get selectorDependencies();
|
|
31
32
|
private get deleteSet();
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Atom } from "../types/Atom";
|
|
2
|
+
import type { StoreData } from "../types/StoreData";
|
|
3
|
+
/** A deferred onSet invocation: the hook, the written value, and the store it
|
|
4
|
+
* was written to. Collected during the write phase of a cross-scope commit so
|
|
5
|
+
* hooks fire only once the whole tree has been written. */
|
|
6
|
+
export type DeferredOnSet = [Atom<any>, any, StoreData];
|
|
7
|
+
/**
|
|
8
|
+
* Write phase for a single store. Applies every value in `pairs` to
|
|
9
|
+
* `data.values`, returning the atoms whose value actually changed (the
|
|
10
|
+
* propagation set), merged with any atoms lazily initialized during the
|
|
11
|
+
* equality checks. This does NOT propagate — see `setAtoms` (single-store
|
|
12
|
+
* fast path) or `Transaction.commit` (cross-scope path) for the notify pass.
|
|
13
|
+
*
|
|
14
|
+
* onSet handling:
|
|
15
|
+
* - `skipOnSet` true → never fire onSet.
|
|
16
|
+
* - `onSetQueue` given → defer onSet by pushing `[atom, value, data]`. The
|
|
17
|
+
* cross-scope commit uses this so a hook never observes a half-applied
|
|
18
|
+
* transaction — it fires only after every store's writes have landed.
|
|
19
|
+
* - otherwise → fire onSet inline (single-store path, unchanged).
|
|
20
|
+
*/
|
|
21
|
+
export declare const writeAtoms: (pairs: Map<Atom<any>, any>, data: StoreData, initializedAtomsSet: Set<Atom>, skipOnSet?: boolean, onSetQueue?: DeferredOnSet[]) => Atom[];
|
|
@@ -3,9 +3,16 @@ export type AtomFamilySubscription<Value extends any = any, Args extends [any, .
|
|
|
3
3
|
state: AtomFamily<Value, Args>;
|
|
4
4
|
callback: (...args: Args) => void;
|
|
5
5
|
requireDeepEqualCheckBeforeCallback: boolean;
|
|
6
|
+
/** Present only on a scope subscription that is delegating to an ancestor.
|
|
7
|
+
* Drops the ancestor delegate (idempotent). Called eagerly when the scope
|
|
8
|
+
* shadows the state so an ancestor write in the same transaction commit
|
|
9
|
+
* does not also notify this subscription. */
|
|
10
|
+
reRoot?: () => void;
|
|
6
11
|
};
|
|
7
12
|
export type SimpleSubscription = {
|
|
8
13
|
requireDeepEqualCheckBeforeCallback: boolean;
|
|
9
14
|
callback: () => void;
|
|
15
|
+
/** See AtomFamilySubscription.reRoot. */
|
|
16
|
+
reRoot?: () => void;
|
|
10
17
|
};
|
|
11
18
|
export type Subscription = SimpleSubscription | AtomFamilySubscription;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const deepFreeze: (obj: any, seen?: WeakSet<
|
|
1
|
+
export declare const deepFreeze: (obj: any, seen?: WeakSet<object>) => any;
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const isProd: () => boolean;
|