valdres 0.2.0-alpha.9 → 0.2.0-y.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 +688 -257
- package/dist/types/src/atom.d.ts +16 -0
- package/dist/types/src/atomFamily.d.ts +4 -0
- package/dist/types/src/globalStore.d.ts +4 -0
- package/dist/types/src/index.d.ts +34 -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 +5 -0
- package/dist/types/src/lib/createStoreData.d.ts +3 -0
- package/dist/types/src/lib/equal.d.ts +1 -0
- package/dist/{src → types/src}/lib/getState.d.ts +4 -4
- package/dist/types/src/lib/globalAtom.d.ts +4 -0
- package/dist/{src → types/src}/lib/initAtom.d.ts +2 -1
- package/dist/{src → types/src}/lib/initSelector.d.ts +1 -2
- package/dist/types/src/lib/isFunction.d.ts +1 -0
- package/dist/types/src/lib/propagateUpdatedAtoms.d.ts +4 -0
- package/dist/{src → types/src}/lib/setAtom.d.ts +1 -1
- package/dist/types/src/lib/storeFromStoreData.d.ts +4 -0
- package/dist/{src → types/src}/lib/subscribe.d.ts +1 -1
- package/dist/types/src/lib/transaction.d.ts +3 -0
- package/dist/{src → types/src}/lib/unsubscribe.d.ts +1 -1
- package/dist/{src → types/src}/lib/updateStateSubscribers.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 +12 -0
- package/dist/types/src/types/AtomFamilyAtom.d.ts +6 -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 +1 -0
- package/dist/{src → types/src}/types/Family.d.ts +1 -1
- package/dist/types/src/types/FamilyKey.d.ts +3 -0
- package/dist/{src → types/src}/types/GetValue.d.ts +3 -3
- 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/{src → types/src}/types/Selector.d.ts +4 -2
- package/dist/types/src/types/SelectorFamily.d.ts +6 -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 +24 -0
- package/dist/{src → types/src}/types/StoreData.d.ts +9 -1
- package/dist/types/src/types/SubscribeFn.d.ts +9 -0
- package/dist/types/src/types/TransactionFn.d.ts +2 -0
- package/dist/{src/types/Store.d.ts → types/src/types/TransactionInterface.d.ts} +9 -6
- 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 -10
- 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/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/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/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/SubscribeFn.d.ts +0 -2
- 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/setAtoms.d.ts +0 -0
- /package/dist/{src → types/src}/lib/stableStringify.d.ts +0 -0
- /package/dist/{src → types/src}/lib/updateSelectorSubscribers.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}/types/Subscription.d.ts +0 -0
- /package/dist/{src → types/src}/utils/isPromiseLike.d.ts +0 -0
package/dist/index.js
CHANGED
|
@@ -1,11 +1,106 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { version } from "../package.json";
|
|
3
3
|
|
|
4
|
-
// src/
|
|
5
|
-
var
|
|
6
|
-
|
|
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) => {
|
|
10
|
+
if (a === b)
|
|
11
|
+
return true;
|
|
12
|
+
if (a && b && typeof a == "object" && typeof b == "object") {
|
|
13
|
+
if (a.constructor !== b.constructor)
|
|
14
|
+
return false;
|
|
15
|
+
var length, i, keys;
|
|
16
|
+
if (Array.isArray(a)) {
|
|
17
|
+
length = a.length;
|
|
18
|
+
if (length != b.length)
|
|
19
|
+
return false;
|
|
20
|
+
for (i = length;i-- !== 0; )
|
|
21
|
+
if (!deepEqualFn(a[i], b[i]))
|
|
22
|
+
return false;
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
var it;
|
|
26
|
+
if (hasMap && a instanceof Map && b instanceof Map) {
|
|
27
|
+
if (a.size !== b.size)
|
|
28
|
+
return false;
|
|
29
|
+
it = a.entries();
|
|
30
|
+
while (!(i = it.next()).done)
|
|
31
|
+
if (!b.has(i.value[0]))
|
|
32
|
+
return false;
|
|
33
|
+
it = a.entries();
|
|
34
|
+
while (!(i = it.next()).done)
|
|
35
|
+
if (!deepEqualFn(i.value[1], b.get(i.value[0])))
|
|
36
|
+
return false;
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
if (hasSet && a instanceof Set && b instanceof Set) {
|
|
40
|
+
if (a.size !== b.size)
|
|
41
|
+
return false;
|
|
42
|
+
it = a.entries();
|
|
43
|
+
while (!(i = it.next()).done)
|
|
44
|
+
if (!b.has(i.value[0]))
|
|
45
|
+
return false;
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
if (hasArrayBuffer && ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
|
|
49
|
+
length = a.length;
|
|
50
|
+
if (length != b.length)
|
|
51
|
+
return false;
|
|
52
|
+
for (i = length;i-- !== 0; )
|
|
53
|
+
if (a[i] !== b[i])
|
|
54
|
+
return false;
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
if (a.constructor === RegExp)
|
|
58
|
+
return a.source === b.source && a.flags === b.flags;
|
|
59
|
+
if (a.valueOf !== Object.prototype.valueOf && typeof a.valueOf === "function" && typeof b.valueOf === "function")
|
|
60
|
+
return a.valueOf() === b.valueOf();
|
|
61
|
+
if (a.toString !== Object.prototype.toString && typeof a.toString === "function" && typeof b.toString === "function")
|
|
62
|
+
return a.toString() === b.toString();
|
|
63
|
+
keys = Object.keys(a);
|
|
64
|
+
length = keys.length;
|
|
65
|
+
if (length !== Object.keys(b).length)
|
|
66
|
+
return false;
|
|
67
|
+
for (i = length;i-- !== 0; )
|
|
68
|
+
if (!Object.prototype.hasOwnProperty.call(b, keys[i]))
|
|
69
|
+
return false;
|
|
70
|
+
if (hasElementType && a instanceof Element)
|
|
71
|
+
return false;
|
|
72
|
+
for (i = length;i-- !== 0; ) {
|
|
73
|
+
if ((keys[i] === "_owner" || keys[i] === "__v" || keys[i] === "__o") && a.$$typeof) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (!deepEqualFn(a[keys[i]], b[keys[i]]))
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
return a !== a && b !== b;
|
|
82
|
+
};
|
|
83
|
+
var equal = (a, b) => {
|
|
84
|
+
try {
|
|
85
|
+
return deepEqualFn(a, b);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
if ((error.message || "").match(/stack|recursion/i)) {
|
|
88
|
+
console.warn("react-fast-compare cannot handle circular refs");
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
7
93
|
};
|
|
8
94
|
|
|
95
|
+
// src/utils/isAtom.ts
|
|
96
|
+
var isAtom = (state) => Object.hasOwn(state, "defaultValue");
|
|
97
|
+
|
|
98
|
+
// src/utils/isFamilyState.ts
|
|
99
|
+
var isFamilyState = (state) => state && Object.hasOwn(state, "family");
|
|
100
|
+
|
|
101
|
+
// src/utils/isFamilyAtom.ts
|
|
102
|
+
var isFamilyAtom = (state) => isFamilyState(state) && isAtom(state);
|
|
103
|
+
|
|
9
104
|
// src/lib/updateStateSubscribers.ts
|
|
10
105
|
var updateStateSubscribers = (state, data) => {
|
|
11
106
|
const subscribtions = data.subscriptions.get(state);
|
|
@@ -14,7 +109,7 @@ var updateStateSubscribers = (state, data) => {
|
|
|
14
109
|
subscribtion.callback();
|
|
15
110
|
}
|
|
16
111
|
}
|
|
17
|
-
if (state
|
|
112
|
+
if (isFamilyState(state)) {
|
|
18
113
|
const familySubscriptions = data.subscriptions.get(state.family);
|
|
19
114
|
if (familySubscriptions?.size) {
|
|
20
115
|
for (const subscribtion of familySubscriptions) {
|
|
@@ -24,14 +119,42 @@ var updateStateSubscribers = (state, data) => {
|
|
|
24
119
|
}
|
|
25
120
|
};
|
|
26
121
|
|
|
27
|
-
// src/
|
|
28
|
-
|
|
122
|
+
// src/utils/isPromiseLike.ts
|
|
123
|
+
var isPromiseLike = (object) => {
|
|
124
|
+
return object && object.then && typeof object.then === "function";
|
|
125
|
+
};
|
|
29
126
|
|
|
30
|
-
// src/
|
|
31
|
-
|
|
127
|
+
// src/utils/isAtomFamily.ts
|
|
128
|
+
var isAtomFamily = (state) => state && Object.hasOwn(state, "__valdresAtomFamilyMap");
|
|
32
129
|
|
|
33
|
-
// src/
|
|
34
|
-
|
|
130
|
+
// src/utils/isSelector.ts
|
|
131
|
+
var isSelector = (state) => state && Object.hasOwn(state, "get");
|
|
132
|
+
|
|
133
|
+
// src/utils/isSelectorFamily.ts
|
|
134
|
+
var isSelectorFamily = (state) => state && Object.hasOwn(state, "__valdresSelectorFamilyMap");
|
|
135
|
+
|
|
136
|
+
// src/lib/isFunction.ts
|
|
137
|
+
var isFunction = (value) => typeof value === "function";
|
|
138
|
+
|
|
139
|
+
// src/lib/setAtom.ts
|
|
140
|
+
var setAtom = (atom, newValue, data, skipOnSet = false) => {
|
|
141
|
+
const currentValue = getState(atom, data);
|
|
142
|
+
if (isFunction(newValue)) {
|
|
143
|
+
newValue = newValue(currentValue);
|
|
144
|
+
if (isPromiseLike(newValue) || isPromiseLike(currentValue))
|
|
145
|
+
throw new Error("Todo, how should we handle this?");
|
|
146
|
+
}
|
|
147
|
+
if (atom.equal(currentValue, newValue))
|
|
148
|
+
return newValue;
|
|
149
|
+
data.values.set(atom, newValue);
|
|
150
|
+
if (atom.onSet && !skipOnSet)
|
|
151
|
+
atom.onSet(newValue, data);
|
|
152
|
+
if (currentValue?.__isEmptyAtomPromise__) {
|
|
153
|
+
currentValue.__resolveEmptyAtomPromise__(newValue);
|
|
154
|
+
}
|
|
155
|
+
propagateUpdatedAtoms([atom], data);
|
|
156
|
+
return newValue;
|
|
157
|
+
};
|
|
35
158
|
|
|
36
159
|
// src/lib/initAtom.ts
|
|
37
160
|
var getAtomInitValue = (atom, data) => {
|
|
@@ -52,6 +175,8 @@ var getAtomInitValue = (atom, data) => {
|
|
|
52
175
|
});
|
|
53
176
|
}
|
|
54
177
|
return value;
|
|
178
|
+
} else if (isSelector(atom.defaultValue)) {
|
|
179
|
+
return getState(atom.defaultValue, data);
|
|
55
180
|
} else {
|
|
56
181
|
return atom.defaultValue;
|
|
57
182
|
}
|
|
@@ -59,6 +184,14 @@ var getAtomInitValue = (atom, data) => {
|
|
|
59
184
|
var initAtom = (atom, data) => {
|
|
60
185
|
let value = getAtomInitValue(atom, data);
|
|
61
186
|
data.values.set(atom, value);
|
|
187
|
+
if (isFamilyAtom(atom)) {
|
|
188
|
+
const currentKeySet = getState(atom.family.__keysAtom, data);
|
|
189
|
+
if (!currentKeySet.has(atom.familyKey)) {
|
|
190
|
+
const newSet = new Set(currentKeySet);
|
|
191
|
+
newSet.add(atom.familyKey);
|
|
192
|
+
setAtom(atom.family.__keysAtom, newSet, data);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
62
195
|
if (atom.onInit)
|
|
63
196
|
atom.onInit((newVal) => {
|
|
64
197
|
value = newVal;
|
|
@@ -67,25 +200,26 @@ var initAtom = (atom, data) => {
|
|
|
67
200
|
return value;
|
|
68
201
|
};
|
|
69
202
|
|
|
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
203
|
// src/lib/getState.ts
|
|
80
|
-
function getState(state, data) {
|
|
204
|
+
function getState(state, data, circularDependencySet) {
|
|
81
205
|
if (data.values.has(state))
|
|
82
206
|
return data.values.get(state);
|
|
83
|
-
if (isAtom(state))
|
|
207
|
+
if (isAtom(state)) {
|
|
208
|
+
if ("parent" in data)
|
|
209
|
+
return getState(state, data.parent, circularDependencySet);
|
|
84
210
|
return initAtom(state, data);
|
|
211
|
+
}
|
|
85
212
|
if (isSelector(state))
|
|
86
|
-
return initSelector(state, data);
|
|
87
|
-
if (
|
|
88
|
-
|
|
213
|
+
return initSelector(state, data, circularDependencySet);
|
|
214
|
+
if (isAtomFamily(state)) {
|
|
215
|
+
if ("parent" in data) {
|
|
216
|
+
const closestData = findClosestStoreWithAtomInitialized(state.__keysAtom, data);
|
|
217
|
+
return getState(state.__keysSelector, closestData, circularDependencySet);
|
|
218
|
+
}
|
|
219
|
+
return getState(state.__keysSelector, data, circularDependencySet);
|
|
220
|
+
}
|
|
221
|
+
if (isSelectorFamily(state)) {
|
|
222
|
+
const array = Array.from(state.__valdresSelectorFamilyMap.keys());
|
|
89
223
|
if (equal(array, state._keyArray))
|
|
90
224
|
return state._keyArray;
|
|
91
225
|
state._keyArray = array;
|
|
@@ -93,6 +227,13 @@ function getState(state, data) {
|
|
|
93
227
|
}
|
|
94
228
|
throw new Error("Invalid object passed to get");
|
|
95
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);
|
|
236
|
+
};
|
|
96
237
|
|
|
97
238
|
// src/lib/initSelector.ts
|
|
98
239
|
class SuspendAndWaitForResolveError extends Error {
|
|
@@ -102,6 +243,36 @@ class SuspendAndWaitForResolveError extends Error {
|
|
|
102
243
|
this.promise = promise;
|
|
103
244
|
}
|
|
104
245
|
}
|
|
246
|
+
var generateSelectorTrace = (selectors) => {
|
|
247
|
+
const lastIndex = selectors.length - 1;
|
|
248
|
+
return [...selectors].reverse().map((selector, index) => {
|
|
249
|
+
const name = selector.name ?? "Anonymous Selector";
|
|
250
|
+
if (index === 0) {
|
|
251
|
+
return `[START] ${name}`;
|
|
252
|
+
} else if (index === lastIndex) {
|
|
253
|
+
return `[CRASH] ${name}`;
|
|
254
|
+
} else {
|
|
255
|
+
return ` ${" ".repeat(index)}${name}`;
|
|
256
|
+
}
|
|
257
|
+
}).join(`
|
|
258
|
+
`);
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
class CircularDependencyError extends Error {
|
|
262
|
+
selectors;
|
|
263
|
+
constructor() {
|
|
264
|
+
super();
|
|
265
|
+
this.selectors = [];
|
|
266
|
+
}
|
|
267
|
+
track(selector) {
|
|
268
|
+
this.selectors.push(selector);
|
|
269
|
+
}
|
|
270
|
+
get message() {
|
|
271
|
+
const firstSelectorName = this.selectors[0].name ?? "Anonymous Selector";
|
|
272
|
+
return `Circular dependency detected in '${firstSelectorName}'
|
|
273
|
+
${generateSelectorTrace(this.selectors)}`;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
105
276
|
var getOrInitConsumersSet = (state, data) => {
|
|
106
277
|
const set = data.stateConsumers.get(state);
|
|
107
278
|
if (set)
|
|
@@ -110,12 +281,16 @@ var getOrInitConsumersSet = (state, data) => {
|
|
|
110
281
|
data.stateConsumers.set(state, newSet);
|
|
111
282
|
return newSet;
|
|
112
283
|
};
|
|
113
|
-
var evaluateSelector = (selector, data) => {
|
|
284
|
+
var evaluateSelector = (selector, data, circularDependencyMap = new WeakSet) => {
|
|
114
285
|
const updatedDependencies = new Set;
|
|
286
|
+
if (circularDependencyMap.has(selector)) {
|
|
287
|
+
throw new CircularDependencyError;
|
|
288
|
+
}
|
|
289
|
+
circularDependencyMap.add(selector);
|
|
115
290
|
let result;
|
|
116
291
|
try {
|
|
117
292
|
result = selector.get((state) => {
|
|
118
|
-
const value = getState(state, data);
|
|
293
|
+
const value = getState(state, data, circularDependencyMap);
|
|
119
294
|
updatedDependencies.add(state);
|
|
120
295
|
if (isPromiseLike(value))
|
|
121
296
|
throw new SuspendAndWaitForResolveError(value);
|
|
@@ -157,12 +332,19 @@ var handleSelectorResult = (value, selector, data) => {
|
|
|
157
332
|
return value;
|
|
158
333
|
}
|
|
159
334
|
};
|
|
160
|
-
var initSelector = (selector, data) => {
|
|
161
|
-
|
|
335
|
+
var initSelector = (selector, data, circularDependencySet = new WeakSet) => {
|
|
336
|
+
let tmpValue;
|
|
337
|
+
try {
|
|
338
|
+
tmpValue = evaluateSelector(selector, data, circularDependencySet);
|
|
339
|
+
} catch (e) {
|
|
340
|
+
if (e instanceof CircularDependencyError)
|
|
341
|
+
e.track(selector);
|
|
342
|
+
throw e;
|
|
343
|
+
}
|
|
162
344
|
const value = handleSelectorResult(tmpValue, selector, data);
|
|
163
345
|
if (data.expiredValues.has(selector)) {
|
|
164
346
|
const expiredValue = data.expiredValues.get(selector);
|
|
165
|
-
if (
|
|
347
|
+
if (selector.equal(expiredValue, value)) {
|
|
166
348
|
data.values.set(selector, expiredValue);
|
|
167
349
|
return expiredValue;
|
|
168
350
|
}
|
|
@@ -181,7 +363,7 @@ var updateSelectorSubscribers = (selector, data) => {
|
|
|
181
363
|
try {
|
|
182
364
|
const oldValue = data.expiredValues.get(selector);
|
|
183
365
|
const newValue = initSelector(selector, data);
|
|
184
|
-
if (
|
|
366
|
+
if (selector.equal(newValue, oldValue))
|
|
185
367
|
return;
|
|
186
368
|
} catch (e) {
|
|
187
369
|
}
|
|
@@ -219,7 +401,7 @@ var propagateUpdatedAtoms = (atoms, data) => {
|
|
|
219
401
|
if (consumers && consumers.size) {
|
|
220
402
|
recursivlyResetSelectorTree(consumers, data, clearedSelectors);
|
|
221
403
|
}
|
|
222
|
-
if (atom
|
|
404
|
+
if (isFamilyAtom(atom)) {
|
|
223
405
|
const consumersFamily = data.stateConsumers.get(atom.family);
|
|
224
406
|
if (consumersFamily?.size) {
|
|
225
407
|
recursivlyResetSelectorTree(consumersFamily, data, clearedSelectors);
|
|
@@ -234,158 +416,47 @@ var propagateUpdatedAtoms = (atoms, data) => {
|
|
|
234
416
|
}
|
|
235
417
|
};
|
|
236
418
|
|
|
237
|
-
// src/lib/
|
|
238
|
-
var
|
|
239
|
-
|
|
240
|
-
if (typeof newValue === "function") {
|
|
241
|
-
newValue = newValue(currentValue);
|
|
242
|
-
if (isPromiseLike(newValue) || isPromiseLike(currentValue))
|
|
243
|
-
throw new Error("Todo, how should we handle this?");
|
|
244
|
-
}
|
|
245
|
-
if (equal4(currentValue, newValue))
|
|
246
|
-
return;
|
|
247
|
-
data.values.set(atom, newValue);
|
|
248
|
-
if (atom.onSet && !skipOnSet)
|
|
249
|
-
atom.onSet(newValue, data);
|
|
250
|
-
if (currentValue?.__isEmptyAtomPromise__) {
|
|
251
|
-
currentValue.__resolveEmptyAtomPromise__(newValue);
|
|
252
|
-
}
|
|
253
|
-
propagateUpdatedAtoms([atom], data);
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
// src/atom.ts
|
|
257
|
-
var globalAtom = (defaultValue, options) => {
|
|
258
|
-
const stores = new Set;
|
|
259
|
-
let value = defaultValue;
|
|
260
|
-
const onSet = (newValue, currentStore) => {
|
|
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);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
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);
|
|
419
|
+
// src/lib/createStoreData.ts
|
|
420
|
+
var generateId = () => (Math.random() + 1).toString(36).substring(7);
|
|
421
|
+
var generateStoreData = (id = generateId()) => {
|
|
287
422
|
return {
|
|
288
|
-
|
|
289
|
-
|
|
423
|
+
id,
|
|
424
|
+
values: new WeakMap,
|
|
425
|
+
expiredValues: new WeakMap,
|
|
426
|
+
subscriptions: new WeakMap,
|
|
427
|
+
subscriptionsRequireEqualCheck: new WeakMap,
|
|
428
|
+
stateConsumers: new WeakMap,
|
|
429
|
+
stateDependencies: new WeakMap,
|
|
430
|
+
scopes: {}
|
|
290
431
|
};
|
|
291
432
|
};
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
return x ? "true" : "false";
|
|
302
|
-
case "number":
|
|
303
|
-
case "symbol":
|
|
304
|
-
return String(x);
|
|
305
|
-
case "string":
|
|
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;
|
|
329
|
-
}
|
|
330
|
-
return stableStringifyRecurse(obj, key);
|
|
331
|
-
}
|
|
332
|
-
if (x instanceof Set) {
|
|
333
|
-
return stableStringifyRecurse(Array.from(x).sort((a, b) => stableStringifyRecurse(a).localeCompare(stableStringifyRecurse(b))), key);
|
|
334
|
-
}
|
|
335
|
-
if (Symbol !== undefined && x[Symbol.iterator] != null && typeof x[Symbol.iterator] === "function") {
|
|
336
|
-
return stableStringifyRecurse(Array.from(x), key);
|
|
433
|
+
function createStoreData(id, parent) {
|
|
434
|
+
if (parent) {
|
|
435
|
+
return {
|
|
436
|
+
...generateStoreData(id),
|
|
437
|
+
parent,
|
|
438
|
+
scopeConsumers: parent ? new Set : undefined
|
|
439
|
+
};
|
|
440
|
+
} else {
|
|
441
|
+
return generateStoreData(id);
|
|
337
442
|
}
|
|
338
|
-
|
|
339
|
-
};
|
|
340
|
-
var stableStringify = (x) => {
|
|
341
|
-
if (typeof x === "string" || typeof x === "boolean" || typeof x === "number")
|
|
342
|
-
return x;
|
|
343
|
-
return stableStringifyRecurse(x);
|
|
344
|
-
};
|
|
345
|
-
|
|
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
|
-
// src/lib/createStoreData.ts
|
|
367
|
-
var generateId = () => (Math.random() + 1).toString(36).substring(7);
|
|
368
|
-
var createStoreData = (id = generateId()) => ({
|
|
369
|
-
id,
|
|
370
|
-
values: new WeakMap,
|
|
371
|
-
expiredValues: new WeakMap,
|
|
372
|
-
subscriptions: new WeakMap,
|
|
373
|
-
subscriptionsRequireEqualCheck: new WeakMap,
|
|
374
|
-
stateConsumers: new WeakMap,
|
|
375
|
-
stateDependencies: new WeakMap
|
|
376
|
-
});
|
|
443
|
+
}
|
|
377
444
|
|
|
378
445
|
// src/lib/resetAtom.ts
|
|
379
|
-
var resetAtom = (
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
446
|
+
var resetAtom = (atom, data) => {
|
|
447
|
+
let value = getAtomInitValue(atom, data);
|
|
448
|
+
data.values.set(atom, value);
|
|
449
|
+
if (!isPromiseLike(value)) {
|
|
450
|
+
propagateUpdatedAtoms([atom], data);
|
|
383
451
|
}
|
|
384
|
-
return
|
|
452
|
+
return value;
|
|
385
453
|
};
|
|
386
454
|
|
|
455
|
+
// src/utils/isFamily.ts
|
|
456
|
+
var isFamily = (state) => isAtomFamily(state) || isSelectorFamily(state);
|
|
457
|
+
|
|
387
458
|
// src/lib/unsubscribe.ts
|
|
388
|
-
var unsubscribe = (state, subscription, data, mount) => {
|
|
459
|
+
var unsubscribe = (state, subscription, data, mount, maxAgeCleanup) => {
|
|
389
460
|
const subscribers = data.subscriptions.get(state);
|
|
390
461
|
if (subscribers) {
|
|
391
462
|
subscribers.delete(subscription);
|
|
@@ -401,6 +472,11 @@ var unsubscribe = (state, subscription, data, mount) => {
|
|
|
401
472
|
data.subscriptionsRequireEqualCheck.delete(state);
|
|
402
473
|
}
|
|
403
474
|
}
|
|
475
|
+
if (subscribers.size === 0) {
|
|
476
|
+
if (maxAgeCleanup)
|
|
477
|
+
maxAgeCleanup();
|
|
478
|
+
data.subscriptions.delete(state);
|
|
479
|
+
}
|
|
404
480
|
if (mount) {
|
|
405
481
|
if (subscribers.size === mount.mountSubscriptions.size) {
|
|
406
482
|
if (typeof mount.onUnmount === "function") {
|
|
@@ -418,10 +494,24 @@ var initSubscribers = (state, data) => {
|
|
|
418
494
|
return set;
|
|
419
495
|
};
|
|
420
496
|
var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) => {
|
|
421
|
-
|
|
497
|
+
let parentUnsubscribe;
|
|
498
|
+
if ("parent" in data && (!data.values.has(state) && isAtom(state) || isAtomFamily(state))) {
|
|
499
|
+
const originalCallback = callback;
|
|
500
|
+
parentUnsubscribe = subscribe(state, originalCallback, requireDeepEqualCheckBeforeCallback, data.parent);
|
|
501
|
+
callback = (arg) => {
|
|
502
|
+
if (parentUnsubscribe) {
|
|
503
|
+
parentUnsubscribe();
|
|
504
|
+
parentUnsubscribe = undefined;
|
|
505
|
+
}
|
|
506
|
+
originalCallback(arg);
|
|
507
|
+
};
|
|
508
|
+
} else if (!data.values.has(state) && isAtom(state)) {
|
|
509
|
+
initAtom(state, data);
|
|
510
|
+
}
|
|
422
511
|
if (isSelector(state) && !data.values.has(state)) {
|
|
423
512
|
initSelector(state, data);
|
|
424
513
|
}
|
|
514
|
+
const subscribers = data.subscriptions.get(state) || initSubscribers(state, data);
|
|
425
515
|
let subscription;
|
|
426
516
|
if (isFamily(state)) {
|
|
427
517
|
subscription = {
|
|
@@ -437,34 +527,67 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
|
|
|
437
527
|
}
|
|
438
528
|
subscribers.add(subscription);
|
|
439
529
|
let mount;
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
530
|
+
let maxAgeCleanup;
|
|
531
|
+
if (subscribers.size === 1) {
|
|
532
|
+
if (isAtom(state) && state.maxAge) {
|
|
533
|
+
let timeout;
|
|
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
|
+
};
|
|
555
|
+
}
|
|
556
|
+
if (state.onMount) {
|
|
557
|
+
const store = storeFromStoreData(data);
|
|
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
|
+
};
|
|
568
|
+
}
|
|
452
569
|
}
|
|
453
570
|
if (requireDeepEqualCheckBeforeCallback && data.subscriptionsRequireEqualCheck.get(state) !== true) {
|
|
454
571
|
data.subscriptionsRequireEqualCheck.set(state, true);
|
|
455
572
|
}
|
|
456
|
-
return () =>
|
|
573
|
+
return () => {
|
|
574
|
+
if (parentUnsubscribe) {
|
|
575
|
+
parentUnsubscribe();
|
|
576
|
+
}
|
|
577
|
+
unsubscribe(state, subscription, data, mount, maxAgeCleanup);
|
|
578
|
+
};
|
|
457
579
|
};
|
|
458
580
|
|
|
459
581
|
// src/lib/setAtoms.ts
|
|
460
|
-
import equal5 from "fast-deep-equal";
|
|
461
582
|
var setAtoms = (pairs, data) => {
|
|
462
583
|
const updatedAtoms = [];
|
|
463
|
-
for (let [
|
|
464
|
-
const currentValue = getState(
|
|
465
|
-
if (!
|
|
466
|
-
updatedAtoms.push(
|
|
467
|
-
|
|
584
|
+
for (let [atom, value] of pairs) {
|
|
585
|
+
const currentValue = getState(atom, data);
|
|
586
|
+
if (!atom.equal(currentValue, value)) {
|
|
587
|
+
updatedAtoms.push(atom);
|
|
588
|
+
if (atom.onSet)
|
|
589
|
+
atom.onSet(value, data);
|
|
590
|
+
data.values.set(atom, value);
|
|
468
591
|
}
|
|
469
592
|
}
|
|
470
593
|
propagateUpdatedAtoms(updatedAtoms, data);
|
|
@@ -491,11 +614,19 @@ var recursivlyResetTxnSelectorCache = (state, txnSubscribers, txnSelectorCache)
|
|
|
491
614
|
}
|
|
492
615
|
}
|
|
493
616
|
};
|
|
494
|
-
var
|
|
617
|
+
var captureScopedTransaction = (scopedData) => {
|
|
618
|
+
let txn;
|
|
619
|
+
transaction((scopedTxn) => {
|
|
620
|
+
txn = scopedTxn;
|
|
621
|
+
}, scopedData, false);
|
|
622
|
+
return txn;
|
|
623
|
+
};
|
|
624
|
+
var transaction = (callback, data, autoCommit = true) => {
|
|
495
625
|
let txnAtomMap = new Map;
|
|
496
626
|
let txnSelectorCache = new Map;
|
|
497
627
|
let txnSubscribers = new Map;
|
|
498
628
|
let dirtySelectors = new Set;
|
|
629
|
+
let scopedTransactions;
|
|
499
630
|
const txnGet = (state) => {
|
|
500
631
|
if (isAtom(state)) {
|
|
501
632
|
return txnAtomMap.has(state) ? txnAtomMap.get(state) : getState(state, data);
|
|
@@ -516,127 +647,427 @@ var transaction = (callback, data) => {
|
|
|
516
647
|
}
|
|
517
648
|
txnSelectorCache.set(state, res);
|
|
518
649
|
return res;
|
|
650
|
+
} else if (isFamily(state)) {
|
|
651
|
+
return txnAtomMap.has(state) ? txnAtomMap.get(state) : getState(state.__keysSelector, data);
|
|
519
652
|
} else {
|
|
520
653
|
throw new Error("Unsupported state");
|
|
521
654
|
}
|
|
522
655
|
};
|
|
523
|
-
const txnSet = (
|
|
524
|
-
if (!isAtom(
|
|
656
|
+
const txnSet = (atom, value) => {
|
|
657
|
+
if (!isAtom(atom))
|
|
525
658
|
throw new Error("Not an atom");
|
|
526
|
-
if (
|
|
527
|
-
const currentValue = txnGet(
|
|
659
|
+
if (isFunction(value)) {
|
|
660
|
+
const currentValue = txnGet(atom);
|
|
528
661
|
value = value(currentValue);
|
|
529
662
|
}
|
|
530
|
-
for (const selector of findDependencies(
|
|
663
|
+
for (const selector of findDependencies(atom, data)) {
|
|
531
664
|
dirtySelectors.add(selector);
|
|
532
665
|
txnSelectorCache.delete(selector);
|
|
533
666
|
}
|
|
534
|
-
if (txnSubscribers.get(
|
|
535
|
-
recursivlyResetTxnSelectorCache(
|
|
667
|
+
if (txnSubscribers.get(atom)?.size) {
|
|
668
|
+
recursivlyResetTxnSelectorCache(atom, txnSubscribers, txnSelectorCache);
|
|
536
669
|
}
|
|
537
|
-
txnAtomMap.set(
|
|
670
|
+
txnAtomMap.set(atom, value);
|
|
671
|
+
return value;
|
|
538
672
|
};
|
|
539
|
-
const txnReset = (
|
|
540
|
-
const value = getAtomInitValue(
|
|
541
|
-
txnAtomMap.set(
|
|
673
|
+
const txnReset = (atom) => {
|
|
674
|
+
const value = getAtomInitValue(atom, data);
|
|
675
|
+
txnAtomMap.set(atom, value);
|
|
542
676
|
return value;
|
|
543
677
|
};
|
|
544
678
|
const commit = () => {
|
|
545
679
|
setAtoms(txnAtomMap, data);
|
|
546
680
|
dirtySelectors.clear();
|
|
681
|
+
if (scopedTransactions) {
|
|
682
|
+
for (const scopedTxn of Object.values(scopedTransactions)) {
|
|
683
|
+
scopedTxn.commit();
|
|
684
|
+
}
|
|
685
|
+
}
|
|
547
686
|
};
|
|
548
|
-
const result = callback(
|
|
549
|
-
|
|
687
|
+
const result = callback({
|
|
688
|
+
set: txnSet,
|
|
689
|
+
get: txnGet,
|
|
690
|
+
reset: txnReset,
|
|
691
|
+
commit,
|
|
692
|
+
scope: (scopeId, callback2) => {
|
|
693
|
+
if (scopeId in data.scopes) {
|
|
694
|
+
const scopedData = data.scopes[scopeId];
|
|
695
|
+
if (scopedTransactions === undefined) {
|
|
696
|
+
scopedTransactions = {};
|
|
697
|
+
}
|
|
698
|
+
if (scopedTransactions[scopeId] === undefined) {
|
|
699
|
+
scopedTransactions[scopeId] = captureScopedTransaction(scopedData);
|
|
700
|
+
}
|
|
701
|
+
return callback2(scopedTransactions[scopeId]);
|
|
702
|
+
} else {
|
|
703
|
+
throw new Error(`Scope '${scopeId}' not found. Registered scopes: ${Object.keys(data.scopes).join(", ")}`);
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
data
|
|
707
|
+
});
|
|
708
|
+
if (autoCommit)
|
|
709
|
+
commit();
|
|
550
710
|
return result;
|
|
551
711
|
};
|
|
552
712
|
|
|
553
713
|
// src/lib/storeFromStoreData.ts
|
|
554
|
-
var
|
|
714
|
+
var SelectorProvidedToSetError = `Invalid state object passed to set().
|
|
715
|
+
You provided a \`selector\`.
|
|
716
|
+
Only \`atom\` cam be set.
|
|
717
|
+
`;
|
|
718
|
+
var InvalidStateSetError = `Invalid state object passed to set().
|
|
719
|
+
Only \`atom\` can be set.
|
|
720
|
+
`;
|
|
721
|
+
function storeFromStoreData(data, detach) {
|
|
555
722
|
const get = (state) => getState(state, data);
|
|
556
723
|
const set = (state, value) => {
|
|
557
|
-
if (
|
|
558
|
-
|
|
559
|
-
|
|
724
|
+
if (isAtom(state))
|
|
725
|
+
return setAtom(state, value, data);
|
|
726
|
+
if (isSelector(state))
|
|
727
|
+
throw new Error(SelectorProvidedToSetError);
|
|
728
|
+
throw new Error(InvalidStateSetError);
|
|
560
729
|
};
|
|
561
|
-
const reset = (
|
|
730
|
+
const reset = (atom) => resetAtom(atom, data);
|
|
562
731
|
const sub = (state, callback, deepEqualCheckBeforeCallback = true) => subscribe(state, callback, deepEqualCheckBeforeCallback, data);
|
|
563
732
|
const txn = (callback) => transaction(callback, data);
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
733
|
+
const scope = (scopeId) => {
|
|
734
|
+
let scopedStoreData;
|
|
735
|
+
if (scopeId in data.scopes) {
|
|
736
|
+
scopedStoreData = data.scopes[scopeId];
|
|
737
|
+
} else {
|
|
738
|
+
scopedStoreData = createStoreData(scopeId, data);
|
|
739
|
+
data.scopes[scopeId] = scopedStoreData;
|
|
740
|
+
}
|
|
741
|
+
const detach2 = () => {
|
|
742
|
+
scopedStoreData.scopeConsumers.delete(detach2);
|
|
743
|
+
if (scopedStoreData.scopeConsumers.size === 0) {
|
|
744
|
+
delete data.scopes[scopeId];
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
scopedStoreData.scopeConsumers.add(detach2);
|
|
748
|
+
const newStore = storeFromStoreData(data.scopes[scopeId], detach2);
|
|
749
|
+
return newStore;
|
|
571
750
|
};
|
|
572
|
-
|
|
751
|
+
if (detach) {
|
|
752
|
+
return {
|
|
753
|
+
get,
|
|
754
|
+
set,
|
|
755
|
+
sub,
|
|
756
|
+
txn,
|
|
757
|
+
reset,
|
|
758
|
+
data,
|
|
759
|
+
scope,
|
|
760
|
+
detach
|
|
761
|
+
};
|
|
762
|
+
} else {
|
|
763
|
+
return {
|
|
764
|
+
get,
|
|
765
|
+
set,
|
|
766
|
+
sub,
|
|
767
|
+
txn,
|
|
768
|
+
reset,
|
|
769
|
+
data,
|
|
770
|
+
scope
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
}
|
|
573
774
|
|
|
574
|
-
// src/
|
|
575
|
-
var
|
|
775
|
+
// src/store.ts
|
|
776
|
+
var store = (id) => {
|
|
576
777
|
const data = createStoreData(id);
|
|
577
778
|
return storeFromStoreData(data);
|
|
578
779
|
};
|
|
780
|
+
|
|
781
|
+
// src/globalStore.ts
|
|
782
|
+
var globalStore = Object.assign(store("valdres-global-store"), {
|
|
783
|
+
atoms: new Map,
|
|
784
|
+
atomFamilies: new Map
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
// src/lib/globalAtom.ts
|
|
788
|
+
var globalAtom = (defaultValue, options) => {
|
|
789
|
+
const stores = new Set;
|
|
790
|
+
let value;
|
|
791
|
+
let initialized = false;
|
|
792
|
+
let onReset;
|
|
793
|
+
if (options.onSet)
|
|
794
|
+
throw new Error("onSet on globalAtom is currently not supported");
|
|
795
|
+
const onInit = (setSelf2, data) => {
|
|
796
|
+
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
|
+
stores.add(data);
|
|
805
|
+
};
|
|
806
|
+
const onSet = (newValue, currentStore) => {
|
|
807
|
+
value = newValue;
|
|
808
|
+
if (stores.size > 1) {
|
|
809
|
+
for (const store2 of stores) {
|
|
810
|
+
if (store2.id !== currentStore.id) {
|
|
811
|
+
setAtom(atom, value, store2, true);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
const getSelf = () => globalStore.get(atom);
|
|
817
|
+
const setSelf = (newValue) => globalStore.set(atom, newValue);
|
|
818
|
+
const resetSelf = () => {
|
|
819
|
+
value = undefined;
|
|
820
|
+
initialized = false;
|
|
821
|
+
for (const store2 of stores) {
|
|
822
|
+
if (store2.stateDependencies.has(atom)) {
|
|
823
|
+
throw new Error("TODO: Reset support for stateDependencies");
|
|
824
|
+
}
|
|
825
|
+
store2.values.delete(atom);
|
|
826
|
+
store2.expiredValues.delete(atom);
|
|
827
|
+
propagateUpdatedAtoms([atom], store2);
|
|
828
|
+
stores.delete(store2);
|
|
829
|
+
onReset?.();
|
|
830
|
+
}
|
|
831
|
+
};
|
|
832
|
+
const atom = {
|
|
833
|
+
equal,
|
|
834
|
+
...options,
|
|
835
|
+
defaultValue,
|
|
836
|
+
name: options?.name,
|
|
837
|
+
onInit,
|
|
838
|
+
onSet,
|
|
839
|
+
setSelf,
|
|
840
|
+
getSelf,
|
|
841
|
+
resetSelf,
|
|
842
|
+
get stores() {
|
|
843
|
+
return stores;
|
|
844
|
+
}
|
|
845
|
+
};
|
|
846
|
+
return atom;
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
// src/atom.ts
|
|
850
|
+
function atom(defaultValue, options) {
|
|
851
|
+
if (!options)
|
|
852
|
+
return { equal, defaultValue };
|
|
853
|
+
if (options.global) {
|
|
854
|
+
return globalAtom(defaultValue, options);
|
|
855
|
+
}
|
|
856
|
+
return {
|
|
857
|
+
equal,
|
|
858
|
+
defaultValue,
|
|
859
|
+
...options
|
|
860
|
+
};
|
|
861
|
+
}
|
|
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
|
+
// src/lib/stableStringify.ts
|
|
874
|
+
var stableStringifyRecurse = (x, key) => {
|
|
875
|
+
if (typeof x === "string" && !x.includes('"') && !x.includes("\\")) {
|
|
876
|
+
return `"${x}"`;
|
|
877
|
+
}
|
|
878
|
+
switch (typeof x) {
|
|
879
|
+
case "undefined":
|
|
880
|
+
return "";
|
|
881
|
+
case "boolean":
|
|
882
|
+
return x ? "true" : "false";
|
|
883
|
+
case "number":
|
|
884
|
+
case "symbol":
|
|
885
|
+
return String(x);
|
|
886
|
+
case "string":
|
|
887
|
+
return JSON.stringify(x);
|
|
888
|
+
case "function":
|
|
889
|
+
return `__FUNCTION(${x.toString()})__`;
|
|
890
|
+
}
|
|
891
|
+
if (x === null) {
|
|
892
|
+
return "null";
|
|
893
|
+
}
|
|
894
|
+
if (typeof x !== "object") {
|
|
895
|
+
return JSON.stringify(x) ?? "";
|
|
896
|
+
}
|
|
897
|
+
if (isPromiseLike(x)) {
|
|
898
|
+
return "__PROMISE__";
|
|
899
|
+
}
|
|
900
|
+
if (Array.isArray(x)) {
|
|
901
|
+
return `[${x.map((v, i) => stableStringifyRecurse(v, i.toString()))}]`;
|
|
902
|
+
}
|
|
903
|
+
if (typeof x.toJSON === "function") {
|
|
904
|
+
return stableStringifyRecurse(x.toJSON(key), key);
|
|
905
|
+
}
|
|
906
|
+
if (x instanceof Map) {
|
|
907
|
+
const obj = {};
|
|
908
|
+
for (const [k, v] of x) {
|
|
909
|
+
obj[typeof k === "string" ? k : stringify(k, opt)] = v;
|
|
910
|
+
}
|
|
911
|
+
return stableStringifyRecurse(obj, key);
|
|
912
|
+
}
|
|
913
|
+
if (x instanceof Set) {
|
|
914
|
+
return stableStringifyRecurse(Array.from(x).sort((a, b) => stableStringifyRecurse(a).localeCompare(stableStringifyRecurse(b))), key);
|
|
915
|
+
}
|
|
916
|
+
if (Symbol !== undefined && x[Symbol.iterator] != null && typeof x[Symbol.iterator] === "function") {
|
|
917
|
+
return stableStringifyRecurse(Array.from(x), key);
|
|
918
|
+
}
|
|
919
|
+
return `{${Object.keys(x).filter((k) => x[k] !== undefined).sort().map((k) => `${stableStringifyRecurse(k)}:${stableStringifyRecurse(x[k], k)}`).join(",")}}`;
|
|
920
|
+
};
|
|
921
|
+
var stableStringify = (x) => {
|
|
922
|
+
if (typeof x === "string" || typeof x === "boolean" || typeof x === "number")
|
|
923
|
+
return x;
|
|
924
|
+
return stableStringifyRecurse(x);
|
|
925
|
+
};
|
|
926
|
+
|
|
927
|
+
// src/selector.ts
|
|
928
|
+
var selector = (get, options) => {
|
|
929
|
+
if (!options)
|
|
930
|
+
return { equal, get };
|
|
931
|
+
return { equal, ...options, get };
|
|
932
|
+
};
|
|
933
|
+
|
|
934
|
+
// src/lib/createAtomFamily.ts
|
|
935
|
+
var createOptions = (options = {}, family, familyKey, keyStringified) => {
|
|
936
|
+
if (options.name) {
|
|
937
|
+
return {
|
|
938
|
+
equal,
|
|
939
|
+
...options,
|
|
940
|
+
name: options?.name + "_" + keyStringified,
|
|
941
|
+
family,
|
|
942
|
+
familyKey
|
|
943
|
+
};
|
|
944
|
+
} else {
|
|
945
|
+
return { equal, ...options, family, familyKey };
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
var handleDefaultValue = (defaultValue, key) => {
|
|
949
|
+
if (isSelectorFamily(defaultValue))
|
|
950
|
+
return defaultValue(key);
|
|
951
|
+
if (typeof defaultValue === "function")
|
|
952
|
+
return () => defaultValue(key);
|
|
953
|
+
return defaultValue;
|
|
954
|
+
};
|
|
955
|
+
var createAtomFamily = (defaultValue, options) => {
|
|
956
|
+
const map = new Map;
|
|
957
|
+
const keysAtom = atom(new Set);
|
|
958
|
+
const atomFamily = Object.assign((key) => {
|
|
959
|
+
const keyStringified = stableStringify(key);
|
|
960
|
+
if (map.has(keyStringified)) {
|
|
961
|
+
return map.get(keyStringified);
|
|
962
|
+
}
|
|
963
|
+
const familyAtom = atomFamilyAtom(handleDefaultValue(defaultValue, key), createOptions(options, atomFamily, Object.freeze(key), keyStringified));
|
|
964
|
+
map.set(keyStringified, familyAtom);
|
|
965
|
+
return familyAtom;
|
|
966
|
+
}, {
|
|
967
|
+
__valdresAtomFamilyMap: map,
|
|
968
|
+
release: (key) => map.delete(key),
|
|
969
|
+
__keysAtom: keysAtom,
|
|
970
|
+
__keysSelector: selector((get) => Array.from(get(keysAtom)))
|
|
971
|
+
});
|
|
972
|
+
if (options?.name)
|
|
973
|
+
Object.defineProperty(atomFamily, "name", {
|
|
974
|
+
value: options.name,
|
|
975
|
+
writable: false
|
|
976
|
+
});
|
|
977
|
+
return atomFamily;
|
|
978
|
+
};
|
|
979
|
+
|
|
980
|
+
// src/lib/createGlobalAtomFamily.ts
|
|
981
|
+
var createGlobalAtomFamily = (defaultValue, options) => {
|
|
982
|
+
if (!options.name)
|
|
983
|
+
throw new Error(`Missing name for global atomFamiliy`);
|
|
984
|
+
if (globalStore.atomFamilies.has(options.name)) {
|
|
985
|
+
return globalStore.atomFamilies.get(options.name);
|
|
986
|
+
}
|
|
987
|
+
const family = createAtomFamily(defaultValue, options);
|
|
988
|
+
globalStore.atomFamilies.set(options.name, family);
|
|
989
|
+
return family;
|
|
990
|
+
};
|
|
991
|
+
|
|
992
|
+
// src/atomFamily.ts
|
|
993
|
+
function atomFamily(defaultValue, options) {
|
|
994
|
+
if (options?.global)
|
|
995
|
+
return createGlobalAtomFamily(defaultValue, options);
|
|
996
|
+
return createAtomFamily(defaultValue, options);
|
|
997
|
+
}
|
|
579
998
|
// src/createStoreWithSelectorSet.ts
|
|
580
|
-
var setSelector = (
|
|
581
|
-
return
|
|
999
|
+
var setSelector = (selector2, values, store2) => {
|
|
1000
|
+
return selector2.set(store2.set, store2.get, store2.reset, ...values);
|
|
582
1001
|
};
|
|
583
1002
|
var createStoreWithSelectorSet = (id) => {
|
|
584
1003
|
const data = createStoreData(id);
|
|
585
|
-
const
|
|
586
|
-
|
|
1004
|
+
const store2 = storeFromStoreData(data);
|
|
1005
|
+
store2.set = (state, value, ...rest) => {
|
|
587
1006
|
if (isAtom(state))
|
|
588
1007
|
return setAtom(state, value, data);
|
|
589
1008
|
if (isSelector(state))
|
|
590
|
-
return setSelector(state, [value, ...rest],
|
|
1009
|
+
return setSelector(state, [value, ...rest], store2);
|
|
591
1010
|
throw new Error("Invalid state object");
|
|
592
1011
|
};
|
|
593
|
-
|
|
594
|
-
return
|
|
1012
|
+
store2.kind = "storeWithSelectorSet";
|
|
1013
|
+
return store2;
|
|
595
1014
|
};
|
|
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
|
-
// src/selector.ts
|
|
603
|
-
var selector = (get, debugLabel) => ({
|
|
604
|
-
get,
|
|
605
|
-
debugLabel
|
|
606
|
-
});
|
|
607
1015
|
// src/selectorFamily.ts
|
|
608
|
-
var
|
|
1016
|
+
var createOptions2 = (options = {}, family, familyKey, keyStringified) => {
|
|
1017
|
+
if (options.name) {
|
|
1018
|
+
return {
|
|
1019
|
+
equal,
|
|
1020
|
+
...options,
|
|
1021
|
+
name: options?.name + "_" + keyStringified,
|
|
1022
|
+
family,
|
|
1023
|
+
familyKey
|
|
1024
|
+
};
|
|
1025
|
+
} else {
|
|
1026
|
+
return { equal, ...options, family, familyKey };
|
|
1027
|
+
}
|
|
1028
|
+
};
|
|
1029
|
+
var selectorFamily = (get, options) => {
|
|
609
1030
|
const map = new Map;
|
|
610
1031
|
const selectorFamily2 = (key) => {
|
|
611
|
-
|
|
612
|
-
try {
|
|
613
|
-
keyStringified = stableStringify(key);
|
|
614
|
-
} catch (e) {
|
|
615
|
-
console.log(`errro`, { key, debugLabel, e });
|
|
616
|
-
throw e;
|
|
617
|
-
}
|
|
1032
|
+
const keyStringified = stableStringify(key);
|
|
618
1033
|
if (map.has(keyStringified))
|
|
619
1034
|
return map.get(keyStringified);
|
|
620
|
-
const
|
|
621
|
-
const newSelector = selector((selectorArgs) => get(key)(selectorArgs), selectorDebugLabel);
|
|
622
|
-
newSelector.family = selectorFamily2;
|
|
1035
|
+
const newSelector = selector((selectorArgs) => get(key)(selectorArgs), createOptions2(options, selectorFamily2, key, keyStringified));
|
|
623
1036
|
map.set(keyStringified, newSelector);
|
|
624
1037
|
return newSelector;
|
|
625
1038
|
};
|
|
626
|
-
selectorFamily2.
|
|
1039
|
+
selectorFamily2.__valdresSelectorFamilyMap = map;
|
|
1040
|
+
if (options?.name)
|
|
1041
|
+
Object.defineProperty(selectorFamily2, "name", {
|
|
1042
|
+
value: options.name,
|
|
1043
|
+
writable: false
|
|
1044
|
+
});
|
|
627
1045
|
return selectorFamily2;
|
|
628
1046
|
};
|
|
1047
|
+
// src/utils/isFamilySelector.ts
|
|
1048
|
+
var isFamilySelector = (state) => isFamilyState(state) && isSelector(state);
|
|
1049
|
+
|
|
1050
|
+
// src/index.ts
|
|
1051
|
+
if (globalThis.__valdres__) {
|
|
1052
|
+
throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${version}`);
|
|
1053
|
+
} else {
|
|
1054
|
+
globalThis.__valdres__ = version;
|
|
1055
|
+
}
|
|
629
1056
|
export {
|
|
1057
|
+
store,
|
|
630
1058
|
selectorFamily,
|
|
631
1059
|
selector,
|
|
632
|
-
|
|
1060
|
+
isSelectorFamily,
|
|
633
1061
|
isSelector,
|
|
634
1062
|
isPromiseLike,
|
|
1063
|
+
isFamilyState,
|
|
1064
|
+
isFamilySelector,
|
|
1065
|
+
isFamilyAtom,
|
|
635
1066
|
isFamily,
|
|
1067
|
+
isAtomFamily,
|
|
636
1068
|
isAtom,
|
|
637
|
-
|
|
1069
|
+
globalStore,
|
|
638
1070
|
createStoreWithSelectorSet,
|
|
639
|
-
createStore,
|
|
640
1071
|
atomFamily,
|
|
641
1072
|
atom
|
|
642
1073
|
};
|