valdres 0.2.0-alpha.3 → 0.2.0-alpha.31

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.
Files changed (88) hide show
  1. package/dist/index.js +581 -276
  2. package/dist/{index.d.ts → types/index.d.ts} +13 -3
  3. package/dist/types/src/atom.d.ts +16 -0
  4. package/dist/types/src/atomFamily.d.ts +10 -0
  5. package/dist/types/src/createStoreWithSelectorSet.d.ts +2 -0
  6. package/dist/types/src/lib/atomFamilyAtom.d.ts +8 -0
  7. package/dist/types/src/lib/createStoreData.d.ts +3 -0
  8. package/dist/types/src/lib/getState.d.ts +7 -0
  9. package/dist/types/src/lib/globalAtom.d.ts +4 -0
  10. package/dist/types/src/lib/globalStore.d.ts +1 -0
  11. package/dist/{src → types/src}/lib/initAtom.d.ts +2 -1
  12. package/dist/types/src/lib/propagateUpdatedAtoms.d.ts +4 -0
  13. package/dist/types/src/lib/setAtom.d.ts +3 -0
  14. package/dist/types/src/lib/storeFromStoreData.d.ts +4 -0
  15. package/dist/{src → types/src}/lib/subscribe.d.ts +1 -1
  16. package/dist/{src → types/src}/lib/transaction.d.ts +2 -1
  17. package/dist/types/src/lib/unsubscribe.d.ts +5 -0
  18. package/dist/{src → types/src}/lib/updateStateSubscribers.d.ts +1 -1
  19. package/dist/types/src/selector.d.ts +4 -0
  20. package/dist/types/src/selectorFamily.d.ts +4 -0
  21. package/dist/types/src/store.d.ts +1 -0
  22. package/dist/types/src/types/Atom.d.ts +14 -0
  23. package/dist/types/src/types/AtomDefaultValue.d.ts +2 -0
  24. package/dist/types/src/types/AtomFamily.d.ts +12 -0
  25. package/dist/types/src/types/AtomFamilyAtom.d.ts +6 -0
  26. package/dist/types/src/types/AtomFamilyGlobalAtom.d.ts +3 -0
  27. package/dist/types/src/types/AtomFamilySelector.d.ts +6 -0
  28. package/dist/types/src/types/AtomOnInit.d.ts +2 -0
  29. package/dist/types/src/types/AtomOnSet.d.ts +2 -0
  30. package/dist/types/src/types/AtomOptions.d.ts +13 -0
  31. package/dist/types/src/types/EqualFunc.d.ts +1 -0
  32. package/dist/{src → types/src}/types/Family.d.ts +1 -1
  33. package/dist/types/src/types/FamilyKey.d.ts +3 -0
  34. package/dist/types/src/types/GetValue.d.ts +8 -0
  35. package/dist/types/src/types/GlobalAtom.d.ts +11 -0
  36. package/dist/types/src/types/GlobalAtomGetSelfFunc.d.ts +1 -0
  37. package/dist/types/src/types/GlobalAtomResetSelfFunc.d.ts +1 -0
  38. package/dist/types/src/types/GlobalAtomSetSelfFunc.d.ts +1 -0
  39. package/dist/types/src/types/Selector.d.ts +11 -0
  40. package/dist/types/src/types/SelectorFamily.d.ts +6 -0
  41. package/dist/types/src/types/SelectorOptions.d.ts +5 -0
  42. package/dist/types/src/types/SetAtom.d.ts +3 -0
  43. package/dist/types/src/types/SetAtomValue.d.ts +1 -0
  44. package/dist/types/src/types/State.d.ts +4 -0
  45. package/dist/types/src/types/Store.d.ts +24 -0
  46. package/dist/{src → types/src}/types/StoreData.d.ts +9 -1
  47. package/dist/types/src/types/Subscription.d.ts +1 -0
  48. package/dist/types/src/utils/isAtom.d.ts +2 -0
  49. package/dist/types/src/utils/isAtomFamily.d.ts +2 -0
  50. package/dist/types/src/utils/isFamily.d.ts +1 -0
  51. package/dist/types/src/utils/isFamilyAtom.d.ts +2 -0
  52. package/dist/types/src/utils/isFamilySelector.d.ts +2 -0
  53. package/dist/types/src/utils/isFamilyState.d.ts +3 -0
  54. package/dist/types/src/utils/isSelector.d.ts +2 -0
  55. package/dist/types/src/utils/isSelectorFamily.d.ts +2 -0
  56. package/package.json +12 -7
  57. package/dist/src/atom.d.ts +0 -9
  58. package/dist/src/atomFamily.d.ts +0 -4
  59. package/dist/src/createStore.d.ts +0 -2
  60. package/dist/src/getDefaultStore.d.ts +0 -2
  61. package/dist/src/lib/createStoreData.d.ts +0 -2
  62. package/dist/src/lib/getState.d.ts +0 -3
  63. package/dist/src/lib/propagateUpdatedAtoms.d.ts +0 -3
  64. package/dist/src/lib/setAtom.d.ts +0 -3
  65. package/dist/src/lib/storeFromStoreData.d.ts +0 -3
  66. package/dist/src/lib/unsubscribe.d.ts +0 -3
  67. package/dist/src/selector.d.ts +0 -3
  68. package/dist/src/selectorFamily.d.ts +0 -2
  69. package/dist/src/types/Atom.d.ts +0 -10
  70. package/dist/src/types/AtomFamily.d.ts +0 -5
  71. package/dist/src/types/GetValue.d.ts +0 -2
  72. package/dist/src/types/Selector.d.ts +0 -8
  73. package/dist/src/types/SelectorFamily.d.ts +0 -5
  74. package/dist/src/types/SetAtom.d.ts +0 -2
  75. package/dist/src/types/State.d.ts +0 -3
  76. package/dist/src/types/Store.d.ts +0 -14
  77. package/dist/src/utils/isAtom.d.ts +0 -2
  78. package/dist/src/utils/isFamily.d.ts +0 -1
  79. package/dist/src/utils/isSelector.d.ts +0 -2
  80. /package/dist/{src → types/src}/lib/initSelector.d.ts +0 -0
  81. /package/dist/{src → types/src}/lib/resetAtom.d.ts +0 -0
  82. /package/dist/{src → types/src}/lib/setAtoms.d.ts +0 -0
  83. /package/dist/{src → types/src}/lib/stableStringify.d.ts +0 -0
  84. /package/dist/{src → types/src}/lib/updateSelectorSubscribers.d.ts +0 -0
  85. /package/dist/{src → types/src}/types/ResetAtom.d.ts +0 -0
  86. /package/dist/{src → types/src}/types/SubscribeFn.d.ts +0 -0
  87. /package/dist/{src → types/src}/types/TransactionFn.d.ts +0 -0
  88. /package/dist/{src → types/src}/utils/isPromiseLike.d.ts +0 -0
package/dist/index.js CHANGED
@@ -1,108 +1,17 @@
1
1
  // src/atom.ts
2
- var atom = (defaultValue, options) => {
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
- };
2
+ import equal3 from "fast-deep-equal/es6";
14
3
 
15
- // src/lib/stableStringify.ts
16
- var stableStringifyRecurse = (x, key) => {
17
- if (typeof x === "string" && !x.includes('"') && !x.includes("\\")) {
18
- return `"${x}"`;
19
- }
20
- switch (typeof x) {
21
- case "undefined":
22
- return "";
23
- case "boolean":
24
- return x ? "true" : "false";
25
- case "number":
26
- case "symbol":
27
- return String(x);
28
- case "string":
29
- return JSON.stringify(x);
30
- case "function":
31
- return `__FUNCTION(${x.toString()})__`;
32
- }
33
- if (x === null) {
34
- return "null";
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;
52
- }
53
- return stableStringifyRecurse(obj, key);
54
- }
55
- if (x instanceof Set) {
56
- return stableStringifyRecurse(Array.from(x).sort((a, b) => stableStringifyRecurse(a).localeCompare(stableStringifyRecurse(b))), key);
57
- }
58
- if (Symbol !== undefined && x[Symbol.iterator] != null && typeof x[Symbol.iterator] === "function") {
59
- return stableStringifyRecurse(Array.from(x), key);
60
- }
61
- return `{${Object.keys(x).filter((k) => x[k] !== undefined).sort().map((k) => `${stableStringifyRecurse(k)}:${stableStringifyRecurse(x[k], k)}`).join(",")}}`;
62
- };
63
- var stableStringify = (x) => {
64
- if (typeof x === "string" || typeof x === "boolean" || typeof x === "number")
65
- return x;
66
- return stableStringifyRecurse(x);
67
- };
68
-
69
- // src/atomFamily.ts
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);
76
- }
77
- const atomDebugLabel = debugLabel && debugLabel + "_" + keyStringified;
78
- const newAtom = atom(typeof defaultValue === "function" ? () => defaultValue(key) : defaultValue, {
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;
88
- };
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
- });
4
+ // src/lib/globalAtom.ts
5
+ import equal2 from "fast-deep-equal/es6";
100
6
 
101
7
  // src/utils/isAtom.ts
102
8
  var isAtom = (state) => Object.hasOwn(state, "defaultValue");
103
9
 
104
- // src/utils/isSelector.ts
105
- var isSelector = (state) => Object.hasOwn(state, "get");
10
+ // src/utils/isFamilyState.ts
11
+ var isFamilyState = (state) => state && Object.hasOwn(state, "family");
12
+
13
+ // src/utils/isFamilyAtom.ts
14
+ var isFamilyAtom = (state) => isFamilyState(state) && isAtom(state);
106
15
 
107
16
  // src/lib/updateStateSubscribers.ts
108
17
  var updateStateSubscribers = (state, data) => {
@@ -112,7 +21,7 @@ var updateStateSubscribers = (state, data) => {
112
21
  subscribtion.callback();
113
22
  }
114
23
  }
115
- if (state.family) {
24
+ if (isFamilyState(state)) {
116
25
  const familySubscriptions = data.subscriptions.get(state.family);
117
26
  if (familySubscriptions?.size) {
118
27
  for (const subscribtion of familySubscriptions) {
@@ -122,11 +31,122 @@ var updateStateSubscribers = (state, data) => {
122
31
  }
123
32
  };
124
33
 
125
- // src/lib/updateSelectorSubscribers.ts
126
- import equal2 from "fast-deep-equal";
34
+ // src/utils/isPromiseLike.ts
35
+ var isPromiseLike = (object) => {
36
+ return object && object.then && typeof object.then === "function";
37
+ };
38
+
39
+ // src/lib/getState.ts
40
+ import equal from "fast-deep-equal/es6";
41
+
42
+ // src/utils/isAtomFamily.ts
43
+ var isAtomFamily = (state) => state && Object.hasOwn(state, "__valdresAtomFamilyMap");
44
+
45
+ // src/utils/isSelector.ts
46
+ var isSelector = (state) => state && Object.hasOwn(state, "get");
47
+
48
+ // src/utils/isSelectorFamily.ts
49
+ var isSelectorFamily = (state) => state && Object.hasOwn(state, "__valdresSelectorFamilyMap");
50
+
51
+ // src/lib/setAtom.ts
52
+ var setAtom = (atom, newValue, data, skipOnSet = false) => {
53
+ const currentValue = getState(atom, data);
54
+ if (typeof newValue === "function") {
55
+ newValue = newValue(currentValue);
56
+ if (isPromiseLike(newValue) || isPromiseLike(currentValue))
57
+ throw new Error("Todo, how should we handle this?");
58
+ }
59
+ if (atom.equal(currentValue, newValue))
60
+ return;
61
+ data.values.set(atom, newValue);
62
+ if (atom.onSet && !skipOnSet)
63
+ atom.onSet(newValue, data);
64
+ if (currentValue?.__isEmptyAtomPromise__) {
65
+ currentValue.__resolveEmptyAtomPromise__(newValue);
66
+ }
67
+ propagateUpdatedAtoms([atom], data);
68
+ };
69
+
70
+ // src/lib/initAtom.ts
71
+ var getAtomInitValue = (atom, data) => {
72
+ if (atom.defaultValue === undefined) {
73
+ let promiseResolve;
74
+ const promise = new Promise((resolve) => {
75
+ promiseResolve = resolve;
76
+ });
77
+ promise.__isEmptyAtomPromise__ = true;
78
+ promise.__resolveEmptyAtomPromise__ = promiseResolve;
79
+ return promise;
80
+ } else if (typeof atom.defaultValue === "function") {
81
+ const value = atom.defaultValue();
82
+ if (isPromiseLike(value)) {
83
+ value.then((resolvedValue) => {
84
+ data.values.set(atom, resolvedValue);
85
+ propagateUpdatedAtoms([atom], data);
86
+ });
87
+ }
88
+ return value;
89
+ } else if (isSelector(atom.defaultValue)) {
90
+ return getState(atom.defaultValue, data);
91
+ } else {
92
+ return atom.defaultValue;
93
+ }
94
+ };
95
+ var initAtom = (atom, data) => {
96
+ let value = getAtomInitValue(atom, data);
97
+ data.values.set(atom, value);
98
+ if (isFamilyAtom(atom)) {
99
+ const currentKeySet = getState(atom.family.__keysAtom, data);
100
+ if (!currentKeySet.has(atom.familyKey)) {
101
+ const newSet = new Set(currentKeySet);
102
+ newSet.add(atom.familyKey);
103
+ setAtom(atom.family.__keysAtom, newSet, data);
104
+ }
105
+ }
106
+ if (atom.onInit)
107
+ atom.onInit((newVal) => {
108
+ value = newVal;
109
+ setAtom(atom, newVal, data, true);
110
+ }, data);
111
+ return value;
112
+ };
113
+
114
+ // src/lib/getState.ts
115
+ function getState(state, data) {
116
+ if (data.values.has(state))
117
+ return data.values.get(state);
118
+ if (isAtom(state)) {
119
+ if ("parent" in data)
120
+ return getState(state, data.parent);
121
+ return initAtom(state, data);
122
+ }
123
+ if (isSelector(state))
124
+ return initSelector(state, data);
125
+ if (isAtomFamily(state)) {
126
+ if ("parent" in data) {
127
+ const closestData = findClosestStoreWithAtomInitialized(state.__keysAtom, data);
128
+ return getState(state.__keysSelector, closestData);
129
+ }
130
+ return getState(state.__keysSelector, data);
131
+ }
132
+ if (isSelectorFamily(state)) {
133
+ const array = Array.from(state.__valdresSelectorFamilyMap.keys());
134
+ if (equal(array, state._keyArray))
135
+ return state._keyArray;
136
+ state._keyArray = array;
137
+ return array;
138
+ }
139
+ throw new Error("Invalid object passed to get");
140
+ }
141
+ var findClosestStoreWithAtomInitialized = (atom, data) => {
142
+ if ("parent" in data === false)
143
+ return data;
144
+ if (data.values.has(atom))
145
+ return data;
146
+ return findClosestStoreWithAtomInitialized(atom, data.parent);
147
+ };
127
148
 
128
149
  // src/lib/initSelector.ts
129
- import equal from "fast-deep-equal";
130
150
  class SuspendAndWaitForResolveError extends Error {
131
151
  promise;
132
152
  constructor(promise) {
@@ -143,17 +163,16 @@ var getOrInitConsumersSet = (state, data) => {
143
163
  return newSet;
144
164
  };
145
165
  var evaluateSelector = (selector, data) => {
146
- const currentDependencies = data.stateDependencies.get(selector) ?? new Set;
147
166
  const updatedDependencies = new Set;
148
167
  let result;
149
168
  try {
150
169
  result = selector.get((state) => {
151
- const value = getState2(state, data);
170
+ const value = getState(state, data);
152
171
  updatedDependencies.add(state);
153
172
  if (isPromiseLike(value))
154
173
  throw new SuspendAndWaitForResolveError(value);
155
174
  return value;
156
- });
175
+ }, data.id);
157
176
  } catch (error) {
158
177
  if (error instanceof SuspendAndWaitForResolveError) {
159
178
  result = error;
@@ -161,6 +180,7 @@ var evaluateSelector = (selector, data) => {
161
180
  throw error;
162
181
  }
163
182
  }
183
+ const currentDependencies = data.stateDependencies.get(selector) ?? new Set;
164
184
  const added = updatedDependencies?.difference(currentDependencies);
165
185
  const removed = currentDependencies?.difference(updatedDependencies);
166
186
  for (const state of added) {
@@ -182,7 +202,7 @@ var handleSelectorResult = (value, selector, data) => {
182
202
  value.then((resolved) => {
183
203
  data.values.set(selector, resolved);
184
204
  updateStateSubscribers(selector, data);
185
- console.log(`TODO: Should we check if other selectors are using this?`);
205
+ console.log("Should we reEvaluate?");
186
206
  });
187
207
  return value;
188
208
  } else {
@@ -194,7 +214,7 @@ var initSelector = (selector, data) => {
194
214
  const value = handleSelectorResult(tmpValue, selector, data);
195
215
  if (data.expiredValues.has(selector)) {
196
216
  const expiredValue = data.expiredValues.get(selector);
197
- if (equal(expiredValue, value)) {
217
+ if (selector.equal(expiredValue, value)) {
198
218
  data.values.set(selector, expiredValue);
199
219
  return expiredValue;
200
220
  }
@@ -209,11 +229,11 @@ var updateSelectorSubscribers = (selector, data) => {
209
229
  const familySubscriptions = selector.family && data.subscriptions.get(selector.family);
210
230
  if (!subscribtions?.size && !familySubscriptions?.size)
211
231
  return;
212
- if (subscribtions?.size && data.subscriptionsRequireEqualCheck.get(selector) || familySubscriptions?.size && data.subscriptionsRequireEqualCheck.get(selector.family)) {
232
+ if (subscribtions?.size && data.subscriptionsRequireEqualCheck.get(selector) || familySubscriptions?.size && selector.family && data.subscriptionsRequireEqualCheck.get(selector.family)) {
213
233
  try {
214
234
  const oldValue = data.expiredValues.get(selector);
215
235
  const newValue = initSelector(selector, data);
216
- if (equal2(newValue, oldValue))
236
+ if (selector.equal(newValue, oldValue))
217
237
  return;
218
238
  } catch (e) {
219
239
  }
@@ -246,13 +266,13 @@ var recursivlyResetSelectorTree = (selectors, data, clearedSelectors) => {
246
266
  };
247
267
  var propagateUpdatedAtoms = (atoms, data) => {
248
268
  const clearedSelectors = new Set;
249
- for (const atom3 of atoms) {
250
- const consumers = data.stateConsumers.get(atom3);
269
+ for (const atom of atoms) {
270
+ const consumers = data.stateConsumers.get(atom);
251
271
  if (consumers && consumers.size) {
252
272
  recursivlyResetSelectorTree(consumers, data, clearedSelectors);
253
273
  }
254
- if (atom3.family) {
255
- const consumersFamily = data.stateConsumers.get(atom3.family);
274
+ if (isFamilyAtom(atom)) {
275
+ const consumersFamily = data.stateConsumers.get(atom.family);
256
276
  if (consumersFamily?.size) {
257
277
  recursivlyResetSelectorTree(consumersFamily, data, clearedSelectors);
258
278
  }
@@ -261,94 +281,52 @@ var propagateUpdatedAtoms = (atoms, data) => {
261
281
  for (const selector of clearedSelectors) {
262
282
  updateSelectorSubscribers(selector, data);
263
283
  }
264
- for (const atom3 of atoms) {
265
- updateStateSubscribers(atom3, data);
284
+ for (const atom of atoms) {
285
+ updateStateSubscribers(atom, data);
266
286
  }
267
287
  };
268
288
 
269
- // src/lib/setAtom.ts
270
- import equal3 from "fast-deep-equal";
271
- var setAtom = (atom3, newValue, data) => {
272
- const currentValue = getState2(atom3, data);
273
- if (typeof newValue === "function") {
274
- newValue = newValue(currentValue);
275
- if (isPromiseLike(newValue) || isPromiseLike(currentValue))
276
- throw new Error("Todo, how should we handle this?");
277
- }
278
- if (equal3(currentValue, newValue))
279
- return;
280
- data.values.set(atom3, newValue);
281
- if (currentValue?.__isEmptyAtomPromise__) {
282
- currentValue.__resolveEmptyAtomPromise__(newValue);
283
- }
284
- propagateUpdatedAtoms([atom3], data);
289
+ // src/lib/createStoreData.ts
290
+ var generateId = () => (Math.random() + 1).toString(36).substring(7);
291
+ var generateStoreData = (id = generateId()) => {
292
+ return {
293
+ id,
294
+ values: new WeakMap,
295
+ expiredValues: new WeakMap,
296
+ subscriptions: new WeakMap,
297
+ subscriptionsRequireEqualCheck: new WeakMap,
298
+ stateConsumers: new WeakMap,
299
+ stateDependencies: new WeakMap,
300
+ scopes: {}
301
+ };
285
302
  };
286
-
287
- // src/lib/initAtom.ts
288
- var getAtomInitValue = (atom3, data) => {
289
- if (atom3.defaultValue === undefined) {
290
- let promiseResolve;
291
- const promise = new Promise((resolve) => {
292
- promiseResolve = resolve;
293
- });
294
- promise.__isEmptyAtomPromise__ = true;
295
- promise.__resolveEmptyAtomPromise__ = promiseResolve;
296
- return promise;
297
- } else if (typeof atom3.defaultValue === "function") {
298
- const value = atom3.defaultValue();
299
- if (isPromiseLike(value)) {
300
- value.then((resolvedValue) => {
301
- data.values.set(atom3, resolvedValue);
302
- propagateUpdatedAtoms([atom3], data);
303
- });
304
- }
305
- return value;
303
+ function createStoreData(id, parent) {
304
+ if (parent) {
305
+ return {
306
+ ...generateStoreData(id),
307
+ parent,
308
+ scopeConsumers: parent ? new Set : undefined
309
+ };
306
310
  } else {
307
- return atom3.defaultValue;
308
- }
309
- };
310
- var initAtom = (atom3, data) => {
311
- const value = getAtomInitValue(atom3, data);
312
- data.values.set(atom3, value);
313
- if (atom3.onInit)
314
- atom3.onInit((newVal) => {
315
- setAtom(atom3, newVal, data);
316
- });
317
- return value;
318
- };
319
-
320
- // src/utils/isFamily.ts
321
- var isFamily = (state) => Object.hasOwn(state, "_map");
322
-
323
- // src/lib/getState.ts
324
- var getState2 = (state, data) => {
325
- if (data.values.has(state))
326
- return data.values.get(state);
327
- if (isAtom(state))
328
- return initAtom(state, data);
329
- if (isSelector(state))
330
- return initSelector(state, data);
331
- if (isFamily(state)) {
332
- const res = [];
333
- for (const atom3 of state._map.values()) {
334
- res.push([atom3.familyKey, getState2(atom3, data)]);
335
- }
336
- return res;
311
+ return generateStoreData(id);
337
312
  }
338
- throw new Error("Invalid object passed to get");
339
- };
313
+ }
340
314
 
341
315
  // src/lib/resetAtom.ts
342
- var resetAtom = (atom3, data) => {
343
- const res = initAtom(atom3, data);
344
- if (!isPromiseLike(res)) {
345
- propagateUpdatedAtoms([atom3], data);
316
+ var resetAtom = (atom, data) => {
317
+ let value = getAtomInitValue(atom, data);
318
+ data.values.set(atom, value);
319
+ if (!isPromiseLike(value)) {
320
+ propagateUpdatedAtoms([atom], data);
346
321
  }
347
- return res;
322
+ return value;
348
323
  };
349
324
 
325
+ // src/utils/isFamily.ts
326
+ var isFamily = (state) => isAtomFamily(state) || isSelectorFamily(state);
327
+
350
328
  // src/lib/unsubscribe.ts
351
- var unsubscribe = (state, subscription, data, mount) => {
329
+ var unsubscribe = (state, subscription, data, mount, maxAgeCleanup) => {
352
330
  const subscribers = data.subscriptions.get(state);
353
331
  if (subscribers) {
354
332
  subscribers.delete(subscription);
@@ -364,10 +342,15 @@ var unsubscribe = (state, subscription, data, mount) => {
364
342
  data.subscriptionsRequireEqualCheck.delete(state);
365
343
  }
366
344
  }
345
+ if (subscribers.size === 0) {
346
+ if (maxAgeCleanup)
347
+ maxAgeCleanup();
348
+ data.subscriptions.delete(state);
349
+ }
367
350
  if (mount) {
368
351
  if (subscribers.size === mount.mountSubscriptions.size) {
369
- if (state.onUnmount) {
370
- state.onUnmount(mount.onMountRes);
352
+ if (typeof mount.onUnmount === "function") {
353
+ mount.onUnmount();
371
354
  }
372
355
  }
373
356
  }
@@ -381,10 +364,24 @@ var initSubscribers = (state, data) => {
381
364
  return set;
382
365
  };
383
366
  var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) => {
384
- const subscribers = data.subscriptions.get(state) || initSubscribers(state, data);
367
+ let parentUnsubscribe;
368
+ if ("parent" in data && !data.values.has(state) && isAtom(state)) {
369
+ const originalCallback = callback;
370
+ parentUnsubscribe = subscribe(state, originalCallback, requireDeepEqualCheckBeforeCallback, data.parent);
371
+ callback = () => {
372
+ if (parentUnsubscribe) {
373
+ parentUnsubscribe();
374
+ parentUnsubscribe = undefined;
375
+ }
376
+ originalCallback();
377
+ };
378
+ } else if (!data.values.has(state) && isAtom(state)) {
379
+ initAtom(state, data);
380
+ }
385
381
  if (isSelector(state) && !data.values.has(state)) {
386
382
  initSelector(state, data);
387
383
  }
384
+ const subscribers = data.subscriptions.get(state) || initSubscribers(state, data);
388
385
  let subscription;
389
386
  if (isFamily(state)) {
390
387
  subscription = {
@@ -400,34 +397,67 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
400
397
  }
401
398
  subscribers.add(subscription);
402
399
  let mount;
403
- if (subscribers.size === 1 && state.onMount) {
404
- const store = storeFromStoreData2(data);
405
- const mountSubscriptions = new Set;
406
- const originalSub = store.sub;
407
- store.sub = (state2, callback2) => {
408
- mountSubscriptions.add(callback2);
409
- return originalSub(state2, callback2);
410
- };
411
- mount = {
412
- onMountRes: state.onMount(store, state),
413
- mountSubscriptions
414
- };
400
+ let maxAgeCleanup;
401
+ if (subscribers.size === 1) {
402
+ if (isAtom(state) && state.maxAge) {
403
+ let timeout;
404
+ const interval = setInterval(() => {
405
+ let value = getAtomInitValue(state, data);
406
+ if (isPromiseLike(value)) {
407
+ if (state.staleWhileRevalidate) {
408
+ const oldValue = data.values.get(state);
409
+ timeout = setTimeout(() => {
410
+ const nowValue = data.values.get(state);
411
+ console.log("todo", oldValue);
412
+ }, state.staleWhileRevalidate);
413
+ value.then((res) => clearTimeout(timeout));
414
+ }
415
+ } else {
416
+ data.values.set(state, value);
417
+ propagateUpdatedAtoms([state], data);
418
+ }
419
+ }, state.maxAge);
420
+ maxAgeCleanup = () => {
421
+ clearInterval(interval);
422
+ if (timeout)
423
+ clearTimeout(timeout);
424
+ };
425
+ }
426
+ if (state.onMount) {
427
+ const store = storeFromStoreData(data);
428
+ const mountSubscriptions = new Set;
429
+ const originalSub = store.sub;
430
+ store.sub = (state2, callback2) => {
431
+ mountSubscriptions.add(callback2);
432
+ return originalSub(state2, callback2);
433
+ };
434
+ mount = {
435
+ onUnmount: state.onMount(store, state),
436
+ mountSubscriptions
437
+ };
438
+ }
415
439
  }
416
440
  if (requireDeepEqualCheckBeforeCallback && data.subscriptionsRequireEqualCheck.get(state) !== true) {
417
441
  data.subscriptionsRequireEqualCheck.set(state, true);
418
442
  }
419
- return () => unsubscribe(state, subscription, data, mount);
443
+ return () => {
444
+ if (parentUnsubscribe) {
445
+ parentUnsubscribe();
446
+ }
447
+ unsubscribe(state, subscription, data, mount, maxAgeCleanup);
448
+ };
420
449
  };
421
450
 
422
451
  // src/lib/setAtoms.ts
423
- import equal4 from "fast-deep-equal";
424
452
  var setAtoms = (pairs, data) => {
425
453
  const updatedAtoms = [];
426
- for (let [atom3, value] of pairs) {
427
- const currentValue = getState2(atom3, data);
428
- if (!equal4(currentValue, value)) {
429
- updatedAtoms.push(atom3);
430
- data.values.set(atom3, value);
454
+ for (let [atom, value] of pairs) {
455
+ const currentValue = getState(atom, data);
456
+ if (!atom.equal(currentValue, value)) {
457
+ updatedAtoms.push(atom);
458
+ if (atom.onSet)
459
+ atom.onSet(value, data);
460
+ data.values.set(atom, value);
431
461
  }
432
462
  }
433
463
  propagateUpdatedAtoms(updatedAtoms, data);
@@ -446,41 +476,62 @@ var findDependencies = (state, data, result = new Set) => {
446
476
  }
447
477
  return result;
448
478
  };
479
+ var recursivlyResetTxnSelectorCache = (state, txnSubscribers, txnSelectorCache) => {
480
+ for (const dep of txnSubscribers.get(state)) {
481
+ txnSelectorCache.delete(dep);
482
+ if (txnSubscribers.get(dep)?.size) {
483
+ recursivlyResetTxnSelectorCache(dep, txnSubscribers, txnSelectorCache);
484
+ }
485
+ }
486
+ };
449
487
  var transaction = (callback, data) => {
450
488
  let txnAtomMap = new Map;
451
489
  let txnSelectorCache = new Map;
490
+ let txnSubscribers = new Map;
452
491
  let dirtySelectors = new Set;
453
492
  const txnGet = (state) => {
454
493
  if (isAtom(state)) {
455
- return txnAtomMap.has(state) ? txnAtomMap.get(state) : getState2(state, data);
456
- } else {
494
+ return txnAtomMap.has(state) ? txnAtomMap.get(state) : getState(state, data);
495
+ } else if (isSelector(state)) {
457
496
  if (txnSelectorCache.has(state)) {
458
497
  return txnSelectorCache.get(state);
459
- } else if (dirtySelectors.has(state)) {
460
- const res = state.get(txnGet);
461
- txnSelectorCache.set(state, res);
462
- return res;
463
- } else {
464
- return getState2(state, data);
465
498
  }
499
+ const deps = new Set;
500
+ const res = state.get((s) => {
501
+ deps.add(s);
502
+ return txnGet(s);
503
+ }, data.id);
504
+ for (const dep of deps) {
505
+ if (!txnSubscribers.has(dep)) {
506
+ txnSubscribers.set(dep, new Set);
507
+ }
508
+ txnSubscribers.get(dep).add(state);
509
+ }
510
+ txnSelectorCache.set(state, res);
511
+ return res;
512
+ } else {
513
+ throw new Error("Unsupported state");
466
514
  }
467
515
  };
468
- const txnSet = (atom3, value) => {
469
- if (!isAtom(atom3))
516
+ const txnSet = (atom, value) => {
517
+ if (!isAtom(atom))
470
518
  throw new Error("Not an atom");
471
519
  if (typeof value === "function") {
472
- const currentValue = txnGet(atom3);
520
+ const currentValue = txnGet(atom);
473
521
  value = value(currentValue);
474
522
  }
475
- for (const selector of findDependencies(atom3, data)) {
523
+ for (const selector of findDependencies(atom, data)) {
476
524
  dirtySelectors.add(selector);
477
525
  txnSelectorCache.delete(selector);
478
526
  }
479
- txnAtomMap.set(atom3, value);
527
+ if (txnSubscribers.get(atom)?.size) {
528
+ recursivlyResetTxnSelectorCache(atom, txnSubscribers, txnSelectorCache);
529
+ }
530
+ txnAtomMap.set(atom, value);
480
531
  };
481
- const txnReset = (atom3) => {
482
- const value = getAtomInitValue(atom3, data);
483
- txnAtomMap.set(atom3, value);
532
+ const txnReset = (atom) => {
533
+ const value = getAtomInitValue(atom, data);
534
+ txnAtomMap.set(atom, value);
484
535
  return value;
485
536
  };
486
537
  const commit = () => {
@@ -493,84 +544,338 @@ var transaction = (callback, data) => {
493
544
  };
494
545
 
495
546
  // src/lib/storeFromStoreData.ts
496
- var storeFromStoreData2 = (data) => {
497
- const get = (state) => getState2(state, data);
547
+ var SelectorProvidedToSetError = `Invalid state object passed to set().
548
+ You provided a \`selector\`.
549
+ Only \`atom\` cam be set.
550
+ `;
551
+ var InvalidStateSetError = `Invalid state object passed to set().
552
+ Only \`atom\` can be set.
553
+ `;
554
+ function storeFromStoreData(data, detach) {
555
+ const get = (state) => getState(state, data);
498
556
  const set = (state, value) => {
499
- if (isAtom(state)) {
557
+ if (isAtom(state))
500
558
  return setAtom(state, value, data);
559
+ if (isSelector(state))
560
+ throw new Error(SelectorProvidedToSetError);
561
+ throw new Error(InvalidStateSetError);
562
+ };
563
+ const reset = (atom) => resetAtom(atom, data);
564
+ const sub = (state, callback, deepEqualCheckBeforeCallback = true) => subscribe(state, callback, deepEqualCheckBeforeCallback, data);
565
+ const txn = (callback) => transaction(callback, data);
566
+ const scope = (scopeId) => {
567
+ let scopedStoreData;
568
+ if (scopeId in data.scopes) {
569
+ scopedStoreData = data.scopes[scopeId];
501
570
  } else {
502
- if (isSelector(state)) {
503
- if (state.set) {
504
- txn((set2, get2) => state.set({ get: get2, set: set2 }, value));
505
- return;
506
- } else {
507
- throw new Error("set on selector is not supported");
571
+ scopedStoreData = createStoreData(scopeId, data);
572
+ data.scopes[scopeId] = scopedStoreData;
573
+ }
574
+ const detach2 = () => {
575
+ scopedStoreData.scopeConsumers.delete(detach2);
576
+ if (scopedStoreData.scopeConsumers.size === 0) {
577
+ delete data.scopes[scopeId];
578
+ }
579
+ };
580
+ scopedStoreData.scopeConsumers.add(detach2);
581
+ const newStore = storeFromStoreData(data.scopes[scopeId], detach2);
582
+ return newStore;
583
+ };
584
+ if (detach) {
585
+ return {
586
+ get,
587
+ set,
588
+ sub,
589
+ txn,
590
+ reset,
591
+ data,
592
+ scope,
593
+ detach
594
+ };
595
+ } else {
596
+ return {
597
+ get,
598
+ set,
599
+ sub,
600
+ txn,
601
+ reset,
602
+ data,
603
+ scope
604
+ };
605
+ }
606
+ }
607
+
608
+ // src/store.ts
609
+ var store = (id) => {
610
+ const data = createStoreData(id);
611
+ return storeFromStoreData(data);
612
+ };
613
+ // package.json
614
+ var version = "0.2.0-alpha.31";
615
+
616
+ // src/lib/globalStore.ts
617
+ if (globalThis.__valdres__) {
618
+ throw new Error(`Error! An instance of valdres is already loaded`);
619
+ } else {
620
+ globalThis.__valdres__ = version;
621
+ }
622
+ var globalStore = store("global");
623
+
624
+ // src/lib/globalAtom.ts
625
+ var globalAtom = (defaultValue, options) => {
626
+ const stores = new Set;
627
+ let value;
628
+ let initialized = false;
629
+ let onReset;
630
+ if (options.onSet)
631
+ throw new Error("onSet on globalAtom is currently not supported");
632
+ const onInit = (setSelf2, data) => {
633
+ setSelf2(globalStore.get(atom));
634
+ if (!initialized && options.onInit) {
635
+ onReset = options.onInit((newVal) => {
636
+ setSelf2(newVal);
637
+ value = newVal;
638
+ }, data);
639
+ initialized = true;
640
+ }
641
+ stores.add(data);
642
+ };
643
+ const onSet = (newValue, currentStore) => {
644
+ value = newValue;
645
+ if (stores.size > 1) {
646
+ for (const store2 of stores) {
647
+ if (store2.id !== currentStore.id) {
648
+ setAtom(atom, value, store2, true);
508
649
  }
509
650
  }
510
- throw new Error("Invalid state object passed to set");
511
651
  }
512
652
  };
513
- const reset = (atom3) => resetAtom(atom3, data);
514
- const sub = (state, callback, deepEqualCheckBeforeCallback = true) => subscribe(state, callback, deepEqualCheckBeforeCallback, data);
515
- const txn = (callback) => transaction(callback, data);
653
+ const getSelf = () => globalStore.get(atom);
654
+ const setSelf = (newValue) => globalStore.set(atom, newValue);
655
+ const resetSelf = () => {
656
+ value = undefined;
657
+ initialized = false;
658
+ for (const store2 of stores) {
659
+ if (store2.stateDependencies.has(atom)) {
660
+ throw new Error("TODO: Reset support for stateDependencies");
661
+ }
662
+ store2.values.delete(atom);
663
+ store2.expiredValues.delete(atom);
664
+ propagateUpdatedAtoms([atom], store2);
665
+ stores.delete(store2);
666
+ onReset?.();
667
+ }
668
+ };
669
+ const atom = {
670
+ equal: equal2,
671
+ ...options,
672
+ defaultValue,
673
+ label: options?.label,
674
+ onInit,
675
+ onSet,
676
+ setSelf,
677
+ getSelf,
678
+ resetSelf,
679
+ get stores() {
680
+ return stores;
681
+ }
682
+ };
683
+ return atom;
684
+ };
685
+
686
+ // src/atom.ts
687
+ function atom(defaultValue, options) {
688
+ if (!options)
689
+ return { equal: equal3, defaultValue };
690
+ if (options.global) {
691
+ return globalAtom(defaultValue, options);
692
+ }
693
+ return {
694
+ equal: equal3,
695
+ defaultValue,
696
+ ...options
697
+ };
698
+ }
699
+ // src/atomFamily.ts
700
+ import equal5 from "fast-deep-equal/es6";
701
+
702
+ // src/lib/atomFamilyAtom.ts
703
+ function atomFamilyAtom(defaultValue, options) {
704
+ if (options.global) {
705
+ return globalAtom(defaultValue, options);
706
+ }
516
707
  return {
517
- get,
518
- set,
519
- sub,
520
- txn,
521
- reset,
522
- data
708
+ ...options,
709
+ defaultValue
523
710
  };
711
+ }
712
+
713
+ // src/lib/stableStringify.ts
714
+ var stableStringifyRecurse = (x, key) => {
715
+ if (typeof x === "string" && !x.includes('"') && !x.includes("\\")) {
716
+ return `"${x}"`;
717
+ }
718
+ switch (typeof x) {
719
+ case "undefined":
720
+ return "";
721
+ case "boolean":
722
+ return x ? "true" : "false";
723
+ case "number":
724
+ case "symbol":
725
+ return String(x);
726
+ case "string":
727
+ return JSON.stringify(x);
728
+ case "function":
729
+ return `__FUNCTION(${x.toString()})__`;
730
+ }
731
+ if (x === null) {
732
+ return "null";
733
+ }
734
+ if (typeof x !== "object") {
735
+ return JSON.stringify(x) ?? "";
736
+ }
737
+ if (isPromiseLike(x)) {
738
+ return "__PROMISE__";
739
+ }
740
+ if (Array.isArray(x)) {
741
+ return `[${x.map((v, i) => stableStringifyRecurse(v, i.toString()))}]`;
742
+ }
743
+ if (typeof x.toJSON === "function") {
744
+ return stableStringifyRecurse(x.toJSON(key), key);
745
+ }
746
+ if (x instanceof Map) {
747
+ const obj = {};
748
+ for (const [k, v] of x) {
749
+ obj[typeof k === "string" ? k : stringify(k, opt)] = v;
750
+ }
751
+ return stableStringifyRecurse(obj, key);
752
+ }
753
+ if (x instanceof Set) {
754
+ return stableStringifyRecurse(Array.from(x).sort((a, b) => stableStringifyRecurse(a).localeCompare(stableStringifyRecurse(b))), key);
755
+ }
756
+ if (Symbol !== undefined && x[Symbol.iterator] != null && typeof x[Symbol.iterator] === "function") {
757
+ return stableStringifyRecurse(Array.from(x), key);
758
+ }
759
+ return `{${Object.keys(x).filter((k) => x[k] !== undefined).sort().map((k) => `${stableStringifyRecurse(k)}:${stableStringifyRecurse(x[k], k)}`).join(",")}}`;
760
+ };
761
+ var stableStringify = (x) => {
762
+ if (typeof x === "string" || typeof x === "boolean" || typeof x === "number")
763
+ return x;
764
+ return stableStringifyRecurse(x);
524
765
  };
525
766
 
526
- // src/createStore.ts
527
- var createStore = (id) => {
528
- const data = createStoreData(id);
529
- return storeFromStoreData2(data);
767
+ // src/selector.ts
768
+ import equal4 from "fast-deep-equal/es6";
769
+ var selector = (get, options) => {
770
+ if (!options)
771
+ return { equal: equal4, get };
772
+ return { equal: equal4, ...options, get };
773
+ };
774
+
775
+ // src/atomFamily.ts
776
+ var createOptions = (options = {}, family, familyKey, keyStringified) => {
777
+ if (options.label) {
778
+ return {
779
+ equal: equal5,
780
+ ...options,
781
+ label: options?.label + "_" + keyStringified,
782
+ family,
783
+ familyKey
784
+ };
785
+ } else {
786
+ return { equal: equal5, ...options, family, familyKey };
787
+ }
788
+ };
789
+ var handleDefaultValue = (defaultValue, key) => {
790
+ if (isSelectorFamily(defaultValue))
791
+ return defaultValue(key);
792
+ if (typeof defaultValue === "function")
793
+ return () => defaultValue(key);
794
+ return defaultValue;
530
795
  };
531
- // src/getDefaultStore.ts
532
- if (!globalThis._valdresStore) {
533
- globalThis._valdresStore = createStore("default");
796
+ function atomFamily(defaultValue, options) {
797
+ const map = new Map;
798
+ const atomFamily2 = (key) => {
799
+ const keyStringified = stableStringify(key);
800
+ if (map.has(keyStringified)) {
801
+ return map.get(keyStringified);
802
+ }
803
+ const familyAtom = atomFamilyAtom(handleDefaultValue(defaultValue, key), createOptions(options, atomFamily2, Object.freeze(key), keyStringified));
804
+ map.set(keyStringified, familyAtom);
805
+ return familyAtom;
806
+ };
807
+ atomFamily2.__valdresAtomFamilyMap = map;
808
+ atomFamily2.release = (key) => map.delete(key);
809
+ const keysAtom = atom(new Set);
810
+ atomFamily2.__keysAtom = keysAtom;
811
+ atomFamily2.__keysSelector = selector((get) => Array.from(get(keysAtom)));
812
+ if (options?.label)
813
+ atomFamily2.label = options.label;
814
+ return atomFamily2;
534
815
  }
535
- var getDefaultStore = () => globalThis._valdresStore;
536
- var resetDefaultStore = () => globalThis._valdresStore = createStore();
537
- // src/selector.ts
538
- var selector = (get, debugLabel) => ({
539
- get,
540
- debugLabel
541
- });
816
+ // src/createStoreWithSelectorSet.ts
817
+ var setSelector = (selector2, values, store2) => {
818
+ return selector2.set(store2.set, store2.get, store2.reset, ...values);
819
+ };
820
+ var createStoreWithSelectorSet = (id) => {
821
+ const data = createStoreData(id);
822
+ const store2 = storeFromStoreData(data);
823
+ store2.set = (state, value, ...rest) => {
824
+ if (isAtom(state))
825
+ return setAtom(state, value, data);
826
+ if (isSelector(state))
827
+ return setSelector(state, [value, ...rest], store2);
828
+ throw new Error("Invalid state object");
829
+ };
830
+ store2.kind = "storeWithSelectorSet";
831
+ return store2;
832
+ };
542
833
  // src/selectorFamily.ts
543
- var selectorFamily = (get, debugLabel) => {
834
+ import equal6 from "fast-deep-equal/es6";
835
+ var createOptions2 = (options = {}, family, familyKey, keyStringified) => {
836
+ if (options.label) {
837
+ return {
838
+ equal: equal6,
839
+ ...options,
840
+ label: options?.label + "_" + keyStringified,
841
+ family,
842
+ familyKey
843
+ };
844
+ } else {
845
+ return { equal: equal6, ...options, family, familyKey };
846
+ }
847
+ };
848
+ var selectorFamily = (get, options) => {
544
849
  const map = new Map;
545
850
  const selectorFamily2 = (key) => {
546
- let keyStringified;
547
- try {
548
- keyStringified = stableStringify(key);
549
- } catch (e) {
550
- console.log(`errro`, { key, debugLabel, e });
551
- throw e;
552
- }
851
+ const keyStringified = stableStringify(key);
553
852
  if (map.has(keyStringified))
554
853
  return map.get(keyStringified);
555
- const selectorDebugLabel = debugLabel ? debugLabel + "_" + keyStringified : undefined;
556
- const newSelector = selector((selectorArgs) => get(key)(selectorArgs), selectorDebugLabel);
557
- newSelector.family = selectorFamily2;
854
+ const newSelector = selector((selectorArgs) => get(key)(selectorArgs), createOptions2(options, selectorFamily2, key, keyStringified));
558
855
  map.set(keyStringified, newSelector);
559
856
  return newSelector;
560
857
  };
561
- selectorFamily2._map = map;
858
+ selectorFamily2.__valdresSelectorFamilyMap = map;
859
+ if (options?.label)
860
+ selectorFamily2.label = options.label;
562
861
  return selectorFamily2;
563
862
  };
863
+ // src/utils/isFamilySelector.ts
864
+ var isFamilySelector = (state) => isFamilyState(state) && isSelector(state);
564
865
  export {
866
+ store,
565
867
  selectorFamily,
566
868
  selector,
567
- resetDefaultStore,
869
+ isSelectorFamily,
568
870
  isSelector,
569
871
  isPromiseLike,
872
+ isFamilyState,
873
+ isFamilySelector,
874
+ isFamilyAtom,
570
875
  isFamily,
876
+ isAtomFamily,
571
877
  isAtom,
572
- getDefaultStore,
573
- createStore,
878
+ createStoreWithSelectorSet,
574
879
  atomFamily,
575
880
  atom
576
881
  };