valdres 0.2.0-alpha.8 → 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 +737 -273
- 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/types/src/lib/setAtom.d.ts +3 -0
- 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/AtomOnInit.d.ts +2 -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 +5 -3
- 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 -8
- 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/setAtom.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 -9
- package/dist/src/types/AtomFamily.d.ts +0 -5
- 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/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,108 +1,105 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
3
|
-
if (!options)
|
|
4
|
-
return { defaultValue };
|
|
5
|
-
return {
|
|
6
|
-
defaultValue,
|
|
7
|
-
...options
|
|
8
|
-
};
|
|
9
|
-
};
|
|
10
|
-
// src/utils/isPromiseLike.ts
|
|
11
|
-
var isPromiseLike = (object) => {
|
|
12
|
-
return object && object.then && typeof object.then === "function";
|
|
13
|
-
};
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { version } from "../package.json";
|
|
14
3
|
|
|
15
|
-
// src/lib/
|
|
16
|
-
var
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
if (typeof x !== "object") {
|
|
37
|
-
return JSON.stringify(x) ?? "";
|
|
38
|
-
}
|
|
39
|
-
if (isPromiseLike(x)) {
|
|
40
|
-
return "__PROMISE__";
|
|
41
|
-
}
|
|
42
|
-
if (Array.isArray(x)) {
|
|
43
|
-
return `[${x.map((v, i) => stableStringifyRecurse(v, i.toString()))}]`;
|
|
44
|
-
}
|
|
45
|
-
if (typeof x.toJSON === "function") {
|
|
46
|
-
return stableStringifyRecurse(x.toJSON(key), key);
|
|
47
|
-
}
|
|
48
|
-
if (x instanceof Map) {
|
|
49
|
-
const obj = {};
|
|
50
|
-
for (const [k, v] of x) {
|
|
51
|
-
obj[typeof k === "string" ? k : stringify(k, opt)] = v;
|
|
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;
|
|
52
24
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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;
|
|
60
80
|
}
|
|
61
|
-
return
|
|
81
|
+
return a !== a && b !== b;
|
|
62
82
|
};
|
|
63
|
-
var
|
|
64
|
-
|
|
65
|
-
return
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
var atomFamily = (defaultValue, debugLabel) => {
|
|
71
|
-
const map = new Map;
|
|
72
|
-
const atomFamily2 = (key, defaultOverride) => {
|
|
73
|
-
const keyStringified = stableStringify(key);
|
|
74
|
-
if (map.has(keyStringified)) {
|
|
75
|
-
return map.get(keyStringified);
|
|
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;
|
|
76
90
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
label: atomDebugLabel
|
|
80
|
-
});
|
|
81
|
-
newAtom.family = atomFamily2;
|
|
82
|
-
newAtom.familyKey = Object.freeze(key);
|
|
83
|
-
map.set(keyStringified, newAtom);
|
|
84
|
-
return newAtom;
|
|
85
|
-
};
|
|
86
|
-
atomFamily2._map = map;
|
|
87
|
-
return atomFamily2;
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
88
93
|
};
|
|
89
|
-
// src/lib/createStoreData.ts
|
|
90
|
-
var generateId = () => (Math.random() + 1).toString(36).substring(7);
|
|
91
|
-
var createStoreData = (id = generateId()) => ({
|
|
92
|
-
id,
|
|
93
|
-
values: new WeakMap,
|
|
94
|
-
expiredValues: new WeakMap,
|
|
95
|
-
subscriptions: new WeakMap,
|
|
96
|
-
subscriptionsRequireEqualCheck: new WeakMap,
|
|
97
|
-
stateConsumers: new WeakMap,
|
|
98
|
-
stateDependencies: new WeakMap
|
|
99
|
-
});
|
|
100
94
|
|
|
101
95
|
// src/utils/isAtom.ts
|
|
102
96
|
var isAtom = (state) => Object.hasOwn(state, "defaultValue");
|
|
103
97
|
|
|
104
|
-
// src/
|
|
105
|
-
|
|
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);
|
|
106
103
|
|
|
107
104
|
// src/lib/updateStateSubscribers.ts
|
|
108
105
|
var updateStateSubscribers = (state, data) => {
|
|
@@ -112,7 +109,7 @@ var updateStateSubscribers = (state, data) => {
|
|
|
112
109
|
subscribtion.callback();
|
|
113
110
|
}
|
|
114
111
|
}
|
|
115
|
-
if (state
|
|
112
|
+
if (isFamilyState(state)) {
|
|
116
113
|
const familySubscriptions = data.subscriptions.get(state.family);
|
|
117
114
|
if (familySubscriptions?.size) {
|
|
118
115
|
for (const subscribtion of familySubscriptions) {
|
|
@@ -122,11 +119,123 @@ var updateStateSubscribers = (state, data) => {
|
|
|
122
119
|
}
|
|
123
120
|
};
|
|
124
121
|
|
|
125
|
-
// src/
|
|
126
|
-
|
|
122
|
+
// src/utils/isPromiseLike.ts
|
|
123
|
+
var isPromiseLike = (object) => {
|
|
124
|
+
return object && object.then && typeof object.then === "function";
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// src/utils/isAtomFamily.ts
|
|
128
|
+
var isAtomFamily = (state) => state && Object.hasOwn(state, "__valdresAtomFamilyMap");
|
|
129
|
+
|
|
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
|
+
};
|
|
158
|
+
|
|
159
|
+
// src/lib/initAtom.ts
|
|
160
|
+
var getAtomInitValue = (atom, data) => {
|
|
161
|
+
if (atom.defaultValue === undefined) {
|
|
162
|
+
let promiseResolve;
|
|
163
|
+
const promise = new Promise((resolve) => {
|
|
164
|
+
promiseResolve = resolve;
|
|
165
|
+
});
|
|
166
|
+
promise.__isEmptyAtomPromise__ = true;
|
|
167
|
+
promise.__resolveEmptyAtomPromise__ = promiseResolve;
|
|
168
|
+
return promise;
|
|
169
|
+
} else if (typeof atom.defaultValue === "function") {
|
|
170
|
+
const value = atom.defaultValue();
|
|
171
|
+
if (isPromiseLike(value)) {
|
|
172
|
+
value.then((resolvedValue) => {
|
|
173
|
+
data.values.set(atom, resolvedValue);
|
|
174
|
+
propagateUpdatedAtoms([atom], data);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
return value;
|
|
178
|
+
} else if (isSelector(atom.defaultValue)) {
|
|
179
|
+
return getState(atom.defaultValue, data);
|
|
180
|
+
} else {
|
|
181
|
+
return atom.defaultValue;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
var initAtom = (atom, data) => {
|
|
185
|
+
let value = getAtomInitValue(atom, data);
|
|
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
|
+
}
|
|
195
|
+
if (atom.onInit)
|
|
196
|
+
atom.onInit((newVal) => {
|
|
197
|
+
value = newVal;
|
|
198
|
+
setAtom(atom, newVal, data, true);
|
|
199
|
+
}, data);
|
|
200
|
+
return value;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
// src/lib/getState.ts
|
|
204
|
+
function getState(state, data, circularDependencySet) {
|
|
205
|
+
if (data.values.has(state))
|
|
206
|
+
return data.values.get(state);
|
|
207
|
+
if (isAtom(state)) {
|
|
208
|
+
if ("parent" in data)
|
|
209
|
+
return getState(state, data.parent, circularDependencySet);
|
|
210
|
+
return initAtom(state, data);
|
|
211
|
+
}
|
|
212
|
+
if (isSelector(state))
|
|
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());
|
|
223
|
+
if (equal(array, state._keyArray))
|
|
224
|
+
return state._keyArray;
|
|
225
|
+
state._keyArray = array;
|
|
226
|
+
return array;
|
|
227
|
+
}
|
|
228
|
+
throw new Error("Invalid object passed to get");
|
|
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
|
+
};
|
|
127
237
|
|
|
128
238
|
// src/lib/initSelector.ts
|
|
129
|
-
import equal from "fast-deep-equal";
|
|
130
239
|
class SuspendAndWaitForResolveError extends Error {
|
|
131
240
|
promise;
|
|
132
241
|
constructor(promise) {
|
|
@@ -134,6 +243,36 @@ class SuspendAndWaitForResolveError extends Error {
|
|
|
134
243
|
this.promise = promise;
|
|
135
244
|
}
|
|
136
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
|
+
}
|
|
137
276
|
var getOrInitConsumersSet = (state, data) => {
|
|
138
277
|
const set = data.stateConsumers.get(state);
|
|
139
278
|
if (set)
|
|
@@ -142,18 +281,21 @@ var getOrInitConsumersSet = (state, data) => {
|
|
|
142
281
|
data.stateConsumers.set(state, newSet);
|
|
143
282
|
return newSet;
|
|
144
283
|
};
|
|
145
|
-
var evaluateSelector = (selector, data) => {
|
|
146
|
-
const currentDependencies = data.stateDependencies.get(selector) ?? new Set;
|
|
284
|
+
var evaluateSelector = (selector, data, circularDependencyMap = new WeakSet) => {
|
|
147
285
|
const updatedDependencies = new Set;
|
|
286
|
+
if (circularDependencyMap.has(selector)) {
|
|
287
|
+
throw new CircularDependencyError;
|
|
288
|
+
}
|
|
289
|
+
circularDependencyMap.add(selector);
|
|
148
290
|
let result;
|
|
149
291
|
try {
|
|
150
292
|
result = selector.get((state) => {
|
|
151
|
-
const value = getState(state, data);
|
|
293
|
+
const value = getState(state, data, circularDependencyMap);
|
|
152
294
|
updatedDependencies.add(state);
|
|
153
295
|
if (isPromiseLike(value))
|
|
154
296
|
throw new SuspendAndWaitForResolveError(value);
|
|
155
297
|
return value;
|
|
156
|
-
});
|
|
298
|
+
}, data.id);
|
|
157
299
|
} catch (error) {
|
|
158
300
|
if (error instanceof SuspendAndWaitForResolveError) {
|
|
159
301
|
result = error;
|
|
@@ -161,6 +303,7 @@ var evaluateSelector = (selector, data) => {
|
|
|
161
303
|
throw error;
|
|
162
304
|
}
|
|
163
305
|
}
|
|
306
|
+
const currentDependencies = data.stateDependencies.get(selector) ?? new Set;
|
|
164
307
|
const added = updatedDependencies?.difference(currentDependencies);
|
|
165
308
|
const removed = currentDependencies?.difference(updatedDependencies);
|
|
166
309
|
for (const state of added) {
|
|
@@ -189,12 +332,19 @@ var handleSelectorResult = (value, selector, data) => {
|
|
|
189
332
|
return value;
|
|
190
333
|
}
|
|
191
334
|
};
|
|
192
|
-
var initSelector = (selector, data) => {
|
|
193
|
-
|
|
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
|
+
}
|
|
194
344
|
const value = handleSelectorResult(tmpValue, selector, data);
|
|
195
345
|
if (data.expiredValues.has(selector)) {
|
|
196
346
|
const expiredValue = data.expiredValues.get(selector);
|
|
197
|
-
if (equal(expiredValue, value)) {
|
|
347
|
+
if (selector.equal(expiredValue, value)) {
|
|
198
348
|
data.values.set(selector, expiredValue);
|
|
199
349
|
return expiredValue;
|
|
200
350
|
}
|
|
@@ -213,7 +363,7 @@ var updateSelectorSubscribers = (selector, data) => {
|
|
|
213
363
|
try {
|
|
214
364
|
const oldValue = data.expiredValues.get(selector);
|
|
215
365
|
const newValue = initSelector(selector, data);
|
|
216
|
-
if (
|
|
366
|
+
if (selector.equal(newValue, oldValue))
|
|
217
367
|
return;
|
|
218
368
|
} catch (e) {
|
|
219
369
|
}
|
|
@@ -246,13 +396,13 @@ var recursivlyResetSelectorTree = (selectors, data, clearedSelectors) => {
|
|
|
246
396
|
};
|
|
247
397
|
var propagateUpdatedAtoms = (atoms, data) => {
|
|
248
398
|
const clearedSelectors = new Set;
|
|
249
|
-
for (const
|
|
250
|
-
const consumers = data.stateConsumers.get(
|
|
399
|
+
for (const atom of atoms) {
|
|
400
|
+
const consumers = data.stateConsumers.get(atom);
|
|
251
401
|
if (consumers && consumers.size) {
|
|
252
402
|
recursivlyResetSelectorTree(consumers, data, clearedSelectors);
|
|
253
403
|
}
|
|
254
|
-
if (
|
|
255
|
-
const consumersFamily = data.stateConsumers.get(
|
|
404
|
+
if (isFamilyAtom(atom)) {
|
|
405
|
+
const consumersFamily = data.stateConsumers.get(atom.family);
|
|
256
406
|
if (consumersFamily?.size) {
|
|
257
407
|
recursivlyResetSelectorTree(consumersFamily, data, clearedSelectors);
|
|
258
408
|
}
|
|
@@ -261,98 +411,52 @@ var propagateUpdatedAtoms = (atoms, data) => {
|
|
|
261
411
|
for (const selector of clearedSelectors) {
|
|
262
412
|
updateSelectorSubscribers(selector, data);
|
|
263
413
|
}
|
|
264
|
-
for (const
|
|
265
|
-
updateStateSubscribers(
|
|
414
|
+
for (const atom of atoms) {
|
|
415
|
+
updateStateSubscribers(atom, data);
|
|
266
416
|
}
|
|
267
417
|
};
|
|
268
418
|
|
|
269
|
-
// src/lib/
|
|
270
|
-
|
|
271
|
-
var
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
currentValue.__resolveEmptyAtomPromise__(newValue);
|
|
283
|
-
}
|
|
284
|
-
propagateUpdatedAtoms([atom2], data);
|
|
419
|
+
// src/lib/createStoreData.ts
|
|
420
|
+
var generateId = () => (Math.random() + 1).toString(36).substring(7);
|
|
421
|
+
var generateStoreData = (id = generateId()) => {
|
|
422
|
+
return {
|
|
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: {}
|
|
431
|
+
};
|
|
285
432
|
};
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
});
|
|
294
|
-
promise.__isEmptyAtomPromise__ = true;
|
|
295
|
-
promise.__resolveEmptyAtomPromise__ = promiseResolve;
|
|
296
|
-
return promise;
|
|
297
|
-
} else if (typeof atom2.defaultValue === "function") {
|
|
298
|
-
const value = atom2.defaultValue();
|
|
299
|
-
if (isPromiseLike(value)) {
|
|
300
|
-
value.then((resolvedValue) => {
|
|
301
|
-
data.values.set(atom2, resolvedValue);
|
|
302
|
-
propagateUpdatedAtoms([atom2], data);
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
return value;
|
|
433
|
+
function createStoreData(id, parent) {
|
|
434
|
+
if (parent) {
|
|
435
|
+
return {
|
|
436
|
+
...generateStoreData(id),
|
|
437
|
+
parent,
|
|
438
|
+
scopeConsumers: parent ? new Set : undefined
|
|
439
|
+
};
|
|
306
440
|
} else {
|
|
307
|
-
return
|
|
441
|
+
return generateStoreData(id);
|
|
308
442
|
}
|
|
309
|
-
};
|
|
310
|
-
var initAtom = (atom2, data) => {
|
|
311
|
-
let value = getAtomInitValue(atom2, data);
|
|
312
|
-
data.values.set(atom2, value);
|
|
313
|
-
if (atom2.onInit)
|
|
314
|
-
atom2.onInit((newVal) => {
|
|
315
|
-
value = newVal;
|
|
316
|
-
setAtom(atom2, newVal, data);
|
|
317
|
-
});
|
|
318
|
-
return value;
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
// src/utils/isSelector.ts
|
|
322
|
-
var isSelector = (state) => Object.hasOwn(state, "get");
|
|
323
|
-
|
|
324
|
-
// src/utils/isFamily.ts
|
|
325
|
-
var isFamily = (state) => Object.hasOwn(state, "_map");
|
|
326
|
-
|
|
327
|
-
// src/lib/getState.ts
|
|
328
|
-
function getState(state, data) {
|
|
329
|
-
if (data.values.has(state))
|
|
330
|
-
return data.values.get(state);
|
|
331
|
-
if (isAtom(state))
|
|
332
|
-
return initAtom(state, data);
|
|
333
|
-
if (isSelector(state))
|
|
334
|
-
return initSelector(state, data);
|
|
335
|
-
if (isFamily(state)) {
|
|
336
|
-
const array = Array.from(state._map.keys());
|
|
337
|
-
if (equal4(array, state._keyArray))
|
|
338
|
-
return state._keyArray;
|
|
339
|
-
state._keyArray = array;
|
|
340
|
-
return array;
|
|
341
|
-
}
|
|
342
|
-
throw new Error("Invalid object passed to get");
|
|
343
443
|
}
|
|
344
444
|
|
|
345
445
|
// src/lib/resetAtom.ts
|
|
346
|
-
var resetAtom = (
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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);
|
|
350
451
|
}
|
|
351
|
-
return
|
|
452
|
+
return value;
|
|
352
453
|
};
|
|
353
454
|
|
|
455
|
+
// src/utils/isFamily.ts
|
|
456
|
+
var isFamily = (state) => isAtomFamily(state) || isSelectorFamily(state);
|
|
457
|
+
|
|
354
458
|
// src/lib/unsubscribe.ts
|
|
355
|
-
var unsubscribe = (state, subscription, data, mount) => {
|
|
459
|
+
var unsubscribe = (state, subscription, data, mount, maxAgeCleanup) => {
|
|
356
460
|
const subscribers = data.subscriptions.get(state);
|
|
357
461
|
if (subscribers) {
|
|
358
462
|
subscribers.delete(subscription);
|
|
@@ -368,6 +472,11 @@ var unsubscribe = (state, subscription, data, mount) => {
|
|
|
368
472
|
data.subscriptionsRequireEqualCheck.delete(state);
|
|
369
473
|
}
|
|
370
474
|
}
|
|
475
|
+
if (subscribers.size === 0) {
|
|
476
|
+
if (maxAgeCleanup)
|
|
477
|
+
maxAgeCleanup();
|
|
478
|
+
data.subscriptions.delete(state);
|
|
479
|
+
}
|
|
371
480
|
if (mount) {
|
|
372
481
|
if (subscribers.size === mount.mountSubscriptions.size) {
|
|
373
482
|
if (typeof mount.onUnmount === "function") {
|
|
@@ -385,10 +494,24 @@ var initSubscribers = (state, data) => {
|
|
|
385
494
|
return set;
|
|
386
495
|
};
|
|
387
496
|
var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) => {
|
|
388
|
-
|
|
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
|
+
}
|
|
389
511
|
if (isSelector(state) && !data.values.has(state)) {
|
|
390
512
|
initSelector(state, data);
|
|
391
513
|
}
|
|
514
|
+
const subscribers = data.subscriptions.get(state) || initSubscribers(state, data);
|
|
392
515
|
let subscription;
|
|
393
516
|
if (isFamily(state)) {
|
|
394
517
|
subscription = {
|
|
@@ -404,34 +527,67 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
|
|
|
404
527
|
}
|
|
405
528
|
subscribers.add(subscription);
|
|
406
529
|
let mount;
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
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
|
+
}
|
|
419
569
|
}
|
|
420
570
|
if (requireDeepEqualCheckBeforeCallback && data.subscriptionsRequireEqualCheck.get(state) !== true) {
|
|
421
571
|
data.subscriptionsRequireEqualCheck.set(state, true);
|
|
422
572
|
}
|
|
423
|
-
return () =>
|
|
573
|
+
return () => {
|
|
574
|
+
if (parentUnsubscribe) {
|
|
575
|
+
parentUnsubscribe();
|
|
576
|
+
}
|
|
577
|
+
unsubscribe(state, subscription, data, mount, maxAgeCleanup);
|
|
578
|
+
};
|
|
424
579
|
};
|
|
425
580
|
|
|
426
581
|
// src/lib/setAtoms.ts
|
|
427
|
-
import equal5 from "fast-deep-equal";
|
|
428
582
|
var setAtoms = (pairs, data) => {
|
|
429
583
|
const updatedAtoms = [];
|
|
430
|
-
for (let [
|
|
431
|
-
const currentValue = getState(
|
|
432
|
-
if (!
|
|
433
|
-
updatedAtoms.push(
|
|
434
|
-
|
|
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);
|
|
435
591
|
}
|
|
436
592
|
}
|
|
437
593
|
propagateUpdatedAtoms(updatedAtoms, data);
|
|
@@ -458,11 +614,19 @@ var recursivlyResetTxnSelectorCache = (state, txnSubscribers, txnSelectorCache)
|
|
|
458
614
|
}
|
|
459
615
|
}
|
|
460
616
|
};
|
|
461
|
-
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) => {
|
|
462
625
|
let txnAtomMap = new Map;
|
|
463
626
|
let txnSelectorCache = new Map;
|
|
464
627
|
let txnSubscribers = new Map;
|
|
465
628
|
let dirtySelectors = new Set;
|
|
629
|
+
let scopedTransactions;
|
|
466
630
|
const txnGet = (state) => {
|
|
467
631
|
if (isAtom(state)) {
|
|
468
632
|
return txnAtomMap.has(state) ? txnAtomMap.get(state) : getState(state, data);
|
|
@@ -474,7 +638,7 @@ var transaction = (callback, data) => {
|
|
|
474
638
|
const res = state.get((s) => {
|
|
475
639
|
deps.add(s);
|
|
476
640
|
return txnGet(s);
|
|
477
|
-
});
|
|
641
|
+
}, data.id);
|
|
478
642
|
for (const dep of deps) {
|
|
479
643
|
if (!txnSubscribers.has(dep)) {
|
|
480
644
|
txnSubscribers.set(dep, new Set);
|
|
@@ -483,127 +647,427 @@ var transaction = (callback, data) => {
|
|
|
483
647
|
}
|
|
484
648
|
txnSelectorCache.set(state, res);
|
|
485
649
|
return res;
|
|
650
|
+
} else if (isFamily(state)) {
|
|
651
|
+
return txnAtomMap.has(state) ? txnAtomMap.get(state) : getState(state.__keysSelector, data);
|
|
486
652
|
} else {
|
|
487
653
|
throw new Error("Unsupported state");
|
|
488
654
|
}
|
|
489
655
|
};
|
|
490
|
-
const txnSet = (
|
|
491
|
-
if (!isAtom(
|
|
656
|
+
const txnSet = (atom, value) => {
|
|
657
|
+
if (!isAtom(atom))
|
|
492
658
|
throw new Error("Not an atom");
|
|
493
|
-
if (
|
|
494
|
-
const currentValue = txnGet(
|
|
659
|
+
if (isFunction(value)) {
|
|
660
|
+
const currentValue = txnGet(atom);
|
|
495
661
|
value = value(currentValue);
|
|
496
662
|
}
|
|
497
|
-
for (const selector of findDependencies(
|
|
663
|
+
for (const selector of findDependencies(atom, data)) {
|
|
498
664
|
dirtySelectors.add(selector);
|
|
499
665
|
txnSelectorCache.delete(selector);
|
|
500
666
|
}
|
|
501
|
-
if (txnSubscribers.get(
|
|
502
|
-
recursivlyResetTxnSelectorCache(
|
|
667
|
+
if (txnSubscribers.get(atom)?.size) {
|
|
668
|
+
recursivlyResetTxnSelectorCache(atom, txnSubscribers, txnSelectorCache);
|
|
503
669
|
}
|
|
504
|
-
txnAtomMap.set(
|
|
670
|
+
txnAtomMap.set(atom, value);
|
|
671
|
+
return value;
|
|
505
672
|
};
|
|
506
|
-
const txnReset = (
|
|
507
|
-
const value = getAtomInitValue(
|
|
508
|
-
txnAtomMap.set(
|
|
673
|
+
const txnReset = (atom) => {
|
|
674
|
+
const value = getAtomInitValue(atom, data);
|
|
675
|
+
txnAtomMap.set(atom, value);
|
|
509
676
|
return value;
|
|
510
677
|
};
|
|
511
678
|
const commit = () => {
|
|
512
679
|
setAtoms(txnAtomMap, data);
|
|
513
680
|
dirtySelectors.clear();
|
|
681
|
+
if (scopedTransactions) {
|
|
682
|
+
for (const scopedTxn of Object.values(scopedTransactions)) {
|
|
683
|
+
scopedTxn.commit();
|
|
684
|
+
}
|
|
685
|
+
}
|
|
514
686
|
};
|
|
515
|
-
const result = callback(
|
|
516
|
-
|
|
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();
|
|
517
710
|
return result;
|
|
518
711
|
};
|
|
519
712
|
|
|
520
713
|
// src/lib/storeFromStoreData.ts
|
|
521
|
-
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) {
|
|
522
722
|
const get = (state) => getState(state, data);
|
|
523
723
|
const set = (state, value) => {
|
|
524
|
-
if (
|
|
525
|
-
|
|
526
|
-
|
|
724
|
+
if (isAtom(state))
|
|
725
|
+
return setAtom(state, value, data);
|
|
726
|
+
if (isSelector(state))
|
|
727
|
+
throw new Error(SelectorProvidedToSetError);
|
|
728
|
+
throw new Error(InvalidStateSetError);
|
|
527
729
|
};
|
|
528
|
-
const reset = (
|
|
730
|
+
const reset = (atom) => resetAtom(atom, data);
|
|
529
731
|
const sub = (state, callback, deepEqualCheckBeforeCallback = true) => subscribe(state, callback, deepEqualCheckBeforeCallback, data);
|
|
530
732
|
const txn = (callback) => transaction(callback, data);
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
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;
|
|
538
750
|
};
|
|
539
|
-
|
|
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
|
+
}
|
|
540
774
|
|
|
541
|
-
// src/
|
|
542
|
-
var
|
|
775
|
+
// src/store.ts
|
|
776
|
+
var store = (id) => {
|
|
543
777
|
const data = createStoreData(id);
|
|
544
778
|
return storeFromStoreData(data);
|
|
545
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
|
+
}
|
|
546
998
|
// src/createStoreWithSelectorSet.ts
|
|
547
|
-
var setSelector = (
|
|
548
|
-
return
|
|
999
|
+
var setSelector = (selector2, values, store2) => {
|
|
1000
|
+
return selector2.set(store2.set, store2.get, store2.reset, ...values);
|
|
549
1001
|
};
|
|
550
1002
|
var createStoreWithSelectorSet = (id) => {
|
|
551
1003
|
const data = createStoreData(id);
|
|
552
|
-
const
|
|
553
|
-
|
|
1004
|
+
const store2 = storeFromStoreData(data);
|
|
1005
|
+
store2.set = (state, value, ...rest) => {
|
|
554
1006
|
if (isAtom(state))
|
|
555
1007
|
return setAtom(state, value, data);
|
|
556
1008
|
if (isSelector(state))
|
|
557
|
-
return setSelector(state, [value, ...rest],
|
|
1009
|
+
return setSelector(state, [value, ...rest], store2);
|
|
558
1010
|
throw new Error("Invalid state object");
|
|
559
1011
|
};
|
|
560
|
-
|
|
561
|
-
return
|
|
1012
|
+
store2.kind = "storeWithSelectorSet";
|
|
1013
|
+
return store2;
|
|
562
1014
|
};
|
|
563
|
-
// src/getDefaultStore.ts
|
|
564
|
-
if (!globalThis._valdresStore) {
|
|
565
|
-
globalThis._valdresStore = createStore("default");
|
|
566
|
-
}
|
|
567
|
-
var getDefaultStore = () => globalThis._valdresStore;
|
|
568
|
-
var resetDefaultStore = () => globalThis._valdresStore = createStore();
|
|
569
|
-
// src/selector.ts
|
|
570
|
-
var selector = (get, debugLabel) => ({
|
|
571
|
-
get,
|
|
572
|
-
debugLabel
|
|
573
|
-
});
|
|
574
1015
|
// src/selectorFamily.ts
|
|
575
|
-
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) => {
|
|
576
1030
|
const map = new Map;
|
|
577
1031
|
const selectorFamily2 = (key) => {
|
|
578
|
-
|
|
579
|
-
try {
|
|
580
|
-
keyStringified = stableStringify(key);
|
|
581
|
-
} catch (e) {
|
|
582
|
-
console.log(`errro`, { key, debugLabel, e });
|
|
583
|
-
throw e;
|
|
584
|
-
}
|
|
1032
|
+
const keyStringified = stableStringify(key);
|
|
585
1033
|
if (map.has(keyStringified))
|
|
586
1034
|
return map.get(keyStringified);
|
|
587
|
-
const
|
|
588
|
-
const newSelector = selector((selectorArgs) => get(key)(selectorArgs), selectorDebugLabel);
|
|
589
|
-
newSelector.family = selectorFamily2;
|
|
1035
|
+
const newSelector = selector((selectorArgs) => get(key)(selectorArgs), createOptions2(options, selectorFamily2, key, keyStringified));
|
|
590
1036
|
map.set(keyStringified, newSelector);
|
|
591
1037
|
return newSelector;
|
|
592
1038
|
};
|
|
593
|
-
selectorFamily2.
|
|
1039
|
+
selectorFamily2.__valdresSelectorFamilyMap = map;
|
|
1040
|
+
if (options?.name)
|
|
1041
|
+
Object.defineProperty(selectorFamily2, "name", {
|
|
1042
|
+
value: options.name,
|
|
1043
|
+
writable: false
|
|
1044
|
+
});
|
|
594
1045
|
return selectorFamily2;
|
|
595
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
|
+
}
|
|
596
1056
|
export {
|
|
1057
|
+
store,
|
|
597
1058
|
selectorFamily,
|
|
598
1059
|
selector,
|
|
599
|
-
|
|
1060
|
+
isSelectorFamily,
|
|
600
1061
|
isSelector,
|
|
601
1062
|
isPromiseLike,
|
|
1063
|
+
isFamilyState,
|
|
1064
|
+
isFamilySelector,
|
|
1065
|
+
isFamilyAtom,
|
|
602
1066
|
isFamily,
|
|
1067
|
+
isAtomFamily,
|
|
603
1068
|
isAtom,
|
|
604
|
-
|
|
1069
|
+
globalStore,
|
|
605
1070
|
createStoreWithSelectorSet,
|
|
606
|
-
createStore,
|
|
607
1071
|
atomFamily,
|
|
608
1072
|
atom
|
|
609
1073
|
};
|