valdres 0.2.0-pre.2 → 0.2.0-pre.20

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
@@ -187,7 +187,7 @@ var isProd = () => {
187
187
 
188
188
  // src/lib/setValueInData.ts
189
189
  var setValueInData = (atom, value, data) => {
190
- if (isProd()) {
190
+ if (atom.mutable || isProd()) {
191
191
  data.values.set(atom, value);
192
192
  return value;
193
193
  } else {
@@ -278,7 +278,7 @@ function getState(state, data, initializedAtomsSet, circularDependencySet) {
278
278
  const closestData = findClosestStoreWithAtomInitialized(state, data);
279
279
  return getState(state, closestData, initializedAtomsSet, circularDependencySet);
280
280
  }
281
- data.values.set(state, []);
281
+ data.values.set(state, renderAtomFamilyIndex(createAtomFamilyIndex()));
282
282
  initializedAtomsSet.add(state);
283
283
  return data.values.get(state);
284
284
  }
@@ -422,30 +422,140 @@ var addSetToSet = (fromSet, toSet) => {
422
422
  }
423
423
  }
424
424
  };
425
- var findClosestStoreWithAtomInitialized2 = (atom, data) => {
426
- if ("parent" in data === false)
427
- return data;
428
- if (data.values.has(atom))
429
- return data;
430
- return findClosestStoreWithAtomInitialized2(atom, data.parent);
425
+ var getAtomFamilyRenderedMap = (index) => {
426
+ if (index.rendered)
427
+ return index.rendered;
428
+ const result = new Map(index.parentIndex ? getAtomFamilyRenderedMap(index.parentIndex) : undefined);
429
+ for (const [atom, timestamp] of index.created) {
430
+ result.set(atom, timestamp);
431
+ }
432
+ for (const [atom, timestamp] of index.deleted) {
433
+ result.delete(atom, timestamp);
434
+ }
435
+ index.rendered = result;
436
+ return result;
431
437
  };
432
- var findInClosestStore = (state, data) => {
433
- const store = findClosestStoreWithAtomInitialized2(state, data);
434
- return store.values.get(state);
438
+ var getSortedKeysByValues = (map) => {
439
+ return Array.from(map.entries()).sort((a, b) => a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0).map((entry) => entry[0]);
435
440
  };
436
- var addFamilyAtomsToSet = (family, familyAtoms, data) => {
437
- const currentAtoms = findInClosestStore(family, data) || [];
438
- const atomsToAdd = [];
439
- for (const familyAtom of familyAtoms) {
440
- if (!currentAtoms.includes(familyAtom)) {
441
- atomsToAdd.push(familyAtom);
441
+ var renderAtomFamilyIndex = (index) => {
442
+ if (index.renderedArray) {
443
+ console.log("Using cached rendered array");
444
+ return index.renderedArray;
445
+ }
446
+ const renderedMap = getAtomFamilyRenderedMap(index);
447
+ const array = getSortedKeysByValues(renderedMap);
448
+ array.__index = index;
449
+ index.renderedArray = array;
450
+ return array;
451
+ };
452
+ var cloneAtomFamilyIndex = (index, parentIndexOverride) => {
453
+ return {
454
+ created: new Map(index.created),
455
+ deleted: new Map(index.deleted),
456
+ rendered: null,
457
+ renderedArray: null,
458
+ parentIndex: parentIndexOverride || index.parentIndex
459
+ };
460
+ };
461
+ var createAtomFamilyIndex = (parentIndex) => {
462
+ return {
463
+ created: new Map,
464
+ deleted: new Map,
465
+ rendered: null,
466
+ renderedArray: null,
467
+ parentIndex
468
+ };
469
+ };
470
+ var deleteFamilyAtomsFromSet = (family, familyAtoms, data, timestamp) => {
471
+ if (familyAtoms.size === 0)
472
+ return;
473
+ const index = findFamilyIndex(family, data);
474
+ for (const atom of familyAtoms) {
475
+ index.deleted.set(atom, timestamp);
476
+ }
477
+ index.rendered = null;
478
+ index.renderedArray = null;
479
+ data.values.set(family, renderAtomFamilyIndex(index));
480
+ recursivlyUpdateIndexes(data, family);
481
+ };
482
+ var initFamilyIndex = (family, data) => {
483
+ if (data.values.has(family))
484
+ return data.values.get(family).__index;
485
+ let parentIndex;
486
+ if ("parent" in data) {
487
+ parentIndex = initFamilyIndex(family, data.parent);
488
+ if (!parentIndex)
489
+ throw new Error("Parent index is missing");
490
+ }
491
+ const index = createAtomFamilyIndex(parentIndex);
492
+ data.values.set(family, renderAtomFamilyIndex(index));
493
+ return index;
494
+ };
495
+ var findFamilyIndex = (family, data) => {
496
+ if (!data.values.has(family)) {
497
+ initFamilyIndex(family, data);
498
+ }
499
+ const value = data.values.get(family);
500
+ if (!value?.__index) {
501
+ console.log("value", value);
502
+ throw new Error("Family index is missing");
503
+ }
504
+ return value.__index;
505
+ };
506
+ var recursivlyUpdateIndexes = (data, family) => {
507
+ Object.keys(data.scopes).forEach((scopeKey) => {
508
+ const scopedData = data.scopes[scopeKey];
509
+ if (scopeKey) {
510
+ if (scopedData.values.has(family)) {
511
+ const index = scopedData.values.get(family).__index;
512
+ index.rendered = null;
513
+ index.renderedArray = null;
514
+ scopedData.values.set(family, renderAtomFamilyIndex(index));
515
+ }
516
+ recursivlyUpdateIndexes(scopedData, family);
517
+ }
518
+ });
519
+ };
520
+ var addFamilyAtomsToSet = (family, familyAtoms, data, timestamp) => {
521
+ if (familyAtoms.size === 0)
522
+ return;
523
+ const index = findFamilyIndex(family, data);
524
+ if (!index)
525
+ throw new Error("index not found");
526
+ for (const atom of familyAtoms) {
527
+ index.created.set(atom, timestamp);
528
+ index.deleted.delete(atom);
529
+ }
530
+ index.rendered = null;
531
+ index.renderedArray = null;
532
+ data.values.set(family, renderAtomFamilyIndex(index));
533
+ recursivlyUpdateIndexes(data, family);
534
+ };
535
+ var propagateDeletedAtoms = (atoms, data, subscriptions = new Set, families = new Map, timestamp = performance.now()) => {
536
+ const selectors = new Set;
537
+ for (const atom of atoms) {
538
+ addSetToSet(data.stateDependents.get(atom), selectors);
539
+ addSetToSet(data.subscriptions.get(atom), subscriptions);
540
+ if (isFamilyAtom(atom)) {
541
+ if (!families.has(atom.family)) {
542
+ families.set(atom.family, new Set);
543
+ }
544
+ families.get(atom.family).add(atom);
442
545
  }
443
546
  }
444
- if (atomsToAdd.length > 0) {
445
- data.values.set(family, [...currentAtoms, ...atomsToAdd]);
547
+ if (families.size > 0) {
548
+ for (const [family, familyAtoms] of families) {
549
+ addSetToSet(data.stateDependents.get(family), selectors);
550
+ addSetToSet(data.subscriptions.get(family), subscriptions);
551
+ if (familyAtoms.size === 0)
552
+ throw new Error("Should not be possible");
553
+ deleteFamilyAtomsFromSet(family, familyAtoms, data, timestamp);
554
+ }
446
555
  }
556
+ propagateDirtySelectors(atoms, selectors, data, subscriptions, families);
447
557
  };
448
- var propagateUpdatedAtoms = (atoms, data, subscriptions = new Set, families = new Map, isRecursive = false) => {
558
+ var propagateUpdatedAtoms = (atoms, data, subscriptions = new Set, families = new Map, isRecursive = false, timestamp = performance.now()) => {
449
559
  const selectors = new Set;
450
560
  for (const atom of atoms) {
451
561
  addSetToSet(data.stateDependents.get(atom), selectors);
@@ -463,7 +573,7 @@ var propagateUpdatedAtoms = (atoms, data, subscriptions = new Set, families = ne
463
573
  addSetToSet(data.subscriptions.get(family), subscriptions);
464
574
  if (familyAtoms.size === 0)
465
575
  throw new Error("Should not be possible");
466
- addFamilyAtomsToSet(family, familyAtoms, data);
576
+ addFamilyAtomsToSet(family, familyAtoms, data, timestamp);
467
577
  }
468
578
  }
469
579
  if (!isRecursive) {
@@ -496,18 +606,6 @@ var propagateDirtySelectors = (updatedAtoms, selectors, data, subscriptions, fam
496
606
  }
497
607
  }
498
608
  };
499
- var findAllDependents = (selector, data, depsRes = new Set, subsRes = new Set) => {
500
- const dependents = data.stateDependents.get(selector);
501
- const subscriptions = data.subscriptions.get(selector);
502
- addSetToSet(dependents, depsRes);
503
- addSetToSet(subscriptions, subsRes);
504
- if (dependents && dependents.size > 0) {
505
- for (const dependent of dependents) {
506
- findAllDependents(dependent, data, depsRes, subsRes);
507
- }
508
- }
509
- return [depsRes, subsRes];
510
- };
511
609
  var recursivlyHandleSelectorUpdates = (selectors, data, collectedSubscribers, updatedInitializedAtoms, seen = new Set) => {
512
610
  const selectorsForNextPass = new Set;
513
611
  for (const selector of selectors) {
@@ -523,23 +621,10 @@ var recursivlyHandleSelectorUpdates = (selectors, data, collectedSubscribers, up
523
621
  data.values.delete(selector);
524
622
  } else {
525
623
  const [wasValueUpdated, didEvalCrash, error] = reEvaluteSelector(selector, data, updatedInitializedAtoms);
526
- if (didEvalCrash) {
527
- const [deps, subs] = findAllDependents(selector, data);
528
- if (deps.size > 0) {
529
- for (const dep of deps) {
530
- data.expiredValues.set(dep, data.values.get(dep));
531
- data.values.delete(dep);
532
- }
533
- }
534
- if (subs.size > 0) {
535
- addSetToSet(subs, collectedSubscribers);
536
- }
537
- } else {
538
- if (!wasValueUpdated)
539
- continue;
540
- addSetToSet(data.stateDependents.get(selector), selectorsForNextPass);
541
- addSetToSet(subscribers, collectedSubscribers);
542
- }
624
+ if (!wasValueUpdated)
625
+ continue;
626
+ addSetToSet(data.stateDependents.get(selector), selectorsForNextPass);
627
+ addSetToSet(subscribers, collectedSubscribers);
543
628
  }
544
629
  }
545
630
  if (selectorsForNextPass.size > 0) {
@@ -575,16 +660,8 @@ function createStoreData(id, parent) {
575
660
 
576
661
  // src/lib/deleteFamilyAtom.ts
577
662
  var deleteFamilyAtom = (atom, data) => {
578
- const array = data.values.get(atom.family);
579
- const index = array.indexOf(atom);
580
- const newArray = [
581
- ...array.slice(0, index),
582
- ...array.slice(index + 1)
583
- ];
584
663
  data.values.delete(atom);
585
- propagateUpdatedAtoms([atom], data);
586
- setValueInData(atom.family, newArray, data);
587
- propagateUpdatedAtoms([atom.family], data);
664
+ propagateDeletedAtoms([atom], data);
588
665
  };
589
666
 
590
667
  // src/lib/resetAtom.ts
@@ -744,6 +821,8 @@ var setAtoms = (pairs, data, initializedAtomsSet) => {
744
821
  value = setValueInData(atom, value, data);
745
822
  if (atom.onSet)
746
823
  atom.onSet(value, data);
824
+ } else {
825
+ setValueInData(atom, value, data);
747
826
  }
748
827
  }
749
828
  const result = new Set([...updatedAtoms, ...initializedAtomsSet]);
@@ -753,174 +832,238 @@ var setAtoms = (pairs, data, initializedAtomsSet) => {
753
832
  };
754
833
 
755
834
  // src/lib/transaction.ts
756
- var findDependencies = (state, data, result = new Set) => {
757
- const dependents = data.stateDependents.get(state);
758
- if (dependents?.size) {
759
- for (const dependent of dependents) {
760
- if (!result.has(dependent)) {
761
- result.add(dependent);
762
- findDependencies(dependent, data, result);
763
- }
764
- }
765
- }
766
- return result;
767
- };
768
- var recursivlyResetTxnSelectorCache = (state, txnSubscribers, txnSelectorCache) => {
769
- for (const dep of txnSubscribers.get(state)) {
770
- txnSelectorCache.delete(dep);
771
- if (txnSubscribers.get(dep)?.size) {
772
- recursivlyResetTxnSelectorCache(dep, txnSubscribers, txnSelectorCache);
773
- }
774
- }
775
- };
776
- var captureScopedTransaction = (scopedData, parentGetInTxnOrData) => {
777
- let txn;
778
- transaction((scopedTxn) => {
779
- txn = scopedTxn;
780
- }, scopedData, false, parentGetInTxnOrData);
781
- return txn;
782
- };
783
835
  var deleteAtomFamilyAtoms = (set, data) => {
784
836
  set.forEach((atom) => {
785
837
  data.values.delete(atom);
786
838
  });
787
839
  };
788
- var transaction = (callback, data, autoCommit = true, parentGetInTxnOrData) => {
789
- const txnAtomMap = new Map;
790
- const txnAtomDeleteSet = new Set;
791
- const txnSelectorCache = new Map;
792
- const txnSubscribers = new Map;
793
- const dirtySelectors = new Set;
794
- let scopedTransactions;
795
- const getInTxnOrData = (state) => {
796
- if (txnAtomMap.has(state)) {
797
- return txnAtomMap.get(state);
840
+
841
+ class Transaction {
842
+ data;
843
+ parentTransaction;
844
+ dirty;
845
+ _scopedTransactions;
846
+ _initializedAtomsSet;
847
+ _deleteSet;
848
+ _selectorDependencies;
849
+ _selectorCache;
850
+ _atomMap;
851
+ constructor(data, parentTransaction, childTransaction) {
852
+ this.data = data;
853
+ this.parentTransaction = parentTransaction;
854
+ this.dirty = false;
855
+ if (childTransaction) {
856
+ this._scopedTransactions = new Map([
857
+ [childTransaction.data.id, childTransaction]
858
+ ]);
859
+ }
860
+ }
861
+ valueFromTxnOrData = (state) => {
862
+ if (this.atomMap.has(state)) {
863
+ return this.atomMap.get(state);
798
864
  }
799
- if (data.values.has(state)) {
800
- return data.values.get(state);
865
+ if (this.data.values.has(state)) {
866
+ return this.data.values.get(state);
801
867
  }
802
- if (parentGetInTxnOrData) {
803
- return parentGetInTxnOrData(state);
868
+ if (this.parentTransaction) {
869
+ return this.parentTransaction.valueFromTxnOrData(state);
804
870
  }
805
871
  };
806
- const initializedAtomsSet = new Set;
807
- const txnGet = (state) => {
808
- if (isAtom(state)) {
809
- const value = getInTxnOrData(state);
872
+ get = (state) => {
873
+ if (isAtom(state) || isAtomFamily(state)) {
874
+ const value = this.valueFromTxnOrData(state);
810
875
  if (value)
811
876
  return value;
812
- return getState(state, data, initializedAtomsSet);
877
+ return getState(state, this.data, this.initializedAtomsSet);
813
878
  } else if (isSelector(state)) {
814
- if (txnSelectorCache.has(state)) {
815
- return txnSelectorCache.get(state);
879
+ if (this.dirty) {
880
+ this.selectorCache.clear();
881
+ this.selectorDependencies.clear();
882
+ this.dirty = false;
883
+ } else if (this.selectorCache.has(state)) {
884
+ return this.selectorCache.get(state);
816
885
  }
817
- const deps = new Set;
818
886
  const res = state.get((s) => {
819
- deps.add(s);
820
- return txnGet(s);
821
- }, data.id);
822
- for (const dep of deps) {
823
- if (!txnSubscribers.has(dep)) {
824
- txnSubscribers.set(dep, new Set);
887
+ if (!this.selectorDependencies.has(s)) {
888
+ this.selectorDependencies.add(s);
825
889
  }
826
- txnSubscribers.get(dep).add(state);
827
- }
828
- txnSelectorCache.set(state, res);
890
+ return this.get(s);
891
+ }, this.data.id);
892
+ this.selectorCache.set(state, res);
829
893
  return res;
830
- } else if (isAtomFamily(state)) {
831
- const value = getInTxnOrData(state);
832
- if (value)
833
- return value;
834
- return getState(state, data, initializedAtomsSet);
835
894
  } else {
836
895
  throw new Error("Unsupported state");
837
896
  }
838
897
  };
839
- const txnSet = (atom, value) => {
898
+ set = (atom, value) => {
840
899
  if (!isAtom(atom))
841
900
  throw new Error("Not an atom");
842
901
  if (isFunction(value)) {
843
- const currentValue = txnGet(atom);
902
+ const currentValue = this.get(atom);
844
903
  value = value(currentValue);
845
904
  }
846
- for (const selector of findDependencies(atom, data)) {
847
- dirtySelectors.add(selector);
848
- txnSelectorCache.delete(selector);
849
- }
850
- if (txnSubscribers.get(atom)?.size) {
851
- recursivlyResetTxnSelectorCache(atom, txnSubscribers, txnSelectorCache);
852
- }
853
905
  if (isProd()) {
854
- txnAtomMap.set(atom, value);
906
+ this.atomMap.set(atom, value);
855
907
  } else {
856
- txnAtomMap.set(atom, deepFreeze(value));
908
+ this.atomMap.set(atom, deepFreeze(value));
857
909
  }
910
+ if (!this.dirty)
911
+ this.dirty = true;
858
912
  if (isFamilyAtom(atom)) {
859
- const currentFamilyList = txnGet(atom.family);
860
- if (!currentFamilyList.includes(atom)) {
861
- const newArr = [...currentFamilyList, atom];
862
- txnAtomMap.set(atom.family, newArr);
913
+ if (!this.atomMap.has(atom.family)) {
914
+ this.cloneFamilyIntoTxn(atom.family);
863
915
  }
916
+ const index = this.atomMap.get(atom.family).__index;
917
+ index.created.set(atom, performance.now());
918
+ index.deleted.delete(atom);
919
+ index.rendered = null;
920
+ index.renderedArray = null;
921
+ this.recursivlyUpdateAtomFamilyIndexes(atom.family);
864
922
  }
865
923
  return value;
866
924
  };
867
- const txnReset = (atom) => {
868
- const value = getAtomInitValue(atom, data, initializedAtomsSet);
869
- txnAtomMap.set(atom, value);
870
- return value;
925
+ batchSetFamilyAtoms = (family, pairs) => {
926
+ if (!this.atomMap.has(family)) {
927
+ this.cloneFamilyIntoTxn(family);
928
+ }
929
+ const index = this.atomMap.get(family).__index;
930
+ for (const [atom, value] of pairs) {
931
+ if (atom.family !== family) {
932
+ throw new Error("Atom does not belong to the provided family");
933
+ }
934
+ index.created.set(atom, performance.now());
935
+ if (index.deleted.has(atom))
936
+ index.deleted.delete(atom);
937
+ this.atomMap.set(atom, value);
938
+ }
939
+ index.rendered = null;
940
+ index.renderedArray = null;
941
+ this.recursivlyUpdateAtomFamilyIndexes(family);
942
+ };
943
+ del = (atom) => {
944
+ if (!this.atomMap.has(atom.family)) {
945
+ this.cloneFamilyIntoTxn(atom.family);
946
+ }
947
+ const index = this.atomMap.get(atom.family).__index;
948
+ index.created.delete(atom);
949
+ index.deleted.set(atom, performance.now());
950
+ index.rendered = null;
951
+ index.renderedArray = null;
952
+ this.atomMap.set(atom.family, renderAtomFamilyIndex(index));
953
+ this.recursivlyUpdateAtomFamilyIndexes(atom.family);
954
+ if (this.data.values.has(atom)) {
955
+ this.deleteSet.add(atom);
956
+ }
957
+ if (this.atomMap.has(atom)) {
958
+ this.atomMap.delete(atom);
959
+ }
960
+ };
961
+ scope = (scopeId, callback) => {
962
+ if (scopeId in this.data.scopes) {
963
+ return this.scopedTransaction(scopeId).execute(callback, false);
964
+ } else {
965
+ throw new Error(`Scope '${scopeId}' not found. Registered scopes: ${Object.keys(this.data.scopes).join(", ")}`);
966
+ }
871
967
  };
872
- const txnDel = (atom) => {
873
- const array = txnGet(atom.family);
874
- const index = array.indexOf(atom);
875
- const newArr = [
876
- ...array.slice(0, index),
877
- ...array.slice(index + 1)
878
- ];
879
- txnAtomMap.set(atom.family, newArr);
880
- if (data.values.has(atom)) {
881
- txnAtomDeleteSet.add(atom);
968
+ parentScope = (callback) => {
969
+ if (!this.parentTransaction) {
970
+ this.parentTransaction = new Transaction(this.data.parent, undefined, this);
882
971
  }
883
- if (txnAtomMap.has(atom)) {
884
- txnAtomMap.delete(atom);
972
+ return this.parentTransaction.execute(callback, false);
973
+ };
974
+ reset = (atom) => {
975
+ const value = getAtomInitValue(atom, this.data, this.initializedAtomsSet);
976
+ this.atomMap.set(atom, value);
977
+ return value;
978
+ };
979
+ execute = (callback, autoCommit = true) => {
980
+ const result = callback(this);
981
+ if (autoCommit)
982
+ this.txnCommit();
983
+ return result;
984
+ };
985
+ txnCommit = () => {
986
+ if (this.parentTransaction) {
987
+ this.parentTransaction.txnCommit();
988
+ } else {
989
+ this.commit();
885
990
  }
886
991
  };
887
- const commit = () => {
888
- setAtoms(txnAtomMap, data, initializedAtomsSet);
889
- if (txnAtomDeleteSet.size) {
890
- deleteAtomFamilyAtoms(txnAtomDeleteSet, data);
992
+ commit = () => {
993
+ const initializedAtomsSet = new Set;
994
+ setAtoms(this.atomMap, this.data, initializedAtomsSet);
995
+ if (this.deleteSet?.size) {
996
+ deleteAtomFamilyAtoms(this.deleteSet, this.data);
891
997
  }
892
- dirtySelectors.clear();
893
- if (scopedTransactions) {
894
- for (const scopedTxn of Object.values(scopedTransactions)) {
998
+ if (this._scopedTransactions) {
999
+ for (const [, scopedTxn] of this._scopedTransactions) {
895
1000
  scopedTxn.commit();
896
1001
  }
897
1002
  }
898
1003
  };
899
- const result = callback({
900
- set: txnSet,
901
- get: txnGet,
902
- del: txnDel,
903
- reset: txnReset,
904
- commit,
905
- scope: (scopeId, callback2) => {
906
- if (scopeId in data.scopes) {
907
- const scopedData = data.scopes[scopeId];
908
- if (scopedTransactions === undefined) {
909
- scopedTransactions = {};
910
- }
911
- if (scopedTransactions[scopeId] === undefined) {
912
- scopedTransactions[scopeId] = captureScopedTransaction(scopedData, getInTxnOrData);
913
- }
914
- return callback2(scopedTransactions[scopeId]);
915
- } else {
916
- throw new Error(`Scope '${scopeId}' not found. Registered scopes: ${Object.keys(data.scopes).join(", ")}`);
1004
+ get atomMap() {
1005
+ if (!this._atomMap)
1006
+ this._atomMap = new Map;
1007
+ return this._atomMap;
1008
+ }
1009
+ get selectorCache() {
1010
+ if (!this._selectorCache)
1011
+ this._selectorCache = new Map;
1012
+ return this._selectorCache;
1013
+ }
1014
+ get selectorDependencies() {
1015
+ if (!this._selectorDependencies)
1016
+ this._selectorDependencies = new Set;
1017
+ return this._selectorDependencies;
1018
+ }
1019
+ get deleteSet() {
1020
+ if (!this._deleteSet)
1021
+ this._deleteSet = new Set;
1022
+ return this._deleteSet;
1023
+ }
1024
+ get initializedAtomsSet() {
1025
+ if (!this._initializedAtomsSet)
1026
+ this._initializedAtomsSet = new Set;
1027
+ return this._initializedAtomsSet;
1028
+ }
1029
+ scopedTransaction(scopeId) {
1030
+ if (!this._scopedTransactions)
1031
+ this._scopedTransactions = new Map;
1032
+ if (!this._scopedTransactions.has(scopeId)) {
1033
+ const scopedData = this.data.scopes[scopeId];
1034
+ const scopedTransaction = new Transaction(scopedData, this);
1035
+ this._scopedTransactions.set(scopeId, scopedTransaction);
1036
+ }
1037
+ return this._scopedTransactions.get(scopeId);
1038
+ }
1039
+ cloneFamilyIntoTxn(family, parentIndex, moveUpIfParent = true) {
1040
+ if (moveUpIfParent && this.parentTransaction)
1041
+ return this.parentTransaction.cloneFamilyIntoTxn(family, parentIndex, moveUpIfParent);
1042
+ const currentFamilyList = this.get(family);
1043
+ const clonedIndex = cloneAtomFamilyIndex(currentFamilyList.__index, parentIndex);
1044
+ if (this._scopedTransactions?.size) {
1045
+ for (const [, scopedTxn] of this._scopedTransactions) {
1046
+ scopedTxn.cloneFamilyIntoTxn(family, clonedIndex, false);
917
1047
  }
918
- },
919
- data
920
- });
921
- if (autoCommit)
922
- commit();
923
- return result;
1048
+ }
1049
+ this.atomMap.set(family, renderAtomFamilyIndex(clonedIndex));
1050
+ }
1051
+ recursivlyUpdateAtomFamilyIndexes(atomFamily) {
1052
+ const currentIndex = this.atomMap.get(atomFamily).__index;
1053
+ currentIndex.rendered = null;
1054
+ currentIndex.renderedArray = null;
1055
+ const updatedValue = renderAtomFamilyIndex(currentIndex);
1056
+ this.atomMap.set(atomFamily, updatedValue);
1057
+ if (this._scopedTransactions?.size) {
1058
+ for (const [, scopedTxn] of this._scopedTransactions) {
1059
+ scopedTxn.recursivlyUpdateAtomFamilyIndexes(atomFamily);
1060
+ }
1061
+ }
1062
+ }
1063
+ }
1064
+ var transaction = (callback, data) => {
1065
+ const txn = new Transaction(data);
1066
+ return txn.execute(callback);
924
1067
  };
925
1068
 
926
1069
  // src/lib/storeFromStoreData.ts
@@ -963,7 +1106,10 @@ function storeFromStoreData(data, detach) {
963
1106
  scopedStoreData.scopeConsumers.delete(detach2);
964
1107
  if (scopedStoreData.scopeConsumers.size === 0) {
965
1108
  delete data.scopes[scopeId];
1109
+ return true;
966
1110
  }
1111
+ console.warn(`Scope ${scopeId} still has ${scopedStoreData.scopeConsumers.size} consumers, will not detach`);
1112
+ return false;
967
1113
  };
968
1114
  scopedStoreData.scopeConsumers.add(detach2);
969
1115
  const newStore = storeFromStoreData(data.scopes[scopeId], detach2);
@@ -1326,9 +1472,9 @@ var isFamilySelector = (state) => isFamilyState(state) && isSelector(state);
1326
1472
 
1327
1473
  // src/index.ts
1328
1474
  if (globalThis.__valdres__) {
1329
- throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${"0.2.0-pre.2"}`);
1475
+ throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${"0.2.0-pre.20"}`);
1330
1476
  } else {
1331
- globalThis.__valdres__ = "0.2.0-pre.2";
1477
+ globalThis.__valdres__ = "0.2.0-pre.20";
1332
1478
  }
1333
1479
  export {
1334
1480
  store,
@@ -34,3 +34,4 @@ export type { Store } from "./types/Store";
34
34
  export type { StoreData } from "./types/StoreData";
35
35
  export type { TransactionFn } from "./types/TransactionFn";
36
36
  export type { TransactionInterface } from "./types/TransactionInterface";
37
+ export type { Transaction } from "./lib/transaction";
@@ -1,5 +1,5 @@
1
1
  import type { AtomFamily } from "./types/AtomFamily";
2
2
  import type { Selector } from "./types/Selector";
3
- export declare const index: <Term, Value extends unknown, FamilyArgs extends [any, ...any[]] = [any, ...any[]]>(family: AtomFamily<Value, FamilyArgs>, callback: (value: Value, term: Term) => boolean, options?: {
3
+ export declare const index: <Term, Value extends any, FamilyArgs extends [any, ...any[]] = [any, ...any[]]>(family: AtomFamily<Value, FamilyArgs>, callback: (value: Value, term: Term) => boolean, options?: {
4
4
  name?: string;
5
5
  }) => ((term: Term) => Selector<Term[]>);
@@ -1,4 +1,4 @@
1
1
  import type { AtomFamily } from "../types/AtomFamily";
2
2
  import type { AtomFamilyDefaultValue } from "../types/AtomFamilyDefaultValue";
3
3
  import type { AtomOptions } from "../types/AtomOptions";
4
- export declare const createAtomFamily: <Value extends unknown, Args extends [any, ...any[]] = [any, ...any[]]>(defaultValue: AtomFamilyDefaultValue<Value, Args>, options?: AtomOptions<Value>) => AtomFamily<Value, Args>;
4
+ export declare const createAtomFamily: <Value extends any, Args extends [any, ...any[]] = [any, ...any[]]>(defaultValue: AtomFamilyDefaultValue<Value, Args>, options?: AtomOptions<Value>) => AtomFamily<Value, Args>;
@@ -1,4 +1,4 @@
1
1
  import type { AtomFamily } from "../types/AtomFamily";
2
2
  import type { AtomFamilyDefaultValue } from "../types/AtomFamilyDefaultValue";
3
3
  import type { AtomOptions } from "../types/AtomOptions";
4
- export declare const createGlobalAtomFamily: <Value extends unknown, Args extends [any, ...any[]] = [any, ...any[]]>(defaultValue: AtomFamilyDefaultValue<Value, Args>, options: AtomOptions<Value>) => AtomFamily<Value, Args>;
4
+ export declare const createGlobalAtomFamily: <Value extends any, Args extends [any, ...any[]] = [any, ...any[]]>(defaultValue: AtomFamilyDefaultValue<Value, Args>, options: AtomOptions<Value>) => AtomFamily<Value, Args>;
@@ -1,8 +1,8 @@
1
1
  import type { Atom } from "../types/Atom";
2
2
  import type { AtomFamily } from "../types/AtomFamily";
3
+ import type { AtomFamilyAtom } from "../types/AtomFamilyAtom";
3
4
  import type { Selector } from "../types/Selector";
4
5
  import type { StoreData } from "../types/StoreData";
5
- import type { AtomFamilyAtom } from "../types/AtomFamilyAtom";
6
6
  export declare function getState<Value extends any, Args extends [any, ...any[]] = [any, ...any[]]>(atom: Atom<Value>, data: StoreData, initializedAtomsSet: Set<Atom>, circularDependencySet?: WeakSet<Selector>): Value;
7
7
  export declare function getState<Value extends any, Args extends [any, ...any[]] = [any, ...any[]]>(selector: Selector<Value>, data: StoreData, initializedAtomsSet: Set<Atom>, circularDependencySet?: WeakSet<Selector>): Value;
8
8
  export declare function getState<Value extends any, Args extends [any, ...any[]] = [any, ...any[]]>(family: AtomFamily<Value, Args>, data: StoreData, initializedAtomsSet: Set<Atom>, circularDependencySet?: WeakSet<Selector>): AtomFamilyAtom<Value, Args>[];
@@ -2,4 +2,4 @@ import type { Atom } from "../types/Atom";
2
2
  import type { AtomFamilyAtom } from "../types/AtomFamilyAtom";
3
3
  import type { StoreData } from "../types/StoreData";
4
4
  export declare const getAtomInitValue: <V = any>(atom: Atom<V>, data: StoreData, initializedAtomsSet: Set<Atom>) => any;
5
- export declare const initAtom: <Value extends unknown, Args extends [any, ...any[]] = [any, ...any[]]>(atom: Atom<Value> | AtomFamilyAtom<Value, Args>, data: StoreData, initializedAtomsSet: Set<Atom>) => void;
5
+ export declare const initAtom: <Value extends any, Args extends [any, ...any[]] = [any, ...any[]]>(atom: Atom<Value> | AtomFamilyAtom<Value, Args>, data: StoreData, initializedAtomsSet: Set<Atom>) => void;
@@ -1 +1 @@
1
- export declare const isFunction: (value: unknown) => value is Function;
1
+ export declare const isFunction: (value: any) => value is Function;
@@ -5,6 +5,21 @@ import type { Family } from "../types/Family";
5
5
  import type { Selector } from "../types/Selector";
6
6
  import type { StoreData } from "../types/StoreData";
7
7
  import type { Subscription } from "../types/Subscription";
8
- export declare const addFamilyAtomsToSet: (family: Family<any>, familyAtoms: Set<AtomFamilyAtom<any>>, data: StoreData) => void;
9
- export declare const propagateUpdatedAtoms: (atoms: (Atom<any> | AtomFamilyAtom<any, any> | AtomFamily<any, any>)[], data: StoreData, subscriptions?: Set<Subscription>, families?: Map<AtomFamily<any>, Set<AtomFamilyAtom<any>>>, isRecursive?: boolean) => void;
8
+ export declare const renderAtomFamilyIndex: (index: AtomFamilyIndex) => unknown[];
9
+ type AtomFamilyIndex = {
10
+ created: Map<AtomFamilyAtom<any, any>, Number>;
11
+ deleted: Map<AtomFamilyAtom<any, any>, Number>;
12
+ rendered: Map<AtomFamilyAtom<any, any>, Number> | null;
13
+ renderedArray: (AtomFamilyAtom<any, any>[] & {
14
+ __index: AtomFamilyIndex;
15
+ }) | null;
16
+ parentIndex?: AtomFamilyIndex;
17
+ };
18
+ export declare const cloneAtomFamilyIndex: (index: AtomFamilyIndex, parentIndexOverride?: AtomFamilyIndex) => AtomFamilyIndex;
19
+ export declare const createAtomFamilyIndex: (parentIndex?: AtomFamilyIndex) => AtomFamilyIndex;
20
+ export declare const deleteFamilyAtomsFromSet: (family: Family<any>, familyAtoms: Set<AtomFamilyAtom<any>>, data: StoreData, timestamp: number) => void;
21
+ export declare const addFamilyAtomsToSet: (family: Family<any>, familyAtoms: Set<AtomFamilyAtom<any>>, data: StoreData, timestamp: Number) => void;
22
+ export declare const propagateDeletedAtoms: (atoms: AtomFamilyAtom<any, any>[], data: StoreData, subscriptions?: Set<Subscription>, families?: Map<AtomFamily<any>, Set<AtomFamilyAtom<any>>>, timestamp?: number) => void;
23
+ export declare const propagateUpdatedAtoms: (atoms: (Atom<any> | AtomFamilyAtom<any, any> | AtomFamily<any, any>)[], data: StoreData, subscriptions?: Set<Subscription>, families?: Map<AtomFamily<any>, Set<AtomFamilyAtom<any>>>, isRecursive?: boolean, timestamp?: number) => void;
10
24
  export declare const propagateDirtySelectors: (updatedAtoms: Atom[], selectors: Set<Selector>, data: StoreData, subscriptions: Set<Subscription>, families: Map<AtomFamily<any>, Set<AtomFamilyAtom<any>>>) => void;
25
+ export {};
@@ -1,8 +1,37 @@
1
1
  import type { Atom } from "../types/Atom";
2
+ import type { AtomFamilyAtom } from "../types/AtomFamilyAtom";
3
+ import type { GetValue } from "../types/GetValue";
2
4
  import type { StoreData } from "../types/StoreData";
3
5
  import type { TransactionFn } from "../types/TransactionFn";
4
- type GetAtomValue = {
5
- <V>(atom: Atom<V>): V;
6
- };
7
- export declare const transaction: (callback: TransactionFn, data: StoreData, autoCommit?: boolean, parentGetInTxnOrData?: GetAtomValue) => any;
8
- export {};
6
+ export declare class Transaction {
7
+ data: StoreData;
8
+ parentTransaction: Transaction | undefined;
9
+ dirty: boolean;
10
+ private _scopedTransactions;
11
+ private _initializedAtomsSet;
12
+ private _deleteSet;
13
+ private _selectorDependencies;
14
+ private _selectorCache;
15
+ private _atomMap;
16
+ constructor(data: StoreData, parentTransaction?: Transaction, childTransaction?: Transaction);
17
+ private valueFromTxnOrData;
18
+ get: GetValue;
19
+ set: <V>(atom: Atom<V>, value: V | ((currentValue: V) => V)) => V;
20
+ batchSetFamilyAtoms: (family: any, pairs: any) => void;
21
+ del: (atom: AtomFamilyAtom<any, any>) => void;
22
+ scope: (scopeId: string, callback: (txn: Transaction) => any) => any;
23
+ parentScope: (callback: (txn: Transaction) => any) => any;
24
+ reset: (atom: Atom) => any;
25
+ execute: (callback: TransactionFn, autoCommit?: boolean) => any;
26
+ private txnCommit;
27
+ commit: () => void;
28
+ private get atomMap();
29
+ private get selectorCache();
30
+ private get selectorDependencies();
31
+ private get deleteSet();
32
+ private get initializedAtomsSet();
33
+ private scopedTransaction;
34
+ private cloneFamilyIntoTxn;
35
+ private recursivlyUpdateAtomFamilyIndexes;
36
+ }
37
+ export declare const transaction: (callback: TransactionFn, data: StoreData) => any;
@@ -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 extends unknown, FamilyArgs extends [any, ...any[]] = [any, ...any[]]>(get: (get: GetValue, storeId: string) => Value | Promise<Value>, options?: SelectorOptions<Value>) => Selector<Value, FamilyArgs>;
4
+ export declare const selector: <Value extends any, FamilyArgs extends [any, ...any[]] = [any, ...any[]]>(get: (get: GetValue, storeId: string) => Value | Promise<Value>, options?: SelectorOptions<Value>) => Selector<Value, FamilyArgs>;
@@ -1,4 +1,4 @@
1
1
  import type { GetValue } from "./types/GetValue";
2
2
  import type { SelectorFamily } from "./types/SelectorFamily";
3
3
  import type { SelectorOptions } from "./types/SelectorOptions";
4
- export declare const selectorFamily: <Value extends unknown, Args extends [any, ...any[]] = [any, ...any[]]>(callback: (...args: Args) => (get: GetValue) => Value | Promise<Value>, options?: SelectorOptions<Value>) => SelectorFamily<Value, Args>;
4
+ export declare const selectorFamily: <Value extends any, Args extends [any, ...any[]] = [any, ...any[]]>(callback: (...args: Args) => (get: GetValue) => Value | Promise<Value>, options?: SelectorOptions<Value>) => SelectorFamily<Value, Args>;
@@ -10,5 +10,6 @@ export type Atom<Value = unknown> = {
10
10
  onSet?: AtomOnSet<Value>;
11
11
  onMount?: () => void | (() => void);
12
12
  maxAge?: number;
13
+ mutable?: boolean;
13
14
  staleWhileRevalidate?: number;
14
15
  };
@@ -5,5 +5,6 @@ export type AtomFamily<Value extends any, Args extends [any, ...any[]] = [any, .
5
5
  release: (...args: Args) => void;
6
6
  equal: EqualFunc<Value>;
7
7
  name?: string;
8
+ mutable?: boolean;
8
9
  __valdresAtomFamilyMap: Map<Value, AtomFamilyAtom<Value, Args>>;
9
10
  };
@@ -8,6 +8,7 @@ export type AtomOptions<Value = unknown> = {
8
8
  onSet?: AtomOnSet<Value>;
9
9
  onMount?: () => () => void;
10
10
  maxAge?: number;
11
+ mutable?: boolean;
11
12
  staleWhileRevalidate?: number;
12
13
  equal?: EqualFunc<Value>;
13
14
  };
@@ -1,2 +1,2 @@
1
- import type { TransactionInterface } from "./TransactionInterface";
2
- export type TransactionFn = (args: TransactionInterface) => any;
1
+ import type { Transaction } from "../lib/transaction";
2
+ export type TransactionFn = (args: Transaction) => any;
@@ -1,2 +1,2 @@
1
1
  import type { AtomFamily } from "../types/AtomFamily";
2
- export declare const isAtomFamily: <Value extends unknown, Args extends [any, ...any[]] = [any, ...any[]]>(state: any) => state is AtomFamily<Value, Args>;
2
+ export declare const isAtomFamily: <Value extends any, Args extends [any, ...any[]] = [any, ...any[]]>(state: any) => state is AtomFamily<Value, Args>;
@@ -1,2 +1,2 @@
1
1
  import type { AtomFamilyAtom } from "../types/AtomFamilyAtom";
2
- export declare const isFamilyAtom: <Value extends unknown, Args extends [any, ...any[]] = [any, ...any[]]>(state: any) => state is AtomFamilyAtom<Value, Args>;
2
+ export declare const isFamilyAtom: <Value extends any, Args extends [any, ...any[]] = [any, ...any[]]>(state: any) => state is AtomFamilyAtom<Value, Args>;
@@ -1,2 +1,2 @@
1
1
  import type { AtomFamilySelector } from "../types/AtomFamilySelector";
2
- export declare const isFamilySelector: <Value extends unknown, Args extends [any, ...any[]] = [any, ...any[]]>(state: any) => state is AtomFamilySelector<Value, Args>;
2
+ export declare const isFamilySelector: <Value extends any, Args extends [any, ...any[]] = [any, ...any[]]>(state: any) => state is AtomFamilySelector<Value, Args>;
@@ -1,3 +1,3 @@
1
1
  import type { AtomFamilyAtom } from "../types/AtomFamilyAtom";
2
2
  import type { AtomFamilySelector } from "../types/AtomFamilySelector";
3
- export declare const isFamilyState: <Value extends unknown, Args extends [any, ...any[]] = [any, ...any[]]>(state: any) => state is AtomFamilyAtom<Value, Args> | AtomFamilySelector<Value, Args>;
3
+ export declare const isFamilyState: <Value extends any, Args extends [any, ...any[]] = [any, ...any[]]>(state: any) => state is AtomFamilyAtom<Value, Args> | AtomFamilySelector<Value, Args>;
@@ -1,2 +1,2 @@
1
1
  import type { SelectorFamily } from "../types/SelectorFamily";
2
- export declare const isSelectorFamily: <Value extends unknown, Args extends [any, ...any[]] = [any, ...any[]]>(state: any) => state is SelectorFamily<Value, Args>;
2
+ export declare const isSelectorFamily: <Value extends any, Args extends [any, ...any[]] = [any, ...any[]]>(state: any) => state is SelectorFamily<Value, Args>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "valdres",
3
- "version": "0.2.0-pre.2",
3
+ "version": "0.2.0-pre.20",
4
4
  "license": "MIT",
5
5
  "author": {
6
6
  "name": "Eigil Sagafos"