atom.io 0.24.4 → 0.24.6

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.
@@ -31,6 +31,10 @@ export function disposeAtom(atomToken: AtomToken<unknown>, store: Store): void {
31
31
  token: atomToken,
32
32
  value: lastValue,
33
33
  })
34
+ const molecule = target.molecules.get(atom.family.subKey)
35
+ if (molecule) {
36
+ molecule.tokens.delete(key)
37
+ }
34
38
  target.atoms.delete(key)
35
39
  target.valueMap.delete(key)
36
40
  const selectorKeys = target.selectorAtoms.getRelatedKeys(key)
@@ -46,7 +50,7 @@ export function disposeAtom(atomToken: AtomToken<unknown>, store: Store): void {
46
50
  }
47
51
  target.selectorAtoms.delete(key)
48
52
  target.atomsThatAreDefault.delete(key)
49
- target.timelineAtoms.delete(key)
53
+ target.timelineTopics.delete(key)
50
54
  if (atomToken.type === `mutable_atom`) {
51
55
  const updateToken = getUpdateToken(atomToken)
52
56
  disposeAtom(updateToken, store)
@@ -22,7 +22,7 @@ import { newest } from "../lineage"
22
22
  import type { Transceiver } from "../mutable"
23
23
  import { NotFoundError } from "../not-found-error"
24
24
  import type { Store } from "../store"
25
- import { isChildStore } from "../transaction"
25
+ import { isChildStore, isRootStore } from "../transaction"
26
26
 
27
27
  export function initFamilyMemberInStore<
28
28
  T extends Transceiver<any>,
@@ -101,13 +101,8 @@ export function initFamilyMemberInStore(
101
101
  }
102
102
  const state = family(key)
103
103
  const target = newest(store)
104
- if (state.family) {
105
- if (isChildStore(target) && target.transactionMeta.phase === `building`) {
106
- target.transactionMeta.update.updates.push({
107
- type: `state_creation`,
108
- token: state,
109
- })
110
- } else {
104
+ if (state.family && target.moleculeInProgress === null) {
105
+ if (isRootStore(target)) {
111
106
  switch (state.type) {
112
107
  case `atom`:
113
108
  case `mutable_atom`:
@@ -118,6 +113,14 @@ export function initFamilyMemberInStore(
118
113
  store.on.selectorCreation.next(state)
119
114
  break
120
115
  }
116
+ } else if (
117
+ isChildStore(target) &&
118
+ target.on.transactionApplying.state === null
119
+ ) {
120
+ target.transactionMeta.update.updates.push({
121
+ type: `state_creation`,
122
+ token: state,
123
+ })
121
124
  }
122
125
  }
123
126
  return state
@@ -5,11 +5,12 @@ import type {
5
5
  StateCreation,
6
6
  StateDisposal,
7
7
  } from "atom.io"
8
- import { parseJson } from "atom.io/json"
8
+ import { parseJson, stringifyJson } from "atom.io/json"
9
9
 
10
10
  import { disposeFromStore, initFamilyMemberInStore } from "../families"
11
11
  import { growMoleculeInStore, makeMoleculeInStore } from "../molecule"
12
- import type { Store } from "../store"
12
+ import { setIntoStore } from "../set-state"
13
+ import { type Store, withdraw } from "../store"
13
14
 
14
15
  export function ingestCreationEvent(
15
16
  update: StateCreation<any>,
@@ -72,7 +73,7 @@ export function ingestMoleculeCreationEvent(
72
73
  case `newValue`:
73
74
  makeMoleculeInStore(
74
75
  store,
75
- update.context[0],
76
+ update.context,
76
77
  update.family,
77
78
  update.token.key,
78
79
  ...update.params,
@@ -93,12 +94,24 @@ export function ingestMoleculeDisposalEvent(
93
94
  disposeFromStore(update.token, store)
94
95
  break
95
96
  case `oldValue`:
96
- makeMoleculeInStore(
97
- store,
98
- update.context[0],
99
- update.family,
100
- update.token.key,
101
- )
97
+ {
98
+ const moleculeToken = makeMoleculeInStore(
99
+ store,
100
+ update.context,
101
+ update.family,
102
+ update.token.key,
103
+ )
104
+ for (const [familyKey, value] of update.values) {
105
+ const memberKey = `${familyKey}(${stringifyJson(moleculeToken.key)})`
106
+ const molecule = withdraw(moleculeToken, store)
107
+ const alreadyCreated = molecule.tokens.has(memberKey)
108
+ const family = store.families.get(familyKey)
109
+ if (family && !alreadyCreated) {
110
+ growMoleculeInStore(molecule, family, store)
111
+ }
112
+ store.valueMap.set(memberKey, value)
113
+ }
114
+ }
102
115
  break
103
116
  }
104
117
  }
@@ -1,3 +1,4 @@
1
+ import { stringifyJson } from "anvl/json"
1
2
  import type {
2
3
  MoleculeConstructor,
3
4
  MoleculeDisposal,
@@ -31,34 +32,44 @@ export function disposeMolecule<M extends MoleculeConstructor>(
31
32
  }
32
33
  const { family } = token
33
34
 
34
- for (const state of molecule.tokens.values()) {
35
- disposeFromStore(state, store)
35
+ const context: MoleculeToken<any>[] = []
36
+ for (const above of molecule.above.values()) {
37
+ context.push(deposit(above))
36
38
  }
37
- for (const child of molecule.below.values()) {
38
- if (child.family?.dependsOn === `all`) {
39
- disposeMolecule(child, store)
40
- } else {
41
- child.above.delete(molecule.stringKey)
42
- if (child.above.size === 0) {
43
- disposeMolecule(child, store)
44
- }
45
- }
39
+ const values: [string, any][] = []
40
+ for (const stateToken of molecule.tokens.values()) {
41
+ // biome-ignore lint/style/noNonNullAssertion: tokens of molecules must have a family
42
+ const tokenFamily = stateToken.family!
43
+ values.push([tokenFamily.key, store.valueMap.get(stateToken.key)])
46
44
  }
47
- molecule.below.clear()
45
+
48
46
  if (family) {
49
47
  const Formula = withdraw(family, store)
50
48
  const disposalEvent: MoleculeDisposal = {
51
49
  type: `molecule_disposal`,
52
50
  token,
53
51
  family,
54
- context: [...molecule.above.values()].map((m) => deposit(m)),
55
- familyKeys: [...molecule.tokens.values()]
56
- .map((t) => t.family?.key)
57
- .filter((k): k is string => typeof k === `string`),
52
+ context,
53
+ values,
58
54
  }
59
55
  if (token.family) {
60
56
  disposalEvent.family = token.family
61
57
  }
58
+ for (const state of molecule.tokens.values()) {
59
+ disposeFromStore(state, store)
60
+ }
61
+ for (const child of molecule.below.values()) {
62
+ if (child.family?.dependsOn === `all`) {
63
+ disposeMolecule(child, store)
64
+ } else {
65
+ child.above.delete(molecule.stringKey)
66
+ if (child.above.size === 0) {
67
+ disposeMolecule(child, store)
68
+ }
69
+ }
70
+ }
71
+ molecule.below.clear()
72
+
62
73
  const isTransaction =
63
74
  isChildStore(store) && store.transactionMeta.phase === `building`
64
75
  if (isTransaction) {
@@ -77,12 +77,8 @@ export function growMoleculeInStore(
77
77
  molecule.tokens.set(stateToken.key, stateToken)
78
78
  const isTransaction =
79
79
  isChildStore(store) && store.transactionMeta.phase === `building`
80
- if (isTransaction) {
81
- store.transactionMeta.update.updates.push({
82
- type: `state_creation`,
83
- token: stateToken,
84
- })
85
- } else {
80
+ const moleculeInProgress = store.moleculeInProgress === molecule.key
81
+ if (!isTransaction && !moleculeInProgress) {
86
82
  molecule.subject.next({ type: `state_creation`, token: stateToken })
87
83
  }
88
84
  return stateToken
@@ -22,7 +22,7 @@ import { getJsonToken } from "../mutable"
22
22
  import { setIntoStore } from "../set-state"
23
23
  import type { Store } from "../store"
24
24
  import { withdraw } from "../store"
25
- import { actUponStore, isChildStore } from "../transaction"
25
+ import { actUponStore, isChildStore, isRootStore } from "../transaction"
26
26
  import { growMoleculeInStore } from "./grow-molecule-in-store"
27
27
  import { Molecule } from "./molecule-internal"
28
28
 
@@ -35,11 +35,7 @@ export function makeMoleculeInStore<M extends MoleculeConstructor>(
35
35
  ): MoleculeToken<M> {
36
36
  const target = newest(store)
37
37
 
38
- const token = {
39
- type: `molecule`,
40
- key,
41
- family: familyToken,
42
- } as const satisfies MoleculeToken<M>
38
+ target.moleculeInProgress = key
43
39
 
44
40
  const contextArray = Array.isArray(context) ? context : [context]
45
41
  const owners = contextArray.map<Molecule<M>>((ctx) => {
@@ -57,8 +53,7 @@ export function makeMoleculeInStore<M extends MoleculeConstructor>(
57
53
  return molecule
58
54
  })
59
55
 
60
- const family = withdraw(familyToken, store)
61
- const molecule = new Molecule(owners, key, family)
56
+ const molecule = new Molecule(owners, key, familyToken)
62
57
  target.molecules.set(stringifyJson(key), molecule)
63
58
  for (const owner of owners) {
64
59
  owner.below.set(molecule.stringKey, molecule)
@@ -116,25 +111,36 @@ export function makeMoleculeInStore<M extends MoleculeConstructor>(
116
111
  ...p,
117
112
  ),
118
113
  } satisfies MoleculeTransactors<MK<M>>
114
+
115
+ const family = withdraw(familyToken, store)
119
116
  const Constructor = family.new
120
117
 
121
- molecule.instance = new Constructor(transactors, token.key, ...params)
118
+ molecule.instance = new Constructor(transactors, key, ...params)
119
+
120
+ const token = {
121
+ type: `molecule`,
122
+ key,
123
+ family: familyToken,
124
+ } as const satisfies MoleculeToken<M>
122
125
 
123
126
  const update = {
124
127
  type: `molecule_creation`,
125
128
  token,
126
- family,
129
+ family: familyToken,
127
130
  context: contextArray,
128
131
  params,
129
132
  } satisfies MoleculeCreation<M>
130
133
 
131
- const isTransaction =
132
- isChildStore(target) && target.transactionMeta.phase === `building`
133
- if (isTransaction) {
134
- target.transactionMeta.update.updates.push(update)
135
- } else {
134
+ if (isRootStore(target)) {
136
135
  family.subject.next(update)
136
+ } else if (
137
+ isChildStore(target) &&
138
+ target.on.transactionApplying.state === null
139
+ ) {
140
+ target.transactionMeta.update.updates.push(update)
137
141
  }
138
142
 
143
+ target.moleculeInProgress = null
144
+
139
145
  return token
140
146
  }
@@ -98,7 +98,7 @@ export class Tracker<Mutable extends Transceiver<any>> {
98
98
  subscribeToState(
99
99
  latestUpdateState,
100
100
  ({ newValue, oldValue }) => {
101
- const timelineId = target.timelineAtoms.getRelatedKey(
101
+ const timelineId = target.timelineTopics.getRelatedKey(
102
102
  latestUpdateState.key,
103
103
  )
104
104
 
@@ -8,10 +8,10 @@ import type { WritableSelector } from ".."
8
8
  import { cacheValue } from "../caching"
9
9
  import { newest } from "../lineage"
10
10
  import { markDone } from "../operation"
11
- import { become } from "../set-state/become"
11
+ import { become } from "../set-state"
12
12
  import type { Store } from "../store"
13
13
  import { Subject } from "../subject"
14
- import { isRootStore } from "../transaction/is-root-store"
14
+ import { isRootStore } from "../transaction"
15
15
  import { registerSelector } from "./register-selector"
16
16
 
17
17
  export const createWritableSelector = <T>(
@@ -25,14 +25,15 @@ export const createWritableSelector = <T>(
25
25
  const { find, get, seek, json } = transactors
26
26
  const readonlyTransactors = { find, get, seek, json }
27
27
 
28
- const getSelf = () => {
28
+ const getSelf = (innerTarget = newest(store)): T => {
29
29
  const value = options.get(readonlyTransactors)
30
- cacheValue(options.key, value, subject, newest(store))
30
+ cacheValue(options.key, value, subject, innerTarget)
31
31
  return value
32
32
  }
33
33
 
34
34
  const setSelf = (next: T | ((oldValue: T) => T)): void => {
35
- const oldValue = getSelf()
35
+ const innerTarget = newest(store)
36
+ const oldValue = getSelf(innerTarget)
36
37
  const newValue = become(next)(oldValue)
37
38
  store.logger.info(
38
39
  `📝`,
@@ -44,9 +45,9 @@ export const createWritableSelector = <T>(
44
45
  newValue,
45
46
  `)`,
46
47
  )
47
- cacheValue(options.key, newValue, subject, store)
48
- markDone(options.key, store)
49
- if (isRootStore(target)) {
48
+ cacheValue(options.key, newValue, subject, innerTarget)
49
+ markDone(options.key, innerTarget)
50
+ if (isRootStore(innerTarget)) {
50
51
  subject.next({ newValue, oldValue })
51
52
  }
52
53
  options.set(transactors, newValue)
@@ -25,6 +25,10 @@ export function disposeSelector(
25
25
  `Standalone selectors cannot be disposed.`,
26
26
  )
27
27
  } else {
28
+ const molecule = target.molecules.get(selector.family.subKey)
29
+ if (molecule) {
30
+ molecule.tokens.delete(key)
31
+ }
28
32
  switch (selectorToken.type) {
29
33
  case `selector`:
30
34
  {
@@ -43,8 +43,9 @@ export const registerSelector = (
43
43
  return dependencyValue
44
44
  },
45
45
  set: (WritableToken, newValue) => {
46
- const state = withdraw(WritableToken, store)
47
- setAtomOrSelector(state, newValue, store)
46
+ const target = newest(store)
47
+ const state = withdraw(WritableToken, target)
48
+ setAtomOrSelector(state, newValue, target)
48
49
  },
49
50
  find: ((token, key) => findInStore(token, key, store)) as typeof findState,
50
51
  seek: ((token, key) => seekInStore(token, key, store)) as typeof seekState,
@@ -1,11 +1,13 @@
1
1
  import type { Atom } from ".."
2
2
  import { evictCachedValue } from "../caching"
3
+ import { newest } from "../lineage"
3
4
  import { isDone, markDone } from "../operation"
4
5
  import type { Store } from "../store"
5
6
 
6
7
  export const evictDownStream = <T>(atom: Atom<T>, store: Store): void => {
7
- const downstreamKeys = store.selectorAtoms.getRelatedKeys(atom.key)
8
- store.logger.info(
8
+ const target = newest(store)
9
+ const downstreamKeys = target.selectorAtoms.getRelatedKeys(atom.key)
10
+ target.logger.info(
9
11
  `🧹`,
10
12
  atom.type,
11
13
  atom.key,
@@ -15,20 +17,20 @@ export const evictDownStream = <T>(atom: Atom<T>, store: Store): void => {
15
17
  downstreamKeys ?? `to evict`,
16
18
  )
17
19
  if (downstreamKeys) {
18
- if (store.operation.open) {
19
- store.logger.info(
20
+ if (target.operation.open) {
21
+ target.logger.info(
20
22
  `🧹`,
21
23
  atom.type,
22
24
  atom.key,
23
- `[ ${[...store.operation.done].join(`, `)} ] already done`,
25
+ `[ ${[...target.operation.done].join(`, `)} ] already done`,
24
26
  )
25
27
  }
26
28
  for (const key of downstreamKeys) {
27
- if (isDone(key, store)) {
29
+ if (isDone(key, target)) {
28
30
  continue
29
31
  }
30
- evictCachedValue(key, store)
31
- markDone(key, store)
32
+ evictCachedValue(key, target)
33
+ markDone(key, target)
32
34
  }
33
35
  }
34
36
  }
@@ -35,7 +35,7 @@ import type {
35
35
  TransactionEpoch,
36
36
  TransactionProgress,
37
37
  } from "../transaction"
38
- import { isRootStore } from "../transaction/is-root-store"
38
+ import { isRootStore } from "../transaction"
39
39
 
40
40
  export class Store implements Lineage {
41
41
  public parent: Store | null = null
@@ -47,24 +47,7 @@ export class Store implements Lineage {
47
47
  public selectors = new Map<string, WritableSelector<any>>()
48
48
  public readonlySelectors = new Map<string, ReadonlySelector<any>>()
49
49
 
50
- public trackers = new Map<string, Tracker<Transceiver<any>>>()
51
- public families = new Map<
52
- string,
53
- | MutableAtomFamily<any, any, any>
54
- | ReadonlySelectorFamily<any, any>
55
- | RegularAtomFamily<any, any>
56
- | WritableSelectorFamily<any, any>
57
- >()
58
-
59
- public timelines = new Map<string, Timeline<any>>()
60
- public transactions = new Map<string, Transaction<Func>>()
61
-
62
50
  public atomsThatAreDefault = new Set<string>()
63
-
64
- public timelineAtoms = new Junction({
65
- between: [`timelineKey`, `atomKey`],
66
- cardinality: `1:n`,
67
- })
68
51
  public selectorAtoms = new Junction({
69
52
  between: [`selectorKey`, `atomKey`],
70
53
  cardinality: `n:n`,
@@ -82,9 +65,37 @@ export class Store implements Lineage {
82
65
  makeContentKey: (...keys) => keys.sort().join(`:`),
83
66
  },
84
67
  )
68
+ public trackers = new Map<string, Tracker<Transceiver<any>>>()
69
+ public families = new Map<
70
+ string,
71
+ | MutableAtomFamily<any, any, any>
72
+ | ReadonlySelectorFamily<any, any>
73
+ | RegularAtomFamily<any, any>
74
+ | WritableSelectorFamily<any, any>
75
+ >()
76
+
77
+ public transactions = new Map<string, Transaction<Func>>()
78
+ public transactionMeta: TransactionEpoch | TransactionProgress<Func> = {
79
+ epoch: new Map<string, number>(),
80
+ actionContinuities: new Junction({
81
+ between: [`continuity`, `action`],
82
+ cardinality: `1:n`,
83
+ }),
84
+ }
85
+
86
+ public timelines = new Map<string, Timeline<any>>()
87
+ public timelineTopics = new Junction<
88
+ `timelineKey`,
89
+ `topicKey`,
90
+ { topicType: `atom_family` | `atom` | `molecule_family` | `molecule` }
91
+ >({
92
+ between: [`timelineKey`, `topicKey`],
93
+ cardinality: `1:n`,
94
+ })
85
95
 
86
96
  public molecules = new Map<string, Molecule<any>>()
87
97
  public moleculeFamilies = new Map<string, MoleculeFamily<any>>()
98
+ public moleculeInProgress: string | null = null
88
99
  public miscResources = new Map<string, Disposable>()
89
100
 
90
101
  public on = {
@@ -107,13 +118,6 @@ export class Store implements Lineage {
107
118
  moleculeDisposal: new Subject<MoleculeToken<any>>(),
108
119
  }
109
120
  public operation: OperationProgress = { open: false }
110
- public transactionMeta: TransactionEpoch | TransactionProgress<Func> = {
111
- epoch: new Map<string, number>(),
112
- actionContinuities: new Junction({
113
- between: [`continuity`, `action`],
114
- cardinality: `1:n`,
115
- }),
116
- }
117
121
 
118
122
  public config: {
119
123
  name: string