valdres 0.2.0-alpha.9 → 0.2.0-pre.1
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 +1058 -345
- package/dist/types/src/atom.d.ts +16 -0
- package/dist/types/src/atomFamily.d.ts +3 -0
- package/dist/types/src/errors/SelectorCircularDependencyError.d.ts +5 -0
- package/dist/types/src/errors/SelectorEvaluationError.d.ts +7 -0
- package/dist/types/src/errors/lib/generateSelectorTrace.d.ts +2 -0
- package/dist/types/src/globalStore.d.ts +4 -0
- package/dist/types/src/index.d.ts +36 -0
- package/dist/types/src/indexConstructor.d.ts +5 -0
- package/dist/types/src/lib/atomFamilyAtom.d.ts +8 -0
- package/dist/types/src/lib/createAtomFamily.d.ts +4 -0
- package/dist/types/src/lib/createGlobalAtomFamily.d.ts +4 -0
- package/dist/types/src/lib/createStoreData.d.ts +3 -0
- package/dist/types/src/lib/deleteFamilyAtom.d.ts +3 -0
- package/dist/types/src/lib/equal.d.ts +1 -0
- package/dist/types/src/lib/getState.d.ts +8 -0
- package/dist/types/src/lib/globalAtom.d.ts +4 -0
- package/dist/types/src/lib/initAtom.d.ts +5 -0
- package/dist/types/src/lib/initSelector.d.ts +10 -0
- package/dist/types/src/lib/isFunction.d.ts +1 -0
- package/dist/types/src/lib/isProd.d.ts +1 -0
- package/dist/types/src/lib/propagateUpdatedAtoms.d.ts +10 -0
- package/dist/{src → types/src}/lib/setAtom.d.ts +1 -1
- package/dist/{src → types/src}/lib/setAtoms.d.ts +1 -1
- package/dist/types/src/lib/setValueInData.d.ts +4 -0
- package/dist/types/src/lib/storeFromStoreData.d.ts +4 -0
- package/dist/types/src/lib/stringifyFamilyArgs.d.ts +1 -0
- package/dist/{src → types/src}/lib/subscribe.d.ts +1 -1
- package/dist/types/src/lib/transaction.d.ts +8 -0
- package/dist/{src → types/src}/lib/unsubscribe.d.ts +1 -1
- package/dist/types/src/selector.d.ts +4 -0
- package/dist/types/src/selectorFamily.d.ts +4 -0
- package/dist/types/src/store.d.ts +1 -0
- package/dist/types/src/types/Atom.d.ts +14 -0
- package/dist/types/src/types/AtomDefaultValue.d.ts +2 -0
- package/dist/types/src/types/AtomFamily.d.ts +9 -0
- package/dist/types/src/types/AtomFamilyAtom.d.ts +7 -0
- package/dist/types/src/types/AtomFamilyDefaultValue.d.ts +5 -0
- package/dist/types/src/types/AtomFamilyGlobalAtom.d.ts +3 -0
- package/dist/types/src/types/AtomFamilySelector.d.ts +6 -0
- package/dist/types/src/types/AtomOnSet.d.ts +2 -0
- package/dist/types/src/types/AtomOptions.d.ts +13 -0
- package/dist/types/src/types/EqualFunc.d.ts +3 -0
- package/dist/types/src/types/Family.d.ts +3 -0
- package/dist/types/src/types/FamilyKey.d.ts +3 -0
- package/dist/types/src/types/GetValue.d.ts +9 -0
- package/dist/types/src/types/GlobalAtom.d.ts +11 -0
- package/dist/types/src/types/GlobalAtomGetSelfFunc.d.ts +1 -0
- package/dist/types/src/types/GlobalAtomResetSelfFunc.d.ts +1 -0
- package/dist/types/src/types/GlobalAtomSetSelfFunc.d.ts +1 -0
- package/dist/types/src/types/Selector.d.ts +11 -0
- package/dist/types/src/types/SelectorFamily.d.ts +5 -0
- package/dist/types/src/types/SelectorOptions.d.ts +5 -0
- package/dist/{src → types/src}/types/SetAtom.d.ts +3 -1
- package/dist/types/src/types/SetAtomValue.d.ts +1 -0
- package/dist/types/src/types/State.d.ts +4 -0
- package/dist/types/src/types/Store.d.ts +26 -0
- package/dist/types/src/types/StoreData.d.ts +18 -0
- package/dist/types/src/types/SubscribeFn.d.ts +9 -0
- package/dist/types/src/types/Subscription.d.ts +11 -0
- package/dist/types/src/types/TransactionFn.d.ts +2 -0
- package/dist/types/src/types/TransactionInterface.d.ts +19 -0
- package/dist/types/src/utils/deepFreeze.d.ts +1 -0
- package/dist/types/src/utils/isAtom.d.ts +2 -0
- package/dist/types/src/utils/isAtomFamily.d.ts +2 -0
- package/dist/types/src/utils/isFamily.d.ts +1 -0
- package/dist/types/src/utils/isFamilyAtom.d.ts +2 -0
- package/dist/types/src/utils/isFamilySelector.d.ts +2 -0
- package/dist/types/src/utils/isFamilyState.d.ts +3 -0
- package/dist/types/src/utils/isSelector.d.ts +2 -0
- package/dist/types/src/utils/isSelectorFamily.d.ts +2 -0
- package/package.json +7 -22
- package/dist/index.d.ts +0 -21
- package/dist/src/atom.d.ts +0 -13
- package/dist/src/atomFamily.d.ts +0 -4
- package/dist/src/createStore.d.ts +0 -2
- package/dist/src/getDefaultStore.d.ts +0 -2
- package/dist/src/lib/createStoreData.d.ts +0 -2
- package/dist/src/lib/getState.d.ts +0 -7
- package/dist/src/lib/initAtom.d.ts +0 -4
- package/dist/src/lib/initSelector.d.ts +0 -4
- package/dist/src/lib/propagateUpdatedAtoms.d.ts +0 -3
- package/dist/src/lib/storeFromStoreData.d.ts +0 -3
- package/dist/src/lib/transaction.d.ts +0 -9
- package/dist/src/lib/updateSelectorSubscribers.d.ts +0 -3
- package/dist/src/lib/updateStateSubscribers.d.ts +0 -3
- package/dist/src/selector.d.ts +0 -3
- package/dist/src/selectorFamily.d.ts +0 -2
- package/dist/src/types/Atom.d.ts +0 -12
- package/dist/src/types/AtomFamily.d.ts +0 -5
- package/dist/src/types/AtomOnSet.d.ts +0 -2
- package/dist/src/types/Family.d.ts +0 -3
- package/dist/src/types/GetValue.d.ts +0 -8
- package/dist/src/types/Selector.d.ts +0 -9
- package/dist/src/types/SelectorFamily.d.ts +0 -5
- package/dist/src/types/SetAtomValue.d.ts +0 -1
- package/dist/src/types/State.d.ts +0 -3
- package/dist/src/types/Store.d.ts +0 -14
- package/dist/src/types/StoreData.d.ts +0 -9
- package/dist/src/types/SubscribeFn.d.ts +0 -2
- package/dist/src/types/Subscription.d.ts +0 -1
- package/dist/src/types/TransactionFn.d.ts +0 -4
- package/dist/src/utils/isAtom.d.ts +0 -2
- package/dist/src/utils/isFamily.d.ts +0 -1
- package/dist/src/utils/isSelector.d.ts +0 -2
- /package/dist/{src → types/src}/createStoreWithSelectorSet.d.ts +0 -0
- /package/dist/{src → types/src}/lib/resetAtom.d.ts +0 -0
- /package/dist/{src → types/src}/lib/stableStringify.d.ts +0 -0
- /package/dist/{src → types/src}/types/AtomOnInit.d.ts +0 -0
- /package/dist/{src → types/src}/types/ResetAtom.d.ts +0 -0
- /package/dist/{src → types/src}/utils/isPromiseLike.d.ts +0 -0
package/dist/index.js
CHANGED
|
@@ -1,40 +1,233 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { version } from "../package.json";
|
|
3
|
+
|
|
4
|
+
// src/lib/equal.ts
|
|
5
|
+
var hasElementType = typeof Element !== "undefined";
|
|
6
|
+
var hasMap = typeof Map === "function";
|
|
7
|
+
var hasSet = typeof Set === "function";
|
|
8
|
+
var hasArrayBuffer = typeof ArrayBuffer === "function" && !!ArrayBuffer.isView;
|
|
9
|
+
var deepEqualFn = (a, b, updatedAtomsSet) => {
|
|
10
|
+
if (updatedAtomsSet) {
|
|
11
|
+
if (updatedAtomsSet.has(a) || updatedAtomsSet.has(b))
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
if (a === b)
|
|
15
|
+
return true;
|
|
16
|
+
if (a && b && typeof a == "object" && typeof b == "object") {
|
|
17
|
+
if (a.constructor !== b.constructor)
|
|
18
|
+
return false;
|
|
19
|
+
var length, i, keys;
|
|
20
|
+
if (Array.isArray(a)) {
|
|
21
|
+
length = a.length;
|
|
22
|
+
if (length != b.length)
|
|
23
|
+
return false;
|
|
24
|
+
for (i = length;i-- !== 0; )
|
|
25
|
+
if (!deepEqualFn(a[i], b[i], updatedAtomsSet))
|
|
26
|
+
return false;
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
var it;
|
|
30
|
+
if (hasMap && a instanceof Map && b instanceof Map) {
|
|
31
|
+
if (a.size !== b.size)
|
|
32
|
+
return false;
|
|
33
|
+
it = a.entries();
|
|
34
|
+
while (!(i = it.next()).done)
|
|
35
|
+
if (!b.has(i.value[0]))
|
|
36
|
+
return false;
|
|
37
|
+
it = a.entries();
|
|
38
|
+
while (!(i = it.next()).done)
|
|
39
|
+
if (!deepEqualFn(i.value[1], b.get(i.value[0]), updatedAtomsSet))
|
|
40
|
+
return false;
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
if (hasSet && a instanceof Set && b instanceof Set) {
|
|
44
|
+
if (a.size !== b.size)
|
|
45
|
+
return false;
|
|
46
|
+
it = a.entries();
|
|
47
|
+
while (!(i = it.next()).done) {
|
|
48
|
+
if (!b.has(i.value[0]))
|
|
49
|
+
return false;
|
|
50
|
+
if (updatedAtomsSet?.has(i.value[0]))
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
if (hasArrayBuffer && ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
|
|
56
|
+
length = a.length;
|
|
57
|
+
if (length != b.length)
|
|
58
|
+
return false;
|
|
59
|
+
for (i = length;i-- !== 0; )
|
|
60
|
+
if (a[i] !== b[i])
|
|
61
|
+
return false;
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
if (a.constructor === RegExp)
|
|
65
|
+
return a.source === b.source && a.flags === b.flags;
|
|
66
|
+
if (a.valueOf !== Object.prototype.valueOf && typeof a.valueOf === "function" && typeof b.valueOf === "function")
|
|
67
|
+
return a.valueOf() === b.valueOf();
|
|
68
|
+
if (a.toString !== Object.prototype.toString && typeof a.toString === "function" && typeof b.toString === "function")
|
|
69
|
+
return a.toString() === b.toString();
|
|
70
|
+
keys = Object.keys(a);
|
|
71
|
+
length = keys.length;
|
|
72
|
+
if (length !== Object.keys(b).length)
|
|
73
|
+
return false;
|
|
74
|
+
for (i = length;i-- !== 0; )
|
|
75
|
+
if (!Object.prototype.hasOwnProperty.call(b, keys[i]))
|
|
76
|
+
return false;
|
|
77
|
+
if (hasElementType && a instanceof Element)
|
|
78
|
+
return false;
|
|
79
|
+
for (i = length;i-- !== 0; ) {
|
|
80
|
+
if ((keys[i] === "_owner" || keys[i] === "__v" || keys[i] === "__o") && a.$$typeof) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (!deepEqualFn(a[keys[i]], b[keys[i]], updatedAtomsSet))
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
return a !== a && b !== b;
|
|
89
|
+
};
|
|
90
|
+
var equal = (a, b, updatedAtomsSet) => {
|
|
91
|
+
try {
|
|
92
|
+
return deepEqualFn(a, b, updatedAtomsSet);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
if ((error.message || "").match(/stack|recursion/i)) {
|
|
95
|
+
console.warn("react-fast-compare cannot handle circular refs");
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// src/utils/isAtom.ts
|
|
103
|
+
var isAtom = (state) => Object.hasOwn(state, "defaultValue");
|
|
104
|
+
|
|
105
|
+
// src/utils/isFamilyState.ts
|
|
106
|
+
var isFamilyState = (state) => state && Object.hasOwn(state, "family");
|
|
107
|
+
|
|
108
|
+
// src/utils/isFamilyAtom.ts
|
|
109
|
+
var isFamilyAtom = (state) => isFamilyState(state) && isAtom(state);
|
|
3
110
|
|
|
4
111
|
// src/utils/isPromiseLike.ts
|
|
5
112
|
var isPromiseLike = (object) => {
|
|
6
113
|
return object && object.then && typeof object.then === "function";
|
|
7
114
|
};
|
|
8
115
|
|
|
9
|
-
// src/lib/
|
|
10
|
-
var
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
116
|
+
// src/errors/lib/generateSelectorTrace.ts
|
|
117
|
+
var generateSelectorTrace = (selectors) => {
|
|
118
|
+
const lastIndex = selectors.length - 1;
|
|
119
|
+
return [...selectors].reverse().map((selector, index) => {
|
|
120
|
+
const name = selector.name ?? "Anonymous Selector";
|
|
121
|
+
if (index === 0) {
|
|
122
|
+
return `[START] ${name}`;
|
|
123
|
+
} else if (index === lastIndex) {
|
|
124
|
+
return `[CRASH] ${name}`;
|
|
125
|
+
} else {
|
|
126
|
+
return ` ${" ".repeat(index)}${name}`;
|
|
15
127
|
}
|
|
128
|
+
}).join(`
|
|
129
|
+
`);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// src/errors/SelectorEvaluationError.ts
|
|
133
|
+
class SelectorEvaluationError extends Error {
|
|
134
|
+
selectors;
|
|
135
|
+
constructor(cause) {
|
|
136
|
+
super();
|
|
137
|
+
this.cause = cause;
|
|
138
|
+
this.selectors = [];
|
|
16
139
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
140
|
+
track(selector) {
|
|
141
|
+
this.selectors.push(selector);
|
|
142
|
+
}
|
|
143
|
+
get message() {
|
|
144
|
+
const firstSelectorName = this.selectors[0].name ?? "Anonymous Selector";
|
|
145
|
+
return `Selector eval crashed in '${firstSelectorName}'
|
|
146
|
+
${generateSelectorTrace(this.selectors)}`;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/utils/isAtomFamily.ts
|
|
151
|
+
var isAtomFamily = (state) => state && Object.hasOwn(state, "__valdresAtomFamilyMap");
|
|
152
|
+
|
|
153
|
+
// src/utils/isSelector.ts
|
|
154
|
+
var isSelector = (state) => state && Object.hasOwn(state, "get");
|
|
155
|
+
|
|
156
|
+
// src/utils/isSelectorFamily.ts
|
|
157
|
+
var isSelectorFamily = (state) => state && Object.hasOwn(state, "__valdresSelectorFamilyMap");
|
|
158
|
+
|
|
159
|
+
// src/lib/isFunction.ts
|
|
160
|
+
var isFunction = (value) => typeof value === "function";
|
|
161
|
+
|
|
162
|
+
// src/utils/deepFreeze.ts
|
|
163
|
+
var deepFreeze = (obj, seen = new WeakSet) => {
|
|
164
|
+
if (obj === null || obj === undefined || seen.has(obj))
|
|
165
|
+
return obj;
|
|
166
|
+
if (obj && typeof obj === "object")
|
|
167
|
+
seen.add(obj);
|
|
168
|
+
if (Array.isArray(obj)) {
|
|
169
|
+
for (const item of obj) {
|
|
170
|
+
if (item && typeof item === "object") {
|
|
171
|
+
deepFreeze(item, seen);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
const propNames = Object.getOwnPropertyNames(obj);
|
|
176
|
+
for (const name of propNames) {
|
|
177
|
+
const value = obj[name];
|
|
178
|
+
if (value && typeof value === "object") {
|
|
179
|
+
deepFreeze(value, seen);
|
|
22
180
|
}
|
|
23
181
|
}
|
|
24
182
|
}
|
|
183
|
+
return Object.freeze(obj);
|
|
25
184
|
};
|
|
26
185
|
|
|
27
|
-
// src/lib/
|
|
28
|
-
|
|
186
|
+
// src/lib/isProd.ts
|
|
187
|
+
var isProd = () => {
|
|
188
|
+
return false;
|
|
189
|
+
};
|
|
29
190
|
|
|
30
|
-
// src/lib/
|
|
31
|
-
|
|
191
|
+
// src/lib/setValueInData.ts
|
|
192
|
+
var setValueInData = (atom, value, data) => {
|
|
193
|
+
if (isProd()) {
|
|
194
|
+
data.values.set(atom, value);
|
|
195
|
+
return value;
|
|
196
|
+
} else {
|
|
197
|
+
const frozenValue = deepFreeze(value);
|
|
198
|
+
data.values.set(atom, frozenValue);
|
|
199
|
+
return frozenValue;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
32
202
|
|
|
33
|
-
// src/lib/
|
|
34
|
-
|
|
203
|
+
// src/lib/setAtom.ts
|
|
204
|
+
var setAtom = (atom, newValue, data, skipOnSet = false) => {
|
|
205
|
+
const initializedAtomsSet = new Set;
|
|
206
|
+
const currentValue = getState(atom, data, initializedAtomsSet);
|
|
207
|
+
if (isFunction(newValue)) {
|
|
208
|
+
newValue = newValue(currentValue);
|
|
209
|
+
if (isPromiseLike(newValue) || isPromiseLike(currentValue))
|
|
210
|
+
throw new Error("Todo, how should we handle this?");
|
|
211
|
+
}
|
|
212
|
+
if (atom.equal(currentValue, newValue))
|
|
213
|
+
return newValue;
|
|
214
|
+
newValue = setValueInData(atom, newValue, data);
|
|
215
|
+
if (atom.onSet && !skipOnSet)
|
|
216
|
+
atom.onSet(newValue, data);
|
|
217
|
+
if (currentValue?.__isEmptyAtomPromise__) {
|
|
218
|
+
currentValue.__resolveEmptyAtomPromise__(newValue);
|
|
219
|
+
}
|
|
220
|
+
if (initializedAtomsSet.size > 0) {
|
|
221
|
+
const all = new Set([...initializedAtomsSet, atom]);
|
|
222
|
+
propagateUpdatedAtoms([...all], data);
|
|
223
|
+
} else {
|
|
224
|
+
propagateUpdatedAtoms([atom], data);
|
|
225
|
+
}
|
|
226
|
+
return newValue;
|
|
227
|
+
};
|
|
35
228
|
|
|
36
229
|
// src/lib/initAtom.ts
|
|
37
|
-
var getAtomInitValue = (atom, data) => {
|
|
230
|
+
var getAtomInitValue = (atom, data, initializedAtomsSet) => {
|
|
38
231
|
if (atom.defaultValue === undefined) {
|
|
39
232
|
let promiseResolve;
|
|
40
233
|
const promise = new Promise((resolve) => {
|
|
@@ -47,45 +240,53 @@ var getAtomInitValue = (atom, data) => {
|
|
|
47
240
|
const value = atom.defaultValue();
|
|
48
241
|
if (isPromiseLike(value)) {
|
|
49
242
|
value.then((resolvedValue) => {
|
|
50
|
-
|
|
243
|
+
setValueInData(atom, resolvedValue, data);
|
|
51
244
|
propagateUpdatedAtoms([atom], data);
|
|
52
245
|
});
|
|
53
246
|
}
|
|
54
247
|
return value;
|
|
248
|
+
} else if (isSelector(atom.defaultValue)) {
|
|
249
|
+
return getState(atom.defaultValue, data, initializedAtomsSet);
|
|
55
250
|
} else {
|
|
56
251
|
return atom.defaultValue;
|
|
57
252
|
}
|
|
58
253
|
};
|
|
59
|
-
var initAtom = (atom, data) => {
|
|
60
|
-
|
|
61
|
-
|
|
254
|
+
var initAtom = (atom, data, initializedAtomsSet) => {
|
|
255
|
+
const tmpVal = getAtomInitValue(atom, data, initializedAtomsSet);
|
|
256
|
+
let value = setValueInData(atom, tmpVal, data);
|
|
62
257
|
if (atom.onInit)
|
|
63
258
|
atom.onInit((newVal) => {
|
|
64
259
|
value = newVal;
|
|
65
260
|
setAtom(atom, newVal, data, true);
|
|
66
261
|
}, data);
|
|
67
|
-
return value;
|
|
68
262
|
};
|
|
69
263
|
|
|
70
|
-
// src/utils/isAtom.ts
|
|
71
|
-
var isAtom = (state) => Object.hasOwn(state, "defaultValue");
|
|
72
|
-
|
|
73
|
-
// src/utils/isSelector.ts
|
|
74
|
-
var isSelector = (state) => Object.hasOwn(state, "get");
|
|
75
|
-
|
|
76
|
-
// src/utils/isFamily.ts
|
|
77
|
-
var isFamily = (state) => Object.hasOwn(state, "_map");
|
|
78
|
-
|
|
79
264
|
// src/lib/getState.ts
|
|
80
|
-
function getState(state, data) {
|
|
265
|
+
function getState(state, data, initializedAtomsSet, circularDependencySet) {
|
|
81
266
|
if (data.values.has(state))
|
|
82
267
|
return data.values.get(state);
|
|
83
|
-
if (isAtom(state))
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
268
|
+
if (isAtom(state)) {
|
|
269
|
+
if ("parent" in data)
|
|
270
|
+
return getState(state, data.parent, initializedAtomsSet, circularDependencySet);
|
|
271
|
+
initAtom(state, data, initializedAtomsSet);
|
|
272
|
+
initializedAtomsSet.add(state);
|
|
273
|
+
return data.values.get(state);
|
|
274
|
+
}
|
|
275
|
+
if (isSelector(state)) {
|
|
276
|
+
initSelector(state, data, initializedAtomsSet, circularDependencySet);
|
|
277
|
+
return data.values.get(state);
|
|
278
|
+
}
|
|
279
|
+
if (isAtomFamily(state)) {
|
|
280
|
+
if ("parent" in data) {
|
|
281
|
+
const closestData = findClosestStoreWithAtomInitialized(state, data);
|
|
282
|
+
return getState(state, closestData, initializedAtomsSet, circularDependencySet);
|
|
283
|
+
}
|
|
284
|
+
data.values.set(state, []);
|
|
285
|
+
initializedAtomsSet.add(state);
|
|
286
|
+
return data.values.get(state);
|
|
287
|
+
}
|
|
288
|
+
if (isSelectorFamily(state)) {
|
|
289
|
+
const array = Array.from(state.__valdresSelectorFamilyMap.keys());
|
|
89
290
|
if (equal(array, state._keyArray))
|
|
90
291
|
return state._keyArray;
|
|
91
292
|
state._keyArray = array;
|
|
@@ -93,6 +294,13 @@ function getState(state, data) {
|
|
|
93
294
|
}
|
|
94
295
|
throw new Error("Invalid object passed to get");
|
|
95
296
|
}
|
|
297
|
+
var findClosestStoreWithAtomInitialized = (atom, data) => {
|
|
298
|
+
if ("parent" in data === false)
|
|
299
|
+
return data;
|
|
300
|
+
if (data.values.has(atom))
|
|
301
|
+
return data;
|
|
302
|
+
return findClosestStoreWithAtomInitialized(atom, data.parent);
|
|
303
|
+
};
|
|
96
304
|
|
|
97
305
|
// src/lib/initSelector.ts
|
|
98
306
|
class SuspendAndWaitForResolveError extends Error {
|
|
@@ -102,20 +310,22 @@ class SuspendAndWaitForResolveError extends Error {
|
|
|
102
310
|
this.promise = promise;
|
|
103
311
|
}
|
|
104
312
|
}
|
|
105
|
-
var
|
|
106
|
-
const set = data.
|
|
313
|
+
var getOrInitDependentsSet = (state, data) => {
|
|
314
|
+
const set = data.stateDependents.get(state);
|
|
107
315
|
if (set)
|
|
108
316
|
return set;
|
|
109
317
|
const newSet = new Set;
|
|
110
|
-
data.
|
|
318
|
+
data.stateDependents.set(state, newSet);
|
|
111
319
|
return newSet;
|
|
112
320
|
};
|
|
113
|
-
var evaluateSelector = (selector, data) => {
|
|
321
|
+
var evaluateSelector = (selector, data, initializedAtomsSet, circularDependencySet = new WeakSet) => {
|
|
114
322
|
const updatedDependencies = new Set;
|
|
323
|
+
if (circularDependencySet.has(selector)) {}
|
|
324
|
+
circularDependencySet.add(selector);
|
|
115
325
|
let result;
|
|
116
326
|
try {
|
|
117
327
|
result = selector.get((state) => {
|
|
118
|
-
const value = getState(state, data);
|
|
328
|
+
const value = getState(state, data, initializedAtomsSet, circularDependencySet);
|
|
119
329
|
updatedDependencies.add(state);
|
|
120
330
|
if (isPromiseLike(value))
|
|
121
331
|
throw new SuspendAndWaitForResolveError(value);
|
|
@@ -124,19 +334,21 @@ var evaluateSelector = (selector, data) => {
|
|
|
124
334
|
} catch (error) {
|
|
125
335
|
if (error instanceof SuspendAndWaitForResolveError) {
|
|
126
336
|
result = error;
|
|
127
|
-
} else {
|
|
337
|
+
} else if (error instanceof SelectorEvaluationError) {
|
|
128
338
|
throw error;
|
|
339
|
+
} else {
|
|
340
|
+
throw new SelectorEvaluationError(error);
|
|
129
341
|
}
|
|
130
342
|
}
|
|
131
343
|
const currentDependencies = data.stateDependencies.get(selector) ?? new Set;
|
|
132
344
|
const added = updatedDependencies?.difference(currentDependencies);
|
|
133
345
|
const removed = currentDependencies?.difference(updatedDependencies);
|
|
134
346
|
for (const state of added) {
|
|
135
|
-
const set =
|
|
347
|
+
const set = getOrInitDependentsSet(state, data);
|
|
136
348
|
set.add(selector);
|
|
137
349
|
}
|
|
138
350
|
for (const state of removed) {
|
|
139
|
-
const set =
|
|
351
|
+
const set = getOrInitDependentsSet(state, data);
|
|
140
352
|
set.delete(selector);
|
|
141
353
|
}
|
|
142
354
|
data.stateDependencies.set(selector, updatedDependencies);
|
|
@@ -144,248 +356,259 @@ var evaluateSelector = (selector, data) => {
|
|
|
144
356
|
};
|
|
145
357
|
var handleSelectorResult = (value, selector, data) => {
|
|
146
358
|
if (value instanceof SuspendAndWaitForResolveError) {
|
|
147
|
-
value.promise.then(() =>
|
|
359
|
+
value.promise.then(() => {
|
|
360
|
+
const initializedAtomsSet = new Set;
|
|
361
|
+
const res = initSelector(selector, data, initializedAtomsSet);
|
|
362
|
+
if (initializedAtomsSet.size > 0) {
|
|
363
|
+
propagateUpdatedAtoms([...initializedAtomsSet], data);
|
|
364
|
+
}
|
|
365
|
+
return res;
|
|
366
|
+
});
|
|
148
367
|
return value.promise;
|
|
149
368
|
} else if (isPromiseLike(value)) {
|
|
150
369
|
value.then((resolved) => {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
370
|
+
setValueInData(selector, resolved, data);
|
|
371
|
+
const dependents = data.stateDependents.get(selector);
|
|
372
|
+
const subs = data.subscriptions.get(selector);
|
|
373
|
+
if (subs && subs.size > 0 || dependents && dependents.size > 0) {
|
|
374
|
+
propagateDirtySelectors([], new Set(dependents), data, new Set(subs), new Map);
|
|
375
|
+
}
|
|
154
376
|
});
|
|
155
377
|
return value;
|
|
156
378
|
} else {
|
|
157
379
|
return value;
|
|
158
380
|
}
|
|
159
381
|
};
|
|
160
|
-
var initSelector = (selector, data) => {
|
|
161
|
-
const
|
|
162
|
-
const
|
|
163
|
-
if (
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
382
|
+
var initSelector = (selector, data, initializedAtomsSet, circularDependencySet = new WeakSet) => {
|
|
383
|
+
const existingValue = data.values.get(selector);
|
|
384
|
+
const udpatedValue = evaluate(selector, data, initializedAtomsSet, circularDependencySet);
|
|
385
|
+
if (selector.equal(existingValue, udpatedValue)) {
|
|
386
|
+
return false;
|
|
387
|
+
} else {
|
|
388
|
+
setValueInData(selector, udpatedValue, data);
|
|
389
|
+
return true;
|
|
169
390
|
}
|
|
170
|
-
data.values.set(selector, value);
|
|
171
|
-
return value;
|
|
172
391
|
};
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
try {
|
|
182
|
-
const oldValue = data.expiredValues.get(selector);
|
|
183
|
-
const newValue = initSelector(selector, data);
|
|
184
|
-
if (equal3(newValue, oldValue))
|
|
185
|
-
return;
|
|
186
|
-
} catch (e) {
|
|
187
|
-
}
|
|
392
|
+
var evaluate = (selector, data, initializedAtomsSet, circularDependencySet) => {
|
|
393
|
+
let tmpValue;
|
|
394
|
+
try {
|
|
395
|
+
tmpValue = evaluateSelector(selector, data, initializedAtomsSet, circularDependencySet);
|
|
396
|
+
} catch (e) {
|
|
397
|
+
if (e instanceof SelectorEvaluationError)
|
|
398
|
+
e.track(selector);
|
|
399
|
+
throw e;
|
|
188
400
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
401
|
+
return handleSelectorResult(tmpValue, selector, data);
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
// src/lib/propagateUpdatedAtoms.ts
|
|
405
|
+
var reEvaluteSelector = (selector, data, updatedAtoms) => {
|
|
406
|
+
const existingValue = data.values.get(selector);
|
|
407
|
+
try {
|
|
408
|
+
const udpatedValue = evaluateSelector(selector, data, updatedAtoms);
|
|
409
|
+
if (selector.equal(existingValue, udpatedValue, updatedAtoms)) {
|
|
410
|
+
return [false, false];
|
|
411
|
+
} else {
|
|
412
|
+
setValueInData(selector, udpatedValue, data);
|
|
413
|
+
return [true, false];
|
|
192
414
|
}
|
|
415
|
+
} catch (error) {
|
|
416
|
+
data.expiredValues.set(selector, data.values.get(selector));
|
|
417
|
+
data.values.delete(selector);
|
|
418
|
+
return [true, true, error];
|
|
193
419
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
420
|
+
};
|
|
421
|
+
var addSetToSet = (fromSet, toSet) => {
|
|
422
|
+
if (fromSet && fromSet.size > 0) {
|
|
423
|
+
for (const item of fromSet) {
|
|
424
|
+
toSet.add(item);
|
|
197
425
|
}
|
|
198
426
|
}
|
|
199
427
|
};
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
428
|
+
var findClosestStoreWithAtomInitialized2 = (atom, data) => {
|
|
429
|
+
if ("parent" in data === false)
|
|
430
|
+
return data;
|
|
431
|
+
if (data.values.has(atom))
|
|
432
|
+
return data;
|
|
433
|
+
return findClosestStoreWithAtomInitialized2(atom, data.parent);
|
|
434
|
+
};
|
|
435
|
+
var findInClosestStore = (state, data) => {
|
|
436
|
+
const store = findClosestStoreWithAtomInitialized2(state, data);
|
|
437
|
+
return store.values.get(state);
|
|
438
|
+
};
|
|
439
|
+
var addFamilyAtomsToSet = (family, familyAtoms, data) => {
|
|
440
|
+
const currentAtoms = findInClosestStore(family, data) || [];
|
|
441
|
+
const atomsToAdd = [];
|
|
442
|
+
for (const familyAtom of familyAtoms) {
|
|
443
|
+
if (!currentAtoms.includes(familyAtom)) {
|
|
444
|
+
atomsToAdd.push(familyAtom);
|
|
212
445
|
}
|
|
213
446
|
}
|
|
447
|
+
if (atomsToAdd.length > 0) {
|
|
448
|
+
data.values.set(family, [...currentAtoms, ...atomsToAdd]);
|
|
449
|
+
}
|
|
214
450
|
};
|
|
215
|
-
var propagateUpdatedAtoms = (atoms, data) => {
|
|
216
|
-
const
|
|
451
|
+
var propagateUpdatedAtoms = (atoms, data, subscriptions = new Set, families = new Map, isRecursive = false) => {
|
|
452
|
+
const selectors = new Set;
|
|
217
453
|
for (const atom of atoms) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
const consumersFamily = data.stateConsumers.get(atom.family);
|
|
224
|
-
if (consumersFamily?.size) {
|
|
225
|
-
recursivlyResetSelectorTree(consumersFamily, data, clearedSelectors);
|
|
454
|
+
addSetToSet(data.stateDependents.get(atom), selectors);
|
|
455
|
+
addSetToSet(data.subscriptions.get(atom), subscriptions);
|
|
456
|
+
if (isFamilyAtom(atom)) {
|
|
457
|
+
if (!families.has(atom.family)) {
|
|
458
|
+
families.set(atom.family, new Set);
|
|
226
459
|
}
|
|
460
|
+
families.get(atom.family).add(atom);
|
|
227
461
|
}
|
|
228
462
|
}
|
|
229
|
-
|
|
230
|
-
|
|
463
|
+
if (families.size > 0) {
|
|
464
|
+
for (const [family, familyAtoms] of families) {
|
|
465
|
+
addSetToSet(data.stateDependents.get(family), selectors);
|
|
466
|
+
addSetToSet(data.subscriptions.get(family), subscriptions);
|
|
467
|
+
if (familyAtoms.size === 0)
|
|
468
|
+
throw new Error("Should not be possible");
|
|
469
|
+
addFamilyAtomsToSet(family, familyAtoms, data);
|
|
470
|
+
}
|
|
231
471
|
}
|
|
232
|
-
|
|
233
|
-
|
|
472
|
+
if (!isRecursive) {
|
|
473
|
+
propagateDirtySelectors(atoms, selectors, data, subscriptions, families);
|
|
234
474
|
}
|
|
235
475
|
};
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
newValue = newValue(currentValue);
|
|
242
|
-
if (isPromiseLike(newValue) || isPromiseLike(currentValue))
|
|
243
|
-
throw new Error("Todo, how should we handle this?");
|
|
476
|
+
var propagateDirtySelectors = (updatedAtoms, selectors, data, subscriptions, families) => {
|
|
477
|
+
const initialUpdatedAtoms = new Set(updatedAtoms);
|
|
478
|
+
const updatedInitializedAtoms = new Set(initialUpdatedAtoms);
|
|
479
|
+
if (selectors.size > 0) {
|
|
480
|
+
recursivlyHandleSelectorUpdates(selectors, data, subscriptions, updatedInitializedAtoms);
|
|
244
481
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
atom.onSet(newValue, data);
|
|
250
|
-
if (currentValue?.__isEmptyAtomPromise__) {
|
|
251
|
-
currentValue.__resolveEmptyAtomPromise__(newValue);
|
|
482
|
+
const addedAtoms = initialUpdatedAtoms.symmetricDifference(updatedInitializedAtoms);
|
|
483
|
+
if (addedAtoms.size) {
|
|
484
|
+
console.log("addedAtoms", addedAtoms);
|
|
485
|
+
console.log("Valdres TODO: Support this case with new atoms added");
|
|
252
486
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
value = newValue;
|
|
262
|
-
if (stores.size > 1) {
|
|
263
|
-
for (const store of stores) {
|
|
264
|
-
if (store.id !== currentStore.id) {
|
|
265
|
-
setAtom(newAtom, value, store, true);
|
|
487
|
+
if (subscriptions.size > 0) {
|
|
488
|
+
for (const subscription of subscriptions) {
|
|
489
|
+
if ("state" in subscription) {
|
|
490
|
+
const updatedFamilyAtoms = families.get(subscription.state);
|
|
491
|
+
if (updatedFamilyAtoms) {
|
|
492
|
+
for (const atom of updatedFamilyAtoms) {
|
|
493
|
+
subscription.callback(...atom.familyArgs);
|
|
494
|
+
}
|
|
266
495
|
}
|
|
496
|
+
} else {
|
|
497
|
+
subscription.callback();
|
|
267
498
|
}
|
|
268
499
|
}
|
|
269
|
-
};
|
|
270
|
-
const newAtom = {
|
|
271
|
-
defaultValue,
|
|
272
|
-
...options,
|
|
273
|
-
onInit: (setSelf, store) => {
|
|
274
|
-
setSelf(value);
|
|
275
|
-
stores.add(store);
|
|
276
|
-
},
|
|
277
|
-
onSet,
|
|
278
|
-
label: options?.label
|
|
279
|
-
};
|
|
280
|
-
return newAtom;
|
|
281
|
-
};
|
|
282
|
-
var atom = (defaultValue, options) => {
|
|
283
|
-
if (!options)
|
|
284
|
-
return { defaultValue };
|
|
285
|
-
if (options.global)
|
|
286
|
-
return globalAtom(defaultValue, options);
|
|
287
|
-
return {
|
|
288
|
-
defaultValue,
|
|
289
|
-
...options
|
|
290
|
-
};
|
|
291
|
-
};
|
|
292
|
-
// src/lib/stableStringify.ts
|
|
293
|
-
var stableStringifyRecurse = (x, key) => {
|
|
294
|
-
if (typeof x === "string" && !x.includes('"') && !x.includes("\\")) {
|
|
295
|
-
return `"${x}"`;
|
|
296
500
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
return JSON.stringify(x);
|
|
307
|
-
case "function":
|
|
308
|
-
return `__FUNCTION(${x.toString()})__`;
|
|
309
|
-
}
|
|
310
|
-
if (x === null) {
|
|
311
|
-
return "null";
|
|
312
|
-
}
|
|
313
|
-
if (typeof x !== "object") {
|
|
314
|
-
return JSON.stringify(x) ?? "";
|
|
315
|
-
}
|
|
316
|
-
if (isPromiseLike(x)) {
|
|
317
|
-
return "__PROMISE__";
|
|
318
|
-
}
|
|
319
|
-
if (Array.isArray(x)) {
|
|
320
|
-
return `[${x.map((v, i) => stableStringifyRecurse(v, i.toString()))}]`;
|
|
321
|
-
}
|
|
322
|
-
if (typeof x.toJSON === "function") {
|
|
323
|
-
return stableStringifyRecurse(x.toJSON(key), key);
|
|
324
|
-
}
|
|
325
|
-
if (x instanceof Map) {
|
|
326
|
-
const obj = {};
|
|
327
|
-
for (const [k, v] of x) {
|
|
328
|
-
obj[typeof k === "string" ? k : stringify(k, opt)] = v;
|
|
501
|
+
};
|
|
502
|
+
var findAllDependents = (selector, data, depsRes = new Set, subsRes = new Set) => {
|
|
503
|
+
const dependents = data.stateDependents.get(selector);
|
|
504
|
+
const subscriptions = data.subscriptions.get(selector);
|
|
505
|
+
addSetToSet(dependents, depsRes);
|
|
506
|
+
addSetToSet(subscriptions, subsRes);
|
|
507
|
+
if (dependents && dependents.size > 0) {
|
|
508
|
+
for (const dependent of dependents) {
|
|
509
|
+
findAllDependents(dependent, data, depsRes, subsRes);
|
|
329
510
|
}
|
|
330
|
-
return stableStringifyRecurse(obj, key);
|
|
331
511
|
}
|
|
332
|
-
|
|
333
|
-
|
|
512
|
+
return [depsRes, subsRes];
|
|
513
|
+
};
|
|
514
|
+
var recursivlyHandleSelectorUpdates = (selectors, data, collectedSubscribers, updatedInitializedAtoms, seen = new Set) => {
|
|
515
|
+
const selectorsForNextPass = new Set;
|
|
516
|
+
for (const selector of selectors) {
|
|
517
|
+
const currentValue = data.values.get(selector);
|
|
518
|
+
if (isPromiseLike(currentValue)) {
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
seen.add(selector);
|
|
522
|
+
const dependents = data.stateDependents.get(selector);
|
|
523
|
+
const subscribers = data.subscriptions.get(selector);
|
|
524
|
+
if ((!dependents || dependents.size === 0) && (!subscribers || subscribers.size === 0)) {
|
|
525
|
+
data.expiredValues.set(selector, data.values.get(selector));
|
|
526
|
+
data.values.delete(selector);
|
|
527
|
+
} else {
|
|
528
|
+
const [wasValueUpdated, didEvalCrash, error] = reEvaluteSelector(selector, data, updatedInitializedAtoms);
|
|
529
|
+
if (didEvalCrash) {
|
|
530
|
+
const [deps, subs] = findAllDependents(selector, data);
|
|
531
|
+
if (deps.size > 0) {
|
|
532
|
+
for (const dep of deps) {
|
|
533
|
+
data.expiredValues.set(dep, data.values.get(dep));
|
|
534
|
+
data.values.delete(dep);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
if (subs.size > 0) {
|
|
538
|
+
addSetToSet(subs, collectedSubscribers);
|
|
539
|
+
}
|
|
540
|
+
} else {
|
|
541
|
+
if (!wasValueUpdated)
|
|
542
|
+
continue;
|
|
543
|
+
addSetToSet(data.stateDependents.get(selector), selectorsForNextPass);
|
|
544
|
+
addSetToSet(subscribers, collectedSubscribers);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
334
547
|
}
|
|
335
|
-
if (
|
|
336
|
-
|
|
548
|
+
if (selectorsForNextPass.size > 0) {
|
|
549
|
+
recursivlyHandleSelectorUpdates(selectorsForNextPass, data, collectedSubscribers, updatedInitializedAtoms, seen);
|
|
337
550
|
}
|
|
338
|
-
return `{${Object.keys(x).filter((k) => x[k] !== undefined).sort().map((k) => `${stableStringifyRecurse(k)}:${stableStringifyRecurse(x[k], k)}`).join(",")}}`;
|
|
339
|
-
};
|
|
340
|
-
var stableStringify = (x) => {
|
|
341
|
-
if (typeof x === "string" || typeof x === "boolean" || typeof x === "number")
|
|
342
|
-
return x;
|
|
343
|
-
return stableStringifyRecurse(x);
|
|
344
551
|
};
|
|
345
552
|
|
|
346
|
-
// src/atomFamily.ts
|
|
347
|
-
var atomFamily = (defaultValue, debugLabel) => {
|
|
348
|
-
const map = new Map;
|
|
349
|
-
const atomFamily2 = (key, defaultOverride) => {
|
|
350
|
-
const keyStringified = stableStringify(key);
|
|
351
|
-
if (map.has(keyStringified)) {
|
|
352
|
-
return map.get(keyStringified);
|
|
353
|
-
}
|
|
354
|
-
const atomDebugLabel = debugLabel && debugLabel + "_" + keyStringified;
|
|
355
|
-
const newAtom = atom(typeof defaultValue === "function" ? () => defaultValue(key) : defaultValue, {
|
|
356
|
-
label: atomDebugLabel
|
|
357
|
-
});
|
|
358
|
-
newAtom.family = atomFamily2;
|
|
359
|
-
newAtom.familyKey = Object.freeze(key);
|
|
360
|
-
map.set(keyStringified, newAtom);
|
|
361
|
-
return newAtom;
|
|
362
|
-
};
|
|
363
|
-
atomFamily2._map = map;
|
|
364
|
-
return atomFamily2;
|
|
365
|
-
};
|
|
366
553
|
// src/lib/createStoreData.ts
|
|
367
554
|
var generateId = () => (Math.random() + 1).toString(36).substring(7);
|
|
368
|
-
var
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
555
|
+
var generateStoreData = (id = generateId()) => {
|
|
556
|
+
return {
|
|
557
|
+
id,
|
|
558
|
+
values: new WeakMap,
|
|
559
|
+
expiredValues: new WeakMap,
|
|
560
|
+
subscriptions: new WeakMap,
|
|
561
|
+
subscriptionsRequireEqualCheck: new WeakMap,
|
|
562
|
+
stateDependents: new WeakMap,
|
|
563
|
+
stateDependencies: new WeakMap,
|
|
564
|
+
scopes: {}
|
|
565
|
+
};
|
|
566
|
+
};
|
|
567
|
+
function createStoreData(id, parent) {
|
|
568
|
+
if (parent) {
|
|
569
|
+
return {
|
|
570
|
+
...generateStoreData(id),
|
|
571
|
+
parent,
|
|
572
|
+
scopeConsumers: parent ? new Set : undefined
|
|
573
|
+
};
|
|
574
|
+
} else {
|
|
575
|
+
return generateStoreData(id);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// src/lib/deleteFamilyAtom.ts
|
|
580
|
+
var deleteFamilyAtom = (atom, data) => {
|
|
581
|
+
const array = data.values.get(atom.family);
|
|
582
|
+
const index = array.indexOf(atom);
|
|
583
|
+
const newArray = [
|
|
584
|
+
...array.slice(0, index),
|
|
585
|
+
...array.slice(index + 1)
|
|
586
|
+
];
|
|
587
|
+
data.values.delete(atom);
|
|
588
|
+
propagateUpdatedAtoms([atom], data);
|
|
589
|
+
setValueInData(atom.family, newArray, data);
|
|
590
|
+
propagateUpdatedAtoms([atom.family], data);
|
|
591
|
+
};
|
|
377
592
|
|
|
378
593
|
// src/lib/resetAtom.ts
|
|
379
|
-
var resetAtom = (
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
594
|
+
var resetAtom = (atom, data) => {
|
|
595
|
+
const initializedAtomsSet = new Set;
|
|
596
|
+
let value = getAtomInitValue(atom, data, initializedAtomsSet);
|
|
597
|
+
setValueInData(atom, value, data);
|
|
598
|
+
if (!isPromiseLike(value)) {
|
|
599
|
+
propagateUpdatedAtoms([atom], data);
|
|
600
|
+
}
|
|
601
|
+
if (initializedAtomsSet.size > 0) {
|
|
602
|
+
throw new Error("Todo - propagateUpdatedAtoms on reset");
|
|
383
603
|
}
|
|
384
|
-
return
|
|
604
|
+
return value;
|
|
385
605
|
};
|
|
386
606
|
|
|
607
|
+
// src/utils/isFamily.ts
|
|
608
|
+
var isFamily = (state) => isAtomFamily(state) || isSelectorFamily(state);
|
|
609
|
+
|
|
387
610
|
// src/lib/unsubscribe.ts
|
|
388
|
-
var unsubscribe = (state, subscription, data, mount) => {
|
|
611
|
+
var unsubscribe = (state, subscription, data, mount, maxAgeCleanup) => {
|
|
389
612
|
const subscribers = data.subscriptions.get(state);
|
|
390
613
|
if (subscribers) {
|
|
391
614
|
subscribers.delete(subscription);
|
|
@@ -401,6 +624,11 @@ var unsubscribe = (state, subscription, data, mount) => {
|
|
|
401
624
|
data.subscriptionsRequireEqualCheck.delete(state);
|
|
402
625
|
}
|
|
403
626
|
}
|
|
627
|
+
if (subscribers.size === 0) {
|
|
628
|
+
if (maxAgeCleanup)
|
|
629
|
+
maxAgeCleanup();
|
|
630
|
+
data.subscriptions.delete(state);
|
|
631
|
+
}
|
|
404
632
|
if (mount) {
|
|
405
633
|
if (subscribers.size === mount.mountSubscriptions.size) {
|
|
406
634
|
if (typeof mount.onUnmount === "function") {
|
|
@@ -418,12 +646,33 @@ var initSubscribers = (state, data) => {
|
|
|
418
646
|
return set;
|
|
419
647
|
};
|
|
420
648
|
var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) => {
|
|
421
|
-
|
|
649
|
+
let parentUnsubscribe;
|
|
650
|
+
if ("parent" in data && (!data.values.has(state) && isAtom(state) || isAtomFamily(state))) {
|
|
651
|
+
const originalCallback = callback;
|
|
652
|
+
parentUnsubscribe = subscribe(state, originalCallback, requireDeepEqualCheckBeforeCallback, data.parent);
|
|
653
|
+
callback = (arg) => {
|
|
654
|
+
if (parentUnsubscribe) {
|
|
655
|
+
parentUnsubscribe();
|
|
656
|
+
parentUnsubscribe = undefined;
|
|
657
|
+
}
|
|
658
|
+
originalCallback(arg);
|
|
659
|
+
};
|
|
660
|
+
} else if (!data.values.has(state) && isAtom(state)) {
|
|
661
|
+
const initializedAtomsSet = new Set;
|
|
662
|
+
initAtom(state, data, initializedAtomsSet);
|
|
663
|
+
if (initializedAtomsSet.size) {
|
|
664
|
+
throw new Error("This should not be possible");
|
|
665
|
+
}
|
|
666
|
+
}
|
|
422
667
|
if (isSelector(state) && !data.values.has(state)) {
|
|
423
|
-
initSelector(state, data);
|
|
668
|
+
initSelector(state, data, new Set, new WeakSet);
|
|
424
669
|
}
|
|
670
|
+
const subscribers = data.subscriptions.get(state) || initSubscribers(state, data);
|
|
425
671
|
let subscription;
|
|
426
672
|
if (isFamily(state)) {
|
|
673
|
+
if (isSelectorFamily(state)) {
|
|
674
|
+
throw new Error("Subscribe to selectorFammily is currently not supported");
|
|
675
|
+
}
|
|
427
676
|
subscription = {
|
|
428
677
|
callback,
|
|
429
678
|
state,
|
|
@@ -437,47 +686,83 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
|
|
|
437
686
|
}
|
|
438
687
|
subscribers.add(subscription);
|
|
439
688
|
let mount;
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
689
|
+
let maxAgeCleanup;
|
|
690
|
+
if (subscribers.size === 1) {
|
|
691
|
+
if (isAtom(state) && state.maxAge) {
|
|
692
|
+
let timeout;
|
|
693
|
+
const interval = setInterval(() => {
|
|
694
|
+
let value = getAtomInitValue(state, data);
|
|
695
|
+
if (isPromiseLike(value)) {
|
|
696
|
+
if (state.staleWhileRevalidate) {
|
|
697
|
+
const oldValue = data.values.get(state);
|
|
698
|
+
timeout = setTimeout(() => {
|
|
699
|
+
const nowValue = data.values.get(state);
|
|
700
|
+
console.log("todo", oldValue);
|
|
701
|
+
}, state.staleWhileRevalidate);
|
|
702
|
+
value.then((res) => clearTimeout(timeout));
|
|
703
|
+
}
|
|
704
|
+
} else {
|
|
705
|
+
setValueInData(state, value, data);
|
|
706
|
+
propagateUpdatedAtoms([state], data);
|
|
707
|
+
}
|
|
708
|
+
}, state.maxAge);
|
|
709
|
+
maxAgeCleanup = () => {
|
|
710
|
+
clearInterval(interval);
|
|
711
|
+
if (timeout)
|
|
712
|
+
clearTimeout(timeout);
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
if (state.onMount) {
|
|
716
|
+
const store = storeFromStoreData(data);
|
|
717
|
+
const mountSubscriptions = new Set;
|
|
718
|
+
const originalSub = store.sub;
|
|
719
|
+
store.sub = (state2, callback2) => {
|
|
720
|
+
mountSubscriptions.add(callback2);
|
|
721
|
+
return originalSub(state2, callback2);
|
|
722
|
+
};
|
|
723
|
+
mount = {
|
|
724
|
+
onUnmount: state.onMount(store, state),
|
|
725
|
+
mountSubscriptions
|
|
726
|
+
};
|
|
727
|
+
}
|
|
452
728
|
}
|
|
453
729
|
if (requireDeepEqualCheckBeforeCallback && data.subscriptionsRequireEqualCheck.get(state) !== true) {
|
|
454
730
|
data.subscriptionsRequireEqualCheck.set(state, true);
|
|
455
731
|
}
|
|
456
|
-
return () =>
|
|
732
|
+
return () => {
|
|
733
|
+
if (parentUnsubscribe) {
|
|
734
|
+
parentUnsubscribe();
|
|
735
|
+
}
|
|
736
|
+
unsubscribe(state, subscription, data, mount, maxAgeCleanup);
|
|
737
|
+
};
|
|
457
738
|
};
|
|
458
739
|
|
|
459
740
|
// src/lib/setAtoms.ts
|
|
460
|
-
|
|
461
|
-
var setAtoms = (pairs, data) => {
|
|
741
|
+
var setAtoms = (pairs, data, initializedAtomsSet) => {
|
|
462
742
|
const updatedAtoms = [];
|
|
463
|
-
for (let [
|
|
464
|
-
const currentValue = getState(
|
|
465
|
-
if (!
|
|
466
|
-
updatedAtoms.push(
|
|
467
|
-
|
|
743
|
+
for (let [atom, value] of pairs) {
|
|
744
|
+
const currentValue = getState(atom, data, initializedAtomsSet);
|
|
745
|
+
if (!atom.equal(currentValue, value)) {
|
|
746
|
+
updatedAtoms.push(atom);
|
|
747
|
+
value = setValueInData(atom, value, data);
|
|
748
|
+
if (atom.onSet)
|
|
749
|
+
atom.onSet(value, data);
|
|
468
750
|
}
|
|
469
751
|
}
|
|
470
|
-
|
|
752
|
+
const result = new Set([...updatedAtoms, ...initializedAtomsSet]);
|
|
753
|
+
if (result.size > 0) {
|
|
754
|
+
propagateUpdatedAtoms([...result], data);
|
|
755
|
+
}
|
|
471
756
|
};
|
|
472
757
|
|
|
473
758
|
// src/lib/transaction.ts
|
|
474
759
|
var findDependencies = (state, data, result = new Set) => {
|
|
475
|
-
const
|
|
476
|
-
if (
|
|
477
|
-
for (const
|
|
478
|
-
if (!result.has(
|
|
479
|
-
result.add(
|
|
480
|
-
findDependencies(
|
|
760
|
+
const dependents = data.stateDependents.get(state);
|
|
761
|
+
if (dependents?.size) {
|
|
762
|
+
for (const dependent of dependents) {
|
|
763
|
+
if (!result.has(dependent)) {
|
|
764
|
+
result.add(dependent);
|
|
765
|
+
findDependencies(dependent, data, result);
|
|
481
766
|
}
|
|
482
767
|
}
|
|
483
768
|
}
|
|
@@ -491,14 +776,43 @@ var recursivlyResetTxnSelectorCache = (state, txnSubscribers, txnSelectorCache)
|
|
|
491
776
|
}
|
|
492
777
|
}
|
|
493
778
|
};
|
|
494
|
-
var
|
|
495
|
-
let
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
779
|
+
var captureScopedTransaction = (scopedData, parentGetInTxnOrData) => {
|
|
780
|
+
let txn;
|
|
781
|
+
transaction((scopedTxn) => {
|
|
782
|
+
txn = scopedTxn;
|
|
783
|
+
}, scopedData, false, parentGetInTxnOrData);
|
|
784
|
+
return txn;
|
|
785
|
+
};
|
|
786
|
+
var deleteAtomFamilyAtoms = (set, data) => {
|
|
787
|
+
set.forEach((atom) => {
|
|
788
|
+
data.values.delete(atom);
|
|
789
|
+
});
|
|
790
|
+
};
|
|
791
|
+
var transaction = (callback, data, autoCommit = true, parentGetInTxnOrData) => {
|
|
792
|
+
const txnAtomMap = new Map;
|
|
793
|
+
const txnAtomDeleteSet = new Set;
|
|
794
|
+
const txnSelectorCache = new Map;
|
|
795
|
+
const txnSubscribers = new Map;
|
|
796
|
+
const dirtySelectors = new Set;
|
|
797
|
+
let scopedTransactions;
|
|
798
|
+
const getInTxnOrData = (state) => {
|
|
799
|
+
if (txnAtomMap.has(state)) {
|
|
800
|
+
return txnAtomMap.get(state);
|
|
801
|
+
}
|
|
802
|
+
if (data.values.has(state)) {
|
|
803
|
+
return data.values.get(state);
|
|
804
|
+
}
|
|
805
|
+
if (parentGetInTxnOrData) {
|
|
806
|
+
return parentGetInTxnOrData(state);
|
|
807
|
+
}
|
|
808
|
+
};
|
|
809
|
+
const initializedAtomsSet = new Set;
|
|
499
810
|
const txnGet = (state) => {
|
|
500
811
|
if (isAtom(state)) {
|
|
501
|
-
|
|
812
|
+
const value = getInTxnOrData(state);
|
|
813
|
+
if (value)
|
|
814
|
+
return value;
|
|
815
|
+
return getState(state, data, initializedAtomsSet);
|
|
502
816
|
} else if (isSelector(state)) {
|
|
503
817
|
if (txnSelectorCache.has(state)) {
|
|
504
818
|
return txnSelectorCache.get(state);
|
|
@@ -516,127 +830,526 @@ var transaction = (callback, data) => {
|
|
|
516
830
|
}
|
|
517
831
|
txnSelectorCache.set(state, res);
|
|
518
832
|
return res;
|
|
833
|
+
} else if (isAtomFamily(state)) {
|
|
834
|
+
const value = getInTxnOrData(state);
|
|
835
|
+
if (value)
|
|
836
|
+
return value;
|
|
837
|
+
return getState(state, data, initializedAtomsSet);
|
|
519
838
|
} else {
|
|
520
839
|
throw new Error("Unsupported state");
|
|
521
840
|
}
|
|
522
841
|
};
|
|
523
|
-
const txnSet = (
|
|
524
|
-
if (!isAtom(
|
|
842
|
+
const txnSet = (atom, value) => {
|
|
843
|
+
if (!isAtom(atom))
|
|
525
844
|
throw new Error("Not an atom");
|
|
526
|
-
if (
|
|
527
|
-
const currentValue = txnGet(
|
|
845
|
+
if (isFunction(value)) {
|
|
846
|
+
const currentValue = txnGet(atom);
|
|
528
847
|
value = value(currentValue);
|
|
529
848
|
}
|
|
530
|
-
for (const selector of findDependencies(
|
|
849
|
+
for (const selector of findDependencies(atom, data)) {
|
|
531
850
|
dirtySelectors.add(selector);
|
|
532
851
|
txnSelectorCache.delete(selector);
|
|
533
852
|
}
|
|
534
|
-
if (txnSubscribers.get(
|
|
535
|
-
recursivlyResetTxnSelectorCache(
|
|
853
|
+
if (txnSubscribers.get(atom)?.size) {
|
|
854
|
+
recursivlyResetTxnSelectorCache(atom, txnSubscribers, txnSelectorCache);
|
|
855
|
+
}
|
|
856
|
+
if (isProd()) {
|
|
857
|
+
txnAtomMap.set(atom, value);
|
|
858
|
+
} else {
|
|
859
|
+
txnAtomMap.set(atom, deepFreeze(value));
|
|
536
860
|
}
|
|
537
|
-
|
|
861
|
+
if (isFamilyAtom(atom)) {
|
|
862
|
+
const currentFamilyList = txnGet(atom.family);
|
|
863
|
+
if (!currentFamilyList.includes(atom)) {
|
|
864
|
+
const newArr = [...currentFamilyList, atom];
|
|
865
|
+
txnAtomMap.set(atom.family, newArr);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
return value;
|
|
538
869
|
};
|
|
539
|
-
const txnReset = (
|
|
540
|
-
const value = getAtomInitValue(
|
|
541
|
-
txnAtomMap.set(
|
|
870
|
+
const txnReset = (atom) => {
|
|
871
|
+
const value = getAtomInitValue(atom, data, initializedAtomsSet);
|
|
872
|
+
txnAtomMap.set(atom, value);
|
|
542
873
|
return value;
|
|
543
874
|
};
|
|
875
|
+
const txnDel = (atom) => {
|
|
876
|
+
const array = txnGet(atom.family);
|
|
877
|
+
const index = array.indexOf(atom);
|
|
878
|
+
const newArr = [
|
|
879
|
+
...array.slice(0, index),
|
|
880
|
+
...array.slice(index + 1)
|
|
881
|
+
];
|
|
882
|
+
txnAtomMap.set(atom.family, newArr);
|
|
883
|
+
if (data.values.has(atom)) {
|
|
884
|
+
txnAtomDeleteSet.add(atom);
|
|
885
|
+
}
|
|
886
|
+
if (txnAtomMap.has(atom)) {
|
|
887
|
+
txnAtomMap.delete(atom);
|
|
888
|
+
}
|
|
889
|
+
};
|
|
544
890
|
const commit = () => {
|
|
545
|
-
setAtoms(txnAtomMap, data);
|
|
891
|
+
setAtoms(txnAtomMap, data, initializedAtomsSet);
|
|
892
|
+
if (txnAtomDeleteSet.size) {
|
|
893
|
+
deleteAtomFamilyAtoms(txnAtomDeleteSet, data);
|
|
894
|
+
}
|
|
546
895
|
dirtySelectors.clear();
|
|
896
|
+
if (scopedTransactions) {
|
|
897
|
+
for (const scopedTxn of Object.values(scopedTransactions)) {
|
|
898
|
+
scopedTxn.commit();
|
|
899
|
+
}
|
|
900
|
+
}
|
|
547
901
|
};
|
|
548
|
-
const result = callback(
|
|
549
|
-
|
|
902
|
+
const result = callback({
|
|
903
|
+
set: txnSet,
|
|
904
|
+
get: txnGet,
|
|
905
|
+
del: txnDel,
|
|
906
|
+
reset: txnReset,
|
|
907
|
+
commit,
|
|
908
|
+
scope: (scopeId, callback2) => {
|
|
909
|
+
if (scopeId in data.scopes) {
|
|
910
|
+
const scopedData = data.scopes[scopeId];
|
|
911
|
+
if (scopedTransactions === undefined) {
|
|
912
|
+
scopedTransactions = {};
|
|
913
|
+
}
|
|
914
|
+
if (scopedTransactions[scopeId] === undefined) {
|
|
915
|
+
scopedTransactions[scopeId] = captureScopedTransaction(scopedData, getInTxnOrData);
|
|
916
|
+
}
|
|
917
|
+
return callback2(scopedTransactions[scopeId]);
|
|
918
|
+
} else {
|
|
919
|
+
throw new Error(`Scope '${scopeId}' not found. Registered scopes: ${Object.keys(data.scopes).join(", ")}`);
|
|
920
|
+
}
|
|
921
|
+
},
|
|
922
|
+
data
|
|
923
|
+
});
|
|
924
|
+
if (autoCommit)
|
|
925
|
+
commit();
|
|
550
926
|
return result;
|
|
551
927
|
};
|
|
552
928
|
|
|
553
929
|
// src/lib/storeFromStoreData.ts
|
|
554
|
-
var
|
|
555
|
-
|
|
930
|
+
var SelectorProvidedToSetError = `Invalid state object passed to set().
|
|
931
|
+
You provided a \`selector\`.
|
|
932
|
+
Only \`atom\` cam be set.
|
|
933
|
+
`;
|
|
934
|
+
var InvalidStateSetError = `Invalid state object passed to set().
|
|
935
|
+
Only \`atom\` can be set.
|
|
936
|
+
`;
|
|
937
|
+
function storeFromStoreData(data, detach) {
|
|
938
|
+
const get = (state) => {
|
|
939
|
+
const set2 = new Set;
|
|
940
|
+
const res = getState(state, data, set2);
|
|
941
|
+
if (set2.size) {
|
|
942
|
+
propagateUpdatedAtoms([...set2], data);
|
|
943
|
+
}
|
|
944
|
+
return res;
|
|
945
|
+
};
|
|
556
946
|
const set = (state, value) => {
|
|
557
|
-
if (
|
|
558
|
-
|
|
559
|
-
|
|
947
|
+
if (isAtom(state))
|
|
948
|
+
return setAtom(state, value, data);
|
|
949
|
+
if (isSelector(state))
|
|
950
|
+
throw new Error(SelectorProvidedToSetError);
|
|
951
|
+
throw new Error(InvalidStateSetError);
|
|
560
952
|
};
|
|
561
|
-
const reset = (
|
|
953
|
+
const reset = (atom) => resetAtom(atom, data);
|
|
954
|
+
const del = (atom) => deleteFamilyAtom(atom, data);
|
|
562
955
|
const sub = (state, callback, deepEqualCheckBeforeCallback = true) => subscribe(state, callback, deepEqualCheckBeforeCallback, data);
|
|
563
956
|
const txn = (callback) => transaction(callback, data);
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
957
|
+
const scope = (scopeId) => {
|
|
958
|
+
let scopedStoreData;
|
|
959
|
+
if (scopeId in data.scopes) {
|
|
960
|
+
scopedStoreData = data.scopes[scopeId];
|
|
961
|
+
} else {
|
|
962
|
+
scopedStoreData = createStoreData(scopeId, data);
|
|
963
|
+
data.scopes[scopeId] = scopedStoreData;
|
|
964
|
+
}
|
|
965
|
+
const detach2 = () => {
|
|
966
|
+
scopedStoreData.scopeConsumers.delete(detach2);
|
|
967
|
+
if (scopedStoreData.scopeConsumers.size === 0) {
|
|
968
|
+
delete data.scopes[scopeId];
|
|
969
|
+
}
|
|
970
|
+
};
|
|
971
|
+
scopedStoreData.scopeConsumers.add(detach2);
|
|
972
|
+
const newStore = storeFromStoreData(data.scopes[scopeId], detach2);
|
|
973
|
+
return newStore;
|
|
571
974
|
};
|
|
572
|
-
|
|
975
|
+
if (detach) {
|
|
976
|
+
return {
|
|
977
|
+
get,
|
|
978
|
+
set,
|
|
979
|
+
sub,
|
|
980
|
+
txn,
|
|
981
|
+
reset,
|
|
982
|
+
del,
|
|
983
|
+
data,
|
|
984
|
+
scope,
|
|
985
|
+
detach
|
|
986
|
+
};
|
|
987
|
+
} else {
|
|
988
|
+
return {
|
|
989
|
+
get,
|
|
990
|
+
set,
|
|
991
|
+
sub,
|
|
992
|
+
txn,
|
|
993
|
+
reset,
|
|
994
|
+
del,
|
|
995
|
+
data,
|
|
996
|
+
scope
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
}
|
|
573
1000
|
|
|
574
|
-
// src/
|
|
575
|
-
var
|
|
1001
|
+
// src/store.ts
|
|
1002
|
+
var store = (id) => {
|
|
576
1003
|
const data = createStoreData(id);
|
|
577
1004
|
return storeFromStoreData(data);
|
|
578
1005
|
};
|
|
1006
|
+
|
|
1007
|
+
// src/globalStore.ts
|
|
1008
|
+
var globalStore = Object.assign(store("valdres-global-store"), {
|
|
1009
|
+
atoms: new Map,
|
|
1010
|
+
atomFamilies: new Map
|
|
1011
|
+
});
|
|
1012
|
+
|
|
1013
|
+
// src/lib/globalAtom.ts
|
|
1014
|
+
var globalAtom = (defaultValue, options) => {
|
|
1015
|
+
const stores = new Set;
|
|
1016
|
+
let value;
|
|
1017
|
+
let initialized = false;
|
|
1018
|
+
let onReset;
|
|
1019
|
+
if (options.onSet)
|
|
1020
|
+
throw new Error("onSet on globalAtom is currently not supported");
|
|
1021
|
+
const onInit = (setSelf2, data) => {
|
|
1022
|
+
setSelf2(globalStore.get(atom));
|
|
1023
|
+
if (!initialized && options.onInit) {
|
|
1024
|
+
onReset = options.onInit((newVal) => {
|
|
1025
|
+
setSelf2(newVal);
|
|
1026
|
+
value = newVal;
|
|
1027
|
+
}, data);
|
|
1028
|
+
initialized = true;
|
|
1029
|
+
}
|
|
1030
|
+
stores.add(data);
|
|
1031
|
+
};
|
|
1032
|
+
const onSet = (newValue, currentStore) => {
|
|
1033
|
+
value = newValue;
|
|
1034
|
+
if (stores.size > 1) {
|
|
1035
|
+
for (const store2 of stores) {
|
|
1036
|
+
if (store2.id !== currentStore.id) {
|
|
1037
|
+
setAtom(atom, value, store2, true);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
};
|
|
1042
|
+
const getSelf = () => globalStore.get(atom);
|
|
1043
|
+
const setSelf = (newValue) => globalStore.set(atom, newValue);
|
|
1044
|
+
const resetSelf = () => {
|
|
1045
|
+
value = undefined;
|
|
1046
|
+
initialized = false;
|
|
1047
|
+
for (const store2 of stores) {
|
|
1048
|
+
if (store2.stateDependencies.has(atom)) {
|
|
1049
|
+
throw new Error("TODO: Reset support for stateDependencies");
|
|
1050
|
+
}
|
|
1051
|
+
store2.values.delete(atom);
|
|
1052
|
+
store2.expiredValues.delete(atom);
|
|
1053
|
+
propagateUpdatedAtoms([atom], store2);
|
|
1054
|
+
stores.delete(store2);
|
|
1055
|
+
onReset?.();
|
|
1056
|
+
}
|
|
1057
|
+
};
|
|
1058
|
+
const atom = {
|
|
1059
|
+
equal,
|
|
1060
|
+
...options,
|
|
1061
|
+
defaultValue,
|
|
1062
|
+
name: options?.name,
|
|
1063
|
+
onInit,
|
|
1064
|
+
onSet,
|
|
1065
|
+
setSelf,
|
|
1066
|
+
getSelf,
|
|
1067
|
+
resetSelf,
|
|
1068
|
+
get stores() {
|
|
1069
|
+
return stores;
|
|
1070
|
+
}
|
|
1071
|
+
};
|
|
1072
|
+
return atom;
|
|
1073
|
+
};
|
|
1074
|
+
|
|
1075
|
+
// src/atom.ts
|
|
1076
|
+
function atom(defaultValue, options) {
|
|
1077
|
+
if (!options)
|
|
1078
|
+
return { equal, defaultValue };
|
|
1079
|
+
if (options.global) {
|
|
1080
|
+
return globalAtom(defaultValue, options);
|
|
1081
|
+
}
|
|
1082
|
+
return {
|
|
1083
|
+
equal,
|
|
1084
|
+
defaultValue,
|
|
1085
|
+
...options
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
// src/lib/atomFamilyAtom.ts
|
|
1089
|
+
function atomFamilyAtom(defaultValue, options) {
|
|
1090
|
+
if (options.global) {
|
|
1091
|
+
return globalAtom(defaultValue, options);
|
|
1092
|
+
}
|
|
1093
|
+
return {
|
|
1094
|
+
...options,
|
|
1095
|
+
defaultValue
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
// src/lib/stableStringify.ts
|
|
1100
|
+
var stableStringifyRecurse = (x, key) => {
|
|
1101
|
+
if (typeof x === "string" && !x.includes('"') && !x.includes("\\")) {
|
|
1102
|
+
return `"${x}"`;
|
|
1103
|
+
}
|
|
1104
|
+
switch (typeof x) {
|
|
1105
|
+
case "undefined":
|
|
1106
|
+
return "";
|
|
1107
|
+
case "boolean":
|
|
1108
|
+
return x ? "true" : "false";
|
|
1109
|
+
case "number":
|
|
1110
|
+
case "symbol":
|
|
1111
|
+
return String(x);
|
|
1112
|
+
case "string":
|
|
1113
|
+
return JSON.stringify(x);
|
|
1114
|
+
case "function":
|
|
1115
|
+
return `__FUNCTION(${x.toString()})__`;
|
|
1116
|
+
}
|
|
1117
|
+
if (x === null) {
|
|
1118
|
+
return "null";
|
|
1119
|
+
}
|
|
1120
|
+
if (typeof x !== "object") {
|
|
1121
|
+
return JSON.stringify(x) ?? "";
|
|
1122
|
+
}
|
|
1123
|
+
if (isPromiseLike(x)) {
|
|
1124
|
+
return "__PROMISE__";
|
|
1125
|
+
}
|
|
1126
|
+
if (Array.isArray(x)) {
|
|
1127
|
+
return `[${x.map((v, i) => stableStringifyRecurse(v, i.toString()))}]`;
|
|
1128
|
+
}
|
|
1129
|
+
if (typeof x.toJSON === "function") {
|
|
1130
|
+
return stableStringifyRecurse(x.toJSON(key), key);
|
|
1131
|
+
}
|
|
1132
|
+
if (x instanceof Map) {
|
|
1133
|
+
const obj = {};
|
|
1134
|
+
for (const [k, v] of x) {
|
|
1135
|
+
obj[typeof k === "string" ? k : stringify(k, opt)] = v;
|
|
1136
|
+
}
|
|
1137
|
+
return stableStringifyRecurse(obj, key);
|
|
1138
|
+
}
|
|
1139
|
+
if (x instanceof Set) {
|
|
1140
|
+
return stableStringifyRecurse(Array.from(x).sort((a, b) => stableStringifyRecurse(a).localeCompare(stableStringifyRecurse(b))), key);
|
|
1141
|
+
}
|
|
1142
|
+
if (Symbol !== undefined && x[Symbol.iterator] != null && typeof x[Symbol.iterator] === "function") {
|
|
1143
|
+
return stableStringifyRecurse(Array.from(x), key);
|
|
1144
|
+
}
|
|
1145
|
+
return `{${Object.keys(x).filter((k) => x[k] !== undefined).sort().map((k) => `${stableStringifyRecurse(k)}:${stableStringifyRecurse(x[k], k)}`).join(",")}}`;
|
|
1146
|
+
};
|
|
1147
|
+
var stableStringify = (x) => {
|
|
1148
|
+
if (typeof x === "string" || typeof x === "boolean" || typeof x === "number")
|
|
1149
|
+
return x;
|
|
1150
|
+
return stableStringifyRecurse(x);
|
|
1151
|
+
};
|
|
1152
|
+
|
|
1153
|
+
// src/lib/stringifyFamilyArgs.ts
|
|
1154
|
+
var stringifyFamilyArgs = (args) => {
|
|
1155
|
+
return args.length === 1 ? stableStringify(args[0]) : stableStringify(args);
|
|
1156
|
+
};
|
|
1157
|
+
|
|
1158
|
+
// src/lib/createAtomFamily.ts
|
|
1159
|
+
var createOptions = (options = {}, family, familyArgs, familyArgsStringified) => {
|
|
1160
|
+
if (options.name) {
|
|
1161
|
+
return {
|
|
1162
|
+
equal,
|
|
1163
|
+
...options,
|
|
1164
|
+
name: options?.name + "_" + familyArgsStringified,
|
|
1165
|
+
family,
|
|
1166
|
+
familyArgs,
|
|
1167
|
+
familyArgsStringified
|
|
1168
|
+
};
|
|
1169
|
+
} else {
|
|
1170
|
+
return { equal, ...options, family, familyArgs, familyArgsStringified };
|
|
1171
|
+
}
|
|
1172
|
+
};
|
|
1173
|
+
var handleDefaultValue = (defaultValue, ...args) => {
|
|
1174
|
+
if (isSelectorFamily(defaultValue))
|
|
1175
|
+
return defaultValue(...args);
|
|
1176
|
+
if (typeof defaultValue === "function")
|
|
1177
|
+
return () => defaultValue(...args);
|
|
1178
|
+
return defaultValue;
|
|
1179
|
+
};
|
|
1180
|
+
var createAtomFamily = (defaultValue, options) => {
|
|
1181
|
+
const map = new Map;
|
|
1182
|
+
const atomFamily = (...args) => {
|
|
1183
|
+
const argsStringified = stringifyFamilyArgs(args);
|
|
1184
|
+
if (map.has(argsStringified)) {
|
|
1185
|
+
return map.get(argsStringified);
|
|
1186
|
+
}
|
|
1187
|
+
const familyAtom = atomFamilyAtom(handleDefaultValue(defaultValue, ...args), createOptions(options, atomFamily, args, argsStringified));
|
|
1188
|
+
map.set(argsStringified, familyAtom);
|
|
1189
|
+
return familyAtom;
|
|
1190
|
+
};
|
|
1191
|
+
if (options?.name)
|
|
1192
|
+
Object.defineProperty(atomFamily, "name", {
|
|
1193
|
+
value: options.name,
|
|
1194
|
+
writable: false
|
|
1195
|
+
});
|
|
1196
|
+
return Object.assign(atomFamily, {
|
|
1197
|
+
__valdresAtomFamilyMap: map,
|
|
1198
|
+
release: (...args) => map.delete(stringifyFamilyArgs(args)),
|
|
1199
|
+
equal
|
|
1200
|
+
});
|
|
1201
|
+
};
|
|
1202
|
+
|
|
1203
|
+
// src/lib/createGlobalAtomFamily.ts
|
|
1204
|
+
var createGlobalAtomFamily = (defaultValue, options) => {
|
|
1205
|
+
if (!options.name)
|
|
1206
|
+
throw new Error(`Missing name for global atomFamiliy`);
|
|
1207
|
+
if (globalStore.atomFamilies.has(options.name)) {
|
|
1208
|
+
return globalStore.atomFamilies.get(options.name);
|
|
1209
|
+
}
|
|
1210
|
+
const family = createAtomFamily(defaultValue, options);
|
|
1211
|
+
globalStore.atomFamilies.set(options.name, family);
|
|
1212
|
+
return family;
|
|
1213
|
+
};
|
|
1214
|
+
|
|
1215
|
+
// src/atomFamily.ts
|
|
1216
|
+
function atomFamily(defaultValue, options) {
|
|
1217
|
+
if (options?.global)
|
|
1218
|
+
return createGlobalAtomFamily(defaultValue, options);
|
|
1219
|
+
return createAtomFamily(defaultValue, options);
|
|
1220
|
+
}
|
|
579
1221
|
// src/createStoreWithSelectorSet.ts
|
|
580
|
-
var setSelector = (selector, values,
|
|
581
|
-
return selector.set(
|
|
1222
|
+
var setSelector = (selector, values, store2) => {
|
|
1223
|
+
return selector.set(store2.set, store2.get, store2.reset, ...values);
|
|
582
1224
|
};
|
|
583
1225
|
var createStoreWithSelectorSet = (id) => {
|
|
584
1226
|
const data = createStoreData(id);
|
|
585
|
-
const
|
|
586
|
-
|
|
1227
|
+
const store2 = storeFromStoreData(data);
|
|
1228
|
+
store2.set = (state, value, ...rest) => {
|
|
587
1229
|
if (isAtom(state))
|
|
588
1230
|
return setAtom(state, value, data);
|
|
589
1231
|
if (isSelector(state))
|
|
590
|
-
return setSelector(state, [value, ...rest],
|
|
1232
|
+
return setSelector(state, [value, ...rest], store2);
|
|
591
1233
|
throw new Error("Invalid state object");
|
|
592
1234
|
};
|
|
593
|
-
|
|
594
|
-
return
|
|
1235
|
+
store2.kind = "storeWithSelectorSet";
|
|
1236
|
+
return store2;
|
|
595
1237
|
};
|
|
596
|
-
// src/getDefaultStore.ts
|
|
597
|
-
if (!globalThis._valdresStore) {
|
|
598
|
-
globalThis._valdresStore = createStore("default");
|
|
599
|
-
}
|
|
600
|
-
var getDefaultStore = () => globalThis._valdresStore;
|
|
601
|
-
var resetDefaultStore = () => globalThis._valdresStore = createStore();
|
|
602
1238
|
// src/selector.ts
|
|
603
|
-
var selector = (get,
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
}
|
|
1239
|
+
var selector = (get, options) => {
|
|
1240
|
+
if (!options)
|
|
1241
|
+
return { equal, get };
|
|
1242
|
+
return { equal, ...options, get };
|
|
1243
|
+
};
|
|
1244
|
+
|
|
1245
|
+
// src/indexConstructor.ts
|
|
1246
|
+
var index = (family, callback, options) => {
|
|
1247
|
+
const map = new Map;
|
|
1248
|
+
const index2 = (term) => {
|
|
1249
|
+
const termKey = stableStringify(term);
|
|
1250
|
+
if (map.has(termKey))
|
|
1251
|
+
return map.get(termKey);
|
|
1252
|
+
const termIndexSelectorSet = new Set;
|
|
1253
|
+
const termIndexSelectorMap = new Map;
|
|
1254
|
+
const termIndexSelector = selector((get) => {
|
|
1255
|
+
const allFamilyAtoms = new Set(get(family));
|
|
1256
|
+
const deletedAtoms = termIndexSelectorSet.symmetricDifference(allFamilyAtoms);
|
|
1257
|
+
const addedAtoms = allFamilyAtoms.difference(termIndexSelectorSet);
|
|
1258
|
+
if (deletedAtoms.size || addedAtoms.size) {
|
|
1259
|
+
deletedAtoms.forEach((atom2) => {
|
|
1260
|
+
termIndexSelectorSet.delete(atom2);
|
|
1261
|
+
termIndexSelectorMap.delete(atom2);
|
|
1262
|
+
});
|
|
1263
|
+
addedAtoms.forEach((atom2) => {
|
|
1264
|
+
termIndexSelectorSet.add(atom2);
|
|
1265
|
+
termIndexSelectorMap.set(atom2, selector((get2) => callback(get2(atom2), term), {
|
|
1266
|
+
name: `index:callback:selector:${atom2.name}`
|
|
1267
|
+
}));
|
|
1268
|
+
});
|
|
1269
|
+
return new Set(termIndexSelectorSet);
|
|
1270
|
+
} else {
|
|
1271
|
+
return termIndexSelectorSet;
|
|
1272
|
+
}
|
|
1273
|
+
}, { name: `index:${options?.name}(${termKey})` });
|
|
1274
|
+
const filteredSelector = selector((get) => {
|
|
1275
|
+
const set = get(termIndexSelector);
|
|
1276
|
+
const res = [];
|
|
1277
|
+
set.forEach((atom2) => {
|
|
1278
|
+
if (get(termIndexSelectorMap.get(atom2))) {
|
|
1279
|
+
res.push(atom2);
|
|
1280
|
+
}
|
|
1281
|
+
});
|
|
1282
|
+
return res;
|
|
1283
|
+
}, {
|
|
1284
|
+
name: `index:${options?.name}:${termKey}:termSelector`
|
|
1285
|
+
});
|
|
1286
|
+
map.set(termKey, filteredSelector);
|
|
1287
|
+
return filteredSelector;
|
|
1288
|
+
};
|
|
1289
|
+
return Object.assign(index2, {
|
|
1290
|
+
map,
|
|
1291
|
+
callback
|
|
1292
|
+
});
|
|
1293
|
+
};
|
|
607
1294
|
// src/selectorFamily.ts
|
|
608
|
-
var
|
|
1295
|
+
var createOptions2 = (options = {}, family, familyArgs, familyArgsStringified) => {
|
|
1296
|
+
if (options.name) {
|
|
1297
|
+
return {
|
|
1298
|
+
equal,
|
|
1299
|
+
...options,
|
|
1300
|
+
name: options?.name + "_" + familyArgsStringified,
|
|
1301
|
+
family,
|
|
1302
|
+
familyArgs,
|
|
1303
|
+
familyArgsStringified
|
|
1304
|
+
};
|
|
1305
|
+
} else {
|
|
1306
|
+
return { equal, ...options, family, familyArgs, familyArgsStringified };
|
|
1307
|
+
}
|
|
1308
|
+
};
|
|
1309
|
+
var selectorFamily = (callback, options) => {
|
|
609
1310
|
const map = new Map;
|
|
610
|
-
const selectorFamily2 = (
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
throw e;
|
|
617
|
-
}
|
|
618
|
-
if (map.has(keyStringified))
|
|
619
|
-
return map.get(keyStringified);
|
|
620
|
-
const selectorDebugLabel = debugLabel ? debugLabel + "_" + keyStringified : undefined;
|
|
621
|
-
const newSelector = selector((selectorArgs) => get(key)(selectorArgs), selectorDebugLabel);
|
|
622
|
-
newSelector.family = selectorFamily2;
|
|
623
|
-
map.set(keyStringified, newSelector);
|
|
1311
|
+
const selectorFamily2 = (...args) => {
|
|
1312
|
+
const argsStringified = stringifyFamilyArgs(args);
|
|
1313
|
+
if (map.has(argsStringified))
|
|
1314
|
+
return map.get(argsStringified);
|
|
1315
|
+
const newSelector = selector((selectorArgs) => callback(...args)(selectorArgs), createOptions2(options, selectorFamily2, args, argsStringified));
|
|
1316
|
+
map.set(argsStringified, newSelector);
|
|
624
1317
|
return newSelector;
|
|
625
1318
|
};
|
|
626
|
-
selectorFamily2.
|
|
1319
|
+
selectorFamily2.__valdresSelectorFamilyMap = map;
|
|
1320
|
+
if (options?.name)
|
|
1321
|
+
Object.defineProperty(selectorFamily2, "name", {
|
|
1322
|
+
value: options.name,
|
|
1323
|
+
writable: false
|
|
1324
|
+
});
|
|
627
1325
|
return selectorFamily2;
|
|
628
1326
|
};
|
|
1327
|
+
// src/utils/isFamilySelector.ts
|
|
1328
|
+
var isFamilySelector = (state) => isFamilyState(state) && isSelector(state);
|
|
1329
|
+
|
|
1330
|
+
// src/index.ts
|
|
1331
|
+
if (globalThis.__valdres__) {
|
|
1332
|
+
throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${version}`);
|
|
1333
|
+
} else {
|
|
1334
|
+
globalThis.__valdres__ = version;
|
|
1335
|
+
}
|
|
629
1336
|
export {
|
|
1337
|
+
store,
|
|
630
1338
|
selectorFamily,
|
|
631
1339
|
selector,
|
|
632
|
-
|
|
1340
|
+
isSelectorFamily,
|
|
633
1341
|
isSelector,
|
|
634
1342
|
isPromiseLike,
|
|
1343
|
+
isFamilyState,
|
|
1344
|
+
isFamilySelector,
|
|
1345
|
+
isFamilyAtom,
|
|
635
1346
|
isFamily,
|
|
1347
|
+
isAtomFamily,
|
|
636
1348
|
isAtom,
|
|
637
|
-
|
|
1349
|
+
index,
|
|
1350
|
+
globalStore,
|
|
1351
|
+
deepFreeze,
|
|
638
1352
|
createStoreWithSelectorSet,
|
|
639
|
-
createStore,
|
|
640
1353
|
atomFamily,
|
|
641
1354
|
atom
|
|
642
1355
|
};
|