valdres 0.2.0-alpha.30 → 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.
package/dist/index.js CHANGED
@@ -1,3 +1,9 @@
1
+ // src/atom.ts
2
+ import equal3 from "fast-deep-equal/es6";
3
+
4
+ // src/lib/globalAtom.ts
5
+ import equal2 from "fast-deep-equal/es6";
6
+
1
7
  // src/utils/isAtom.ts
2
8
  var isAtom = (state) => Object.hasOwn(state, "defaultValue");
3
9
 
@@ -7,42 +13,137 @@ var isFamilyState = (state) => state && Object.hasOwn(state, "family");
7
13
  // src/utils/isFamilyAtom.ts
8
14
  var isFamilyAtom = (state) => isFamilyState(state) && isAtom(state);
9
15
 
16
+ // src/lib/updateStateSubscribers.ts
17
+ var updateStateSubscribers = (state, data) => {
18
+ const subscribtions = data.subscriptions.get(state);
19
+ if (subscribtions?.size) {
20
+ for (const subscribtion of subscribtions) {
21
+ subscribtion.callback();
22
+ }
23
+ }
24
+ if (isFamilyState(state)) {
25
+ const familySubscriptions = data.subscriptions.get(state.family);
26
+ if (familySubscriptions?.size) {
27
+ for (const subscribtion of familySubscriptions) {
28
+ subscribtion.callback(state.familyKey);
29
+ }
30
+ }
31
+ }
32
+ };
33
+
10
34
  // src/utils/isPromiseLike.ts
11
35
  var isPromiseLike = (object) => {
12
36
  return object && object.then && typeof object.then === "function";
13
37
  };
14
38
 
15
- // src/utils/isSelector.ts
16
- var isSelector = (state) => state && Object.hasOwn(state, "get");
17
-
18
39
  // src/lib/getState.ts
19
- import equal2 from "fast-deep-equal/es6";
40
+ import equal from "fast-deep-equal/es6";
20
41
 
21
42
  // src/utils/isAtomFamily.ts
22
43
  var isAtomFamily = (state) => state && Object.hasOwn(state, "__valdresAtomFamilyMap");
23
44
 
45
+ // src/utils/isSelector.ts
46
+ var isSelector = (state) => state && Object.hasOwn(state, "get");
47
+
24
48
  // src/utils/isSelectorFamily.ts
25
49
  var isSelectorFamily = (state) => state && Object.hasOwn(state, "__valdresSelectorFamilyMap");
26
50
 
27
- // src/lib/initSelector.ts
28
- import equal from "fast-deep-equal/es6";
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
+ };
29
69
 
30
- // src/lib/updateStateSubscribers.ts
31
- var updateStateSubscribers = (state, data) => {
32
- const subscribtions = data.subscriptions.get(state);
33
- if (subscribtions?.size) {
34
- for (const subscribtion of subscribtions) {
35
- subscribtion.callback();
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
+ });
36
87
  }
88
+ return value;
89
+ } else if (isSelector(atom.defaultValue)) {
90
+ return getState(atom.defaultValue, data);
91
+ } else {
92
+ return atom.defaultValue;
37
93
  }
38
- if (isFamilyState(state)) {
39
- const familySubscriptions = data.subscriptions.get(state.family);
40
- if (familySubscriptions?.size) {
41
- for (const subscribtion of familySubscriptions) {
42
- subscribtion.callback(state.familyKey);
43
- }
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);
44
104
  }
45
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);
46
147
  };
47
148
 
48
149
  // src/lib/initSelector.ts
@@ -113,7 +214,7 @@ var initSelector = (selector, data) => {
113
214
  const value = handleSelectorResult(tmpValue, selector, data);
114
215
  if (data.expiredValues.has(selector)) {
115
216
  const expiredValue = data.expiredValues.get(selector);
116
- if (equal(expiredValue, value)) {
217
+ if (selector.equal(expiredValue, value)) {
117
218
  data.values.set(selector, expiredValue);
118
219
  return expiredValue;
119
220
  }
@@ -122,43 +223,7 @@ var initSelector = (selector, data) => {
122
223
  return value;
123
224
  };
124
225
 
125
- // src/lib/getState.ts
126
- function getState(state, data) {
127
- if (data.values.has(state))
128
- return data.values.get(state);
129
- if (isAtom(state)) {
130
- if ("parent" in data)
131
- return getState(state, data.parent);
132
- return initAtom(state, data);
133
- }
134
- if (isSelector(state))
135
- return initSelector(state, data);
136
- if (isAtomFamily(state)) {
137
- if ("parent" in data) {
138
- const closestData = findClosestStoreWithAtomInitialized(state.__keysAtom, data);
139
- return getState(state.__keysSelector, closestData);
140
- }
141
- return getState(state.__keysSelector, data);
142
- }
143
- if (isSelectorFamily(state)) {
144
- const array = Array.from(state.__valdresSelectorFamilyMap.keys());
145
- if (equal2(array, state._keyArray))
146
- return state._keyArray;
147
- state._keyArray = array;
148
- return array;
149
- }
150
- throw new Error("Invalid object passed to get");
151
- }
152
- var findClosestStoreWithAtomInitialized = (atom, data) => {
153
- if ("parent" in data === false)
154
- return data;
155
- if (data.values.has(atom))
156
- return data;
157
- return findClosestStoreWithAtomInitialized(atom, data.parent);
158
- };
159
-
160
226
  // src/lib/updateSelectorSubscribers.ts
161
- import equal3 from "fast-deep-equal/es6";
162
227
  var updateSelectorSubscribers = (selector, data) => {
163
228
  const subscribtions = data.subscriptions.get(selector);
164
229
  const familySubscriptions = selector.family && data.subscriptions.get(selector.family);
@@ -168,7 +233,7 @@ var updateSelectorSubscribers = (selector, data) => {
168
233
  try {
169
234
  const oldValue = data.expiredValues.get(selector);
170
235
  const newValue = initSelector(selector, data);
171
- if (equal3(newValue, oldValue))
236
+ if (selector.equal(newValue, oldValue))
172
237
  return;
173
238
  } catch (e) {
174
239
  }
@@ -203,291 +268,24 @@ var propagateUpdatedAtoms = (atoms, data) => {
203
268
  const clearedSelectors = new Set;
204
269
  for (const atom of atoms) {
205
270
  const consumers = data.stateConsumers.get(atom);
206
- if (consumers && consumers.size) {
207
- recursivlyResetSelectorTree(consumers, data, clearedSelectors);
208
- }
209
- if (isFamilyAtom(atom)) {
210
- const consumersFamily = data.stateConsumers.get(atom.family);
211
- if (consumersFamily?.size) {
212
- recursivlyResetSelectorTree(consumersFamily, data, clearedSelectors);
213
- }
214
- }
215
- }
216
- for (const selector of clearedSelectors) {
217
- updateSelectorSubscribers(selector, data);
218
- }
219
- for (const atom of atoms) {
220
- updateStateSubscribers(atom, data);
221
- }
222
- };
223
-
224
- // src/lib/setAtom.ts
225
- import equal4 from "fast-deep-equal/es6";
226
- var setAtom = (atom, newValue, data, skipOnSet = false) => {
227
- const currentValue = getState(atom, data);
228
- if (typeof newValue === "function") {
229
- newValue = newValue(currentValue);
230
- if (isPromiseLike(newValue) || isPromiseLike(currentValue))
231
- throw new Error("Todo, how should we handle this?");
232
- }
233
- if (equal4(currentValue, newValue))
234
- return;
235
- data.values.set(atom, newValue);
236
- if (atom.onSet && !skipOnSet)
237
- atom.onSet(newValue, data);
238
- if (currentValue?.__isEmptyAtomPromise__) {
239
- currentValue.__resolveEmptyAtomPromise__(newValue);
240
- }
241
- propagateUpdatedAtoms([atom], data);
242
- };
243
-
244
- // src/lib/initAtom.ts
245
- var getAtomInitValue = (atom, data) => {
246
- if (atom.defaultValue === undefined) {
247
- let promiseResolve;
248
- const promise = new Promise((resolve) => {
249
- promiseResolve = resolve;
250
- });
251
- promise.__isEmptyAtomPromise__ = true;
252
- promise.__resolveEmptyAtomPromise__ = promiseResolve;
253
- return promise;
254
- } else if (typeof atom.defaultValue === "function") {
255
- const value = atom.defaultValue();
256
- if (isPromiseLike(value)) {
257
- value.then((resolvedValue) => {
258
- data.values.set(atom, resolvedValue);
259
- propagateUpdatedAtoms([atom], data);
260
- });
261
- }
262
- return value;
263
- } else if (isSelector(atom.defaultValue)) {
264
- return getState(atom.defaultValue, data);
265
- } else {
266
- return atom.defaultValue;
267
- }
268
- };
269
- var initAtom = (atom, data) => {
270
- let value = getAtomInitValue(atom, data);
271
- data.values.set(atom, value);
272
- if (isFamilyAtom(atom)) {
273
- const currentKeySet = getState(atom.family.__keysAtom, data);
274
- if (!currentKeySet.has(atom.familyKey)) {
275
- const newSet = new Set(currentKeySet);
276
- newSet.add(atom.familyKey);
277
- setAtom(atom.family.__keysAtom, newSet, data);
278
- }
279
- }
280
- if (atom.onInit)
281
- atom.onInit((newVal) => {
282
- value = newVal;
283
- setAtom(atom, newVal, data, true);
284
- }, data);
285
- return value;
286
- };
287
-
288
- // src/lib/globalAtom.ts
289
- var getFirstItemInSet = (set) => {
290
- for (let item of set) {
291
- return item;
292
- }
293
- throw new Error("Non Empty Set");
294
- };
295
- var globalAtom = (defaultValue, options) => {
296
- const stores = new Set;
297
- let value = defaultValue;
298
- let initialized = false;
299
- let onReset;
300
- if (options.onSet)
301
- throw new Error("onSet on globalAtom is currently not supported");
302
- const onInit = (setSelf2, data) => {
303
- if (!initialized) {
304
- if (value === defaultValue) {
305
- value = getAtomInitValue(atom, data);
306
- }
307
- setSelf2(value);
308
- initialized = true;
309
- if (options.onInit) {
310
- onReset = options.onInit((newVal) => {
311
- setSelf2(newVal);
312
- value = newVal;
313
- }, data);
314
- }
315
- } else {
316
- setSelf2(value);
317
- }
318
- stores.add(data);
319
- };
320
- const onSet = (newValue, currentStore) => {
321
- value = newValue;
322
- if (stores.size > 1) {
323
- for (const store of stores) {
324
- if (store.id !== currentStore.id) {
325
- setAtom(atom, value, store, true);
326
- }
327
- }
328
- }
329
- };
330
- const setSelf = (newValue) => {
331
- value = newValue;
332
- if (stores.size > 0) {
333
- getFirstItemInSet(stores);
334
- const store = getFirstItemInSet(stores);
335
- setAtom(atom, newValue, store);
336
- }
337
- };
338
- const resetSelf = () => {
339
- value = defaultValue;
340
- initialized = false;
341
- for (const store of stores) {
342
- if (store.stateDependencies.has(atom)) {
343
- throw new Error("TODO: Reset support for stateDependencies");
344
- }
345
- store.values.delete(atom);
346
- store.expiredValues.delete(atom);
347
- propagateUpdatedAtoms([atom], store);
348
- stores.delete(store);
349
- onReset?.();
350
- }
351
- };
352
- const atom = {
353
- ...options,
354
- defaultValue,
355
- label: options?.label,
356
- onInit,
357
- onSet,
358
- setSelf,
359
- resetSelf,
360
- get currentValue() {
361
- return value;
362
- }
363
- };
364
- return atom;
365
- };
366
-
367
- // src/atom.ts
368
- function atom(defaultValue, options) {
369
- if (!options)
370
- return { defaultValue };
371
- if (options.global) {
372
- return globalAtom(defaultValue, options);
373
- }
374
- return {
375
- defaultValue,
376
- ...options
377
- };
378
- }
379
- // src/lib/atomFamilyAtom.ts
380
- function atomFamilyAtom(defaultValue, options) {
381
- if (options.global) {
382
- return globalAtom(defaultValue, options);
383
- }
384
- return {
385
- ...options,
386
- defaultValue
387
- };
388
- }
389
-
390
- // src/lib/stableStringify.ts
391
- var stableStringifyRecurse = (x, key) => {
392
- if (typeof x === "string" && !x.includes('"') && !x.includes("\\")) {
393
- return `"${x}"`;
394
- }
395
- switch (typeof x) {
396
- case "undefined":
397
- return "";
398
- case "boolean":
399
- return x ? "true" : "false";
400
- case "number":
401
- case "symbol":
402
- return String(x);
403
- case "string":
404
- return JSON.stringify(x);
405
- case "function":
406
- return `__FUNCTION(${x.toString()})__`;
407
- }
408
- if (x === null) {
409
- return "null";
410
- }
411
- if (typeof x !== "object") {
412
- return JSON.stringify(x) ?? "";
413
- }
414
- if (isPromiseLike(x)) {
415
- return "__PROMISE__";
416
- }
417
- if (Array.isArray(x)) {
418
- return `[${x.map((v, i) => stableStringifyRecurse(v, i.toString()))}]`;
419
- }
420
- if (typeof x.toJSON === "function") {
421
- return stableStringifyRecurse(x.toJSON(key), key);
422
- }
423
- if (x instanceof Map) {
424
- const obj = {};
425
- for (const [k, v] of x) {
426
- obj[typeof k === "string" ? k : stringify(k, opt)] = v;
271
+ if (consumers && consumers.size) {
272
+ recursivlyResetSelectorTree(consumers, data, clearedSelectors);
273
+ }
274
+ if (isFamilyAtom(atom)) {
275
+ const consumersFamily = data.stateConsumers.get(atom.family);
276
+ if (consumersFamily?.size) {
277
+ recursivlyResetSelectorTree(consumersFamily, data, clearedSelectors);
278
+ }
427
279
  }
428
- return stableStringifyRecurse(obj, key);
429
280
  }
430
- if (x instanceof Set) {
431
- return stableStringifyRecurse(Array.from(x).sort((a, b) => stableStringifyRecurse(a).localeCompare(stableStringifyRecurse(b))), key);
281
+ for (const selector of clearedSelectors) {
282
+ updateSelectorSubscribers(selector, data);
432
283
  }
433
- if (Symbol !== undefined && x[Symbol.iterator] != null && typeof x[Symbol.iterator] === "function") {
434
- return stableStringifyRecurse(Array.from(x), key);
284
+ for (const atom of atoms) {
285
+ updateStateSubscribers(atom, data);
435
286
  }
436
- return `{${Object.keys(x).filter((k) => x[k] !== undefined).sort().map((k) => `${stableStringifyRecurse(k)}:${stableStringifyRecurse(x[k], k)}`).join(",")}}`;
437
- };
438
- var stableStringify = (x) => {
439
- if (typeof x === "string" || typeof x === "boolean" || typeof x === "number")
440
- return x;
441
- return stableStringifyRecurse(x);
442
- };
443
-
444
- // src/selector.ts
445
- var selector = (get, options) => {
446
- if (!options)
447
- return { get };
448
- return { ...options, get };
449
287
  };
450
288
 
451
- // src/atomFamily.ts
452
- var createOptions = (options = {}, family, familyKey, keyStringified) => {
453
- if (options.label) {
454
- return {
455
- ...options,
456
- label: options?.label + "_" + keyStringified,
457
- family,
458
- familyKey
459
- };
460
- } else {
461
- return { ...options, family, familyKey };
462
- }
463
- };
464
- var handleDefaultValue = (defaultValue, key) => {
465
- if (isSelectorFamily(defaultValue))
466
- return defaultValue(key);
467
- if (typeof defaultValue === "function")
468
- return () => defaultValue(key);
469
- return defaultValue;
470
- };
471
- function atomFamily(defaultValue, options) {
472
- const map = new Map;
473
- const atomFamily2 = (key) => {
474
- const keyStringified = stableStringify(key);
475
- if (map.has(keyStringified)) {
476
- return map.get(keyStringified);
477
- }
478
- const familyAtom = atomFamilyAtom(handleDefaultValue(defaultValue, key), createOptions(options, atomFamily2, Object.freeze(key), keyStringified));
479
- map.set(keyStringified, familyAtom);
480
- return familyAtom;
481
- };
482
- atomFamily2.__valdresAtomFamilyMap = map;
483
- atomFamily2.release = (key) => map.delete(key);
484
- const keysAtom = atom(new Set);
485
- atomFamily2.__keysAtom = keysAtom;
486
- atomFamily2.__keysSelector = selector((get) => Array.from(get(keysAtom)));
487
- if (options?.label)
488
- atomFamily2.label = options.label;
489
- return atomFamily2;
490
- }
491
289
  // src/lib/createStoreData.ts
492
290
  var generateId = () => (Math.random() + 1).toString(36).substring(7);
493
291
  var generateStoreData = (id = generateId()) => {
@@ -515,11 +313,11 @@ function createStoreData(id, parent) {
515
313
  }
516
314
 
517
315
  // src/lib/resetAtom.ts
518
- var resetAtom = (atom2, data) => {
519
- let value = getAtomInitValue(atom2, data);
520
- data.values.set(atom2, value);
316
+ var resetAtom = (atom, data) => {
317
+ let value = getAtomInitValue(atom, data);
318
+ data.values.set(atom, value);
521
319
  if (!isPromiseLike(value)) {
522
- propagateUpdatedAtoms([atom2], data);
320
+ propagateUpdatedAtoms([atom], data);
523
321
  }
524
322
  return value;
525
323
  };
@@ -566,18 +364,24 @@ var initSubscribers = (state, data) => {
566
364
  return set;
567
365
  };
568
366
  var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) => {
367
+ let parentUnsubscribe;
569
368
  if ("parent" in data && !data.values.has(state) && isAtom(state)) {
570
- const parentUnsubscribe = subscribe(state, callback, requireDeepEqualCheckBeforeCallback, data.parent);
571
- let originalCallback = callback;
369
+ const originalCallback = callback;
370
+ parentUnsubscribe = subscribe(state, originalCallback, requireDeepEqualCheckBeforeCallback, data.parent);
572
371
  callback = () => {
573
- parentUnsubscribe();
372
+ if (parentUnsubscribe) {
373
+ parentUnsubscribe();
374
+ parentUnsubscribe = undefined;
375
+ }
574
376
  originalCallback();
575
377
  };
378
+ } else if (!data.values.has(state) && isAtom(state)) {
379
+ initAtom(state, data);
576
380
  }
577
- const subscribers = data.subscriptions.get(state) || initSubscribers(state, data);
578
381
  if (isSelector(state) && !data.values.has(state)) {
579
382
  initSelector(state, data);
580
383
  }
384
+ const subscribers = data.subscriptions.get(state) || initSubscribers(state, data);
581
385
  let subscription;
582
386
  if (isFamily(state)) {
583
387
  subscription = {
@@ -636,20 +440,24 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
636
440
  if (requireDeepEqualCheckBeforeCallback && data.subscriptionsRequireEqualCheck.get(state) !== true) {
637
441
  data.subscriptionsRequireEqualCheck.set(state, true);
638
442
  }
639
- return () => unsubscribe(state, subscription, data, mount, maxAgeCleanup);
443
+ return () => {
444
+ if (parentUnsubscribe) {
445
+ parentUnsubscribe();
446
+ }
447
+ unsubscribe(state, subscription, data, mount, maxAgeCleanup);
448
+ };
640
449
  };
641
450
 
642
451
  // src/lib/setAtoms.ts
643
- import equal5 from "fast-deep-equal/es6";
644
452
  var setAtoms = (pairs, data) => {
645
453
  const updatedAtoms = [];
646
- for (let [atom2, value] of pairs) {
647
- const currentValue = getState(atom2, data);
648
- if (!equal5(currentValue, value)) {
649
- updatedAtoms.push(atom2);
650
- if (atom2.onSet)
651
- atom2.onSet(value, data);
652
- data.values.set(atom2, 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);
653
461
  }
654
462
  }
655
463
  propagateUpdatedAtoms(updatedAtoms, data);
@@ -705,25 +513,25 @@ var transaction = (callback, data) => {
705
513
  throw new Error("Unsupported state");
706
514
  }
707
515
  };
708
- const txnSet = (atom2, value) => {
709
- if (!isAtom(atom2))
516
+ const txnSet = (atom, value) => {
517
+ if (!isAtom(atom))
710
518
  throw new Error("Not an atom");
711
519
  if (typeof value === "function") {
712
- const currentValue = txnGet(atom2);
520
+ const currentValue = txnGet(atom);
713
521
  value = value(currentValue);
714
522
  }
715
- for (const selector2 of findDependencies(atom2, data)) {
716
- dirtySelectors.add(selector2);
717
- txnSelectorCache.delete(selector2);
523
+ for (const selector of findDependencies(atom, data)) {
524
+ dirtySelectors.add(selector);
525
+ txnSelectorCache.delete(selector);
718
526
  }
719
- if (txnSubscribers.get(atom2)?.size) {
720
- recursivlyResetTxnSelectorCache(atom2, txnSubscribers, txnSelectorCache);
527
+ if (txnSubscribers.get(atom)?.size) {
528
+ recursivlyResetTxnSelectorCache(atom, txnSubscribers, txnSelectorCache);
721
529
  }
722
- txnAtomMap.set(atom2, value);
530
+ txnAtomMap.set(atom, value);
723
531
  };
724
- const txnReset = (atom2) => {
725
- const value = getAtomInitValue(atom2, data);
726
- txnAtomMap.set(atom2, value);
532
+ const txnReset = (atom) => {
533
+ const value = getAtomInitValue(atom, data);
534
+ txnAtomMap.set(atom, value);
727
535
  return value;
728
536
  };
729
537
  const commit = () => {
@@ -752,7 +560,7 @@ function storeFromStoreData(data, detach) {
752
560
  throw new Error(SelectorProvidedToSetError);
753
561
  throw new Error(InvalidStateSetError);
754
562
  };
755
- const reset = (atom2) => resetAtom(atom2, data);
563
+ const reset = (atom) => resetAtom(atom, data);
756
564
  const sub = (state, callback, deepEqualCheckBeforeCallback = true) => subscribe(state, callback, deepEqualCheckBeforeCallback, data);
757
565
  const txn = (callback) => transaction(callback, data);
758
566
  const scope = (scopeId) => {
@@ -797,32 +605,244 @@ function storeFromStoreData(data, detach) {
797
605
  }
798
606
  }
799
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);
649
+ }
650
+ }
651
+ }
652
+ };
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
+ }
707
+ return {
708
+ ...options,
709
+ defaultValue
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);
765
+ };
766
+
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;
795
+ };
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;
815
+ }
800
816
  // src/createStoreWithSelectorSet.ts
801
- var setSelector = (selector2, values, store) => {
802
- return selector2.set(store.set, store.get, store.reset, ...values);
817
+ var setSelector = (selector2, values, store2) => {
818
+ return selector2.set(store2.set, store2.get, store2.reset, ...values);
803
819
  };
804
820
  var createStoreWithSelectorSet = (id) => {
805
821
  const data = createStoreData(id);
806
- const store = storeFromStoreData(data);
807
- store.set = (state, value, ...rest) => {
822
+ const store2 = storeFromStoreData(data);
823
+ store2.set = (state, value, ...rest) => {
808
824
  if (isAtom(state))
809
825
  return setAtom(state, value, data);
810
826
  if (isSelector(state))
811
- return setSelector(state, [value, ...rest], store);
827
+ return setSelector(state, [value, ...rest], store2);
812
828
  throw new Error("Invalid state object");
813
829
  };
814
- store.kind = "storeWithSelectorSet";
815
- return store;
830
+ store2.kind = "storeWithSelectorSet";
831
+ return store2;
816
832
  };
817
833
  // src/selectorFamily.ts
818
- var createOptions2 = (options, key) => {
834
+ import equal6 from "fast-deep-equal/es6";
835
+ var createOptions2 = (options = {}, family, familyKey, keyStringified) => {
819
836
  if (options.label) {
820
837
  return {
838
+ equal: equal6,
821
839
  ...options,
822
- label: options?.label + "_" + key
840
+ label: options?.label + "_" + keyStringified,
841
+ family,
842
+ familyKey
823
843
  };
824
844
  } else {
825
- return options;
845
+ return { equal: equal6, ...options, family, familyKey };
826
846
  }
827
847
  };
828
848
  var selectorFamily = (get, options) => {
@@ -831,8 +851,7 @@ var selectorFamily = (get, options) => {
831
851
  const keyStringified = stableStringify(key);
832
852
  if (map.has(keyStringified))
833
853
  return map.get(keyStringified);
834
- const newSelector = selector((selectorArgs) => get(key)(selectorArgs), options ? createOptions2(options, keyStringified) : undefined);
835
- newSelector.family = selectorFamily2;
854
+ const newSelector = selector((selectorArgs) => get(key)(selectorArgs), createOptions2(options, selectorFamily2, key, keyStringified));
836
855
  map.set(keyStringified, newSelector);
837
856
  return newSelector;
838
857
  };
@@ -841,11 +860,6 @@ var selectorFamily = (get, options) => {
841
860
  selectorFamily2.label = options.label;
842
861
  return selectorFamily2;
843
862
  };
844
- // src/store.ts
845
- var store = (id) => {
846
- const data = createStoreData(id);
847
- return storeFromStoreData(data);
848
- };
849
863
  // src/utils/isFamilySelector.ts
850
864
  var isFamilySelector = (state) => isFamilyState(state) && isSelector(state);
851
865
  export {
@@ -15,6 +15,7 @@ export { isSelector } from "./src/utils/isSelector";
15
15
  export { isSelectorFamily } from "./src/utils/isSelectorFamily";
16
16
  export type { Atom } from "./src/types/Atom";
17
17
  export type { AtomFamily } from "./src/types/AtomFamily";
18
+ export type { FamilyKey } from "./src/types/FamilyKey";
18
19
  export type { GetValue } from "./src/types/GetValue";
19
20
  export type { GlobalAtom } from "./src/types/GlobalAtom";
20
21
  export type { ResetAtom } from "./src/types/ResetAtom";
@@ -1,4 +1,4 @@
1
1
  import type { AtomDefaultValue } from "../types/AtomDefaultValue";
2
2
  import type { AtomOptions } from "./../types/AtomOptions";
3
3
  import type { GlobalAtom } from "./../types/GlobalAtom";
4
- export declare const globalAtom: <Value = any>(defaultValue: AtomDefaultValue<Value>, options: AtomOptions<Value>) => GlobalAtom<Value>;
4
+ export declare const globalAtom: <Value = unknown>(defaultValue: AtomDefaultValue<Value>, options: AtomOptions<Value>) => GlobalAtom<Value>;
@@ -0,0 +1 @@
1
+ export declare const globalStore: import("../..").Store;
@@ -1,4 +1,4 @@
1
1
  import type { Family } from "../types/Family";
2
2
  import type { State } from "../types/State";
3
3
  import type { StoreData } from "../types/StoreData";
4
- export declare const subscribe: <V>(state: State<V> | Family<V>, callback: any, requireDeepEqualCheckBeforeCallback: boolean, data: StoreData) => () => void;
4
+ export declare const subscribe: <V>(state: State<V> | Family<V>, callback: () => void, requireDeepEqualCheckBeforeCallback: boolean, data: StoreData) => () => void;
@@ -1,4 +1,4 @@
1
1
  import type { GetValue } from "./types/GetValue";
2
2
  import type { Selector } from "./types/Selector";
3
3
  import type { SelectorOptions } from "./types/SelectorOptions";
4
- export declare const selector: <Value, FamilyKey = undefined>(get: (get: GetValue, storeId: string) => Value, options?: SelectorOptions) => Selector<Value, FamilyKey>;
4
+ export declare const selector: <Value, FamilyKey = undefined>(get: (get: GetValue, storeId: string) => Value, options?: SelectorOptions<Value>) => Selector<Value, FamilyKey>;
@@ -1,3 +1,4 @@
1
1
  import type { SelectorFamily } from "./types/SelectorFamily";
2
2
  import type { SelectorOptions } from "./types/SelectorOptions";
3
- export declare const selectorFamily: <Key, Value>(get: any, options?: SelectorOptions) => SelectorFamily<Key, Value>;
3
+ import type { GetValue } from "./types/GetValue";
4
+ export declare const selectorFamily: <Key, Value>(get: (key: Key) => (get: GetValue) => Value, options?: SelectorOptions<Value>) => SelectorFamily<Key, Value>;
@@ -1,7 +1,9 @@
1
1
  import type { AtomDefaultValue } from "./AtomDefaultValue";
2
2
  import type { AtomOnInit } from "./AtomOnInit";
3
3
  import type { AtomOnSet } from "./AtomOnSet";
4
+ import type { EqualFunc } from "./EqualFunc";
4
5
  export type Atom<Value = unknown> = {
6
+ equal: EqualFunc<Value>;
5
7
  defaultValue?: AtomDefaultValue<Value>;
6
8
  label?: string;
7
9
  onInit?: AtomOnInit<Value>;
@@ -1,4 +1,5 @@
1
1
  import type { AtomOnSet } from "./AtomOnSet";
2
+ import type { EqualFunc } from "./EqualFunc";
2
3
  import type { StoreData } from "./StoreData";
3
4
  export type AtomOptions<Value = unknown> = {
4
5
  global?: boolean;
@@ -8,4 +9,5 @@ export type AtomOptions<Value = unknown> = {
8
9
  onMount?: () => () => void;
9
10
  maxAge?: number;
10
11
  staleWhileRevalidate?: number;
12
+ equal?: EqualFunc<Value>;
11
13
  };
@@ -0,0 +1 @@
1
+ export type EqualFunc<Value> = (a: Value, b: Value) => boolean;
@@ -2,7 +2,7 @@ import type { Atom } from "./Atom";
2
2
  import type { AtomFamily } from "./AtomFamily";
3
3
  import type { Selector } from "./Selector";
4
4
  export type GetValue = {
5
- <V>(atom: Atom<V>, scopeId?: string): V;
6
- <V>(selector: Selector<V>, scopeId?: string): V;
7
- <V, K>(family: AtomFamily<K, V>, scopeId?: string): K[];
5
+ <V>(atom: Atom<V>): V;
6
+ <V>(selector: Selector<V>): V;
7
+ <V, K>(family: AtomFamily<K, V>): K[];
8
8
  };
@@ -1,7 +1,11 @@
1
1
  import type { Atom } from "./Atom";
2
- import type { GlobalAtomSetSelfFunc } from "./GlobalAtomSetSelfFunc";
2
+ import type { GlobalAtomGetSelfFunc } from "./GlobalAtomGetSelfFunc";
3
3
  import type { GlobalAtomResetSelfFunc } from "./GlobalAtomResetSelfFunc";
4
+ import type { GlobalAtomSetSelfFunc } from "./GlobalAtomSetSelfFunc";
5
+ import type { StoreData } from "./StoreData";
4
6
  export type GlobalAtom<Value = unknown> = Atom<Value> & {
5
7
  setSelf: GlobalAtomSetSelfFunc<Value>;
6
8
  resetSelf: GlobalAtomResetSelfFunc;
9
+ getSelf: GlobalAtomGetSelfFunc<Value>;
10
+ stores: Set<StoreData>;
7
11
  };
@@ -0,0 +1 @@
1
+ export type GlobalAtomGetSelfFunc<Value = unknown> = () => Value;
@@ -1,7 +1,9 @@
1
+ import type { EqualFunc } from "./EqualFunc";
1
2
  import type { GetValue } from "./GetValue";
2
3
  import type { SelectorFamily } from "./SelectorFamily";
3
4
  export type Selector<Value = unknown, FamilyKey = undefined> = {
4
5
  get: (get: GetValue, storeId: string) => Value;
6
+ equal: EqualFunc<Value>;
5
7
  label?: string;
6
8
  family?: SelectorFamily<FamilyKey, Value>;
7
9
  familyKey?: FamilyKey;
@@ -1,3 +1,5 @@
1
- export type SelectorOptions = {
1
+ import type { EqualFunc } from "./EqualFunc";
2
+ export type SelectorOptions<Value> = {
2
3
  label?: string;
4
+ equal?: EqualFunc<Value>;
3
5
  };
@@ -1,3 +1,4 @@
1
1
  import type { Atom } from "./Atom";
2
+ import type { AtomFamily } from "./AtomFamily";
2
3
  import type { Selector } from "./Selector";
3
- export type State<V = any> = Atom<V> | Selector<V>;
4
+ export type State<K = any, V = any> = Atom<V> | Selector<V> | AtomFamily<K, V>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "valdres",
3
- "version": "0.2.0-alpha.30",
3
+ "version": "0.2.0-alpha.31",
4
4
  "license": "MIT",
5
5
  "author": {
6
6
  "name": "Eigil Sagafos"
@@ -33,11 +33,11 @@
33
33
  "react": ">=18",
34
34
  "react-dom": ">=18",
35
35
  "recoil": "0.7.7",
36
- "typescript": "5.6.2"
36
+ "typescript": "5.6.3"
37
37
  },
38
38
  "publishConfig": {
39
39
  "access": "public",
40
40
  "registry": "https://registry.npmjs.org/"
41
41
  },
42
- "gitHead": "5b94699fe0e875ccfd7e95e535bec8a7ecedcb30"
42
+ "gitHead": "7196fb6f087130428b9b0c2ea76b9d1690b45fb4"
43
43
  }