valdres 0.2.0-y.0 → 1.0.0-beta.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/index.js +1869 -515
- package/dist/types/atomFamily.d.ts +3 -0
- package/dist/types/cacheMeta.d.ts +4 -0
- package/dist/types/errors/SelectorCircularDependencyError.d.ts +5 -0
- package/dist/types/errors/SelectorEvaluationError.d.ts +7 -0
- package/dist/types/errors/lib/generateSelectorTrace.d.ts +2 -0
- package/dist/types/{src/index.d.ts → index.d.ts} +8 -2
- package/dist/types/indexConstructor.d.ts +5 -0
- package/dist/types/lib/asyncDependencyTracking.d.ts +25 -0
- package/dist/types/lib/atomFamilyIndex.d.ts +17 -0
- package/dist/types/lib/createAtomFamily.d.ts +4 -0
- package/dist/types/lib/createGlobalAtomFamily.d.ts +4 -0
- package/dist/types/{src/lib → lib}/createStoreData.d.ts +5 -2
- package/dist/types/lib/deleteFamilyAtom.d.ts +3 -0
- package/dist/types/lib/equal.d.ts +1 -0
- package/dist/types/lib/familyKey.d.ts +2 -0
- package/dist/types/lib/getState.d.ts +8 -0
- package/dist/types/lib/initAtom.d.ts +5 -0
- package/dist/types/lib/initSelector.d.ts +24 -0
- package/dist/types/lib/isFunction.d.ts +1 -0
- package/dist/types/lib/isProd.d.ts +1 -0
- package/dist/types/lib/maxAgeCleanups.d.ts +4 -0
- package/dist/types/lib/mountAtom.d.ts +36 -0
- package/dist/types/lib/propagateUpdatedAtoms.d.ts +11 -0
- package/dist/types/{src/lib → lib}/setAtom.d.ts +2 -1
- package/dist/types/{src/lib → lib}/setAtoms.d.ts +1 -1
- package/dist/types/lib/setValueInData.d.ts +7 -0
- package/dist/types/lib/stringifyFamilyArgs.d.ts +1 -0
- package/dist/types/{src/lib → lib}/subscribe.d.ts +2 -0
- package/dist/types/lib/transaction.d.ts +37 -0
- package/dist/types/{src/lib → lib}/unsubscribe.d.ts +1 -1
- package/dist/types/selector.d.ts +4 -0
- package/dist/types/selectorFamily.d.ts +4 -0
- package/dist/types/store.d.ts +6 -0
- package/dist/types/types/Atom.d.ts +29 -0
- package/dist/types/types/AtomFamily.d.ts +11 -0
- package/dist/types/types/AtomFamilyAtom.d.ts +7 -0
- package/dist/types/types/AtomFamilyDefaultValue.d.ts +5 -0
- package/dist/types/types/AtomFamilySelector.d.ts +6 -0
- package/dist/types/types/AtomOnInit.d.ts +9 -0
- package/dist/types/types/AtomOnMount.d.ts +14 -0
- package/dist/types/types/AtomOptions.d.ts +15 -0
- package/dist/types/types/EqualFunc.d.ts +3 -0
- package/dist/types/types/Family.d.ts +3 -0
- package/dist/types/types/GetValue.d.ts +9 -0
- package/dist/types/{src/types → types}/GlobalAtom.d.ts +6 -0
- package/dist/types/types/GlobalAtomSetSelfFunc.d.ts +2 -0
- package/dist/types/types/Reactive.d.ts +3 -0
- package/dist/types/types/Selector.d.ts +16 -0
- package/dist/types/types/SelectorFamily.d.ts +7 -0
- package/dist/types/{src/types → types}/SelectorOptions.d.ts +1 -1
- package/dist/types/types/SetAtomValue.d.ts +1 -0
- package/dist/types/types/State.d.ts +4 -0
- package/dist/types/types/Store.d.ts +31 -0
- package/dist/types/types/StoreData.d.ts +28 -0
- package/dist/types/types/SubscribeFn.d.ts +9 -0
- package/dist/types/types/Subscription.d.ts +11 -0
- package/dist/types/types/TransactionFn.d.ts +2 -0
- package/dist/types/{src/types → types}/TransactionInterface.d.ts +2 -0
- package/dist/types/utils/deepFreeze.d.ts +1 -0
- package/dist/types/utils/isAtomFamily.d.ts +2 -0
- package/dist/types/utils/isFamily.d.ts +1 -0
- package/dist/types/utils/isFamilyAtom.d.ts +2 -0
- package/dist/types/utils/isFamilySelector.d.ts +2 -0
- package/dist/types/utils/isFamilyState.d.ts +3 -0
- package/dist/types/utils/isGlobalAtom.d.ts +2 -0
- package/dist/types/utils/isSelectorFamily.d.ts +2 -0
- package/dist/types/utils/resolveReactive.d.ts +4 -0
- package/package.json +7 -19
- package/dist/types/src/atomFamily.d.ts +0 -4
- package/dist/types/src/createStoreWithSelectorSet.d.ts +0 -2
- package/dist/types/src/lib/atomFamilyAtom.d.ts +0 -8
- package/dist/types/src/lib/createAtomFamily.d.ts +0 -4
- package/dist/types/src/lib/createGlobalAtomFamily.d.ts +0 -5
- package/dist/types/src/lib/equal.d.ts +0 -1
- package/dist/types/src/lib/getState.d.ts +0 -7
- package/dist/types/src/lib/initAtom.d.ts +0 -5
- package/dist/types/src/lib/initSelector.d.ts +0 -3
- package/dist/types/src/lib/isFunction.d.ts +0 -1
- package/dist/types/src/lib/propagateUpdatedAtoms.d.ts +0 -4
- package/dist/types/src/lib/transaction.d.ts +0 -3
- package/dist/types/src/lib/updateSelectorSubscribers.d.ts +0 -3
- package/dist/types/src/lib/updateStateSubscribers.d.ts +0 -3
- package/dist/types/src/selector.d.ts +0 -4
- package/dist/types/src/selectorFamily.d.ts +0 -4
- package/dist/types/src/store.d.ts +0 -1
- package/dist/types/src/types/Atom.d.ts +0 -14
- package/dist/types/src/types/AtomFamily.d.ts +0 -12
- package/dist/types/src/types/AtomFamilyAtom.d.ts +0 -6
- package/dist/types/src/types/AtomFamilyDefaultValue.d.ts +0 -5
- package/dist/types/src/types/AtomFamilyGlobalAtom.d.ts +0 -3
- package/dist/types/src/types/AtomFamilySelector.d.ts +0 -6
- package/dist/types/src/types/AtomOnInit.d.ts +0 -2
- package/dist/types/src/types/AtomOptions.d.ts +0 -13
- package/dist/types/src/types/EqualFunc.d.ts +0 -1
- package/dist/types/src/types/Family.d.ts +0 -3
- package/dist/types/src/types/GetValue.d.ts +0 -8
- package/dist/types/src/types/GlobalAtomSetSelfFunc.d.ts +0 -1
- package/dist/types/src/types/Selector.d.ts +0 -11
- package/dist/types/src/types/SelectorFamily.d.ts +0 -6
- package/dist/types/src/types/SetAtomValue.d.ts +0 -1
- package/dist/types/src/types/State.d.ts +0 -4
- package/dist/types/src/types/Store.d.ts +0 -24
- package/dist/types/src/types/StoreData.d.ts +0 -17
- package/dist/types/src/types/SubscribeFn.d.ts +0 -9
- package/dist/types/src/types/Subscription.d.ts +0 -1
- package/dist/types/src/types/TransactionFn.d.ts +0 -2
- package/dist/types/src/utils/isAtomFamily.d.ts +0 -2
- package/dist/types/src/utils/isFamily.d.ts +0 -1
- package/dist/types/src/utils/isFamilyAtom.d.ts +0 -2
- package/dist/types/src/utils/isFamilySelector.d.ts +0 -2
- package/dist/types/src/utils/isFamilyState.d.ts +0 -3
- package/dist/types/src/utils/isSelectorFamily.d.ts +0 -2
- /package/dist/types/{src/atom.d.ts → atom.d.ts} +0 -0
- /package/dist/types/{src/globalStore.d.ts → globalStore.d.ts} +0 -0
- /package/dist/types/{src/lib → lib}/globalAtom.d.ts +0 -0
- /package/dist/types/{src/lib → lib}/resetAtom.d.ts +0 -0
- /package/dist/types/{src/lib → lib}/stableStringify.d.ts +0 -0
- /package/dist/types/{src/lib → lib}/storeFromStoreData.d.ts +0 -0
- /package/dist/types/{src/types → types}/AtomDefaultValue.d.ts +0 -0
- /package/dist/types/{src/types → types}/AtomOnSet.d.ts +0 -0
- /package/dist/types/{src/types → types}/FamilyKey.d.ts +0 -0
- /package/dist/types/{src/types → types}/GlobalAtomGetSelfFunc.d.ts +0 -0
- /package/dist/types/{src/types → types}/GlobalAtomResetSelfFunc.d.ts +0 -0
- /package/dist/types/{src/types → types}/ResetAtom.d.ts +0 -0
- /package/dist/types/{src/types → types}/SetAtom.d.ts +0 -0
- /package/dist/types/{src/utils → utils}/isAtom.d.ts +0 -0
- /package/dist/types/{src/utils → utils}/isPromiseLike.d.ts +0 -0
- /package/dist/types/{src/utils → utils}/isSelector.d.ts +0 -0
package/dist/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
// src/index.ts
|
|
2
|
-
import { version } from "../package.json";
|
|
3
|
-
|
|
4
1
|
// src/lib/equal.ts
|
|
5
2
|
var hasElementType = typeof Element !== "undefined";
|
|
6
3
|
var hasMap = typeof Map === "function";
|
|
7
4
|
var hasSet = typeof Set === "function";
|
|
8
5
|
var hasArrayBuffer = typeof ArrayBuffer === "function" && !!ArrayBuffer.isView;
|
|
9
|
-
var deepEqualFn = (a, b) => {
|
|
6
|
+
var deepEqualFn = (a, b, updatedAtomsSet) => {
|
|
7
|
+
if (updatedAtomsSet) {
|
|
8
|
+
if (updatedAtomsSet.has(a) || updatedAtomsSet.has(b))
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
10
11
|
if (a === b)
|
|
11
12
|
return true;
|
|
12
13
|
if (a && b && typeof a == "object" && typeof b == "object") {
|
|
@@ -18,7 +19,7 @@ var deepEqualFn = (a, b) => {
|
|
|
18
19
|
if (length != b.length)
|
|
19
20
|
return false;
|
|
20
21
|
for (i = length;i-- !== 0; )
|
|
21
|
-
if (!deepEqualFn(a[i], b[i]))
|
|
22
|
+
if (!deepEqualFn(a[i], b[i], updatedAtomsSet))
|
|
22
23
|
return false;
|
|
23
24
|
return true;
|
|
24
25
|
}
|
|
@@ -32,7 +33,7 @@ var deepEqualFn = (a, b) => {
|
|
|
32
33
|
return false;
|
|
33
34
|
it = a.entries();
|
|
34
35
|
while (!(i = it.next()).done)
|
|
35
|
-
if (!deepEqualFn(i.value[1], b.get(i.value[0])))
|
|
36
|
+
if (!deepEqualFn(i.value[1], b.get(i.value[0]), updatedAtomsSet))
|
|
36
37
|
return false;
|
|
37
38
|
return true;
|
|
38
39
|
}
|
|
@@ -40,9 +41,12 @@ var deepEqualFn = (a, b) => {
|
|
|
40
41
|
if (a.size !== b.size)
|
|
41
42
|
return false;
|
|
42
43
|
it = a.entries();
|
|
43
|
-
while (!(i = it.next()).done)
|
|
44
|
+
while (!(i = it.next()).done) {
|
|
44
45
|
if (!b.has(i.value[0]))
|
|
45
46
|
return false;
|
|
47
|
+
if (updatedAtomsSet?.has(i.value[0]))
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
46
50
|
return true;
|
|
47
51
|
}
|
|
48
52
|
if (hasArrayBuffer && ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
|
|
@@ -73,16 +77,16 @@ var deepEqualFn = (a, b) => {
|
|
|
73
77
|
if ((keys[i] === "_owner" || keys[i] === "__v" || keys[i] === "__o") && a.$$typeof) {
|
|
74
78
|
continue;
|
|
75
79
|
}
|
|
76
|
-
if (!deepEqualFn(a[keys[i]], b[keys[i]]))
|
|
80
|
+
if (!deepEqualFn(a[keys[i]], b[keys[i]], updatedAtomsSet))
|
|
77
81
|
return false;
|
|
78
82
|
}
|
|
79
83
|
return true;
|
|
80
84
|
}
|
|
81
85
|
return a !== a && b !== b;
|
|
82
86
|
};
|
|
83
|
-
var equal = (a, b) => {
|
|
87
|
+
var equal = (a, b, updatedAtomsSet) => {
|
|
84
88
|
try {
|
|
85
|
-
return deepEqualFn(a, b);
|
|
89
|
+
return deepEqualFn(a, b, updatedAtomsSet);
|
|
86
90
|
} catch (error) {
|
|
87
91
|
if ((error.message || "").match(/stack|recursion/i)) {
|
|
88
92
|
console.warn("react-fast-compare cannot handle circular refs");
|
|
@@ -95,154 +99,203 @@ var equal = (a, b) => {
|
|
|
95
99
|
// src/utils/isAtom.ts
|
|
96
100
|
var isAtom = (state) => Object.hasOwn(state, "defaultValue");
|
|
97
101
|
|
|
102
|
+
// src/utils/isGlobalAtom.ts
|
|
103
|
+
var isGlobalAtom = (state) => Object.hasOwn(state, "stores");
|
|
104
|
+
|
|
105
|
+
// src/utils/isSelector.ts
|
|
106
|
+
var isSelector = (state) => state && Object.hasOwn(state, "get");
|
|
107
|
+
|
|
108
|
+
// src/utils/isAtomFamily.ts
|
|
109
|
+
var isAtomFamily = (state) => state && Object.hasOwn(state, "__valdresAtomFamilyMap");
|
|
110
|
+
|
|
98
111
|
// src/utils/isFamilyState.ts
|
|
99
112
|
var isFamilyState = (state) => state && Object.hasOwn(state, "family");
|
|
100
113
|
|
|
101
114
|
// src/utils/isFamilyAtom.ts
|
|
102
115
|
var isFamilyAtom = (state) => isFamilyState(state) && isAtom(state);
|
|
103
116
|
|
|
104
|
-
// src/
|
|
105
|
-
var
|
|
106
|
-
const subscribtions = data.subscriptions.get(state);
|
|
107
|
-
if (subscribtions?.size) {
|
|
108
|
-
for (const subscribtion of subscribtions) {
|
|
109
|
-
subscribtion.callback();
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (isFamilyState(state)) {
|
|
113
|
-
const familySubscriptions = data.subscriptions.get(state.family);
|
|
114
|
-
if (familySubscriptions?.size) {
|
|
115
|
-
for (const subscribtion of familySubscriptions) {
|
|
116
|
-
subscribtion.callback(state.familyKey);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
};
|
|
117
|
+
// src/utils/isSelectorFamily.ts
|
|
118
|
+
var isSelectorFamily = (state) => state && Object.hasOwn(state, "__valdresSelectorFamilyMap");
|
|
121
119
|
|
|
122
120
|
// src/utils/isPromiseLike.ts
|
|
123
121
|
var isPromiseLike = (object) => {
|
|
124
122
|
return object && object.then && typeof object.then === "function";
|
|
125
123
|
};
|
|
126
124
|
|
|
127
|
-
// src/utils/
|
|
128
|
-
var
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
125
|
+
// src/utils/deepFreeze.ts
|
|
126
|
+
var deepFreeze = (obj, seen = new WeakSet) => {
|
|
127
|
+
if (obj === null || obj === undefined)
|
|
128
|
+
return obj;
|
|
129
|
+
if (typeof obj !== "object" && typeof obj !== "function")
|
|
130
|
+
return obj;
|
|
131
|
+
if (seen.has(obj) || Object.isFrozen(obj))
|
|
132
|
+
return obj;
|
|
133
|
+
seen.add(obj);
|
|
134
|
+
if (Array.isArray(obj)) {
|
|
135
|
+
for (const item of obj) {
|
|
136
|
+
if (item && typeof item === "object") {
|
|
137
|
+
deepFreeze(item, seen);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
const propNames = Object.getOwnPropertyNames(obj);
|
|
142
|
+
for (const name of propNames) {
|
|
143
|
+
const value = obj[name];
|
|
144
|
+
if (value && typeof value === "object") {
|
|
145
|
+
deepFreeze(value, seen);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return Object.freeze(obj);
|
|
150
|
+
};
|
|
135
151
|
|
|
136
|
-
// src/lib/
|
|
137
|
-
var
|
|
152
|
+
// src/lib/isProd.ts
|
|
153
|
+
var isProd = () => {
|
|
154
|
+
return false;
|
|
155
|
+
};
|
|
138
156
|
|
|
139
|
-
// src/lib/
|
|
140
|
-
var
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
157
|
+
// src/lib/setValueInData.ts
|
|
158
|
+
var trackScopeValue = (key, data) => {
|
|
159
|
+
const parent = data.parent;
|
|
160
|
+
let set = parent.scopeValueIndex.get(key);
|
|
161
|
+
if (!set) {
|
|
162
|
+
set = new Set;
|
|
163
|
+
parent.scopeValueIndex.set(key, set);
|
|
146
164
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
165
|
+
set.add(data);
|
|
166
|
+
data.scopeIndexKeys.add(key);
|
|
167
|
+
};
|
|
168
|
+
var setValueInData = (atom, value, data) => {
|
|
169
|
+
const isNewAtomInScope = "parent" in data && Object.hasOwn(atom, "defaultValue") && !data.values.has(atom);
|
|
170
|
+
let written;
|
|
171
|
+
if (atom.mutable || isProd()) {
|
|
172
|
+
data.values.set(atom, value);
|
|
173
|
+
written = value;
|
|
174
|
+
} else {
|
|
175
|
+
const frozenValue = value !== null && (typeof value === "object" || typeof value === "function") ? deepFreeze(value) : value;
|
|
176
|
+
data.values.set(atom, frozenValue);
|
|
177
|
+
written = frozenValue;
|
|
178
|
+
}
|
|
179
|
+
if (isNewAtomInScope)
|
|
180
|
+
trackScopeValue(atom, data);
|
|
181
|
+
if (atom.maxAge !== undefined) {
|
|
182
|
+
data.lastValueWriteAt.set(atom, Date.now());
|
|
154
183
|
}
|
|
155
|
-
|
|
156
|
-
return newValue;
|
|
184
|
+
return written;
|
|
157
185
|
};
|
|
158
186
|
|
|
159
|
-
// src/lib/
|
|
160
|
-
var
|
|
161
|
-
if (
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
} else if (typeof atom.defaultValue === "function") {
|
|
170
|
-
const value = atom.defaultValue();
|
|
171
|
-
if (isPromiseLike(value)) {
|
|
172
|
-
value.then((resolvedValue) => {
|
|
173
|
-
data.values.set(atom, resolvedValue);
|
|
174
|
-
propagateUpdatedAtoms([atom], data);
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
return value;
|
|
178
|
-
} else if (isSelector(atom.defaultValue)) {
|
|
179
|
-
return getState(atom.defaultValue, data);
|
|
180
|
-
} else {
|
|
181
|
-
return atom.defaultValue;
|
|
187
|
+
// src/lib/atomFamilyIndex.ts
|
|
188
|
+
var getAtomFamilyRenderedMap = (index) => {
|
|
189
|
+
if (index.rendered)
|
|
190
|
+
return index.rendered;
|
|
191
|
+
const result = new Map(index.parentIndex ? getAtomFamilyRenderedMap(index.parentIndex) : undefined);
|
|
192
|
+
for (const [atom, timestamp] of index.created) {
|
|
193
|
+
result.set(atom, timestamp);
|
|
194
|
+
}
|
|
195
|
+
for (const [atom, timestamp] of index.deleted) {
|
|
196
|
+
result.delete(atom);
|
|
182
197
|
}
|
|
198
|
+
index.rendered = result;
|
|
199
|
+
return result;
|
|
183
200
|
};
|
|
184
|
-
var
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const newSet = new Set(currentKeySet);
|
|
191
|
-
newSet.add(atom.familyKey);
|
|
192
|
-
setAtom(atom.family.__keysAtom, newSet, data);
|
|
193
|
-
}
|
|
201
|
+
var getSortedKeysByValues = (map) => {
|
|
202
|
+
return Array.from(map.entries()).sort((a, b) => a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0).map((entry) => entry[0]);
|
|
203
|
+
};
|
|
204
|
+
var renderAtomFamilyIndex = (index) => {
|
|
205
|
+
if (index.renderedArray) {
|
|
206
|
+
return index.renderedArray;
|
|
194
207
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
return value;
|
|
208
|
+
const renderedMap = getAtomFamilyRenderedMap(index);
|
|
209
|
+
const array = getSortedKeysByValues(renderedMap);
|
|
210
|
+
array.__index = index;
|
|
211
|
+
index.renderedArray = array;
|
|
212
|
+
return array;
|
|
201
213
|
};
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
214
|
+
var cloneAtomFamilyIndex = (index, parentIndexOverride) => {
|
|
215
|
+
return {
|
|
216
|
+
created: new Map(index.created),
|
|
217
|
+
deleted: new Map(index.deleted),
|
|
218
|
+
rendered: null,
|
|
219
|
+
renderedArray: null,
|
|
220
|
+
parentIndex: parentIndexOverride || index.parentIndex
|
|
221
|
+
};
|
|
222
|
+
};
|
|
223
|
+
var createAtomFamilyIndex = (parentIndex) => {
|
|
224
|
+
return {
|
|
225
|
+
created: new Map,
|
|
226
|
+
deleted: new Map,
|
|
227
|
+
rendered: null,
|
|
228
|
+
renderedArray: null,
|
|
229
|
+
parentIndex
|
|
230
|
+
};
|
|
231
|
+
};
|
|
232
|
+
var deleteFamilyAtomsFromSet = (family, familyAtoms, data, timestamp) => {
|
|
233
|
+
if (familyAtoms.size === 0)
|
|
234
|
+
return;
|
|
235
|
+
const index = findFamilyIndex(family, data);
|
|
236
|
+
for (const atom of familyAtoms) {
|
|
237
|
+
index.deleted.set(atom, timestamp);
|
|
211
238
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
return
|
|
239
|
+
index.rendered = null;
|
|
240
|
+
index.renderedArray = null;
|
|
241
|
+
data.values.set(family, renderAtomFamilyIndex(index));
|
|
242
|
+
recursivelyUpdateIndexes(data, family);
|
|
243
|
+
};
|
|
244
|
+
var initFamilyIndex = (family, data) => {
|
|
245
|
+
if (data.values.has(family))
|
|
246
|
+
return data.values.get(family).__index;
|
|
247
|
+
let parentIndex;
|
|
248
|
+
if ("parent" in data) {
|
|
249
|
+
parentIndex = initFamilyIndex(family, data.parent);
|
|
250
|
+
if (!parentIndex)
|
|
251
|
+
throw new Error("Parent index is missing");
|
|
220
252
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
state._keyArray = array;
|
|
226
|
-
return array;
|
|
253
|
+
const index = createAtomFamilyIndex(parentIndex);
|
|
254
|
+
data.values.set(family, renderAtomFamilyIndex(index));
|
|
255
|
+
if ("parent" in data) {
|
|
256
|
+
trackScopeValue(family, data);
|
|
227
257
|
}
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
var findClosestStoreWithAtomInitialized = (atom, data) => {
|
|
231
|
-
if ("parent" in data === false)
|
|
232
|
-
return data;
|
|
233
|
-
if (data.values.has(atom))
|
|
234
|
-
return data;
|
|
235
|
-
return findClosestStoreWithAtomInitialized(atom, data.parent);
|
|
258
|
+
return index;
|
|
236
259
|
};
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
promise;
|
|
241
|
-
constructor(promise) {
|
|
242
|
-
super();
|
|
243
|
-
this.promise = promise;
|
|
260
|
+
var findFamilyIndex = (family, data) => {
|
|
261
|
+
if (!data.values.has(family)) {
|
|
262
|
+
initFamilyIndex(family, data);
|
|
244
263
|
}
|
|
245
|
-
|
|
264
|
+
const value = data.values.get(family);
|
|
265
|
+
if (!value?.__index) {
|
|
266
|
+
throw new Error("Family index is missing");
|
|
267
|
+
}
|
|
268
|
+
return value.__index;
|
|
269
|
+
};
|
|
270
|
+
var recursivelyUpdateIndexes = (data, family) => {
|
|
271
|
+
const childScopesWithFamily = data.scopeValueIndex.get(family);
|
|
272
|
+
if (!childScopesWithFamily || childScopesWithFamily.size === 0)
|
|
273
|
+
return;
|
|
274
|
+
for (const scopedData of childScopesWithFamily) {
|
|
275
|
+
const index = scopedData.values.get(family).__index;
|
|
276
|
+
index.rendered = null;
|
|
277
|
+
index.renderedArray = null;
|
|
278
|
+
scopedData.values.set(family, renderAtomFamilyIndex(index));
|
|
279
|
+
recursivelyUpdateIndexes(scopedData, family);
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
var addFamilyAtomsToSet = (family, familyAtoms, data, timestamp) => {
|
|
283
|
+
if (familyAtoms.size === 0)
|
|
284
|
+
return;
|
|
285
|
+
const index = findFamilyIndex(family, data);
|
|
286
|
+
if (!index)
|
|
287
|
+
throw new Error("index not found");
|
|
288
|
+
for (const atom of familyAtoms) {
|
|
289
|
+
index.created.set(atom, timestamp);
|
|
290
|
+
index.deleted.delete(atom);
|
|
291
|
+
}
|
|
292
|
+
index.rendered = null;
|
|
293
|
+
index.renderedArray = null;
|
|
294
|
+
data.values.set(family, renderAtomFamilyIndex(index));
|
|
295
|
+
recursivelyUpdateIndexes(data, family);
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
// src/errors/lib/generateSelectorTrace.ts
|
|
246
299
|
var generateSelectorTrace = (selectors) => {
|
|
247
300
|
const lastIndex = selectors.length - 1;
|
|
248
301
|
return [...selectors].reverse().map((selector, index) => {
|
|
@@ -258,205 +311,844 @@ var generateSelectorTrace = (selectors) => {
|
|
|
258
311
|
`);
|
|
259
312
|
};
|
|
260
313
|
|
|
261
|
-
|
|
314
|
+
// src/errors/SelectorEvaluationError.ts
|
|
315
|
+
class SelectorEvaluationError extends Error {
|
|
262
316
|
selectors;
|
|
263
|
-
constructor() {
|
|
317
|
+
constructor(cause) {
|
|
264
318
|
super();
|
|
319
|
+
this.cause = cause;
|
|
265
320
|
this.selectors = [];
|
|
266
321
|
}
|
|
267
322
|
track(selector) {
|
|
268
323
|
this.selectors.push(selector);
|
|
269
324
|
}
|
|
325
|
+
get message() {
|
|
326
|
+
const firstSelectorName = this.selectors[0].name ?? "Anonymous Selector";
|
|
327
|
+
return `Selector eval crashed in '${firstSelectorName}'
|
|
328
|
+
${generateSelectorTrace(this.selectors)}`;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// src/errors/SelectorCircularDependencyError.ts
|
|
333
|
+
class SelectorCircularDependencyError extends SelectorEvaluationError {
|
|
334
|
+
constructor() {
|
|
335
|
+
super();
|
|
336
|
+
}
|
|
270
337
|
get message() {
|
|
271
338
|
const firstSelectorName = this.selectors[0].name ?? "Anonymous Selector";
|
|
272
339
|
return `Circular dependency detected in '${firstSelectorName}'
|
|
273
340
|
${generateSelectorTrace(this.selectors)}`;
|
|
274
341
|
}
|
|
275
342
|
}
|
|
276
|
-
|
|
277
|
-
|
|
343
|
+
|
|
344
|
+
// src/lib/asyncDependencyTracking.ts
|
|
345
|
+
var pendingAsyncDeps = new WeakMap;
|
|
346
|
+
var latestEvalContext = new WeakMap;
|
|
347
|
+
|
|
348
|
+
class SuspendAndWaitForResolveError extends Error {
|
|
349
|
+
promise;
|
|
350
|
+
constructor(promise) {
|
|
351
|
+
super();
|
|
352
|
+
this.promise = promise;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
var isSuspendError = (e) => {
|
|
356
|
+
return e instanceof SuspendAndWaitForResolveError;
|
|
357
|
+
};
|
|
358
|
+
var getOrInitDependentsSet = (state, data) => {
|
|
359
|
+
const set = data.stateDependents.get(state);
|
|
278
360
|
if (set)
|
|
279
361
|
return set;
|
|
280
362
|
const newSet = new Set;
|
|
281
|
-
data.
|
|
363
|
+
data.stateDependents.set(state, newSet);
|
|
282
364
|
return newSet;
|
|
283
365
|
};
|
|
284
|
-
var
|
|
285
|
-
|
|
286
|
-
if (
|
|
287
|
-
|
|
366
|
+
var lateGet = (state, selector, data) => {
|
|
367
|
+
let deps = data.stateDependencies.get(selector);
|
|
368
|
+
if (!deps) {
|
|
369
|
+
deps = new Set;
|
|
370
|
+
data.stateDependencies.set(selector, deps);
|
|
371
|
+
}
|
|
372
|
+
const isNewDep = !deps.has(state);
|
|
373
|
+
if (isNewDep) {
|
|
374
|
+
deps.add(state);
|
|
375
|
+
const dependents = getOrInitDependentsSet(state, data);
|
|
376
|
+
dependents.add(selector);
|
|
377
|
+
}
|
|
378
|
+
const lateInitSet = new Set;
|
|
379
|
+
try {
|
|
380
|
+
return getState(state, data, lateInitSet);
|
|
381
|
+
} finally {
|
|
382
|
+
if (isNewDep && isTransitivelySubscribed(selector, data)) {
|
|
383
|
+
mountTransitiveDeps(state, data);
|
|
384
|
+
}
|
|
288
385
|
}
|
|
289
|
-
|
|
386
|
+
};
|
|
387
|
+
var cleanUpRejectedPromise = (selector, data, promise) => {
|
|
388
|
+
if (data.values.has(selector) && data.values.get(selector) !== promise)
|
|
389
|
+
return;
|
|
390
|
+
data.values.delete(selector);
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
// src/lib/initSelector.ts
|
|
394
|
+
class NeedsInitError {
|
|
395
|
+
selector;
|
|
396
|
+
constructor(selector) {
|
|
397
|
+
this.selector = selector;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
var _evalDepth = 0;
|
|
401
|
+
var _inTrampoline = false;
|
|
402
|
+
var MAX_EVAL_DEPTH = 100;
|
|
403
|
+
var sharedCircularDepSet = new WeakSet;
|
|
404
|
+
var neverAbortedSignal = new AbortController().signal;
|
|
405
|
+
var syncOptionsCache = new WeakMap;
|
|
406
|
+
var evaluateSelector = (selector, data, initializedAtomsSet, circularDependencySet = sharedCircularDepSet, addedDepsOut, removedDepsOut) => {
|
|
407
|
+
const currentDependencies = data.stateDependencies.get(selector);
|
|
408
|
+
const updatedDepsArray = [];
|
|
409
|
+
let depsChanged = false;
|
|
410
|
+
let evaluationComplete = false;
|
|
411
|
+
const prevCtx = latestEvalContext.get(selector);
|
|
412
|
+
if (prevCtx)
|
|
413
|
+
prevCtx.revoked = true;
|
|
414
|
+
const evalCtx = { revoked: false };
|
|
415
|
+
latestEvalContext.set(selector, evalCtx);
|
|
416
|
+
if (circularDependencySet.has(selector)) {
|
|
417
|
+
throw new SelectorCircularDependencyError;
|
|
418
|
+
}
|
|
419
|
+
circularDependencySet.add(selector);
|
|
420
|
+
const prev = data.abortControllers.get(selector);
|
|
421
|
+
let options;
|
|
422
|
+
if (prev === false) {
|
|
423
|
+
let cached = syncOptionsCache.get(data);
|
|
424
|
+
if (!cached) {
|
|
425
|
+
cached = { signal: neverAbortedSignal, storeId: data.id };
|
|
426
|
+
syncOptionsCache.set(data, cached);
|
|
427
|
+
}
|
|
428
|
+
options = cached;
|
|
429
|
+
} else {
|
|
430
|
+
if (prev)
|
|
431
|
+
prev.abort();
|
|
432
|
+
const abortController = new AbortController;
|
|
433
|
+
data.abortControllers.set(selector, abortController);
|
|
434
|
+
options = { signal: abortController.signal, storeId: data.id };
|
|
435
|
+
}
|
|
436
|
+
let allDepsThisEval;
|
|
290
437
|
let result;
|
|
291
438
|
try {
|
|
292
439
|
result = selector.get((state) => {
|
|
293
|
-
|
|
294
|
-
|
|
440
|
+
if (evaluationComplete) {
|
|
441
|
+
if (!evalCtx.revoked && allDepsThisEval) {
|
|
442
|
+
allDepsThisEval.add(state);
|
|
443
|
+
}
|
|
444
|
+
if (evalCtx.revoked) {
|
|
445
|
+
return getState(state, data, new Set);
|
|
446
|
+
}
|
|
447
|
+
return lateGet(state, selector, data);
|
|
448
|
+
}
|
|
449
|
+
const value = getState(state, data, initializedAtomsSet, circularDependencySet);
|
|
450
|
+
updatedDepsArray.push(state);
|
|
451
|
+
if (!depsChanged && (!currentDependencies || !currentDependencies.has(state))) {
|
|
452
|
+
depsChanged = true;
|
|
453
|
+
}
|
|
295
454
|
if (isPromiseLike(value))
|
|
296
455
|
throw new SuspendAndWaitForResolveError(value);
|
|
297
456
|
return value;
|
|
298
|
-
},
|
|
457
|
+
}, options);
|
|
299
458
|
} catch (error) {
|
|
459
|
+
if (error instanceof NeedsInitError) {
|
|
460
|
+
circularDependencySet.delete(selector);
|
|
461
|
+
throw error;
|
|
462
|
+
}
|
|
300
463
|
if (error instanceof SuspendAndWaitForResolveError) {
|
|
301
464
|
result = error;
|
|
302
|
-
} else {
|
|
465
|
+
} else if (error instanceof SelectorEvaluationError) {
|
|
303
466
|
throw error;
|
|
467
|
+
} else {
|
|
468
|
+
throw new SelectorEvaluationError(error);
|
|
304
469
|
}
|
|
305
470
|
}
|
|
306
|
-
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
471
|
+
evaluationComplete = true;
|
|
472
|
+
const isAsyncResult = result instanceof SuspendAndWaitForResolveError || isPromiseLike(result);
|
|
473
|
+
if (!isAsyncResult && !depsChanged && currentDependencies && currentDependencies.size !== updatedDepsArray.length) {
|
|
474
|
+
depsChanged = true;
|
|
475
|
+
}
|
|
476
|
+
if (depsChanged || !currentDependencies) {
|
|
477
|
+
const updatedDependencies = new Set(updatedDepsArray);
|
|
478
|
+
if (isAsyncResult && currentDependencies) {
|
|
479
|
+
for (const dep of currentDependencies) {
|
|
480
|
+
updatedDependencies.add(dep);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
const prev2 = currentDependencies ?? new Set;
|
|
484
|
+
for (const state of updatedDependencies) {
|
|
485
|
+
if (!prev2.has(state)) {
|
|
486
|
+
const set = getOrInitDependentsSet(state, data);
|
|
487
|
+
set.add(selector);
|
|
488
|
+
if (addedDepsOut)
|
|
489
|
+
addedDepsOut.add(state);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
if (!isAsyncResult) {
|
|
493
|
+
for (const state of prev2) {
|
|
494
|
+
if (!updatedDependencies.has(state)) {
|
|
495
|
+
const set = getOrInitDependentsSet(state, data);
|
|
496
|
+
set.delete(selector);
|
|
497
|
+
if (removedDepsOut)
|
|
498
|
+
removedDepsOut.add(state);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
data.stateDependencies.set(selector, updatedDependencies);
|
|
312
503
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
set
|
|
504
|
+
if (isPromiseLike(result)) {
|
|
505
|
+
allDepsThisEval = new Set(updatedDepsArray);
|
|
506
|
+
pendingAsyncDeps.set(result, allDepsThisEval);
|
|
316
507
|
}
|
|
317
|
-
|
|
508
|
+
circularDependencySet.delete(selector);
|
|
318
509
|
return result;
|
|
319
510
|
};
|
|
320
511
|
var handleSelectorResult = (value, selector, data) => {
|
|
321
512
|
if (value instanceof SuspendAndWaitForResolveError) {
|
|
322
|
-
|
|
323
|
-
|
|
513
|
+
data.abortControllers.delete(selector);
|
|
514
|
+
const promise = value.promise;
|
|
515
|
+
promise.then(() => {
|
|
516
|
+
if (!data.stateDependencies.has(selector))
|
|
517
|
+
return;
|
|
518
|
+
if (data.values.has(selector) && data.values.get(selector) !== promise)
|
|
519
|
+
return;
|
|
520
|
+
const initializedAtomsSet = new Set;
|
|
521
|
+
const res = initSelector(selector, data, initializedAtomsSet);
|
|
522
|
+
if (initializedAtomsSet.size > 0) {
|
|
523
|
+
propagateUpdatedAtoms([...initializedAtomsSet], data);
|
|
524
|
+
}
|
|
525
|
+
return res;
|
|
526
|
+
}).catch(() => {
|
|
527
|
+
cleanUpRejectedPromise(selector, data, promise);
|
|
528
|
+
});
|
|
529
|
+
return promise;
|
|
324
530
|
} else if (isPromiseLike(value)) {
|
|
325
531
|
value.then((resolved) => {
|
|
326
|
-
data.
|
|
327
|
-
|
|
328
|
-
|
|
532
|
+
if (!data.stateDependencies.has(selector)) {
|
|
533
|
+
pendingAsyncDeps.delete(value);
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
if (data.values.has(selector) && data.values.get(selector) !== value) {
|
|
537
|
+
pendingAsyncDeps.delete(value);
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
const evalDeps = pendingAsyncDeps.get(value);
|
|
541
|
+
if (evalDeps) {
|
|
542
|
+
pendingAsyncDeps.delete(value);
|
|
543
|
+
const currentDeps = data.stateDependencies.get(selector);
|
|
544
|
+
if (currentDeps) {
|
|
545
|
+
for (const dep of currentDeps) {
|
|
546
|
+
if (!evalDeps.has(dep)) {
|
|
547
|
+
currentDeps.delete(dep);
|
|
548
|
+
const dependents2 = data.stateDependents.get(dep);
|
|
549
|
+
if (dependents2)
|
|
550
|
+
dependents2.delete(selector);
|
|
551
|
+
unmountOrphanedDeps(dep, data);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
setValueInData(selector, resolved, data);
|
|
557
|
+
const dependents = data.stateDependents.get(selector);
|
|
558
|
+
const subs = data.subscriptions.get(selector);
|
|
559
|
+
if (subs && subs.size > 0 || dependents && dependents.size > 0) {
|
|
560
|
+
propagateDirtySelectors([], new Set(dependents), data, new Set(subs), new Map);
|
|
561
|
+
}
|
|
562
|
+
}).catch(() => {
|
|
563
|
+
pendingAsyncDeps.delete(value);
|
|
564
|
+
cleanUpRejectedPromise(selector, data, value);
|
|
329
565
|
});
|
|
330
566
|
return value;
|
|
331
567
|
} else {
|
|
568
|
+
data.abortControllers.set(selector, false);
|
|
332
569
|
return value;
|
|
333
570
|
}
|
|
334
571
|
};
|
|
335
|
-
var
|
|
572
|
+
var initSelectorDirect = (selector, data, initializedAtomsSet, circularDependencySet) => {
|
|
573
|
+
const existingValue = data.values.get(selector);
|
|
574
|
+
const updatedValue = evaluate(selector, data, initializedAtomsSet, circularDependencySet);
|
|
575
|
+
const areEqual = isPromiseLike(existingValue) || isPromiseLike(updatedValue) ? existingValue === updatedValue : selector.equal(existingValue, updatedValue);
|
|
576
|
+
if (areEqual) {
|
|
577
|
+
return false;
|
|
578
|
+
} else {
|
|
579
|
+
setValueInData(selector, updatedValue, data);
|
|
580
|
+
return true;
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
var initSelectorTrampoline = (selector, data, initializedAtomsSet, circularDependencySet) => {
|
|
584
|
+
const stack = [selector];
|
|
585
|
+
const inStack = new Set([selector]);
|
|
586
|
+
while (stack.length > 0) {
|
|
587
|
+
const current = stack[stack.length - 1];
|
|
588
|
+
if (data.values.has(current)) {
|
|
589
|
+
stack.pop();
|
|
590
|
+
inStack.delete(current);
|
|
591
|
+
continue;
|
|
592
|
+
}
|
|
593
|
+
try {
|
|
594
|
+
initSelectorDirect(current, data, initializedAtomsSet, circularDependencySet);
|
|
595
|
+
stack.pop();
|
|
596
|
+
inStack.delete(current);
|
|
597
|
+
} catch (e) {
|
|
598
|
+
if (e instanceof NeedsInitError) {
|
|
599
|
+
if (inStack.has(e.selector)) {
|
|
600
|
+
throw new SelectorCircularDependencyError;
|
|
601
|
+
}
|
|
602
|
+
stack.push(e.selector);
|
|
603
|
+
inStack.add(e.selector);
|
|
604
|
+
} else {
|
|
605
|
+
throw e;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
var initSelector = (selector, data, initializedAtomsSet, circularDependencySet = sharedCircularDepSet) => {
|
|
611
|
+
const isTopLevel = _evalDepth === 0 && !_inTrampoline;
|
|
612
|
+
_evalDepth++;
|
|
613
|
+
const existingValue = data.values.get(selector);
|
|
614
|
+
try {
|
|
615
|
+
return initSelectorDirect(selector, data, initializedAtomsSet, circularDependencySet);
|
|
616
|
+
} catch (e) {
|
|
617
|
+
if (e instanceof NeedsInitError && isTopLevel) {
|
|
618
|
+
_inTrampoline = true;
|
|
619
|
+
try {
|
|
620
|
+
initSelectorTrampoline(selector, data, initializedAtomsSet, circularDependencySet);
|
|
621
|
+
} finally {
|
|
622
|
+
_inTrampoline = false;
|
|
623
|
+
}
|
|
624
|
+
const newValue = data.values.get(selector);
|
|
625
|
+
const areEqual = isPromiseLike(existingValue) || isPromiseLike(newValue) ? existingValue === newValue : selector.equal(existingValue, newValue);
|
|
626
|
+
return !areEqual;
|
|
627
|
+
}
|
|
628
|
+
throw e;
|
|
629
|
+
} finally {
|
|
630
|
+
_evalDepth--;
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
var evaluate = (selector, data, initializedAtomsSet, circularDependencySet) => {
|
|
336
634
|
let tmpValue;
|
|
337
635
|
try {
|
|
338
|
-
tmpValue = evaluateSelector(selector, data, circularDependencySet);
|
|
636
|
+
tmpValue = evaluateSelector(selector, data, initializedAtomsSet, circularDependencySet);
|
|
339
637
|
} catch (e) {
|
|
340
|
-
if (e instanceof
|
|
638
|
+
if (e instanceof SelectorEvaluationError)
|
|
341
639
|
e.track(selector);
|
|
342
640
|
throw e;
|
|
343
641
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
642
|
+
return handleSelectorResult(tmpValue, selector, data);
|
|
643
|
+
};
|
|
644
|
+
|
|
645
|
+
// src/lib/propagateUpdatedAtoms.ts
|
|
646
|
+
var reEvaluteSelector = (selector, data, updatedAtoms) => {
|
|
647
|
+
const existingValue = data.values.get(selector);
|
|
648
|
+
const addedDeps = new Set;
|
|
649
|
+
const removedDeps = new Set;
|
|
650
|
+
try {
|
|
651
|
+
const rawValue = evaluateSelector(selector, data, updatedAtoms, undefined, addedDeps, removedDeps);
|
|
652
|
+
const udpatedValue = handleSelectorResult(rawValue, selector, data);
|
|
653
|
+
const areEqual = isPromiseLike(existingValue) || isPromiseLike(udpatedValue) ? existingValue === udpatedValue : selector.equal(existingValue, udpatedValue, updatedAtoms);
|
|
654
|
+
if (areEqual) {
|
|
655
|
+
return [false, false, undefined, addedDeps, removedDeps];
|
|
656
|
+
} else {
|
|
657
|
+
setValueInData(selector, udpatedValue, data);
|
|
658
|
+
return [true, false, undefined, addedDeps, removedDeps];
|
|
350
659
|
}
|
|
660
|
+
} catch (error) {
|
|
661
|
+
data.values.delete(selector);
|
|
662
|
+
return [true, true, error, addedDeps, removedDeps];
|
|
351
663
|
}
|
|
352
|
-
data.values.set(selector, value);
|
|
353
|
-
return value;
|
|
354
664
|
};
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
665
|
+
var callSubscribers = (subscriptions, families) => {
|
|
666
|
+
let firstError;
|
|
667
|
+
let hasError = false;
|
|
668
|
+
for (const subscription of subscriptions) {
|
|
669
|
+
if ("state" in subscription) {
|
|
670
|
+
const updatedFamilyAtoms = families?.get(subscription.state);
|
|
671
|
+
if (updatedFamilyAtoms) {
|
|
672
|
+
for (const atom of updatedFamilyAtoms) {
|
|
673
|
+
try {
|
|
674
|
+
subscription.callback(...atom.familyArgs);
|
|
675
|
+
} catch (error) {
|
|
676
|
+
if (!hasError) {
|
|
677
|
+
firstError = error;
|
|
678
|
+
hasError = true;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
} else {
|
|
684
|
+
try {
|
|
685
|
+
subscription.callback();
|
|
686
|
+
} catch (error) {
|
|
687
|
+
if (!hasError) {
|
|
688
|
+
firstError = error;
|
|
689
|
+
hasError = true;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
if (hasError)
|
|
695
|
+
throw firstError;
|
|
696
|
+
};
|
|
697
|
+
var addSetToSet = (fromSet, toSet) => {
|
|
698
|
+
if (fromSet && fromSet.size > 0) {
|
|
699
|
+
for (const item of fromSet) {
|
|
700
|
+
toSet.add(item);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
var propagateDeletedAtoms = (atoms, data, subscriptions = new Set, families = new Map, timestamp = performance.now()) => {
|
|
705
|
+
const selectors = new Set;
|
|
706
|
+
for (const atom of atoms) {
|
|
707
|
+
addSetToSet(data.stateDependents.get(atom), selectors);
|
|
708
|
+
addSetToSet(data.subscriptions.get(atom), subscriptions);
|
|
709
|
+
if (isFamilyAtom(atom)) {
|
|
710
|
+
if (!families.has(atom.family)) {
|
|
711
|
+
families.set(atom.family, new Set);
|
|
712
|
+
}
|
|
713
|
+
families.get(atom.family).add(atom);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
if (families.size > 0) {
|
|
717
|
+
for (const [family, familyAtoms] of families) {
|
|
718
|
+
addSetToSet(data.stateDependents.get(family), selectors);
|
|
719
|
+
addSetToSet(data.subscriptions.get(family), subscriptions);
|
|
720
|
+
if (familyAtoms.size === 0)
|
|
721
|
+
throw new Error("Should not be possible");
|
|
722
|
+
deleteFamilyAtomsFromSet(family, familyAtoms, data, timestamp);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
propagateDirtySelectors(atoms, selectors, data, subscriptions, families);
|
|
726
|
+
if (families.size > 0 && data.scopes && data.scopes.size > 0) {
|
|
727
|
+
const scopeFamilies = new Map;
|
|
728
|
+
for (const family of families.keys()) {
|
|
729
|
+
const scopesWithFamily = data.scopeValueIndex.get(family);
|
|
730
|
+
if (scopesWithFamily) {
|
|
731
|
+
for (const scope of scopesWithFamily) {
|
|
732
|
+
let list = scopeFamilies.get(scope);
|
|
733
|
+
if (!list) {
|
|
734
|
+
list = [];
|
|
735
|
+
scopeFamilies.set(scope, list);
|
|
736
|
+
}
|
|
737
|
+
list.push(family);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
for (const [scope, familiesInScope] of scopeFamilies) {
|
|
742
|
+
propagateUpdatedAtoms(familiesInScope, scope, undefined, undefined, false, timestamp, true);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
};
|
|
746
|
+
var propagateUpdatedAtoms = (atoms, data, subscriptions, families, isRecursive = false, timestamp = performance.now(), selectorsOnly = false, isInitOnly = false) => {
|
|
747
|
+
if (atoms.length === 1 && !isRecursive && !selectorsOnly) {
|
|
748
|
+
const atom = atoms[0];
|
|
749
|
+
if (!isFamilyAtom(atom) && !isAtomFamily(atom)) {
|
|
750
|
+
const dependents = data.stateDependents.get(atom);
|
|
751
|
+
if ((!dependents || dependents.size === 0) && (!data.scopes || data.scopes.size === 0)) {
|
|
752
|
+
const subs = data.subscriptions.get(atom);
|
|
753
|
+
if (subs && subs.size > 0) {
|
|
754
|
+
callSubscribers(subs);
|
|
755
|
+
}
|
|
367
756
|
return;
|
|
368
|
-
|
|
757
|
+
}
|
|
369
758
|
}
|
|
370
759
|
}
|
|
371
|
-
if (
|
|
372
|
-
|
|
373
|
-
|
|
760
|
+
if (!subscriptions)
|
|
761
|
+
subscriptions = new Set;
|
|
762
|
+
if (!families)
|
|
763
|
+
families = new Map;
|
|
764
|
+
const selectors = new Set;
|
|
765
|
+
for (const atom of atoms) {
|
|
766
|
+
addSetToSet(data.stateDependents.get(atom), selectors);
|
|
767
|
+
if (!selectorsOnly) {
|
|
768
|
+
addSetToSet(data.subscriptions.get(atom), subscriptions);
|
|
769
|
+
if (isFamilyAtom(atom)) {
|
|
770
|
+
if (!families.has(atom.family)) {
|
|
771
|
+
families.set(atom.family, new Set);
|
|
772
|
+
}
|
|
773
|
+
families.get(atom.family).add(atom);
|
|
774
|
+
}
|
|
374
775
|
}
|
|
375
776
|
}
|
|
376
|
-
if (
|
|
377
|
-
for (const
|
|
378
|
-
|
|
777
|
+
if (families.size > 0) {
|
|
778
|
+
for (const [family, familyAtoms] of families) {
|
|
779
|
+
addSetToSet(data.stateDependents.get(family), selectors);
|
|
780
|
+
addSetToSet(data.subscriptions.get(family), subscriptions);
|
|
781
|
+
if (familyAtoms.size === 0)
|
|
782
|
+
throw new Error("Should not be possible");
|
|
783
|
+
addFamilyAtomsToSet(family, familyAtoms, data, timestamp);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
if (!isRecursive) {
|
|
787
|
+
propagateDirtySelectors(atoms, selectors, data, subscriptions, families, isInitOnly);
|
|
788
|
+
if (data.scopes && data.scopes.size > 0) {
|
|
789
|
+
if (atoms.length === 1) {
|
|
790
|
+
const atom = atoms[0];
|
|
791
|
+
const shadowingScopes = isAtomFamily(atom) ? undefined : data.scopeValueIndex.get(atom);
|
|
792
|
+
for (const [, scope] of data.scopes) {
|
|
793
|
+
if (!shadowingScopes || !shadowingScopes.has(scope)) {
|
|
794
|
+
propagateUpdatedAtoms(atoms, scope, undefined, undefined, false, timestamp, true, isInitOnly);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
} else {
|
|
798
|
+
let anyShadowed = false;
|
|
799
|
+
let atomShadows;
|
|
800
|
+
for (const atom of atoms) {
|
|
801
|
+
if (!isAtomFamily(atom)) {
|
|
802
|
+
const s = data.scopeValueIndex.get(atom);
|
|
803
|
+
if (s && s.size > 0) {
|
|
804
|
+
if (!atomShadows)
|
|
805
|
+
atomShadows = new Map;
|
|
806
|
+
atomShadows.set(atom, s);
|
|
807
|
+
anyShadowed = true;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
if (!anyShadowed) {
|
|
812
|
+
for (const [, scope] of data.scopes) {
|
|
813
|
+
propagateUpdatedAtoms(atoms, scope, undefined, undefined, false, timestamp, true, isInitOnly);
|
|
814
|
+
}
|
|
815
|
+
} else {
|
|
816
|
+
for (const [, scope] of data.scopes) {
|
|
817
|
+
const atomsToUpdateInScope = [];
|
|
818
|
+
for (const atom of atoms) {
|
|
819
|
+
if (isAtomFamily(atom)) {
|
|
820
|
+
atomsToUpdateInScope.push(atom);
|
|
821
|
+
} else {
|
|
822
|
+
const s = atomShadows.get(atom);
|
|
823
|
+
if (!s || !s.has(scope)) {
|
|
824
|
+
atomsToUpdateInScope.push(atom);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
if (atomsToUpdateInScope.length > 0) {
|
|
829
|
+
propagateUpdatedAtoms(atomsToUpdateInScope, scope, undefined, undefined, false, timestamp, true, isInitOnly);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
}
|
|
379
834
|
}
|
|
380
835
|
}
|
|
381
836
|
};
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
837
|
+
var propagateDirtySelectors = (updatedAtoms, selectors, data, subscriptions, families, isInitOnly = false) => {
|
|
838
|
+
const updatedInitializedAtoms = new Set(updatedAtoms);
|
|
839
|
+
if (selectors.size > 0) {
|
|
840
|
+
propagateSelectorUpdates(selectors, data, subscriptions, updatedInitializedAtoms, isInitOnly);
|
|
841
|
+
}
|
|
842
|
+
if (subscriptions.size > 0) {
|
|
843
|
+
callSubscribers(subscriptions, families);
|
|
844
|
+
}
|
|
845
|
+
};
|
|
846
|
+
var propagateSelectorUpdates = (selectors, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly = false) => {
|
|
847
|
+
let currentSelectors = selectors;
|
|
848
|
+
while (currentSelectors.size > 0) {
|
|
849
|
+
const selectorsForNextPass = new Set;
|
|
850
|
+
for (const selector of currentSelectors) {
|
|
851
|
+
const currentValue = data.values.get(selector);
|
|
852
|
+
if (isPromiseLike(currentValue) && isInitOnly) {
|
|
853
|
+
continue;
|
|
854
|
+
}
|
|
855
|
+
const dependents = data.stateDependents.get(selector);
|
|
856
|
+
const subscribers = data.subscriptions.get(selector);
|
|
857
|
+
if (!isPromiseLike(currentValue) && (!dependents || dependents.size === 0) && (!subscribers || subscribers.size === 0)) {
|
|
858
|
+
data.values.delete(selector);
|
|
859
|
+
} else {
|
|
860
|
+
const [wasValueUpdated, didEvalCrash, error, addedDeps, removedDeps] = reEvaluteSelector(selector, data, updatedInitializedAtoms);
|
|
861
|
+
if ((addedDeps.size > 0 || removedDeps.size > 0) && isTransitivelySubscribed(selector, data)) {
|
|
862
|
+
for (const dep of addedDeps) {
|
|
863
|
+
mountTransitiveDeps(dep, data);
|
|
864
|
+
}
|
|
865
|
+
for (const dep of removedDeps) {
|
|
866
|
+
unmountOrphanedDeps(dep, data);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
if (!wasValueUpdated)
|
|
870
|
+
continue;
|
|
871
|
+
addSetToSet(data.stateDependents.get(selector), selectorsForNextPass);
|
|
872
|
+
addSetToSet(subscribers, collectedSubscribers);
|
|
393
873
|
}
|
|
394
874
|
}
|
|
875
|
+
currentSelectors = selectorsForNextPass;
|
|
395
876
|
}
|
|
396
877
|
};
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
878
|
+
|
|
879
|
+
// src/lib/isFunction.ts
|
|
880
|
+
var isFunction = (value) => typeof value === "function";
|
|
881
|
+
|
|
882
|
+
// src/lib/setAtom.ts
|
|
883
|
+
var handlePromise = (atom, promise, currentValue, data, skipOnSet) => {
|
|
884
|
+
const emptyAtomPromise = currentValue?.__isEmptyAtomPromise__ ? currentValue : currentValue?.__emptyAtomPromiseOrigin__ ?? null;
|
|
885
|
+
if (emptyAtomPromise) {
|
|
886
|
+
promise.__emptyAtomPromiseOrigin__ = emptyAtomPromise;
|
|
887
|
+
}
|
|
888
|
+
setValueInData(atom, promise, data);
|
|
889
|
+
promise.then((resolvedValue) => {
|
|
890
|
+
if (data.values.get(atom) !== promise)
|
|
891
|
+
return;
|
|
892
|
+
setValueInData(atom, resolvedValue, data);
|
|
893
|
+
if (atom.onSet && !skipOnSet)
|
|
894
|
+
atom.onSet(resolvedValue, data);
|
|
895
|
+
if (emptyAtomPromise) {
|
|
896
|
+
emptyAtomPromise.__resolveEmptyAtomPromise__(resolvedValue);
|
|
403
897
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
898
|
+
propagateUpdatedAtoms([atom], data);
|
|
899
|
+
}).catch(() => {
|
|
900
|
+
if (data.values.get(atom) !== promise)
|
|
901
|
+
return;
|
|
902
|
+
setValueInData(atom, currentValue, data);
|
|
903
|
+
propagateUpdatedAtoms([atom], data);
|
|
904
|
+
});
|
|
905
|
+
};
|
|
906
|
+
var setAtom = (atom, newValue, data, skipOnSet = false) => {
|
|
907
|
+
let initializedAtomsSet;
|
|
908
|
+
let currentValue;
|
|
909
|
+
if (data.values.has(atom)) {
|
|
910
|
+
currentValue = data.values.get(atom);
|
|
911
|
+
} else {
|
|
912
|
+
initializedAtomsSet = new Set;
|
|
913
|
+
currentValue = getState(atom, data, initializedAtomsSet);
|
|
914
|
+
}
|
|
915
|
+
if (isFunction(newValue)) {
|
|
916
|
+
newValue = newValue(currentValue);
|
|
917
|
+
}
|
|
918
|
+
if (isPromiseLike(newValue)) {
|
|
919
|
+
const promise = Promise.resolve(newValue);
|
|
920
|
+
if (currentValue === promise)
|
|
921
|
+
return promise;
|
|
922
|
+
handlePromise(atom, promise, currentValue, data, skipOnSet);
|
|
923
|
+
if (initializedAtomsSet && initializedAtomsSet.size > 0) {
|
|
924
|
+
initializedAtomsSet.add(atom);
|
|
925
|
+
propagateUpdatedAtoms([...initializedAtomsSet], data);
|
|
926
|
+
} else {
|
|
927
|
+
propagateUpdatedAtoms([atom], data);
|
|
928
|
+
}
|
|
929
|
+
return promise;
|
|
930
|
+
}
|
|
931
|
+
let syncValue = newValue;
|
|
932
|
+
const areEqual = isPromiseLike(currentValue) ? currentValue === syncValue : atom.equal(currentValue, syncValue);
|
|
933
|
+
if (areEqual)
|
|
934
|
+
return syncValue;
|
|
935
|
+
syncValue = setValueInData(atom, syncValue, data);
|
|
936
|
+
if (atom.onSet && !skipOnSet)
|
|
937
|
+
atom.onSet(syncValue, data);
|
|
938
|
+
if (currentValue?.__isEmptyAtomPromise__) {
|
|
939
|
+
currentValue.__resolveEmptyAtomPromise__(syncValue);
|
|
940
|
+
}
|
|
941
|
+
if (initializedAtomsSet && initializedAtomsSet.size > 0) {
|
|
942
|
+
initializedAtomsSet.add(atom);
|
|
943
|
+
propagateUpdatedAtoms([...initializedAtomsSet], data);
|
|
944
|
+
} else {
|
|
945
|
+
propagateUpdatedAtoms([atom], data);
|
|
946
|
+
}
|
|
947
|
+
return syncValue;
|
|
948
|
+
};
|
|
949
|
+
|
|
950
|
+
// src/lib/initAtom.ts
|
|
951
|
+
var getAtomInitValue = (atom, data, initializedAtomsSet) => {
|
|
952
|
+
if (atom.defaultValue === undefined) {
|
|
953
|
+
let promiseResolve;
|
|
954
|
+
const promise = new Promise((resolve) => {
|
|
955
|
+
promiseResolve = resolve;
|
|
956
|
+
});
|
|
957
|
+
promise.__isEmptyAtomPromise__ = true;
|
|
958
|
+
promise.__resolveEmptyAtomPromise__ = promiseResolve;
|
|
959
|
+
return promise;
|
|
960
|
+
} else if (typeof atom.defaultValue === "function") {
|
|
961
|
+
const value = atom.defaultValue();
|
|
962
|
+
if (isPromiseLike(value)) {
|
|
963
|
+
value.then((resolvedValue) => {
|
|
964
|
+
if (data.values.get(atom) !== value)
|
|
965
|
+
return;
|
|
966
|
+
setValueInData(atom, resolvedValue, data);
|
|
967
|
+
propagateUpdatedAtoms([atom], data);
|
|
968
|
+
}, () => {
|
|
969
|
+
if (data.values.get(atom) === value) {
|
|
970
|
+
data.values.delete(atom);
|
|
971
|
+
}
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
return value;
|
|
975
|
+
} else if (isSelector(atom.defaultValue)) {
|
|
976
|
+
return getState(atom.defaultValue, data, initializedAtomsSet);
|
|
977
|
+
} else {
|
|
978
|
+
return atom.defaultValue;
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
var initAtom = (atom, data, initializedAtomsSet) => {
|
|
982
|
+
const tmpVal = getAtomInitValue(atom, data, initializedAtomsSet);
|
|
983
|
+
let value = setValueInData(atom, tmpVal, data);
|
|
984
|
+
if (atom.onInit)
|
|
985
|
+
atom.onInit((newVal) => {
|
|
986
|
+
value = newVal;
|
|
987
|
+
setAtom(atom, newVal, data, true);
|
|
988
|
+
}, data);
|
|
989
|
+
};
|
|
990
|
+
|
|
991
|
+
// src/lib/getState.ts
|
|
992
|
+
function getState(state, data, initializedAtomsSet, circularDependencySet) {
|
|
993
|
+
if (data.values.has(state))
|
|
994
|
+
return data.values.get(state);
|
|
995
|
+
if (isAtom(state)) {
|
|
996
|
+
if ("parent" in data)
|
|
997
|
+
return getState(state, data.parent, initializedAtomsSet, circularDependencySet);
|
|
998
|
+
if (isFamilyAtom(state)) {
|
|
999
|
+
const familyValue = data.values.get(state.family);
|
|
1000
|
+
if (familyValue?.__index) {
|
|
1001
|
+
if (isAtomDeletedInFamilyIndex(state, familyValue.__index)) {
|
|
1002
|
+
return state.defaultValue;
|
|
1003
|
+
}
|
|
408
1004
|
}
|
|
409
1005
|
}
|
|
1006
|
+
initAtom(state, data, initializedAtomsSet);
|
|
1007
|
+
initializedAtomsSet.add(state);
|
|
1008
|
+
return data.values.get(state);
|
|
410
1009
|
}
|
|
411
|
-
|
|
412
|
-
|
|
1010
|
+
if (isSelector(state)) {
|
|
1011
|
+
if (_evalDepth >= MAX_EVAL_DEPTH) {
|
|
1012
|
+
throw new NeedsInitError(state);
|
|
1013
|
+
}
|
|
1014
|
+
initSelector(state, data, initializedAtomsSet, circularDependencySet);
|
|
1015
|
+
return data.values.get(state);
|
|
413
1016
|
}
|
|
414
|
-
|
|
415
|
-
|
|
1017
|
+
if (isAtomFamily(state)) {
|
|
1018
|
+
if ("parent" in data) {
|
|
1019
|
+
const closestData = findClosestStoreWithAtomInitialized(state, data);
|
|
1020
|
+
return getState(state, closestData, initializedAtomsSet, circularDependencySet);
|
|
1021
|
+
}
|
|
1022
|
+
data.values.set(state, renderAtomFamilyIndex(createAtomFamilyIndex()));
|
|
1023
|
+
initializedAtomsSet.add(state);
|
|
1024
|
+
return data.values.get(state);
|
|
416
1025
|
}
|
|
1026
|
+
if (isSelectorFamily(state)) {
|
|
1027
|
+
const array = Array.from(state.__valdresSelectorFamilyMap.keys());
|
|
1028
|
+
if (equal(array, state._keyArray))
|
|
1029
|
+
return state._keyArray;
|
|
1030
|
+
state._keyArray = array;
|
|
1031
|
+
return array;
|
|
1032
|
+
}
|
|
1033
|
+
throw new Error("Invalid object passed to get");
|
|
1034
|
+
}
|
|
1035
|
+
var findClosestStoreWithAtomInitialized = (atom, data) => {
|
|
1036
|
+
if ("parent" in data === false)
|
|
1037
|
+
return data;
|
|
1038
|
+
if (data.values.has(atom))
|
|
1039
|
+
return data;
|
|
1040
|
+
return findClosestStoreWithAtomInitialized(atom, data.parent);
|
|
1041
|
+
};
|
|
1042
|
+
var isAtomDeletedInFamilyIndex = (atom, index) => {
|
|
1043
|
+
if (index.deleted.has(atom))
|
|
1044
|
+
return true;
|
|
1045
|
+
if (index.created.has(atom))
|
|
1046
|
+
return false;
|
|
1047
|
+
if (index.parentIndex)
|
|
1048
|
+
return isAtomDeletedInFamilyIndex(atom, index.parentIndex);
|
|
1049
|
+
return false;
|
|
1050
|
+
};
|
|
1051
|
+
|
|
1052
|
+
// src/utils/resolveReactive.ts
|
|
1053
|
+
var isReactive = (value) => typeof value === "object" && value !== null && (isAtom(value) || isSelector(value));
|
|
1054
|
+
var resolveReactive = (value, data) => {
|
|
1055
|
+
if (typeof value === "object" && value !== null && (isAtom(value) || isSelector(value))) {
|
|
1056
|
+
if (data.values.has(value))
|
|
1057
|
+
return data.values.get(value);
|
|
1058
|
+
return getState(value, data, new Set);
|
|
1059
|
+
}
|
|
1060
|
+
return value;
|
|
417
1061
|
};
|
|
418
1062
|
|
|
419
1063
|
// src/lib/createStoreData.ts
|
|
420
|
-
var
|
|
421
|
-
var
|
|
1064
|
+
var nextId = 0;
|
|
1065
|
+
var generateId = () => "__valdres_store_" + nextId++;
|
|
1066
|
+
function makeLazyGetter(key) {
|
|
422
1067
|
return {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
1068
|
+
get() {
|
|
1069
|
+
const map = new WeakMap;
|
|
1070
|
+
Object.defineProperty(this, key, {
|
|
1071
|
+
value: map,
|
|
1072
|
+
writable: true,
|
|
1073
|
+
configurable: true
|
|
1074
|
+
});
|
|
1075
|
+
return map;
|
|
1076
|
+
},
|
|
1077
|
+
configurable: true
|
|
431
1078
|
};
|
|
432
|
-
}
|
|
433
|
-
|
|
1079
|
+
}
|
|
1080
|
+
var lazyProto = Object.create(Object.prototype);
|
|
1081
|
+
Object.defineProperties(lazyProto, {
|
|
1082
|
+
subscriptions: makeLazyGetter("subscriptions"),
|
|
1083
|
+
subscriptionsRequireEqualCheck: makeLazyGetter("subscriptionsRequireEqualCheck"),
|
|
1084
|
+
stateDependents: makeLazyGetter("stateDependents"),
|
|
1085
|
+
stateDependencies: makeLazyGetter("stateDependencies"),
|
|
1086
|
+
mounts: makeLazyGetter("mounts"),
|
|
1087
|
+
abortControllers: makeLazyGetter("abortControllers"),
|
|
1088
|
+
lastValueWriteAt: makeLazyGetter("lastValueWriteAt")
|
|
1089
|
+
});
|
|
1090
|
+
function createStoreData(id, parent, options) {
|
|
1091
|
+
const data = Object.create(lazyProto);
|
|
1092
|
+
data.id = id ?? generateId();
|
|
1093
|
+
data.values = new WeakMap;
|
|
1094
|
+
data.scopes = new Map;
|
|
1095
|
+
data.scopeValueIndex = new WeakMap;
|
|
1096
|
+
if (options?.batchUpdates) {
|
|
1097
|
+
data.batchUpdates = true;
|
|
1098
|
+
}
|
|
434
1099
|
if (parent) {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
scopeConsumers: parent ? new Set : undefined
|
|
439
|
-
};
|
|
440
|
-
} else {
|
|
441
|
-
return generateStoreData(id);
|
|
1100
|
+
data.parent = parent;
|
|
1101
|
+
data.scopeConsumers = new Set;
|
|
1102
|
+
data.scopeIndexKeys = new Set;
|
|
442
1103
|
}
|
|
1104
|
+
return data;
|
|
443
1105
|
}
|
|
444
1106
|
|
|
1107
|
+
// src/lib/deleteFamilyAtom.ts
|
|
1108
|
+
var deleteFamilyAtom = (atom, data) => {
|
|
1109
|
+
data.values.delete(atom);
|
|
1110
|
+
if (atom.family) {
|
|
1111
|
+
atom.family.release(...atom.familyArgs);
|
|
1112
|
+
}
|
|
1113
|
+
propagateDeletedAtoms([atom], data);
|
|
1114
|
+
};
|
|
1115
|
+
|
|
445
1116
|
// src/lib/resetAtom.ts
|
|
446
1117
|
var resetAtom = (atom, data) => {
|
|
447
|
-
|
|
448
|
-
|
|
1118
|
+
const initializedAtomsSet = new Set;
|
|
1119
|
+
let value = getAtomInitValue(atom, data, initializedAtomsSet);
|
|
1120
|
+
setValueInData(atom, value, data);
|
|
449
1121
|
if (!isPromiseLike(value)) {
|
|
450
1122
|
propagateUpdatedAtoms([atom], data);
|
|
451
1123
|
}
|
|
1124
|
+
if (initializedAtomsSet.size > 0) {
|
|
1125
|
+
throw new Error("Todo - propagateUpdatedAtoms on reset");
|
|
1126
|
+
}
|
|
452
1127
|
return value;
|
|
453
1128
|
};
|
|
454
1129
|
|
|
455
1130
|
// src/utils/isFamily.ts
|
|
456
1131
|
var isFamily = (state) => isAtomFamily(state) || isSelectorFamily(state);
|
|
457
1132
|
|
|
1133
|
+
// src/lib/maxAgeCleanups.ts
|
|
1134
|
+
var maxAgeCleanups = new WeakMap;
|
|
1135
|
+
var setMaxAgeCleanup = (data, state, cleanup) => {
|
|
1136
|
+
let storeMap = maxAgeCleanups.get(data);
|
|
1137
|
+
if (!storeMap) {
|
|
1138
|
+
storeMap = new WeakMap;
|
|
1139
|
+
maxAgeCleanups.set(data, storeMap);
|
|
1140
|
+
}
|
|
1141
|
+
storeMap.set(state, cleanup);
|
|
1142
|
+
};
|
|
1143
|
+
var getMaxAgeCleanup = (data, state) => {
|
|
1144
|
+
return maxAgeCleanups.get(data)?.get(state);
|
|
1145
|
+
};
|
|
1146
|
+
var deleteMaxAgeCleanup = (data, state) => {
|
|
1147
|
+
maxAgeCleanups.get(data)?.delete(state);
|
|
1148
|
+
};
|
|
1149
|
+
|
|
458
1150
|
// src/lib/unsubscribe.ts
|
|
459
|
-
var unsubscribe = (state, subscription, data
|
|
1151
|
+
var unsubscribe = (state, subscription, data) => {
|
|
460
1152
|
const subscribers = data.subscriptions.get(state);
|
|
461
1153
|
if (subscribers) {
|
|
462
1154
|
subscribers.delete(subscription);
|
|
@@ -472,26 +1164,246 @@ var unsubscribe = (state, subscription, data, mount, maxAgeCleanup) => {
|
|
|
472
1164
|
data.subscriptionsRequireEqualCheck.delete(state);
|
|
473
1165
|
}
|
|
474
1166
|
}
|
|
475
|
-
if (subscribers.size === 0) {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
1167
|
+
if (subscribers.size === 0) {
|
|
1168
|
+
const maxAgeCleanup = getMaxAgeCleanup(data, state);
|
|
1169
|
+
if (maxAgeCleanup) {
|
|
1170
|
+
maxAgeCleanup();
|
|
1171
|
+
deleteMaxAgeCleanup(data, state);
|
|
1172
|
+
}
|
|
1173
|
+
data.subscriptions.delete(state);
|
|
1174
|
+
unmountOrphanedDeps(state, data);
|
|
1175
|
+
cleanupOrphanedDeps(state, data);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
};
|
|
1179
|
+
var cleanupOrphanedDeps = (state, data, visited = new Set) => {
|
|
1180
|
+
if (visited.has(state))
|
|
1181
|
+
return;
|
|
1182
|
+
visited.add(state);
|
|
1183
|
+
if (isTransitivelySubscribed(state, data))
|
|
1184
|
+
return;
|
|
1185
|
+
const deps = data.stateDependencies.get(state);
|
|
1186
|
+
if (deps) {
|
|
1187
|
+
for (const dep of deps) {
|
|
1188
|
+
const depDependents = data.stateDependents.get(dep);
|
|
1189
|
+
if (depDependents) {
|
|
1190
|
+
depDependents.delete(state);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
data.stateDependencies.delete(state);
|
|
1194
|
+
data.values.delete(state);
|
|
1195
|
+
data.abortControllers.delete(state);
|
|
1196
|
+
}
|
|
1197
|
+
const dependents = data.stateDependents.get(state);
|
|
1198
|
+
if (dependents) {
|
|
1199
|
+
for (const dep of [...dependents]) {
|
|
1200
|
+
cleanupOrphanedDeps(dep, data, visited);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
};
|
|
1204
|
+
|
|
1205
|
+
// src/lib/subscribe.ts
|
|
1206
|
+
var initSubscribers = (state, data) => {
|
|
1207
|
+
const set = new Set;
|
|
1208
|
+
data.subscriptions.set(state, set);
|
|
1209
|
+
return set;
|
|
1210
|
+
};
|
|
1211
|
+
var installMaxAgeTimer = (state, data) => {
|
|
1212
|
+
if (!state.maxAge)
|
|
1213
|
+
return;
|
|
1214
|
+
const globalState = isGlobalAtom(state) ? state : undefined;
|
|
1215
|
+
const existing = globalState?.maxAgeInterval;
|
|
1216
|
+
if (existing) {
|
|
1217
|
+
existing.refCount++;
|
|
1218
|
+
const metaAtom2 = state.__cacheMeta ??= { equal, defaultValue: null };
|
|
1219
|
+
for (const s of globalState.stores) {
|
|
1220
|
+
if (s !== data && s.values.has(metaAtom2)) {
|
|
1221
|
+
setValueInData(metaAtom2, s.values.get(metaAtom2), data);
|
|
1222
|
+
propagateUpdatedAtoms([metaAtom2], data);
|
|
1223
|
+
break;
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
setMaxAgeCleanup(data, state, () => {
|
|
1227
|
+
if (existing.refCount <= 0)
|
|
1228
|
+
return;
|
|
1229
|
+
existing.refCount--;
|
|
1230
|
+
if (existing.refCount === 0) {
|
|
1231
|
+
existing.cleanup();
|
|
1232
|
+
if (globalState.maxAgeInterval === existing) {
|
|
1233
|
+
globalState.maxAgeInterval = undefined;
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
});
|
|
1237
|
+
return;
|
|
1238
|
+
}
|
|
1239
|
+
const pendingTimeouts = new Set;
|
|
1240
|
+
let revalidating = false;
|
|
1241
|
+
let cancelled = false;
|
|
1242
|
+
let lastSuccessTime = Date.now();
|
|
1243
|
+
const NO_VALUE = Symbol();
|
|
1244
|
+
let lastGoodValue = NO_VALUE;
|
|
1245
|
+
let currentInterval;
|
|
1246
|
+
const getMaxAge = () => resolveReactive(state.maxAge, data);
|
|
1247
|
+
const getSWR = () => state.staleWhileRevalidate !== undefined ? resolveReactive(state.staleWhileRevalidate, data) : Infinity;
|
|
1248
|
+
const getStaleIfError = () => state.staleIfError !== undefined ? resolveReactive(state.staleIfError, data) : Infinity;
|
|
1249
|
+
const metaAtom = state.__cacheMeta ??= { equal, defaultValue: null };
|
|
1250
|
+
const updateMeta = () => {
|
|
1251
|
+
const meta = {
|
|
1252
|
+
isRevalidating: revalidating,
|
|
1253
|
+
lastSuccessAt: lastSuccessTime,
|
|
1254
|
+
maxAge: getMaxAge(),
|
|
1255
|
+
staleWhileRevalidate: getSWR(),
|
|
1256
|
+
staleIfError: getStaleIfError()
|
|
1257
|
+
};
|
|
1258
|
+
if (globalState) {
|
|
1259
|
+
for (const store of globalState.stores) {
|
|
1260
|
+
setValueInData(metaAtom, meta, store);
|
|
1261
|
+
propagateUpdatedAtoms([metaAtom], store);
|
|
1262
|
+
}
|
|
1263
|
+
} else {
|
|
1264
|
+
setValueInData(metaAtom, meta, data);
|
|
1265
|
+
propagateUpdatedAtoms([metaAtom], data);
|
|
1266
|
+
}
|
|
1267
|
+
};
|
|
1268
|
+
const isPastStaleIfErrorWindow = () => {
|
|
1269
|
+
const elapsed = Date.now() - lastSuccessTime;
|
|
1270
|
+
return elapsed >= getMaxAge() + getStaleIfError();
|
|
1271
|
+
};
|
|
1272
|
+
const setAndPropagate = (atom, val) => {
|
|
1273
|
+
if (globalState) {
|
|
1274
|
+
for (const store of globalState.stores) {
|
|
1275
|
+
setValueInData(atom, val, store);
|
|
1276
|
+
propagateUpdatedAtoms([atom], store);
|
|
1277
|
+
}
|
|
1278
|
+
} else {
|
|
1279
|
+
setValueInData(atom, val, data);
|
|
1280
|
+
propagateUpdatedAtoms([atom], data);
|
|
1281
|
+
}
|
|
1282
|
+
};
|
|
1283
|
+
const getValueStore = () => {
|
|
1284
|
+
if (globalState) {
|
|
1285
|
+
for (const s of globalState.stores)
|
|
1286
|
+
return s;
|
|
1287
|
+
}
|
|
1288
|
+
return data;
|
|
1289
|
+
};
|
|
1290
|
+
const tick = () => {
|
|
1291
|
+
if (revalidating)
|
|
1292
|
+
return;
|
|
1293
|
+
if (typeof state.defaultValue !== "function")
|
|
1294
|
+
return;
|
|
1295
|
+
const valueStore = getValueStore();
|
|
1296
|
+
if (valueStore.values.has(state)) {
|
|
1297
|
+
const currentValue = valueStore.values.get(state);
|
|
1298
|
+
if (!isPromiseLike(currentValue)) {
|
|
1299
|
+
lastGoodValue = currentValue;
|
|
1300
|
+
}
|
|
479
1301
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
1302
|
+
const value = state.defaultValue();
|
|
1303
|
+
if (isPromiseLike(value)) {
|
|
1304
|
+
revalidating = true;
|
|
1305
|
+
updateMeta();
|
|
1306
|
+
const swr = getSWR();
|
|
1307
|
+
const handleResolve = (resolved) => {
|
|
1308
|
+
if (cancelled)
|
|
1309
|
+
return;
|
|
1310
|
+
revalidating = false;
|
|
1311
|
+
lastSuccessTime = Date.now();
|
|
1312
|
+
lastGoodValue = resolved;
|
|
1313
|
+
setAndPropagate(state, resolved);
|
|
1314
|
+
updateMeta();
|
|
1315
|
+
};
|
|
1316
|
+
const handleReject = () => {
|
|
1317
|
+
if (cancelled)
|
|
1318
|
+
return;
|
|
1319
|
+
revalidating = false;
|
|
1320
|
+
if (!isPastStaleIfErrorWindow() && lastGoodValue !== NO_VALUE) {
|
|
1321
|
+
setAndPropagate(state, lastGoodValue);
|
|
1322
|
+
} else {
|
|
1323
|
+
setAndPropagate(state, value);
|
|
1324
|
+
}
|
|
1325
|
+
updateMeta();
|
|
1326
|
+
};
|
|
1327
|
+
if (swr > 0) {
|
|
1328
|
+
let timeoutRef;
|
|
1329
|
+
if (Number.isFinite(swr)) {
|
|
1330
|
+
timeoutRef = setTimeout(() => {
|
|
1331
|
+
pendingTimeouts.delete(timeoutRef);
|
|
1332
|
+
if (cancelled || !revalidating)
|
|
1333
|
+
return;
|
|
1334
|
+
setAndPropagate(state, value);
|
|
1335
|
+
}, swr);
|
|
1336
|
+
pendingTimeouts.add(timeoutRef);
|
|
484
1337
|
}
|
|
1338
|
+
value.then((resolved) => {
|
|
1339
|
+
if (timeoutRef !== undefined) {
|
|
1340
|
+
clearTimeout(timeoutRef);
|
|
1341
|
+
pendingTimeouts.delete(timeoutRef);
|
|
1342
|
+
}
|
|
1343
|
+
handleResolve(resolved);
|
|
1344
|
+
}, () => {
|
|
1345
|
+
if (timeoutRef !== undefined) {
|
|
1346
|
+
clearTimeout(timeoutRef);
|
|
1347
|
+
pendingTimeouts.delete(timeoutRef);
|
|
1348
|
+
}
|
|
1349
|
+
handleReject();
|
|
1350
|
+
});
|
|
1351
|
+
} else {
|
|
1352
|
+
setAndPropagate(state, value);
|
|
1353
|
+
value.then(handleResolve, handleReject);
|
|
485
1354
|
}
|
|
1355
|
+
} else {
|
|
1356
|
+
lastSuccessTime = Date.now();
|
|
1357
|
+
lastGoodValue = value;
|
|
1358
|
+
setAndPropagate(state, value);
|
|
1359
|
+
updateMeta();
|
|
486
1360
|
}
|
|
1361
|
+
};
|
|
1362
|
+
const startInterval = () => {
|
|
1363
|
+
currentInterval = setInterval(tick, getMaxAge());
|
|
1364
|
+
};
|
|
1365
|
+
startInterval();
|
|
1366
|
+
updateMeta();
|
|
1367
|
+
const configUnsubs = [];
|
|
1368
|
+
if (isReactive(state.maxAge)) {
|
|
1369
|
+
configUnsubs.push(subscribe(state.maxAge, () => {
|
|
1370
|
+
clearInterval(currentInterval);
|
|
1371
|
+
startInterval();
|
|
1372
|
+
updateMeta();
|
|
1373
|
+
}, false, data));
|
|
1374
|
+
}
|
|
1375
|
+
if (state.staleWhileRevalidate && isReactive(state.staleWhileRevalidate)) {
|
|
1376
|
+
configUnsubs.push(subscribe(state.staleWhileRevalidate, () => updateMeta(), false, data));
|
|
1377
|
+
}
|
|
1378
|
+
if (state.staleIfError && isReactive(state.staleIfError)) {
|
|
1379
|
+
configUnsubs.push(subscribe(state.staleIfError, () => updateMeta(), false, data));
|
|
1380
|
+
}
|
|
1381
|
+
const cleanup = () => {
|
|
1382
|
+
cancelled = true;
|
|
1383
|
+
clearInterval(currentInterval);
|
|
1384
|
+
for (const t of pendingTimeouts)
|
|
1385
|
+
clearTimeout(t);
|
|
1386
|
+
pendingTimeouts.clear();
|
|
1387
|
+
for (const unsub of configUnsubs)
|
|
1388
|
+
unsub();
|
|
1389
|
+
};
|
|
1390
|
+
if (globalState) {
|
|
1391
|
+
const entry = { cleanup, refCount: 1 };
|
|
1392
|
+
globalState.maxAgeInterval = entry;
|
|
1393
|
+
setMaxAgeCleanup(data, state, () => {
|
|
1394
|
+
if (entry.refCount <= 0)
|
|
1395
|
+
return;
|
|
1396
|
+
entry.refCount--;
|
|
1397
|
+
if (entry.refCount === 0) {
|
|
1398
|
+
entry.cleanup();
|
|
1399
|
+
if (globalState.maxAgeInterval === entry) {
|
|
1400
|
+
globalState.maxAgeInterval = undefined;
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
});
|
|
1404
|
+
} else {
|
|
1405
|
+
setMaxAgeCleanup(data, state, cleanup);
|
|
487
1406
|
}
|
|
488
|
-
};
|
|
489
|
-
|
|
490
|
-
// src/lib/subscribe.ts
|
|
491
|
-
var initSubscribers = (state, data) => {
|
|
492
|
-
const set = new Set;
|
|
493
|
-
data.subscriptions.set(state, set);
|
|
494
|
-
return set;
|
|
495
1407
|
};
|
|
496
1408
|
var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) => {
|
|
497
1409
|
let parentUnsubscribe;
|
|
@@ -506,14 +1418,21 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
|
|
|
506
1418
|
originalCallback(arg);
|
|
507
1419
|
};
|
|
508
1420
|
} else if (!data.values.has(state) && isAtom(state)) {
|
|
509
|
-
|
|
1421
|
+
const initializedAtomsSet = new Set;
|
|
1422
|
+
initAtom(state, data, initializedAtomsSet);
|
|
1423
|
+
if (initializedAtomsSet.size) {
|
|
1424
|
+
throw new Error("This should not be possible");
|
|
1425
|
+
}
|
|
510
1426
|
}
|
|
511
1427
|
if (isSelector(state) && !data.values.has(state)) {
|
|
512
|
-
initSelector(state, data);
|
|
1428
|
+
initSelector(state, data, new Set, new WeakSet);
|
|
513
1429
|
}
|
|
514
1430
|
const subscribers = data.subscriptions.get(state) || initSubscribers(state, data);
|
|
515
1431
|
let subscription;
|
|
516
1432
|
if (isFamily(state)) {
|
|
1433
|
+
if (isSelectorFamily(state)) {
|
|
1434
|
+
throw new Error("Subscribe to selectorFammily is currently not supported");
|
|
1435
|
+
}
|
|
517
1436
|
subscription = {
|
|
518
1437
|
callback,
|
|
519
1438
|
state,
|
|
@@ -526,45 +1445,12 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
|
|
|
526
1445
|
};
|
|
527
1446
|
}
|
|
528
1447
|
subscribers.add(subscription);
|
|
529
|
-
let mount;
|
|
530
|
-
let maxAgeCleanup;
|
|
531
1448
|
if (subscribers.size === 1) {
|
|
532
1449
|
if (isAtom(state) && state.maxAge) {
|
|
533
|
-
|
|
534
|
-
const interval = setInterval(() => {
|
|
535
|
-
let value = getAtomInitValue(state, data);
|
|
536
|
-
if (isPromiseLike(value)) {
|
|
537
|
-
if (state.staleWhileRevalidate) {
|
|
538
|
-
const oldValue = data.values.get(state);
|
|
539
|
-
timeout = setTimeout(() => {
|
|
540
|
-
const nowValue = data.values.get(state);
|
|
541
|
-
console.log("todo", oldValue);
|
|
542
|
-
}, state.staleWhileRevalidate);
|
|
543
|
-
value.then((res) => clearTimeout(timeout));
|
|
544
|
-
}
|
|
545
|
-
} else {
|
|
546
|
-
data.values.set(state, value);
|
|
547
|
-
propagateUpdatedAtoms([state], data);
|
|
548
|
-
}
|
|
549
|
-
}, state.maxAge);
|
|
550
|
-
maxAgeCleanup = () => {
|
|
551
|
-
clearInterval(interval);
|
|
552
|
-
if (timeout)
|
|
553
|
-
clearTimeout(timeout);
|
|
554
|
-
};
|
|
1450
|
+
installMaxAgeTimer(state, data);
|
|
555
1451
|
}
|
|
556
|
-
if (state
|
|
557
|
-
|
|
558
|
-
const mountSubscriptions = new Set;
|
|
559
|
-
const originalSub = store.sub;
|
|
560
|
-
store.sub = (state2, callback2) => {
|
|
561
|
-
mountSubscriptions.add(callback2);
|
|
562
|
-
return originalSub(state2, callback2);
|
|
563
|
-
};
|
|
564
|
-
mount = {
|
|
565
|
-
onUnmount: state.onMount(store, state),
|
|
566
|
-
mountSubscriptions
|
|
567
|
-
};
|
|
1452
|
+
if (!isFamily(state)) {
|
|
1453
|
+
mountTransitiveDeps(state, data);
|
|
568
1454
|
}
|
|
569
1455
|
}
|
|
570
1456
|
if (requireDeepEqualCheckBeforeCallback && data.subscriptionsRequireEqualCheck.get(state) !== true) {
|
|
@@ -574,140 +1460,273 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
|
|
|
574
1460
|
if (parentUnsubscribe) {
|
|
575
1461
|
parentUnsubscribe();
|
|
576
1462
|
}
|
|
577
|
-
unsubscribe(state, subscription, data
|
|
1463
|
+
unsubscribe(state, subscription, data);
|
|
578
1464
|
};
|
|
579
1465
|
};
|
|
580
1466
|
|
|
581
1467
|
// src/lib/setAtoms.ts
|
|
582
|
-
var setAtoms = (pairs, data) => {
|
|
1468
|
+
var setAtoms = (pairs, data, initializedAtomsSet) => {
|
|
583
1469
|
const updatedAtoms = [];
|
|
584
1470
|
for (let [atom, value] of pairs) {
|
|
585
|
-
const currentValue = getState(atom, data);
|
|
586
|
-
|
|
1471
|
+
const currentValue = getState(atom, data, initializedAtomsSet);
|
|
1472
|
+
const areEqual = isPromiseLike(currentValue) || isPromiseLike(value) ? currentValue === value : atom.equal(currentValue, value);
|
|
1473
|
+
if (!areEqual) {
|
|
587
1474
|
updatedAtoms.push(atom);
|
|
1475
|
+
value = setValueInData(atom, value, data);
|
|
588
1476
|
if (atom.onSet)
|
|
589
1477
|
atom.onSet(value, data);
|
|
590
|
-
|
|
1478
|
+
} else {
|
|
1479
|
+
setValueInData(atom, value, data);
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
if (initializedAtomsSet.size > 0) {
|
|
1483
|
+
for (const atom of initializedAtomsSet) {
|
|
1484
|
+
updatedAtoms.push(atom);
|
|
591
1485
|
}
|
|
592
1486
|
}
|
|
593
|
-
|
|
1487
|
+
if (updatedAtoms.length > 0) {
|
|
1488
|
+
propagateUpdatedAtoms(updatedAtoms, data);
|
|
1489
|
+
}
|
|
594
1490
|
};
|
|
595
1491
|
|
|
596
1492
|
// src/lib/transaction.ts
|
|
597
|
-
var
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
if (!result.has(consumer)) {
|
|
602
|
-
result.add(consumer);
|
|
603
|
-
findDependencies(consumer, data, result);
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
return result;
|
|
1493
|
+
var deleteAtomFamilyAtoms = (set, data) => {
|
|
1494
|
+
set.forEach((atom) => {
|
|
1495
|
+
data.values.delete(atom);
|
|
1496
|
+
});
|
|
608
1497
|
};
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
1498
|
+
|
|
1499
|
+
class Transaction {
|
|
1500
|
+
data;
|
|
1501
|
+
parentTransaction;
|
|
1502
|
+
dirty;
|
|
1503
|
+
_scopedTransactions;
|
|
1504
|
+
_initializedAtomsSet;
|
|
1505
|
+
_deleteSet;
|
|
1506
|
+
_selectorDependencies;
|
|
1507
|
+
_selectorCache;
|
|
1508
|
+
_atomMap;
|
|
1509
|
+
constructor(data, parentTransaction, childTransaction) {
|
|
1510
|
+
this.data = data;
|
|
1511
|
+
this.parentTransaction = parentTransaction;
|
|
1512
|
+
this.dirty = false;
|
|
1513
|
+
this._atomMap = new Map;
|
|
1514
|
+
if (childTransaction) {
|
|
1515
|
+
this._scopedTransactions = new Map([
|
|
1516
|
+
[childTransaction.data.id, childTransaction]
|
|
1517
|
+
]);
|
|
614
1518
|
}
|
|
615
1519
|
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
1520
|
+
hasTxnOrData = (state) => {
|
|
1521
|
+
if (this._atomMap.has(state))
|
|
1522
|
+
return true;
|
|
1523
|
+
if (this.data.values.has(state))
|
|
1524
|
+
return true;
|
|
1525
|
+
if (this.parentTransaction)
|
|
1526
|
+
return this.parentTransaction.hasTxnOrData(state);
|
|
1527
|
+
return false;
|
|
1528
|
+
};
|
|
1529
|
+
valueFromTxnOrData = (state) => {
|
|
1530
|
+
if (this._atomMap.has(state)) {
|
|
1531
|
+
return this._atomMap.get(state);
|
|
1532
|
+
}
|
|
1533
|
+
if (this.data.values.has(state)) {
|
|
1534
|
+
return this.data.values.get(state);
|
|
1535
|
+
}
|
|
1536
|
+
if (this.parentTransaction) {
|
|
1537
|
+
return this.parentTransaction.valueFromTxnOrData(state);
|
|
1538
|
+
}
|
|
1539
|
+
};
|
|
1540
|
+
get = (state) => {
|
|
1541
|
+
if (isAtom(state) || isAtomFamily(state)) {
|
|
1542
|
+
if (this.hasTxnOrData(state)) {
|
|
1543
|
+
return this.valueFromTxnOrData(state);
|
|
1544
|
+
}
|
|
1545
|
+
return getState(state, this.data, this.initializedAtomsSet);
|
|
633
1546
|
} else if (isSelector(state)) {
|
|
634
|
-
if (
|
|
635
|
-
|
|
1547
|
+
if (this.dirty) {
|
|
1548
|
+
this.selectorCache.clear();
|
|
1549
|
+
this.selectorDependencies.clear();
|
|
1550
|
+
this.dirty = false;
|
|
1551
|
+
} else if (this.selectorCache.has(state)) {
|
|
1552
|
+
return this.selectorCache.get(state);
|
|
636
1553
|
}
|
|
637
|
-
const deps = new Set;
|
|
638
1554
|
const res = state.get((s) => {
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
}, data.id);
|
|
642
|
-
for (const dep of deps) {
|
|
643
|
-
if (!txnSubscribers.has(dep)) {
|
|
644
|
-
txnSubscribers.set(dep, new Set);
|
|
1555
|
+
if (!this.selectorDependencies.has(s)) {
|
|
1556
|
+
this.selectorDependencies.add(s);
|
|
645
1557
|
}
|
|
646
|
-
|
|
647
|
-
}
|
|
648
|
-
|
|
1558
|
+
return this.get(s);
|
|
1559
|
+
}, this.data.id);
|
|
1560
|
+
this.selectorCache.set(state, res);
|
|
649
1561
|
return res;
|
|
650
|
-
} else if (isFamily(state)) {
|
|
651
|
-
return txnAtomMap.has(state) ? txnAtomMap.get(state) : getState(state.__keysSelector, data);
|
|
652
1562
|
} else {
|
|
653
1563
|
throw new Error("Unsupported state");
|
|
654
1564
|
}
|
|
655
1565
|
};
|
|
656
|
-
|
|
1566
|
+
set = (atom, value) => {
|
|
657
1567
|
if (!isAtom(atom))
|
|
658
1568
|
throw new Error("Not an atom");
|
|
659
1569
|
if (isFunction(value)) {
|
|
660
|
-
const currentValue =
|
|
1570
|
+
const currentValue = this.get(atom);
|
|
661
1571
|
value = value(currentValue);
|
|
662
1572
|
}
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
txnSelectorCache.delete(selector);
|
|
1573
|
+
if (!atom.mutable && !isProd() && value !== null && (typeof value === "object" || typeof value === "function")) {
|
|
1574
|
+
value = deepFreeze(value);
|
|
666
1575
|
}
|
|
667
|
-
|
|
668
|
-
|
|
1576
|
+
this._atomMap.set(atom, value);
|
|
1577
|
+
if (!this.dirty)
|
|
1578
|
+
this.dirty = true;
|
|
1579
|
+
if (isFamilyAtom(atom)) {
|
|
1580
|
+
if (!this._atomMap.has(atom.family)) {
|
|
1581
|
+
this.cloneFamilyIntoTxn(atom.family);
|
|
1582
|
+
}
|
|
1583
|
+
const index = this._atomMap.get(atom.family).__index;
|
|
1584
|
+
index.created.set(atom, performance.now());
|
|
1585
|
+
index.deleted.delete(atom);
|
|
1586
|
+
index.rendered = null;
|
|
1587
|
+
index.renderedArray = null;
|
|
1588
|
+
this.recursivelyUpdateAtomFamilyIndexes(atom.family);
|
|
669
1589
|
}
|
|
670
|
-
txnAtomMap.set(atom, value);
|
|
671
1590
|
return value;
|
|
672
1591
|
};
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
1592
|
+
batchSetFamilyAtoms = (family, pairs) => {
|
|
1593
|
+
if (!this._atomMap.has(family)) {
|
|
1594
|
+
this.cloneFamilyIntoTxn(family);
|
|
1595
|
+
}
|
|
1596
|
+
const index = this._atomMap.get(family).__index;
|
|
1597
|
+
for (const [atom, value] of pairs) {
|
|
1598
|
+
if (atom.family !== family) {
|
|
1599
|
+
throw new Error("Atom does not belong to the provided family");
|
|
1600
|
+
}
|
|
1601
|
+
index.created.set(atom, performance.now());
|
|
1602
|
+
if (index.deleted.has(atom))
|
|
1603
|
+
index.deleted.delete(atom);
|
|
1604
|
+
this._atomMap.set(atom, value);
|
|
1605
|
+
}
|
|
1606
|
+
index.rendered = null;
|
|
1607
|
+
index.renderedArray = null;
|
|
1608
|
+
this.recursivelyUpdateAtomFamilyIndexes(family);
|
|
1609
|
+
};
|
|
1610
|
+
del = (atom) => {
|
|
1611
|
+
if (!this._atomMap.has(atom.family)) {
|
|
1612
|
+
this.cloneFamilyIntoTxn(atom.family);
|
|
1613
|
+
}
|
|
1614
|
+
const index = this._atomMap.get(atom.family).__index;
|
|
1615
|
+
index.created.delete(atom);
|
|
1616
|
+
index.deleted.set(atom, performance.now());
|
|
1617
|
+
index.rendered = null;
|
|
1618
|
+
index.renderedArray = null;
|
|
1619
|
+
this._atomMap.set(atom.family, renderAtomFamilyIndex(index));
|
|
1620
|
+
this.recursivelyUpdateAtomFamilyIndexes(atom.family);
|
|
1621
|
+
if (this.data.values.has(atom)) {
|
|
1622
|
+
this.deleteSet.add(atom);
|
|
1623
|
+
}
|
|
1624
|
+
if (this._atomMap.has(atom)) {
|
|
1625
|
+
this._atomMap.delete(atom);
|
|
1626
|
+
}
|
|
1627
|
+
};
|
|
1628
|
+
scope = (scopeId, callback) => {
|
|
1629
|
+
if (this.data.scopes.has(scopeId)) {
|
|
1630
|
+
return this.scopedTransaction(scopeId).execute(callback, false);
|
|
1631
|
+
} else {
|
|
1632
|
+
throw new Error(`Scope '${scopeId}' not found. Registered scopes: ${[...this.data.scopes.keys()].join(", ")}`);
|
|
1633
|
+
}
|
|
1634
|
+
};
|
|
1635
|
+
parentScope = (callback) => {
|
|
1636
|
+
if (!this.parentTransaction) {
|
|
1637
|
+
this.parentTransaction = new Transaction(this.data.parent, undefined, this);
|
|
1638
|
+
}
|
|
1639
|
+
return this.parentTransaction.execute(callback, false);
|
|
1640
|
+
};
|
|
1641
|
+
reset = (atom) => {
|
|
1642
|
+
const value = getAtomInitValue(atom, this.data, this.initializedAtomsSet);
|
|
1643
|
+
this._atomMap.set(atom, value);
|
|
676
1644
|
return value;
|
|
677
1645
|
};
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
1646
|
+
execute = (callback, autoCommit = true) => {
|
|
1647
|
+
const result = callback(this);
|
|
1648
|
+
if (autoCommit)
|
|
1649
|
+
this.txnCommit();
|
|
1650
|
+
return result;
|
|
1651
|
+
};
|
|
1652
|
+
txnCommit = () => {
|
|
1653
|
+
if (this.parentTransaction) {
|
|
1654
|
+
this.parentTransaction.txnCommit();
|
|
1655
|
+
} else {
|
|
1656
|
+
this.commit();
|
|
1657
|
+
}
|
|
1658
|
+
};
|
|
1659
|
+
commit = () => {
|
|
1660
|
+
const initializedAtomsSet = new Set;
|
|
1661
|
+
setAtoms(this._atomMap, this.data, initializedAtomsSet);
|
|
1662
|
+
if (this.deleteSet?.size) {
|
|
1663
|
+
deleteAtomFamilyAtoms(this.deleteSet, this.data);
|
|
1664
|
+
propagateDeletedAtoms([...this.deleteSet], this.data);
|
|
1665
|
+
}
|
|
1666
|
+
if (this._scopedTransactions) {
|
|
1667
|
+
for (const [, scopedTxn] of this._scopedTransactions) {
|
|
683
1668
|
scopedTxn.commit();
|
|
684
1669
|
}
|
|
685
1670
|
}
|
|
686
1671
|
};
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
1672
|
+
get selectorCache() {
|
|
1673
|
+
if (!this._selectorCache)
|
|
1674
|
+
this._selectorCache = new Map;
|
|
1675
|
+
return this._selectorCache;
|
|
1676
|
+
}
|
|
1677
|
+
get selectorDependencies() {
|
|
1678
|
+
if (!this._selectorDependencies)
|
|
1679
|
+
this._selectorDependencies = new Set;
|
|
1680
|
+
return this._selectorDependencies;
|
|
1681
|
+
}
|
|
1682
|
+
get deleteSet() {
|
|
1683
|
+
if (!this._deleteSet)
|
|
1684
|
+
this._deleteSet = new Set;
|
|
1685
|
+
return this._deleteSet;
|
|
1686
|
+
}
|
|
1687
|
+
get initializedAtomsSet() {
|
|
1688
|
+
if (!this._initializedAtomsSet)
|
|
1689
|
+
this._initializedAtomsSet = new Set;
|
|
1690
|
+
return this._initializedAtomsSet;
|
|
1691
|
+
}
|
|
1692
|
+
scopedTransaction(scopeId) {
|
|
1693
|
+
if (!this._scopedTransactions)
|
|
1694
|
+
this._scopedTransactions = new Map;
|
|
1695
|
+
if (!this._scopedTransactions.has(scopeId)) {
|
|
1696
|
+
const scopedData = this.data.scopes.get(scopeId);
|
|
1697
|
+
const scopedTransaction = new Transaction(scopedData, this);
|
|
1698
|
+
this._scopedTransactions.set(scopeId, scopedTransaction);
|
|
1699
|
+
}
|
|
1700
|
+
return this._scopedTransactions.get(scopeId);
|
|
1701
|
+
}
|
|
1702
|
+
cloneFamilyIntoTxn(family, parentIndex, moveUpIfParent = true) {
|
|
1703
|
+
if (moveUpIfParent && this.parentTransaction)
|
|
1704
|
+
return this.parentTransaction.cloneFamilyIntoTxn(family, parentIndex, moveUpIfParent);
|
|
1705
|
+
const currentFamilyList = this.get(family);
|
|
1706
|
+
const clonedIndex = cloneAtomFamilyIndex(currentFamilyList.__index, parentIndex);
|
|
1707
|
+
if (this._scopedTransactions?.size) {
|
|
1708
|
+
for (const [, scopedTxn] of this._scopedTransactions) {
|
|
1709
|
+
scopedTxn.cloneFamilyIntoTxn(family, clonedIndex, false);
|
|
704
1710
|
}
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
1711
|
+
}
|
|
1712
|
+
this._atomMap.set(family, renderAtomFamilyIndex(clonedIndex));
|
|
1713
|
+
}
|
|
1714
|
+
recursivelyUpdateAtomFamilyIndexes(atomFamily) {
|
|
1715
|
+
const currentIndex = this._atomMap.get(atomFamily).__index;
|
|
1716
|
+
currentIndex.rendered = null;
|
|
1717
|
+
currentIndex.renderedArray = null;
|
|
1718
|
+
const updatedValue = renderAtomFamilyIndex(currentIndex);
|
|
1719
|
+
this._atomMap.set(atomFamily, updatedValue);
|
|
1720
|
+
if (this._scopedTransactions?.size) {
|
|
1721
|
+
for (const [, scopedTxn] of this._scopedTransactions) {
|
|
1722
|
+
scopedTxn.recursivelyUpdateAtomFamilyIndexes(atomFamily);
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
var transaction = (callback, data) => {
|
|
1728
|
+
const txn = new Transaction(data);
|
|
1729
|
+
return txn.execute(callback);
|
|
711
1730
|
};
|
|
712
1731
|
|
|
713
1732
|
// src/lib/storeFromStoreData.ts
|
|
@@ -718,35 +1737,150 @@ Only \`atom\` cam be set.
|
|
|
718
1737
|
var InvalidStateSetError = `Invalid state object passed to set().
|
|
719
1738
|
Only \`atom\` can be set.
|
|
720
1739
|
`;
|
|
1740
|
+
var isCachedValueStale = (state, data) => {
|
|
1741
|
+
const atom = state;
|
|
1742
|
+
const maxAge = atom.maxAge;
|
|
1743
|
+
if (maxAge === undefined)
|
|
1744
|
+
return false;
|
|
1745
|
+
if (isGlobalAtom(atom)) {
|
|
1746
|
+
if (atom.maxAgeInterval !== undefined)
|
|
1747
|
+
return false;
|
|
1748
|
+
} else {
|
|
1749
|
+
const subs = data.subscriptions.get(state);
|
|
1750
|
+
if (subs && subs.size > 0)
|
|
1751
|
+
return false;
|
|
1752
|
+
}
|
|
1753
|
+
const lastWrite = data.lastValueWriteAt.get(state);
|
|
1754
|
+
if (lastWrite === undefined)
|
|
1755
|
+
return false;
|
|
1756
|
+
const ttl = typeof maxAge === "number" ? maxAge : resolveReactive(maxAge, data);
|
|
1757
|
+
return Date.now() - lastWrite > ttl;
|
|
1758
|
+
};
|
|
721
1759
|
function storeFromStoreData(data, detach) {
|
|
722
|
-
const
|
|
723
|
-
|
|
1760
|
+
const _initSet = new Set;
|
|
1761
|
+
let _pendingTxn = null;
|
|
1762
|
+
const flushPendingTxn = () => {
|
|
1763
|
+
if (_pendingTxn) {
|
|
1764
|
+
const txnToCommit = _pendingTxn;
|
|
1765
|
+
_pendingTxn = null;
|
|
1766
|
+
txnToCommit.commit();
|
|
1767
|
+
}
|
|
1768
|
+
};
|
|
1769
|
+
const ensurePendingTxn = () => {
|
|
1770
|
+
if (!_pendingTxn) {
|
|
1771
|
+
_pendingTxn = new Transaction(data);
|
|
1772
|
+
queueMicrotask(() => {
|
|
1773
|
+
try {
|
|
1774
|
+
flushPendingTxn();
|
|
1775
|
+
} catch (error) {
|
|
1776
|
+
setTimeout(() => {
|
|
1777
|
+
throw error;
|
|
1778
|
+
}, 0);
|
|
1779
|
+
}
|
|
1780
|
+
});
|
|
1781
|
+
}
|
|
1782
|
+
return _pendingTxn;
|
|
1783
|
+
};
|
|
1784
|
+
const getDefault = (state) => {
|
|
1785
|
+
if (data.values.has(state)) {
|
|
1786
|
+
if (!isCachedValueStale(state, data)) {
|
|
1787
|
+
return data.values.get(state);
|
|
1788
|
+
}
|
|
1789
|
+
data.values.delete(state);
|
|
1790
|
+
data.lastValueWriteAt.delete(state);
|
|
1791
|
+
}
|
|
1792
|
+
let res;
|
|
1793
|
+
try {
|
|
1794
|
+
res = getState(state, data, _initSet);
|
|
1795
|
+
} finally {
|
|
1796
|
+
if (_initSet.size) {
|
|
1797
|
+
const atoms = [..._initSet];
|
|
1798
|
+
_initSet.clear();
|
|
1799
|
+
propagateUpdatedAtoms(atoms, data, undefined, undefined, false, undefined, false, true);
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
return res;
|
|
1803
|
+
};
|
|
1804
|
+
const getBatched = (state) => {
|
|
1805
|
+
if (_pendingTxn) {
|
|
1806
|
+
return _pendingTxn.get(state);
|
|
1807
|
+
}
|
|
1808
|
+
return getDefault(state);
|
|
1809
|
+
};
|
|
1810
|
+
const get = data.batchUpdates ? getBatched : getDefault;
|
|
1811
|
+
const setDefault = (state, value) => {
|
|
724
1812
|
if (isAtom(state))
|
|
725
1813
|
return setAtom(state, value, data);
|
|
726
1814
|
if (isSelector(state))
|
|
727
1815
|
throw new Error(SelectorProvidedToSetError);
|
|
728
1816
|
throw new Error(InvalidStateSetError);
|
|
729
1817
|
};
|
|
730
|
-
const
|
|
1818
|
+
const setBatched = (state, value) => {
|
|
1819
|
+
if (isAtom(state)) {
|
|
1820
|
+
return ensurePendingTxn().set(state, value);
|
|
1821
|
+
}
|
|
1822
|
+
if (isSelector(state))
|
|
1823
|
+
throw new Error(SelectorProvidedToSetError);
|
|
1824
|
+
throw new Error(InvalidStateSetError);
|
|
1825
|
+
};
|
|
1826
|
+
const set = data.batchUpdates ? setBatched : setDefault;
|
|
1827
|
+
const reset = (atom) => {
|
|
1828
|
+
if (data.batchUpdates)
|
|
1829
|
+
flushPendingTxn();
|
|
1830
|
+
return resetAtom(atom, data);
|
|
1831
|
+
};
|
|
1832
|
+
const del = (atom) => {
|
|
1833
|
+
if (data.batchUpdates)
|
|
1834
|
+
flushPendingTxn();
|
|
1835
|
+
return deleteFamilyAtom(atom, data);
|
|
1836
|
+
};
|
|
731
1837
|
const sub = (state, callback, deepEqualCheckBeforeCallback = true) => subscribe(state, callback, deepEqualCheckBeforeCallback, data);
|
|
732
|
-
const txn = (callback) =>
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
1838
|
+
const txn = (callback) => {
|
|
1839
|
+
if (data.batchUpdates)
|
|
1840
|
+
flushPendingTxn();
|
|
1841
|
+
return transaction(callback, data);
|
|
1842
|
+
};
|
|
1843
|
+
const scope = (scopeId, callback) => {
|
|
1844
|
+
if (callback) {
|
|
1845
|
+
if (!data.scopes.has(scopeId)) {
|
|
1846
|
+
throw new Error(`Scope ${scopeId} does not exist`);
|
|
1847
|
+
}
|
|
1848
|
+
const scopedStoreData = data.scopes.get(scopeId);
|
|
1849
|
+
const scopedStore = storeFromStoreData(scopedStoreData);
|
|
1850
|
+
const res = callback(scopedStore);
|
|
1851
|
+
return res;
|
|
737
1852
|
} else {
|
|
738
|
-
scopedStoreData
|
|
739
|
-
data.scopes
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
delete data.scopes[scopeId];
|
|
1853
|
+
let scopedStoreData;
|
|
1854
|
+
if (data.scopes.has(scopeId)) {
|
|
1855
|
+
scopedStoreData = data.scopes.get(scopeId);
|
|
1856
|
+
} else {
|
|
1857
|
+
scopedStoreData = createStoreData(scopeId, data, data.batchUpdates ? { batchUpdates: true } : undefined);
|
|
1858
|
+
data.scopes.set(scopeId, scopedStoreData);
|
|
745
1859
|
}
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
1860
|
+
const detach2 = (expectedToDestroy = false) => {
|
|
1861
|
+
scopedStoreData.scopeConsumers.delete(detach2);
|
|
1862
|
+
if (scopedStoreData.scopeConsumers.size === 0) {
|
|
1863
|
+
data.scopes.delete(scopeId);
|
|
1864
|
+
for (const key of scopedStoreData.scopeIndexKeys) {
|
|
1865
|
+
const set2 = data.scopeValueIndex.get(key);
|
|
1866
|
+
if (set2) {
|
|
1867
|
+
set2.delete(scopedStoreData);
|
|
1868
|
+
if (set2.size === 0)
|
|
1869
|
+
data.scopeValueIndex.delete(key);
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
scopedStoreData.scopeIndexKeys.clear();
|
|
1873
|
+
return true;
|
|
1874
|
+
}
|
|
1875
|
+
if (expectedToDestroy) {
|
|
1876
|
+
console.warn(`Scope ${scopeId} still has ${scopedStoreData.scopeConsumers.size} consumers, will not detach`);
|
|
1877
|
+
}
|
|
1878
|
+
return false;
|
|
1879
|
+
};
|
|
1880
|
+
scopedStoreData.scopeConsumers.add(detach2);
|
|
1881
|
+
const newStore = storeFromStoreData(data.scopes.get(scopeId), detach2);
|
|
1882
|
+
return newStore;
|
|
1883
|
+
}
|
|
750
1884
|
};
|
|
751
1885
|
if (detach) {
|
|
752
1886
|
return {
|
|
@@ -755,6 +1889,7 @@ function storeFromStoreData(data, detach) {
|
|
|
755
1889
|
sub,
|
|
756
1890
|
txn,
|
|
757
1891
|
reset,
|
|
1892
|
+
del,
|
|
758
1893
|
data,
|
|
759
1894
|
scope,
|
|
760
1895
|
detach
|
|
@@ -766,15 +1901,121 @@ function storeFromStoreData(data, detach) {
|
|
|
766
1901
|
sub,
|
|
767
1902
|
txn,
|
|
768
1903
|
reset,
|
|
1904
|
+
del,
|
|
769
1905
|
data,
|
|
770
1906
|
scope
|
|
771
1907
|
};
|
|
772
1908
|
}
|
|
773
1909
|
}
|
|
774
1910
|
|
|
1911
|
+
// src/lib/mountAtom.ts
|
|
1912
|
+
var isTransitivelySubscribed = (state, data, visited = new Set) => {
|
|
1913
|
+
const stack = [state];
|
|
1914
|
+
while (stack.length > 0) {
|
|
1915
|
+
const current = stack.pop();
|
|
1916
|
+
if (visited.has(current))
|
|
1917
|
+
continue;
|
|
1918
|
+
visited.add(current);
|
|
1919
|
+
const subs = data.subscriptions.get(current);
|
|
1920
|
+
if (subs && subs.size > 0)
|
|
1921
|
+
return true;
|
|
1922
|
+
const dependents = data.stateDependents.get(current);
|
|
1923
|
+
if (dependents) {
|
|
1924
|
+
for (const dep of dependents) {
|
|
1925
|
+
if (!visited.has(dep))
|
|
1926
|
+
stack.push(dep);
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
return false;
|
|
1931
|
+
};
|
|
1932
|
+
var mountAtom = (state, data) => {
|
|
1933
|
+
const onMountFn = state.__valdresOnMount ?? state.onMount;
|
|
1934
|
+
if (!onMountFn || data.mounts.has(state))
|
|
1935
|
+
return;
|
|
1936
|
+
const mountEntry = {};
|
|
1937
|
+
data.mounts.set(state, mountEntry);
|
|
1938
|
+
const store = data.storeRef ?? storeFromStoreData(data);
|
|
1939
|
+
try {
|
|
1940
|
+
mountEntry.cleanup = onMountFn(store, state);
|
|
1941
|
+
} catch (error) {
|
|
1942
|
+
data.mounts.delete(state);
|
|
1943
|
+
throw error;
|
|
1944
|
+
}
|
|
1945
|
+
};
|
|
1946
|
+
var unmountAtom = (state, data) => {
|
|
1947
|
+
const mount = data.mounts.get(state);
|
|
1948
|
+
if (!mount)
|
|
1949
|
+
return;
|
|
1950
|
+
data.mounts.delete(state);
|
|
1951
|
+
if (typeof mount.cleanup === "function") {
|
|
1952
|
+
mount.cleanup();
|
|
1953
|
+
}
|
|
1954
|
+
};
|
|
1955
|
+
var mountTransitiveDeps = (state, data, visited = new Set) => {
|
|
1956
|
+
let firstError = null;
|
|
1957
|
+
const stack = [state];
|
|
1958
|
+
while (stack.length > 0) {
|
|
1959
|
+
const current = stack.pop();
|
|
1960
|
+
if (visited.has(current))
|
|
1961
|
+
continue;
|
|
1962
|
+
visited.add(current);
|
|
1963
|
+
if (current.__valdresOnMount || current.onMount) {
|
|
1964
|
+
try {
|
|
1965
|
+
mountAtom(current, data);
|
|
1966
|
+
} catch (error) {
|
|
1967
|
+
if (!firstError)
|
|
1968
|
+
firstError = { value: error };
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
const deps = data.stateDependencies.get(current);
|
|
1972
|
+
if (deps) {
|
|
1973
|
+
for (const dep of deps) {
|
|
1974
|
+
if (!visited.has(dep))
|
|
1975
|
+
stack.push(dep);
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
if (firstError) {
|
|
1980
|
+
throw firstError.value;
|
|
1981
|
+
}
|
|
1982
|
+
};
|
|
1983
|
+
var unmountOrphanedDeps = (state, data, visited = new Set) => {
|
|
1984
|
+
let firstError = null;
|
|
1985
|
+
const stack = [state];
|
|
1986
|
+
while (stack.length > 0) {
|
|
1987
|
+
const current = stack.pop();
|
|
1988
|
+
if (visited.has(current))
|
|
1989
|
+
continue;
|
|
1990
|
+
visited.add(current);
|
|
1991
|
+
if ((current.__valdresOnMount || current.onMount) && data.mounts.has(current)) {
|
|
1992
|
+
if (!isTransitivelySubscribed(current, data)) {
|
|
1993
|
+
try {
|
|
1994
|
+
unmountAtom(current, data);
|
|
1995
|
+
} catch (error) {
|
|
1996
|
+
if (!firstError)
|
|
1997
|
+
firstError = { value: error };
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
const deps = data.stateDependencies.get(current);
|
|
2002
|
+
if (deps) {
|
|
2003
|
+
for (const dep of deps) {
|
|
2004
|
+
if (!visited.has(dep))
|
|
2005
|
+
stack.push(dep);
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
if (firstError) {
|
|
2010
|
+
throw firstError.value;
|
|
2011
|
+
}
|
|
2012
|
+
};
|
|
2013
|
+
|
|
775
2014
|
// src/store.ts
|
|
776
|
-
var store = (
|
|
777
|
-
const
|
|
2015
|
+
var store = (idOrOptions) => {
|
|
2016
|
+
const id = typeof idOrOptions === "string" ? idOrOptions : idOrOptions?.id;
|
|
2017
|
+
const options = typeof idOrOptions === "object" ? idOrOptions : undefined;
|
|
2018
|
+
const data = createStoreData(id, undefined, options);
|
|
778
2019
|
return storeFromStoreData(data);
|
|
779
2020
|
};
|
|
780
2021
|
|
|
@@ -787,61 +2028,114 @@ var globalStore = Object.assign(store("valdres-global-store"), {
|
|
|
787
2028
|
// src/lib/globalAtom.ts
|
|
788
2029
|
var globalAtom = (defaultValue, options) => {
|
|
789
2030
|
const stores = new Set;
|
|
790
|
-
let value;
|
|
791
|
-
let initialized = false;
|
|
792
|
-
let onReset;
|
|
793
2031
|
if (options.onSet)
|
|
794
2032
|
throw new Error("onSet on globalAtom is currently not supported");
|
|
795
2033
|
const onInit = (setSelf2, data) => {
|
|
796
2034
|
setSelf2(globalStore.get(atom));
|
|
797
|
-
if (!initialized && options.onInit) {
|
|
798
|
-
onReset = options.onInit((newVal) => {
|
|
799
|
-
setSelf2(newVal);
|
|
800
|
-
value = newVal;
|
|
801
|
-
}, data);
|
|
802
|
-
initialized = true;
|
|
803
|
-
}
|
|
804
2035
|
stores.add(data);
|
|
805
2036
|
};
|
|
806
2037
|
const onSet = (newValue, currentStore) => {
|
|
807
|
-
value = newValue;
|
|
808
2038
|
if (stores.size > 1) {
|
|
809
2039
|
for (const store2 of stores) {
|
|
810
2040
|
if (store2.id !== currentStore.id) {
|
|
811
|
-
setAtom(atom,
|
|
2041
|
+
setAtom(atom, newValue, store2, true);
|
|
812
2042
|
}
|
|
813
2043
|
}
|
|
814
2044
|
}
|
|
815
2045
|
};
|
|
2046
|
+
let mountCount = 0;
|
|
2047
|
+
let userCleanup;
|
|
2048
|
+
const userOnMount = options.onMount;
|
|
2049
|
+
const onMount = userOnMount ? (...args) => {
|
|
2050
|
+
mountCount++;
|
|
2051
|
+
if (mountCount === 1) {
|
|
2052
|
+
try {
|
|
2053
|
+
userCleanup = userOnMount(...args);
|
|
2054
|
+
} catch (error) {
|
|
2055
|
+
mountCount--;
|
|
2056
|
+
userCleanup = undefined;
|
|
2057
|
+
throw error;
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
return () => {
|
|
2061
|
+
if (mountCount <= 0)
|
|
2062
|
+
return;
|
|
2063
|
+
mountCount--;
|
|
2064
|
+
if (mountCount === 0 && typeof userCleanup === "function") {
|
|
2065
|
+
const cleanup = userCleanup;
|
|
2066
|
+
userCleanup = undefined;
|
|
2067
|
+
cleanup();
|
|
2068
|
+
}
|
|
2069
|
+
};
|
|
2070
|
+
} : undefined;
|
|
816
2071
|
const getSelf = () => globalStore.get(atom);
|
|
817
2072
|
const setSelf = (newValue) => globalStore.set(atom, newValue);
|
|
818
2073
|
const resetSelf = () => {
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
for (const
|
|
822
|
-
if (
|
|
823
|
-
|
|
2074
|
+
const snapshot = [...stores];
|
|
2075
|
+
const subscribedStores = [];
|
|
2076
|
+
for (const s of snapshot) {
|
|
2077
|
+
if (isTransitivelySubscribed(atom, s)) {
|
|
2078
|
+
subscribedStores.push(s);
|
|
824
2079
|
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
2080
|
+
}
|
|
2081
|
+
let firstError;
|
|
2082
|
+
const recordError = (e) => {
|
|
2083
|
+
if (!firstError)
|
|
2084
|
+
firstError = e;
|
|
2085
|
+
};
|
|
2086
|
+
for (const s of snapshot) {
|
|
2087
|
+
try {
|
|
2088
|
+
unmountAtom(atom, s);
|
|
2089
|
+
} catch (e) {
|
|
2090
|
+
recordError(e);
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
if (atom.maxAgeInterval) {
|
|
2094
|
+
atom.maxAgeInterval.cleanup();
|
|
2095
|
+
atom.maxAgeInterval.refCount = 0;
|
|
2096
|
+
atom.maxAgeInterval = undefined;
|
|
2097
|
+
}
|
|
2098
|
+
for (const store2 of snapshot) {
|
|
828
2099
|
stores.delete(store2);
|
|
829
|
-
|
|
2100
|
+
store2.values.delete(atom);
|
|
2101
|
+
try {
|
|
2102
|
+
propagateUpdatedAtoms([atom], store2);
|
|
2103
|
+
} catch (e) {
|
|
2104
|
+
recordError(e);
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
for (const s of subscribedStores) {
|
|
2108
|
+
stores.add(s);
|
|
2109
|
+
if (atom.maxAge && (s.subscriptions.get(atom)?.size ?? 0) > 0) {
|
|
2110
|
+
installMaxAgeTimer(atom, s);
|
|
2111
|
+
}
|
|
2112
|
+
try {
|
|
2113
|
+
mountAtom(atom, s);
|
|
2114
|
+
} catch (e) {
|
|
2115
|
+
recordError(e);
|
|
2116
|
+
}
|
|
830
2117
|
}
|
|
2118
|
+
if (firstError)
|
|
2119
|
+
throw firstError;
|
|
2120
|
+
};
|
|
2121
|
+
const detach = (storeData) => {
|
|
2122
|
+
stores.delete(storeData);
|
|
831
2123
|
};
|
|
832
2124
|
const atom = {
|
|
833
2125
|
equal,
|
|
834
2126
|
...options,
|
|
835
2127
|
defaultValue,
|
|
836
|
-
name: options?.name,
|
|
837
2128
|
onInit,
|
|
838
2129
|
onSet,
|
|
2130
|
+
onMount,
|
|
839
2131
|
setSelf,
|
|
840
2132
|
getSelf,
|
|
841
2133
|
resetSelf,
|
|
2134
|
+
detach,
|
|
842
2135
|
get stores() {
|
|
843
2136
|
return stores;
|
|
844
|
-
}
|
|
2137
|
+
},
|
|
2138
|
+
maxAgeInterval: undefined
|
|
845
2139
|
};
|
|
846
2140
|
return atom;
|
|
847
2141
|
};
|
|
@@ -859,17 +2153,6 @@ function atom(defaultValue, options) {
|
|
|
859
2153
|
...options
|
|
860
2154
|
};
|
|
861
2155
|
}
|
|
862
|
-
// src/lib/atomFamilyAtom.ts
|
|
863
|
-
function atomFamilyAtom(defaultValue, options) {
|
|
864
|
-
if (options.global) {
|
|
865
|
-
return globalAtom(defaultValue, options);
|
|
866
|
-
}
|
|
867
|
-
return {
|
|
868
|
-
...options,
|
|
869
|
-
defaultValue
|
|
870
|
-
};
|
|
871
|
-
}
|
|
872
|
-
|
|
873
2156
|
// src/lib/stableStringify.ts
|
|
874
2157
|
var stableStringifyRecurse = (x, key) => {
|
|
875
2158
|
if (typeof x === "string" && !x.includes('"') && !x.includes("\\")) {
|
|
@@ -924,57 +2207,73 @@ var stableStringify = (x) => {
|
|
|
924
2207
|
return stableStringifyRecurse(x);
|
|
925
2208
|
};
|
|
926
2209
|
|
|
927
|
-
// src/
|
|
928
|
-
var
|
|
929
|
-
|
|
930
|
-
return { equal, get };
|
|
931
|
-
return { equal, ...options, get };
|
|
2210
|
+
// src/lib/stringifyFamilyArgs.ts
|
|
2211
|
+
var stringifyFamilyArgs = (args) => {
|
|
2212
|
+
return args.length === 1 ? stableStringify(args[0]) : stableStringify(args);
|
|
932
2213
|
};
|
|
933
2214
|
|
|
934
|
-
// src/lib/
|
|
935
|
-
var
|
|
936
|
-
if (
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
family,
|
|
942
|
-
familyKey
|
|
943
|
-
};
|
|
944
|
-
} else {
|
|
945
|
-
return { equal, ...options, family, familyKey };
|
|
2215
|
+
// src/lib/familyKey.ts
|
|
2216
|
+
var familyKey = (args) => {
|
|
2217
|
+
if (args.length === 1) {
|
|
2218
|
+
const a = args[0];
|
|
2219
|
+
const t = typeof a;
|
|
2220
|
+
if (t === "string" || t === "number" || t === "boolean")
|
|
2221
|
+
return a;
|
|
946
2222
|
}
|
|
2223
|
+
return stringifyFamilyArgs(args);
|
|
947
2224
|
};
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
return defaultValue(key);
|
|
951
|
-
if (typeof defaultValue === "function")
|
|
952
|
-
return () => defaultValue(key);
|
|
953
|
-
return defaultValue;
|
|
954
|
-
};
|
|
2225
|
+
|
|
2226
|
+
// src/lib/createAtomFamily.ts
|
|
955
2227
|
var createAtomFamily = (defaultValue, options) => {
|
|
956
2228
|
const map = new Map;
|
|
957
|
-
const
|
|
958
|
-
const
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
const
|
|
964
|
-
|
|
2229
|
+
const isSelectorFamilyDefault = isSelectorFamily(defaultValue);
|
|
2230
|
+
const isFunctionDefault = !isSelectorFamilyDefault && typeof defaultValue === "function";
|
|
2231
|
+
const hasName = !!options?.name;
|
|
2232
|
+
const isGlobal = !!options?.global;
|
|
2233
|
+
const atomFamily = (...args) => {
|
|
2234
|
+
const key = familyKey(args);
|
|
2235
|
+
const cached = map.get(key);
|
|
2236
|
+
if (cached !== undefined)
|
|
2237
|
+
return cached;
|
|
2238
|
+
let dv;
|
|
2239
|
+
if (isSelectorFamilyDefault) {
|
|
2240
|
+
dv = defaultValue(...args);
|
|
2241
|
+
} else if (isFunctionDefault) {
|
|
2242
|
+
dv = () => defaultValue(...args);
|
|
2243
|
+
} else {
|
|
2244
|
+
dv = defaultValue;
|
|
2245
|
+
}
|
|
2246
|
+
const memberName = hasName ? options.name + "_" + key : undefined;
|
|
2247
|
+
let familyAtom;
|
|
2248
|
+
if (isGlobal) {
|
|
2249
|
+
familyAtom = globalAtom(dv, {
|
|
2250
|
+
...options,
|
|
2251
|
+
name: memberName
|
|
2252
|
+
});
|
|
2253
|
+
} else {
|
|
2254
|
+
familyAtom = {
|
|
2255
|
+
equal,
|
|
2256
|
+
...options,
|
|
2257
|
+
defaultValue: dv,
|
|
2258
|
+
name: memberName
|
|
2259
|
+
};
|
|
2260
|
+
}
|
|
2261
|
+
familyAtom.family = atomFamily;
|
|
2262
|
+
familyAtom.familyArgs = args;
|
|
2263
|
+
familyAtom.familyArgsStringified = key;
|
|
2264
|
+
map.set(key, familyAtom);
|
|
965
2265
|
return familyAtom;
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
release: (key) => map.delete(key),
|
|
969
|
-
__keysAtom: keysAtom,
|
|
970
|
-
__keysSelector: selector((get) => Array.from(get(keysAtom)))
|
|
971
|
-
});
|
|
972
|
-
if (options?.name)
|
|
2266
|
+
};
|
|
2267
|
+
if (hasName)
|
|
973
2268
|
Object.defineProperty(atomFamily, "name", {
|
|
974
2269
|
value: options.name,
|
|
975
2270
|
writable: false
|
|
976
2271
|
});
|
|
977
|
-
return atomFamily
|
|
2272
|
+
return Object.assign(atomFamily, {
|
|
2273
|
+
__valdresAtomFamilyMap: map,
|
|
2274
|
+
release: (...args) => map.delete(familyKey(args)),
|
|
2275
|
+
equal
|
|
2276
|
+
});
|
|
978
2277
|
};
|
|
979
2278
|
|
|
980
2279
|
// src/lib/createGlobalAtomFamily.ts
|
|
@@ -995,49 +2294,100 @@ function atomFamily(defaultValue, options) {
|
|
|
995
2294
|
return createGlobalAtomFamily(defaultValue, options);
|
|
996
2295
|
return createAtomFamily(defaultValue, options);
|
|
997
2296
|
}
|
|
998
|
-
// src/
|
|
999
|
-
var
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
2297
|
+
// src/selector.ts
|
|
2298
|
+
var selector = (get, options) => {
|
|
2299
|
+
if (get.constructor?.name === "AsyncFunction") {
|
|
2300
|
+
throw new Error("selector() does not accept async functions. " + "Use a sync function that returns a Promise instead.");
|
|
2301
|
+
}
|
|
2302
|
+
if (!options)
|
|
2303
|
+
return { equal, get };
|
|
2304
|
+
return { equal, ...options, get };
|
|
2305
|
+
};
|
|
2306
|
+
|
|
2307
|
+
// src/cacheMeta.ts
|
|
2308
|
+
var cacheMeta = (sourceAtom) => {
|
|
2309
|
+
if (sourceAtom.__cacheMetaSelector)
|
|
2310
|
+
return sourceAtom.__cacheMetaSelector;
|
|
2311
|
+
if (!sourceAtom.__cacheMeta) {
|
|
2312
|
+
sourceAtom.__cacheMeta = { equal, defaultValue: null };
|
|
2313
|
+
}
|
|
2314
|
+
sourceAtom.__cacheMetaSelector = selector((get) => get(sourceAtom.__cacheMeta));
|
|
2315
|
+
return sourceAtom.__cacheMetaSelector;
|
|
2316
|
+
};
|
|
2317
|
+
// src/indexConstructor.ts
|
|
2318
|
+
var index = (family, callback, options) => {
|
|
2319
|
+
const map = new Map;
|
|
2320
|
+
const index2 = (term) => {
|
|
2321
|
+
const termKey = stableStringify(term);
|
|
2322
|
+
if (map.has(termKey))
|
|
2323
|
+
return map.get(termKey);
|
|
2324
|
+
const termIndexSelectorSet = new Set;
|
|
2325
|
+
const termIndexSelectorMap = new Map;
|
|
2326
|
+
const termIndexSelector = selector((get) => {
|
|
2327
|
+
const allFamilyAtoms = new Set(get(family));
|
|
2328
|
+
const deletedAtoms = termIndexSelectorSet.symmetricDifference(allFamilyAtoms);
|
|
2329
|
+
const addedAtoms = allFamilyAtoms.difference(termIndexSelectorSet);
|
|
2330
|
+
if (deletedAtoms.size || addedAtoms.size) {
|
|
2331
|
+
deletedAtoms.forEach((atom2) => {
|
|
2332
|
+
termIndexSelectorSet.delete(atom2);
|
|
2333
|
+
termIndexSelectorMap.delete(atom2);
|
|
2334
|
+
});
|
|
2335
|
+
addedAtoms.forEach((atom2) => {
|
|
2336
|
+
termIndexSelectorSet.add(atom2);
|
|
2337
|
+
termIndexSelectorMap.set(atom2, selector((get2) => callback(get2(atom2), term), {
|
|
2338
|
+
name: `index:callback:selector:${atom2.name}`
|
|
2339
|
+
}));
|
|
2340
|
+
});
|
|
2341
|
+
return new Set(termIndexSelectorSet);
|
|
2342
|
+
} else {
|
|
2343
|
+
return termIndexSelectorSet;
|
|
2344
|
+
}
|
|
2345
|
+
}, { name: `index:${options?.name}(${termKey})` });
|
|
2346
|
+
const filteredSelector = selector((get) => {
|
|
2347
|
+
const set = get(termIndexSelector);
|
|
2348
|
+
const res = [];
|
|
2349
|
+
set.forEach((atom2) => {
|
|
2350
|
+
if (get(termIndexSelectorMap.get(atom2))) {
|
|
2351
|
+
res.push(atom2);
|
|
2352
|
+
}
|
|
2353
|
+
});
|
|
2354
|
+
return res;
|
|
2355
|
+
}, {
|
|
2356
|
+
name: `index:${options?.name}:${termKey}:termSelector`
|
|
2357
|
+
});
|
|
2358
|
+
map.set(termKey, filteredSelector);
|
|
2359
|
+
return filteredSelector;
|
|
1011
2360
|
};
|
|
1012
|
-
|
|
1013
|
-
|
|
2361
|
+
return Object.assign(index2, {
|
|
2362
|
+
map,
|
|
2363
|
+
callback
|
|
2364
|
+
});
|
|
1014
2365
|
};
|
|
1015
2366
|
// src/selectorFamily.ts
|
|
1016
|
-
var
|
|
1017
|
-
|
|
1018
|
-
|
|
2367
|
+
var selectorFamily = (callback, options) => {
|
|
2368
|
+
const map = new Map;
|
|
2369
|
+
const hasName = !!options?.name;
|
|
2370
|
+
const selectorFamily2 = (...args) => {
|
|
2371
|
+
const key = familyKey(args);
|
|
2372
|
+
const cached = map.get(key);
|
|
2373
|
+
if (cached !== undefined)
|
|
2374
|
+
return cached;
|
|
2375
|
+
const get = (selectorArgs) => callback(...args)(selectorArgs);
|
|
2376
|
+
const newSelector = {
|
|
1019
2377
|
equal,
|
|
1020
2378
|
...options,
|
|
1021
|
-
|
|
1022
|
-
family,
|
|
1023
|
-
|
|
2379
|
+
get,
|
|
2380
|
+
family: selectorFamily2,
|
|
2381
|
+
familyArgs: args,
|
|
2382
|
+
familyArgsStringified: key,
|
|
2383
|
+
name: hasName ? options.name + "_" + key : undefined
|
|
1024
2384
|
};
|
|
1025
|
-
|
|
1026
|
-
return { equal, ...options, family, familyKey };
|
|
1027
|
-
}
|
|
1028
|
-
};
|
|
1029
|
-
var selectorFamily = (get, options) => {
|
|
1030
|
-
const map = new Map;
|
|
1031
|
-
const selectorFamily2 = (key) => {
|
|
1032
|
-
const keyStringified = stableStringify(key);
|
|
1033
|
-
if (map.has(keyStringified))
|
|
1034
|
-
return map.get(keyStringified);
|
|
1035
|
-
const newSelector = selector((selectorArgs) => get(key)(selectorArgs), createOptions2(options, selectorFamily2, key, keyStringified));
|
|
1036
|
-
map.set(keyStringified, newSelector);
|
|
2385
|
+
map.set(key, newSelector);
|
|
1037
2386
|
return newSelector;
|
|
1038
2387
|
};
|
|
1039
2388
|
selectorFamily2.__valdresSelectorFamilyMap = map;
|
|
1040
|
-
|
|
2389
|
+
selectorFamily2.release = (...args) => map.delete(familyKey(args));
|
|
2390
|
+
if (hasName)
|
|
1041
2391
|
Object.defineProperty(selectorFamily2, "name", {
|
|
1042
2392
|
value: options.name,
|
|
1043
2393
|
writable: false
|
|
@@ -1049,14 +2399,15 @@ var isFamilySelector = (state) => isFamilyState(state) && isSelector(state);
|
|
|
1049
2399
|
|
|
1050
2400
|
// src/index.ts
|
|
1051
2401
|
if (globalThis.__valdres__) {
|
|
1052
|
-
throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${
|
|
2402
|
+
throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${"1.0.0-beta.0"}`);
|
|
1053
2403
|
} else {
|
|
1054
|
-
globalThis.__valdres__ =
|
|
2404
|
+
globalThis.__valdres__ = "1.0.0-beta.0";
|
|
1055
2405
|
}
|
|
1056
2406
|
export {
|
|
1057
2407
|
store,
|
|
1058
2408
|
selectorFamily,
|
|
1059
2409
|
selector,
|
|
2410
|
+
isSuspendError,
|
|
1060
2411
|
isSelectorFamily,
|
|
1061
2412
|
isSelector,
|
|
1062
2413
|
isPromiseLike,
|
|
@@ -1066,8 +2417,11 @@ export {
|
|
|
1066
2417
|
isFamily,
|
|
1067
2418
|
isAtomFamily,
|
|
1068
2419
|
isAtom,
|
|
2420
|
+
index,
|
|
1069
2421
|
globalStore,
|
|
1070
|
-
|
|
2422
|
+
deepFreeze,
|
|
2423
|
+
cacheMeta,
|
|
1071
2424
|
atomFamily,
|
|
1072
|
-
atom
|
|
2425
|
+
atom,
|
|
2426
|
+
Transaction
|
|
1073
2427
|
};
|