atom.io 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,58 @@
1
- import type { Atom, ReadonlySelector, Selector } from "."
2
- import { getState__INTERNAL, withdraw } from "./get"
3
- import { recallState } from "./operation"
4
- import { traceAllSelectorAtoms } from "./selector-internal"
5
- import type { Store } from "./store"
6
- import { IMPLICIT } from "./store"
7
- import { __INTERNAL__ } from ".."
1
+ import {
2
+ getState__INTERNAL,
3
+ withdraw,
4
+ recallState,
5
+ traceAllSelectorAtoms,
6
+ } from "."
7
+ import type { Atom, ReadonlySelector, Selector, Store } from "."
8
+ import type { StateUpdate } from ".."
8
9
 
9
- export const subscribeToRootAtoms = <T>(
10
+ export const prepareUpdate = <T>(
10
11
  state: Atom<T> | ReadonlySelector<T> | Selector<T>,
11
- store: Store = IMPLICIT.STORE
12
+ store: Store
13
+ ): StateUpdate<T> => {
14
+ const oldValue = recallState(state, store)
15
+ const newValue = getState__INTERNAL(state, store)
16
+ return { newValue, oldValue }
17
+ }
18
+
19
+ export const stowUpdate = <T>(
20
+ state: Atom<T>,
21
+ update: StateUpdate<T>,
22
+ store: Store
23
+ ): void => {
24
+ const { key } = state
25
+ const { logger } = store.config
26
+ if (store.transactionStatus.phase !== `building`) {
27
+ store.config.logger?.warn(
28
+ `stowUpdate called outside of a transaction. This is probably a bug.`
29
+ )
30
+ return
31
+ }
32
+ store.transactionStatus.atomUpdates.push({ key, ...update })
33
+ logger?.info(`📝 ${key} stowed (`, update.oldValue, `->`, update.newValue, `)`)
34
+ }
35
+
36
+ export const emitUpdate = <T>(
37
+ state: Atom<T> | ReadonlySelector<T> | Selector<T>,
38
+ update: StateUpdate<T>,
39
+ store: Store
40
+ ): void => {
41
+ const { key } = state
42
+ const { logger } = store.config
43
+ logger?.info(
44
+ `📢 ${state.type} "${key}" went (`,
45
+ update.oldValue,
46
+ `->`,
47
+ update.newValue,
48
+ `)`
49
+ )
50
+ state.subject.next(update)
51
+ }
52
+
53
+ export const subscribeToRootAtoms = <T>(
54
+ state: ReadonlySelector<T> | Selector<T>,
55
+ store: Store
12
56
  ): { unsubscribe: () => void }[] | null => {
13
57
  const dependencySubscriptions =
14
58
  `default` in state
@@ -17,11 +61,11 @@ export const subscribeToRootAtoms = <T>(
17
61
  const atom = withdraw(atomToken, store)
18
62
  return atom.subject.subscribe((atomChange) => {
19
63
  store.config.logger?.info(
20
- `📢 atom changed: "${atomToken.key}" (`,
64
+ `📢 selector "${state.key}" saw root "${atomToken.key}" go (`,
21
65
  atomChange.oldValue,
22
66
  `->`,
23
67
  atomChange.newValue,
24
- `) re-evaluating "${state.key}"`
68
+ `)`
25
69
  )
26
70
  const oldValue = recallState(state, store)
27
71
  const newValue = getState__INTERNAL(state, store)
@@ -0,0 +1,196 @@
1
+ import HAMT from "hamt_plus"
2
+
3
+ import type { KeyedStateUpdate, TransactionUpdate, Store } from "."
4
+ import { IMPLICIT, withdraw } from "."
5
+ import { setState } from ".."
6
+ import type { AtomToken, TimelineOptions, TimelineToken, ƒn } from ".."
7
+
8
+ export type Timeline = {
9
+ key: string
10
+ type: `timeline`
11
+ next: () => void
12
+ prev: () => void
13
+ }
14
+
15
+ export type TimelineStateUpdate = KeyedStateUpdate<unknown> & {
16
+ type: `state_update`
17
+ }
18
+ export type TimelineTransactionUpdate = TransactionUpdate<ƒn> & {
19
+ type: `transaction_update`
20
+ }
21
+
22
+ export type TimelineData = {
23
+ at: number
24
+ timeTraveling: boolean
25
+ history: (TimelineStateUpdate | TimelineTransactionUpdate)[]
26
+ }
27
+
28
+ export function timeline__INTERNAL(
29
+ options: TimelineOptions,
30
+ store: Store = IMPLICIT.STORE
31
+ ): TimelineToken {
32
+ let incompleteTransactionKey: string | null = null
33
+ const timelineData: TimelineData = {
34
+ at: 0,
35
+ timeTraveling: false,
36
+ history: [],
37
+ }
38
+
39
+ const subscribeToAtom = (token: AtomToken<any>) => {
40
+ const state = withdraw(token, store)
41
+ state.subject.subscribe((update) => {
42
+ const storeCurrentTransactionKey =
43
+ store.transactionStatus.phase === `applying`
44
+ ? store.transactionStatus.key
45
+ : null
46
+ store.config.logger?.info(
47
+ `⏳ timeline "${options.key}" saw atom "${token.key}" go (`,
48
+ update.oldValue,
49
+ `->`,
50
+ update.newValue,
51
+ storeCurrentTransactionKey
52
+ ? `) in "${storeCurrentTransactionKey}"`
53
+ : `) independently`
54
+ )
55
+
56
+ if (
57
+ storeCurrentTransactionKey &&
58
+ store.transactionStatus.phase === `applying`
59
+ ) {
60
+ const currentTransaction = withdraw(
61
+ { key: storeCurrentTransactionKey, type: `transaction` },
62
+ store
63
+ )
64
+ if (incompleteTransactionKey !== storeCurrentTransactionKey) {
65
+ if (incompleteTransactionKey) {
66
+ store.config.logger?.error(
67
+ `Timeline "${options.key}" was unable to resolve transaction "${incompleteTransactionKey}. This is probably a bug.`
68
+ )
69
+ }
70
+ incompleteTransactionKey = storeCurrentTransactionKey
71
+ const subscription = currentTransaction.subject.subscribe((update) => {
72
+ if (timelineData.timeTraveling === false) {
73
+ timelineData.history.push({
74
+ type: `transaction_update`,
75
+ ...update,
76
+ atomUpdates: update.atomUpdates.filter((atomUpdate) =>
77
+ options.atoms.some((atom) => atom.key === atomUpdate.key)
78
+ ),
79
+ })
80
+ }
81
+ timelineData.at = timelineData.history.length
82
+ subscription.unsubscribe()
83
+ incompleteTransactionKey = null
84
+ store.config.logger?.info(
85
+ `⌛ timeline "${options.key}" pushed a transaction_update from "${update.key}"`
86
+ )
87
+ })
88
+ }
89
+ } else {
90
+ if (timelineData.timeTraveling === false) {
91
+ timelineData.history.push({
92
+ type: `state_update`,
93
+ key: token.key,
94
+ oldValue: update.oldValue,
95
+ newValue: update.newValue,
96
+ })
97
+ store.config.logger?.info(
98
+ `⌛ timeline "${options.key}" pushed a state_update to "${token.key}"`
99
+ )
100
+ timelineData.at = timelineData.history.length
101
+ }
102
+ }
103
+ })
104
+ }
105
+
106
+ for (const tokenOrFamily of options.atoms) {
107
+ if (tokenOrFamily.type === `atom_family`) {
108
+ const family = tokenOrFamily
109
+ family.subject.subscribe((token) => subscribeToAtom(token))
110
+ } else {
111
+ const token = tokenOrFamily
112
+ subscribeToAtom(token)
113
+ }
114
+ }
115
+
116
+ store.timelineStore = HAMT.set(options.key, timelineData, store.timelineStore)
117
+
118
+ return {
119
+ key: options.key,
120
+ type: `timeline`,
121
+ }
122
+ }
123
+
124
+ export const redo__INTERNAL = (
125
+ token: TimelineToken,
126
+ store: Store = IMPLICIT.STORE
127
+ ): void => {
128
+ const timelineData = store.timelineStore.get(token.key)
129
+ if (!timelineData) {
130
+ store.config.logger?.error(
131
+ `Tried to redo on timeline "${token.key}" has not been initialized.`
132
+ )
133
+ return
134
+ }
135
+ if (timelineData.at === timelineData.history.length) {
136
+ store.config.logger?.warn(
137
+ `Tried to redo on timeline "${token.key}" but there is nothing to redo.`
138
+ )
139
+ return
140
+ }
141
+ timelineData.timeTraveling = true
142
+ const update = timelineData.history[timelineData.at]
143
+ switch (update.type) {
144
+ case `state_update`: {
145
+ const { key, newValue } = update
146
+ setState({ key, type: `atom` }, newValue)
147
+ break
148
+ }
149
+ case `transaction_update`: {
150
+ for (const atomUpdate of update.atomUpdates) {
151
+ const { key, newValue } = atomUpdate
152
+ setState({ key, type: `atom` }, newValue)
153
+ }
154
+ break
155
+ }
156
+ }
157
+ ++timelineData.at
158
+ timelineData.timeTraveling = false
159
+ }
160
+
161
+ export const undo__INTERNAL = (
162
+ token: TimelineToken,
163
+ store: Store = IMPLICIT.STORE
164
+ ): void => {
165
+ const timelineData = store.timelineStore.get(token.key)
166
+ if (!timelineData) {
167
+ store.config.logger?.error(
168
+ `Tried to undo on timeline "${token.key}" has not been initialized.`
169
+ )
170
+ return
171
+ }
172
+ if (timelineData.at === 0) {
173
+ store.config.logger?.warn(
174
+ `Tried to undo on timeline "${token.key}" but there is nothing to undo.`
175
+ )
176
+ return
177
+ }
178
+ timelineData.timeTraveling = true
179
+ --timelineData.at
180
+ const update = timelineData.history[timelineData.at]
181
+ switch (update.type) {
182
+ case `state_update`: {
183
+ const { key, oldValue } = update
184
+ setState({ key, type: `atom` }, oldValue)
185
+ break
186
+ }
187
+ case `transaction_update`: {
188
+ for (const atomUpdate of update.atomUpdates) {
189
+ const { key, oldValue } = atomUpdate
190
+ setState({ key, type: `atom` }, oldValue)
191
+ }
192
+ break
193
+ }
194
+ }
195
+ timelineData.timeTraveling = false
196
+ }
@@ -1,34 +1,175 @@
1
- import type { Store } from "./store"
1
+ import HAMT from "hamt_plus"
2
+ import * as Rx from "rxjs"
2
3
 
3
- export const finishTransaction = (store: Store): void => {
4
- store.transaction = { open: false }
5
- store.config.logger?.info(`🛬`, `transaction done`)
4
+ import type { Store, StoreCore } from "."
5
+ import { deposit, withdraw, IMPLICIT } from "."
6
+ import { getState, setState } from ".."
7
+ import type {
8
+ AtomToken,
9
+ StateUpdate,
10
+ Transaction,
11
+ TransactionOptions,
12
+ TransactionToken,
13
+ ƒn,
14
+ } from ".."
15
+
16
+ export const TRANSACTION_PHASES = [`idle`, `building`, `applying`] as const
17
+ export type TransactionPhase = (typeof TRANSACTION_PHASES)[number]
18
+
19
+ export type KeyedStateUpdate<T> = StateUpdate<T> & {
20
+ key: string
21
+ }
22
+ export type TransactionUpdate<ƒ extends ƒn> = {
23
+ key: string
24
+ atomUpdates: KeyedStateUpdate<unknown>[]
25
+ params: Parameters<ƒ>
26
+ output: ReturnType<ƒ>
27
+ }
28
+
29
+ export type TransactionUpdateInProgress<ƒ extends ƒn> = TransactionUpdate<ƒ> & {
30
+ phase: `applying` | `building`
31
+ core: StoreCore
32
+ }
33
+ export type TransactionIdle = {
34
+ phase: `idle`
6
35
  }
7
- export const startTransaction = (store: Store): void => {
8
- store.transaction = {
9
- open: true,
10
- prev: {
36
+ export type TransactionStatus<ƒ extends ƒn> =
37
+ | TransactionIdle
38
+ | TransactionUpdateInProgress<ƒ>
39
+
40
+ export const buildTransaction = (
41
+ key: string,
42
+ params: any[],
43
+ store: Store
44
+ ): void => {
45
+ store.transactionStatus = {
46
+ key,
47
+ phase: `building`,
48
+ core: {
11
49
  atoms: store.atoms,
50
+ atomsThatAreDefault: store.atomsThatAreDefault,
51
+ operation: { open: false },
12
52
  readonlySelectors: store.readonlySelectors,
53
+ timelines: store.timelines,
54
+ timelineAtoms: store.timelineAtoms,
55
+ transactions: store.transactions,
56
+ selectorAtoms: store.selectorAtoms,
13
57
  selectorGraph: store.selectorGraph,
14
58
  selectors: store.selectors,
15
59
  valueMap: store.valueMap,
16
60
  },
61
+ atomUpdates: [],
62
+ params,
63
+ output: undefined,
64
+ }
65
+ store.config.logger?.info(`🛫`, `transaction "${key}" started`)
66
+ }
67
+ export const applyTransaction = <ƒ extends ƒn>(
68
+ output: ReturnType<ƒ>,
69
+ store: Store
70
+ ): void => {
71
+ if (store.transactionStatus.phase !== `building`) {
72
+ store.config.logger?.warn(
73
+ `abortTransaction called outside of a transaction. This is probably a bug.`
74
+ )
75
+ return
76
+ }
77
+ store.config.logger?.info(
78
+ ` ▶️ apply transaction "${store.transactionStatus.key}" (init)`
79
+ )
80
+ store.transactionStatus.phase = `applying`
81
+ store.transactionStatus.output = output
82
+ const { atomUpdates } = store.transactionStatus
83
+ for (const { key, oldValue, newValue } of atomUpdates) {
84
+ const token: AtomToken<unknown> = { key, type: `atom` }
85
+ const state = withdraw(token, store)
86
+ setState(state, newValue, store)
87
+ }
88
+ const myTransaction = withdraw<ƒ>(
89
+ { key: store.transactionStatus.key, type: `transaction` },
90
+ store
91
+ )
92
+ myTransaction.subject.next({
93
+ key: store.transactionStatus.key,
94
+ atomUpdates,
95
+ output,
96
+ params: store.transactionStatus.params as Parameters<ƒ>,
97
+ })
98
+ store.transactionStatus = { phase: `idle` }
99
+ store.config.logger?.info(`🛬`, `transaction done`)
100
+ }
101
+ export const undoTransactionUpdate = <ƒ extends ƒn>(
102
+ update: TransactionUpdate<ƒ>,
103
+ store: Store
104
+ ): void => {
105
+ store.config.logger?.info(` ⏮ undo transaction "${update.key}" (undo)`)
106
+ for (const { key, oldValue, newValue } of update.atomUpdates) {
107
+ const token: AtomToken<unknown> = { key, type: `atom` }
108
+ const state = withdraw(token, store)
109
+ setState(state, oldValue, store)
110
+ }
111
+ }
112
+ export const redoTransactionUpdate = <ƒ extends ƒn>(
113
+ update: TransactionUpdate<ƒ>,
114
+ store: Store
115
+ ): void => {
116
+ store.config.logger?.info(` ⏭ redo transaction "${update.key}" (redo)`)
117
+ for (const { key, oldValue, newValue } of update.atomUpdates) {
118
+ const token: AtomToken<unknown> = { key, type: `atom` }
119
+ const state = withdraw(token, store)
120
+ setState(state, newValue, store)
17
121
  }
18
- store.config.logger?.info(`🛫`, `transaction start`)
19
122
  }
123
+
20
124
  export const abortTransaction = (store: Store): void => {
21
- if (!store.transaction.open) {
125
+ if (store.transactionStatus.phase === `idle`) {
22
126
  store.config.logger?.warn(
23
127
  `abortTransaction called outside of a transaction. This is probably a bug.`
24
128
  )
25
129
  return
26
130
  }
27
- store.atoms = store.transaction.prev.atoms
28
- store.readonlySelectors = store.transaction.prev.readonlySelectors
29
- store.selectorGraph = store.transaction.prev.selectorGraph
30
- store.selectors = store.transaction.prev.selectors
31
- store.valueMap = store.transaction.prev.valueMap
32
- store.transaction = { open: false }
131
+ store.transactionStatus = { phase: `idle` }
33
132
  store.config.logger?.info(`🪂`, `transaction fail`)
34
133
  }
134
+
135
+ export function transaction__INTERNAL<ƒ extends ƒn>(
136
+ options: TransactionOptions<ƒ>,
137
+ store: Store = IMPLICIT.STORE
138
+ ): TransactionToken<ƒ> {
139
+ const newTransaction: Transaction<ƒ> = {
140
+ key: options.key,
141
+ type: `transaction`,
142
+ run: (...params: Parameters<ƒ>) => {
143
+ buildTransaction(options.key, params, store)
144
+ try {
145
+ const output = options.do(
146
+ {
147
+ get: (token) => getState(token, store),
148
+ set: (token, value) => setState(token, value, store),
149
+ },
150
+ ...params
151
+ )
152
+ applyTransaction(output, store)
153
+ return output
154
+ } catch (thrown) {
155
+ abortTransaction(store)
156
+ store.config.logger?.error(`Transaction ${options.key} failed`, thrown)
157
+ throw thrown
158
+ }
159
+ },
160
+ subject: new Rx.Subject(),
161
+ }
162
+ const core = target(store)
163
+ core.transactions = HAMT.set(
164
+ newTransaction.key,
165
+ newTransaction,
166
+ core.transactions
167
+ )
168
+ const token = deposit(newTransaction)
169
+ return token
170
+ }
171
+
172
+ export const target = (store: Store = IMPLICIT.STORE): StoreCore =>
173
+ store.transactionStatus.phase === `building`
174
+ ? store.transactionStatus.core
175
+ : store
@@ -2,11 +2,10 @@ import type Preact from "preact/hooks"
2
2
 
3
3
  import type React from "react"
4
4
 
5
- import type { Modifier } from "~/packages/anvl/src/function"
5
+ import { subscribe, setState, __INTERNAL__ } from "atom.io"
6
+ import type { ReadonlyValueToken, StateToken } from "atom.io"
6
7
 
7
- import type { ReadonlyValueToken, StateToken } from ".."
8
- import { subscribe, setState, __INTERNAL__ } from ".."
9
- import { withdraw } from "../internal"
8
+ import type { Modifier } from "~/packages/anvl/src/function"
10
9
 
11
10
  export type AtomStoreReactConfig = {
12
11
  useState: typeof Preact.useState | typeof React.useState
@@ -26,7 +25,7 @@ export const composeStoreHooks = ({
26
25
  }
27
26
 
28
27
  function useO<T>(token: ReadonlyValueToken<T> | StateToken<T>): T {
29
- const state = withdraw(token, store)
28
+ const state = __INTERNAL__.withdraw(token, store)
30
29
  const initialValue = __INTERNAL__.getState__INTERNAL(state, store)
31
30
  const [current, dispatch] = useState(initialValue)
32
31
  useEffect(() => {
@@ -40,7 +39,7 @@ export const composeStoreHooks = ({
40
39
  store
41
40
  )
42
41
  return unsubscribe
43
- }, [current, dispatch])
42
+ }, [])
44
43
 
45
44
  return current
46
45
  }
package/src/selector.ts CHANGED
@@ -1,13 +1,9 @@
1
- import HAMT from "hamt_plus"
2
- import * as Rx from "rxjs"
1
+ import type * as Rx from "rxjs"
3
2
 
4
- import { become } from "~/packages/anvl/src/function"
5
3
  import type { Serializable } from "~/packages/anvl/src/json"
6
- import { stringifyJson } from "~/packages/anvl/src/json"
7
4
 
8
5
  import type { ReadonlyValueToken, SelectorToken } from "."
9
- import type { Selector, Store } from "./internal"
10
- import { IMPLICIT, markDone, deposit, registerSelector } from "./internal"
6
+ import { selectorFamily__INTERNAL, selector__INTERNAL } from "./internal"
11
7
  import type { ReadonlyTransactors, Transactors } from "./transaction"
12
8
 
13
9
  export type SelectorOptions<T> = {
@@ -17,67 +13,14 @@ export type SelectorOptions<T> = {
17
13
  }
18
14
  export type ReadonlySelectorOptions<T> = Omit<SelectorOptions<T>, `set`>
19
15
 
16
+ export function selector<T>(options: SelectorOptions<T>): SelectorToken<T>
20
17
  export function selector<T>(
21
- options: SelectorOptions<T>,
22
- store?: Store
23
- ): SelectorToken<T>
24
- export function selector<T>(
25
- options: ReadonlySelectorOptions<T>,
26
- store?: Store
18
+ options: ReadonlySelectorOptions<T>
27
19
  ): ReadonlyValueToken<T>
28
20
  export function selector<T>(
29
- options: ReadonlySelectorOptions<T> | SelectorOptions<T>,
30
- store: Store = IMPLICIT.STORE
21
+ options: ReadonlySelectorOptions<T> | SelectorOptions<T>
31
22
  ): ReadonlyValueToken<T> | SelectorToken<T> {
32
- if (HAMT.has(options.key, store.selectors)) {
33
- throw new Error(`Key "${options.key}" already exists in the store.`)
34
- }
35
-
36
- const subject = new Rx.Subject<{ newValue: T; oldValue: T }>()
37
-
38
- const { get, set } = registerSelector(options.key, store)
39
- const getSelf = () => {
40
- const value = options.get({ get })
41
- store.valueMap = HAMT.set(options.key, value, store.valueMap)
42
- return value
43
- }
44
-
45
- if (!(`set` in options)) {
46
- const readonlySelector = {
47
- ...options,
48
- subject,
49
- get: getSelf,
50
- }
51
- store.readonlySelectors = HAMT.set(
52
- options.key,
53
- readonlySelector,
54
- store.readonlySelectors
55
- )
56
- const initialValue = getSelf()
57
- store.config.logger?.info(` ✨ "${options.key}" =`, initialValue)
58
- return { ...readonlySelector, type: `readonly_selector` }
59
- }
60
-
61
- const setSelf = (next: T | ((oldValue: T) => T)): void => {
62
- store.config.logger?.info(` <- "${options.key}" became`, next)
63
- const oldValue = getSelf()
64
- const newValue = become(next)(oldValue)
65
- store.valueMap = HAMT.set(options.key, newValue, store.valueMap)
66
- markDone(options.key, store)
67
- subject.next({ newValue, oldValue })
68
- options.set({ get, set }, newValue)
69
- }
70
-
71
- const mySelector: Selector<T> = {
72
- ...options,
73
- subject,
74
- get: getSelf,
75
- set: setSelf,
76
- }
77
- store.selectors = HAMT.set(options.key, mySelector, store.selectors)
78
- const initialValue = getSelf()
79
- store.config.logger?.info(` ✨ "${options.key}" =`, initialValue)
80
- return { ...mySelector, type: `selector` }
23
+ return selector__INTERNAL(options)
81
24
  }
82
25
 
83
26
  export type SelectorFamilyOptions<T, K extends Serializable> = {
@@ -90,43 +33,30 @@ export type ReadonlySelectorFamilyOptions<T, K extends Serializable> = Omit<
90
33
  `set`
91
34
  >
92
35
 
36
+ export type SelectorFamily<T, K extends Serializable = Serializable> = ((
37
+ key: K
38
+ ) => SelectorToken<T>) & {
39
+ key: string
40
+ type: `selector_family`
41
+ subject: Rx.Subject<SelectorToken<T>>
42
+ }
43
+
44
+ export type ReadonlySelectorFamily<T, K extends Serializable = Serializable> = ((
45
+ key: K
46
+ ) => ReadonlyValueToken<T>) & {
47
+ key: string
48
+ type: `readonly_selector_family`
49
+ subject: Rx.Subject<ReadonlyValueToken<T>>
50
+ }
51
+
93
52
  export function selectorFamily<T, K extends Serializable>(
94
- options: SelectorFamilyOptions<T, K>,
95
- store?: Store
96
- ): (key: K) => SelectorToken<T>
53
+ options: SelectorFamilyOptions<T, K>
54
+ ): SelectorFamily<T, K>
97
55
  export function selectorFamily<T, K extends Serializable>(
98
- options: ReadonlySelectorFamilyOptions<T, K>,
99
- store?: Store
100
- ): (key: K) => ReadonlyValueToken<T>
56
+ options: ReadonlySelectorFamilyOptions<T, K>
57
+ ): ReadonlySelectorFamily<T, K>
101
58
  export function selectorFamily<T, K extends Serializable>(
102
- options: ReadonlySelectorFamilyOptions<T, K> | SelectorFamilyOptions<T, K>,
103
- store: Store = IMPLICIT.STORE
104
- ): (key: K) => ReadonlyValueToken<T> | SelectorToken<T> {
105
- return (key: K): ReadonlyValueToken<T> | SelectorToken<T> => {
106
- const fullKey = `${options.key}__${stringifyJson(key)}`
107
- const existing =
108
- store.selectors.get(fullKey) ?? store.readonlySelectors.get(fullKey)
109
- if (existing) {
110
- return deposit(existing)
111
- }
112
- const readonlySelectorOptions: ReadonlySelectorOptions<T> = {
113
- key: fullKey,
114
- get: options.get(key),
115
- }
116
- if (!(`set` in options)) {
117
- return selector<T>(
118
- {
119
- ...readonlySelectorOptions,
120
- },
121
- store
122
- )
123
- }
124
- return selector<T>(
125
- {
126
- ...readonlySelectorOptions,
127
- set: options.set(key),
128
- },
129
- store
130
- )
131
- }
59
+ options: ReadonlySelectorFamilyOptions<T, K> | SelectorFamilyOptions<T, K>
60
+ ): ReadonlySelectorFamily<T, K> | SelectorFamily<T, K> {
61
+ return selectorFamily__INTERNAL(options)
132
62
  }