atom.io 0.3.0 → 0.3.1
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/README.md +4 -6
- package/dist/index.d.ts +37 -35
- package/dist/index.js +188 -95
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +185 -93
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +11 -5
- package/src/internal/families-internal.ts +3 -3
- package/src/internal/get.ts +1 -1
- package/src/internal/index.ts +0 -1
- package/src/internal/operation.ts +15 -3
- package/src/internal/selector-internal.ts +3 -2
- package/src/internal/store.ts +1 -2
- package/src/internal/timeline-internal.ts +112 -15
- package/src/{internal/logger.ts → logger.ts} +2 -2
- package/src/selector.ts +5 -5
- package/src/subscribe.ts +1 -1
- package/src/timeline.ts +2 -7
- package/src/transaction.ts +7 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "atom.io",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Reactive state graph for React, Preact, and vanilla",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"fp-ts": "2.14.0",
|
|
50
50
|
"hamt_plus": "1.0.2",
|
|
51
|
-
"rxjs": "7.8.
|
|
51
|
+
"rxjs": "7.8.1"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@testing-library/preact": "3.2.3",
|
package/src/index.ts
CHANGED
|
@@ -7,18 +7,17 @@ import {
|
|
|
7
7
|
isAtomDefault,
|
|
8
8
|
isSelectorDefault,
|
|
9
9
|
withdraw,
|
|
10
|
-
setLogLevel,
|
|
11
|
-
useLogger,
|
|
12
10
|
} from "./internal"
|
|
13
11
|
import * as __INTERNAL__ from "./internal"
|
|
14
12
|
import type { Store } from "./internal/store"
|
|
15
13
|
|
|
16
14
|
export * from "./atom"
|
|
15
|
+
export * from "./logger"
|
|
17
16
|
export * from "./selector"
|
|
17
|
+
export * from "./subscribe"
|
|
18
18
|
export * from "./timeline"
|
|
19
19
|
export * from "./transaction"
|
|
20
|
-
export
|
|
21
|
-
export { __INTERNAL__, setLogLevel, useLogger }
|
|
20
|
+
export { __INTERNAL__ }
|
|
22
21
|
export type { Serializable } from "~/packages/anvl/src/json"
|
|
23
22
|
|
|
24
23
|
export type AtomToken<_> = {
|
|
@@ -62,7 +61,14 @@ export const setState = <T, New extends T>(
|
|
|
62
61
|
value: New | ((oldValue: T) => New),
|
|
63
62
|
store: Store = IMPLICIT.STORE
|
|
64
63
|
): void => {
|
|
65
|
-
|
|
64
|
+
try {
|
|
65
|
+
openOperation(token, store)
|
|
66
|
+
} catch (thrown) {
|
|
67
|
+
if (!(typeof thrown === `symbol`)) {
|
|
68
|
+
throw thrown
|
|
69
|
+
}
|
|
70
|
+
return
|
|
71
|
+
}
|
|
66
72
|
const state = withdraw(token, store)
|
|
67
73
|
setState__INTERNAL(state, value, store)
|
|
68
74
|
closeOperation(store)
|
|
@@ -34,7 +34,7 @@ export function atomFamily__INTERNAL<T, K extends Serializable>(
|
|
|
34
34
|
(key: K): AtomToken<T> => {
|
|
35
35
|
const subKey = stringifyJson(key)
|
|
36
36
|
const family: FamilyMetadata = { key: options.key, subKey }
|
|
37
|
-
const fullKey = `${options.key}
|
|
37
|
+
const fullKey = `${options.key}(${subKey})`
|
|
38
38
|
const existing = withdraw({ key: fullKey, type: `atom` }, store)
|
|
39
39
|
const token = existing
|
|
40
40
|
? deposit(existing)
|
|
@@ -71,7 +71,7 @@ export function readonlySelectorFamily__INTERNAL<T, K extends Serializable>(
|
|
|
71
71
|
(key: K): ReadonlyValueToken<T> => {
|
|
72
72
|
const subKey = stringifyJson(key)
|
|
73
73
|
const family: FamilyMetadata = { key: options.key, subKey }
|
|
74
|
-
const fullKey = `${options.key}
|
|
74
|
+
const fullKey = `${options.key}(${subKey})`
|
|
75
75
|
const existing = core.readonlySelectors.get(fullKey)
|
|
76
76
|
if (existing) {
|
|
77
77
|
return deposit(existing)
|
|
@@ -117,7 +117,7 @@ export function selectorFamily__INTERNAL<T, K extends Serializable>(
|
|
|
117
117
|
(key: K): SelectorToken<T> => {
|
|
118
118
|
const subKey = stringifyJson(key)
|
|
119
119
|
const family: FamilyMetadata = { key: options.key, subKey }
|
|
120
|
-
const fullKey = `${options.key}
|
|
120
|
+
const fullKey = `${options.key}(${subKey})`
|
|
121
121
|
const existing = core.selectors.get(fullKey)
|
|
122
122
|
if (existing) {
|
|
123
123
|
return deposit(existing)
|
package/src/internal/get.ts
CHANGED
|
@@ -96,7 +96,7 @@ export const getState__INTERNAL = <T>(
|
|
|
96
96
|
store.config.logger?.info(`>> read "${state.key}"`)
|
|
97
97
|
return readCachedValue(state.key, store)
|
|
98
98
|
}
|
|
99
|
-
if (`
|
|
99
|
+
if (state.type !== `atom`) {
|
|
100
100
|
store.config.logger?.info(`-> calc "${state.key}"`)
|
|
101
101
|
return computeSelectorState(state)
|
|
102
102
|
}
|
package/src/internal/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { Atom, ReadonlySelector, Selector } from "."
|
|
|
5
5
|
import { target } from "."
|
|
6
6
|
import type { Store } from "./store"
|
|
7
7
|
import { IMPLICIT } from "./store"
|
|
8
|
+
import type { StateToken } from ".."
|
|
8
9
|
|
|
9
10
|
export type OperationProgress =
|
|
10
11
|
| {
|
|
@@ -14,21 +15,32 @@ export type OperationProgress =
|
|
|
14
15
|
open: true
|
|
15
16
|
done: Set<string>
|
|
16
17
|
prev: Hamt<any, string>
|
|
18
|
+
time: number
|
|
19
|
+
token: StateToken<any>
|
|
17
20
|
}
|
|
18
21
|
|
|
19
|
-
export const openOperation = (store: Store): void => {
|
|
22
|
+
export const openOperation = (token: StateToken<any>, store: Store): void => {
|
|
20
23
|
const core = target(store)
|
|
24
|
+
if (core.operation.open) {
|
|
25
|
+
console.warn(core.operation.open)
|
|
26
|
+
store.config.logger?.error(
|
|
27
|
+
`❌ failed to setState to "${token.key}" during a setState for "${core.operation.token.key}"`
|
|
28
|
+
)
|
|
29
|
+
throw Symbol(`violation`)
|
|
30
|
+
}
|
|
21
31
|
core.operation = {
|
|
22
32
|
open: true,
|
|
23
33
|
done: new Set(),
|
|
24
34
|
prev: store.valueMap,
|
|
35
|
+
time: Date.now(),
|
|
36
|
+
token,
|
|
25
37
|
}
|
|
26
|
-
store.config.logger?.info(
|
|
38
|
+
store.config.logger?.info(`⭕ operation start from "${token.key}"`)
|
|
27
39
|
}
|
|
28
40
|
export const closeOperation = (store: Store): void => {
|
|
29
41
|
const core = target(store)
|
|
30
42
|
core.operation = { open: false }
|
|
31
|
-
store.config.logger?.info(
|
|
43
|
+
store.config.logger?.info(`🔴 operation done`)
|
|
32
44
|
}
|
|
33
45
|
|
|
34
46
|
export const isDone = (key: string, store: Store = IMPLICIT.STORE): boolean => {
|
|
@@ -138,8 +138,9 @@ export const registerSelector = (
|
|
|
138
138
|
)
|
|
139
139
|
} else {
|
|
140
140
|
store.config.logger?.info(
|
|
141
|
-
`🔌 registerSelector "${selectorKey}" <- "${dependency.key}" =`,
|
|
142
|
-
dependencyValue
|
|
141
|
+
`🔌 registerSelector "${selectorKey}" <- ( "${dependency.key}" =`,
|
|
142
|
+
dependencyValue,
|
|
143
|
+
`)`
|
|
143
144
|
)
|
|
144
145
|
core.selectorGraph = core.selectorGraph.set(selectorKey, dependency.key, {
|
|
145
146
|
source: dependency.key,
|
package/src/internal/store.ts
CHANGED
|
@@ -10,11 +10,10 @@ import type {
|
|
|
10
10
|
ReadonlySelector,
|
|
11
11
|
Selector,
|
|
12
12
|
TransactionStatus,
|
|
13
|
-
Logger,
|
|
14
13
|
Timeline,
|
|
15
14
|
TimelineData,
|
|
16
15
|
} from "."
|
|
17
|
-
import type { Transaction, ƒn } from ".."
|
|
16
|
+
import type { Logger, Transaction, ƒn } from ".."
|
|
18
17
|
|
|
19
18
|
export type StoreCore = Pick<
|
|
20
19
|
Store,
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
/* eslint-disable max-lines */
|
|
2
|
+
|
|
1
3
|
import HAMT from "hamt_plus"
|
|
2
4
|
|
|
3
5
|
import type { KeyedStateUpdate, TransactionUpdate, Store } from "."
|
|
4
|
-
import { IMPLICIT, withdraw } from "."
|
|
6
|
+
import { target, IMPLICIT, withdraw } from "."
|
|
5
7
|
import { setState } from ".."
|
|
6
8
|
import type { AtomToken, TimelineOptions, TimelineToken, ƒn } from ".."
|
|
7
9
|
|
|
@@ -12,8 +14,13 @@ export type Timeline = {
|
|
|
12
14
|
prev: () => void
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
export type
|
|
16
|
-
type: `
|
|
17
|
+
export type TimelineAtomUpdate = KeyedStateUpdate<unknown> & {
|
|
18
|
+
type: `atom_update`
|
|
19
|
+
}
|
|
20
|
+
export type TimelineSelectorUpdate = {
|
|
21
|
+
key: string
|
|
22
|
+
type: `selector_update`
|
|
23
|
+
atomUpdates: TimelineAtomUpdate[]
|
|
17
24
|
}
|
|
18
25
|
export type TimelineTransactionUpdate = TransactionUpdate<ƒn> & {
|
|
19
26
|
type: `transaction_update`
|
|
@@ -22,13 +29,19 @@ export type TimelineTransactionUpdate = TransactionUpdate<ƒn> & {
|
|
|
22
29
|
export type TimelineData = {
|
|
23
30
|
at: number
|
|
24
31
|
timeTraveling: boolean
|
|
25
|
-
history: (
|
|
32
|
+
history: (
|
|
33
|
+
| TimelineAtomUpdate
|
|
34
|
+
| TimelineSelectorUpdate
|
|
35
|
+
| TimelineTransactionUpdate
|
|
36
|
+
)[]
|
|
26
37
|
}
|
|
27
38
|
|
|
28
39
|
export function timeline__INTERNAL(
|
|
29
40
|
options: TimelineOptions,
|
|
30
41
|
store: Store = IMPLICIT.STORE
|
|
31
42
|
): TimelineToken {
|
|
43
|
+
let incompleteSelectorTime: number | null = null
|
|
44
|
+
// let selectorAtomUpdates: TimelineAtomUpdate[] = []
|
|
32
45
|
let incompleteTransactionKey: string | null = null
|
|
33
46
|
const timelineData: TimelineData = {
|
|
34
47
|
at: 0,
|
|
@@ -39,6 +52,15 @@ export function timeline__INTERNAL(
|
|
|
39
52
|
const subscribeToAtom = (token: AtomToken<any>) => {
|
|
40
53
|
const state = withdraw(token, store)
|
|
41
54
|
state.subject.subscribe((update) => {
|
|
55
|
+
const storeCurrentSelectorKey =
|
|
56
|
+
store.operation.open && store.operation.token.type === `selector`
|
|
57
|
+
? store.operation.token.key
|
|
58
|
+
: null
|
|
59
|
+
const storeCurrentSelectorTime =
|
|
60
|
+
store.operation.open && store.operation.token.type === `selector`
|
|
61
|
+
? store.operation.time
|
|
62
|
+
: null
|
|
63
|
+
|
|
42
64
|
const storeCurrentTransactionKey =
|
|
43
65
|
store.transactionStatus.phase === `applying`
|
|
44
66
|
? store.transactionStatus.key
|
|
@@ -70,6 +92,9 @@ export function timeline__INTERNAL(
|
|
|
70
92
|
incompleteTransactionKey = storeCurrentTransactionKey
|
|
71
93
|
const subscription = currentTransaction.subject.subscribe((update) => {
|
|
72
94
|
if (timelineData.timeTraveling === false) {
|
|
95
|
+
if (timelineData.at !== timelineData.history.length) {
|
|
96
|
+
timelineData.history.splice(timelineData.at)
|
|
97
|
+
}
|
|
73
98
|
timelineData.history.push({
|
|
74
99
|
type: `transaction_update`,
|
|
75
100
|
...update,
|
|
@@ -82,39 +107,100 @@ export function timeline__INTERNAL(
|
|
|
82
107
|
subscription.unsubscribe()
|
|
83
108
|
incompleteTransactionKey = null
|
|
84
109
|
store.config.logger?.info(
|
|
85
|
-
`⌛ timeline "${options.key}"
|
|
110
|
+
`⌛ timeline "${options.key}" got a transaction_update "${update.key}"`
|
|
86
111
|
)
|
|
87
112
|
})
|
|
88
113
|
}
|
|
114
|
+
} else if (storeCurrentSelectorKey) {
|
|
115
|
+
if (timelineData.timeTraveling === false) {
|
|
116
|
+
if (storeCurrentSelectorTime !== incompleteSelectorTime) {
|
|
117
|
+
const newSelectorUpdate: TimelineSelectorUpdate = {
|
|
118
|
+
type: `selector_update`,
|
|
119
|
+
key: storeCurrentSelectorKey,
|
|
120
|
+
atomUpdates: [],
|
|
121
|
+
}
|
|
122
|
+
newSelectorUpdate.atomUpdates.push({
|
|
123
|
+
key: token.key,
|
|
124
|
+
type: `atom_update`,
|
|
125
|
+
...update,
|
|
126
|
+
})
|
|
127
|
+
if (timelineData.at !== timelineData.history.length) {
|
|
128
|
+
timelineData.history.splice(timelineData.at)
|
|
129
|
+
}
|
|
130
|
+
timelineData.history.push(newSelectorUpdate)
|
|
131
|
+
|
|
132
|
+
store.config.logger?.info(
|
|
133
|
+
`⌛ timeline "${options.key}" got a selector_update "${storeCurrentSelectorKey}" with`,
|
|
134
|
+
newSelectorUpdate.atomUpdates.map((atomUpdate) => atomUpdate.key)
|
|
135
|
+
)
|
|
136
|
+
timelineData.at = timelineData.history.length
|
|
137
|
+
incompleteSelectorTime = storeCurrentSelectorTime
|
|
138
|
+
} else {
|
|
139
|
+
const latestUpdate = timelineData.history.at(-1)
|
|
140
|
+
if (latestUpdate?.type === `selector_update`) {
|
|
141
|
+
latestUpdate.atomUpdates.push({
|
|
142
|
+
key: token.key,
|
|
143
|
+
type: `atom_update`,
|
|
144
|
+
...update,
|
|
145
|
+
})
|
|
146
|
+
store.config.logger?.info(
|
|
147
|
+
` ⌛ timeline "${options.key}" set selector_update "${storeCurrentSelectorKey}" to`,
|
|
148
|
+
latestUpdate?.atomUpdates.map((atomUpdate) => atomUpdate.key)
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
89
153
|
} else {
|
|
90
154
|
if (timelineData.timeTraveling === false) {
|
|
155
|
+
incompleteSelectorTime = null
|
|
156
|
+
if (timelineData.at !== timelineData.history.length) {
|
|
157
|
+
timelineData.history.splice(timelineData.at)
|
|
158
|
+
}
|
|
91
159
|
timelineData.history.push({
|
|
92
|
-
type: `
|
|
160
|
+
type: `atom_update`,
|
|
93
161
|
key: token.key,
|
|
94
162
|
oldValue: update.oldValue,
|
|
95
163
|
newValue: update.newValue,
|
|
96
164
|
})
|
|
97
165
|
store.config.logger?.info(
|
|
98
|
-
`⌛ timeline "${options.key}"
|
|
166
|
+
`⌛ timeline "${options.key}" got a state_update to "${token.key}"`
|
|
99
167
|
)
|
|
100
168
|
timelineData.at = timelineData.history.length
|
|
101
169
|
}
|
|
102
170
|
}
|
|
103
171
|
})
|
|
104
172
|
}
|
|
105
|
-
|
|
173
|
+
const core = target(store)
|
|
106
174
|
for (const tokenOrFamily of options.atoms) {
|
|
175
|
+
const timelineKey = core.timelineAtoms.getRelatedId(tokenOrFamily.key)
|
|
176
|
+
if (timelineKey) {
|
|
177
|
+
store.config.logger?.error(
|
|
178
|
+
`❌ Failed to add atom "${tokenOrFamily.key}" to timeline "${options.key}" because it belongs to timeline "${timelineKey}"`
|
|
179
|
+
)
|
|
180
|
+
continue
|
|
181
|
+
}
|
|
107
182
|
if (tokenOrFamily.type === `atom_family`) {
|
|
108
183
|
const family = tokenOrFamily
|
|
109
184
|
family.subject.subscribe((token) => subscribeToAtom(token))
|
|
110
185
|
} else {
|
|
111
186
|
const token = tokenOrFamily
|
|
187
|
+
if (`family` in token && token.family) {
|
|
188
|
+
const familyTimelineKey = core.timelineAtoms.getRelatedId(
|
|
189
|
+
token.family.key
|
|
190
|
+
)
|
|
191
|
+
if (familyTimelineKey) {
|
|
192
|
+
store.config.logger?.error(
|
|
193
|
+
`❌ Failed to add atom "${token.key}" to timeline "${options.key}" because its family "${token.family.key}" belongs to timeline "${familyTimelineKey}"`
|
|
194
|
+
)
|
|
195
|
+
continue
|
|
196
|
+
}
|
|
197
|
+
}
|
|
112
198
|
subscribeToAtom(token)
|
|
113
199
|
}
|
|
200
|
+
core.timelineAtoms = core.timelineAtoms.set(tokenOrFamily.key, options.key)
|
|
114
201
|
}
|
|
115
202
|
|
|
116
203
|
store.timelineStore = HAMT.set(options.key, timelineData, store.timelineStore)
|
|
117
|
-
|
|
118
204
|
return {
|
|
119
205
|
key: options.key,
|
|
120
206
|
type: `timeline`,
|
|
@@ -125,27 +211,29 @@ export const redo__INTERNAL = (
|
|
|
125
211
|
token: TimelineToken,
|
|
126
212
|
store: Store = IMPLICIT.STORE
|
|
127
213
|
): void => {
|
|
214
|
+
store.config.logger?.info(`⏩ redo "${token.key}"`)
|
|
128
215
|
const timelineData = store.timelineStore.get(token.key)
|
|
129
216
|
if (!timelineData) {
|
|
130
217
|
store.config.logger?.error(
|
|
131
|
-
`
|
|
218
|
+
`Failed to redo on timeline "${token.key}". This timeline has not been initialized.`
|
|
132
219
|
)
|
|
133
220
|
return
|
|
134
221
|
}
|
|
135
222
|
if (timelineData.at === timelineData.history.length) {
|
|
136
223
|
store.config.logger?.warn(
|
|
137
|
-
`
|
|
224
|
+
`Failed to redo at the end of timeline "${token.key}". There is nothing to redo.`
|
|
138
225
|
)
|
|
139
226
|
return
|
|
140
227
|
}
|
|
141
228
|
timelineData.timeTraveling = true
|
|
142
229
|
const update = timelineData.history[timelineData.at]
|
|
143
230
|
switch (update.type) {
|
|
144
|
-
case `
|
|
231
|
+
case `atom_update`: {
|
|
145
232
|
const { key, newValue } = update
|
|
146
233
|
setState({ key, type: `atom` }, newValue)
|
|
147
234
|
break
|
|
148
235
|
}
|
|
236
|
+
case `selector_update`:
|
|
149
237
|
case `transaction_update`: {
|
|
150
238
|
for (const atomUpdate of update.atomUpdates) {
|
|
151
239
|
const { key, newValue } = atomUpdate
|
|
@@ -156,34 +244,40 @@ export const redo__INTERNAL = (
|
|
|
156
244
|
}
|
|
157
245
|
++timelineData.at
|
|
158
246
|
timelineData.timeTraveling = false
|
|
247
|
+
store.config.logger?.info(
|
|
248
|
+
`⏹️ "${token.key}" is now at ${timelineData.at} / ${timelineData.history.length}`
|
|
249
|
+
)
|
|
159
250
|
}
|
|
160
251
|
|
|
161
252
|
export const undo__INTERNAL = (
|
|
162
253
|
token: TimelineToken,
|
|
163
254
|
store: Store = IMPLICIT.STORE
|
|
164
255
|
): void => {
|
|
256
|
+
store.config.logger?.info(`⏪ undo "${token.key}"`)
|
|
165
257
|
const timelineData = store.timelineStore.get(token.key)
|
|
166
258
|
if (!timelineData) {
|
|
167
259
|
store.config.logger?.error(
|
|
168
|
-
`
|
|
260
|
+
`Failed to undo on timeline "${token.key}". This timeline has not been initialized.`
|
|
169
261
|
)
|
|
170
262
|
return
|
|
171
263
|
}
|
|
172
264
|
if (timelineData.at === 0) {
|
|
173
265
|
store.config.logger?.warn(
|
|
174
|
-
`
|
|
266
|
+
`Failed to undo at the beginning of timeline "${token.key}". There is nothing to undo.`
|
|
175
267
|
)
|
|
176
268
|
return
|
|
177
269
|
}
|
|
178
270
|
timelineData.timeTraveling = true
|
|
271
|
+
|
|
179
272
|
--timelineData.at
|
|
180
273
|
const update = timelineData.history[timelineData.at]
|
|
181
274
|
switch (update.type) {
|
|
182
|
-
case `
|
|
275
|
+
case `atom_update`: {
|
|
183
276
|
const { key, oldValue } = update
|
|
184
277
|
setState({ key, type: `atom` }, oldValue)
|
|
185
278
|
break
|
|
186
279
|
}
|
|
280
|
+
case `selector_update`:
|
|
187
281
|
case `transaction_update`: {
|
|
188
282
|
for (const atomUpdate of update.atomUpdates) {
|
|
189
283
|
const { key, oldValue } = atomUpdate
|
|
@@ -193,4 +287,7 @@ export const undo__INTERNAL = (
|
|
|
193
287
|
}
|
|
194
288
|
}
|
|
195
289
|
timelineData.timeTraveling = false
|
|
290
|
+
store.config.logger?.info(
|
|
291
|
+
`⏹️ "${token.key}" is now at ${timelineData.at} / ${timelineData.history.length}`
|
|
292
|
+
)
|
|
196
293
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { doNothing } from "~/packages/anvl/src/function"
|
|
2
2
|
|
|
3
|
-
import type { Store } from "./store"
|
|
4
|
-
import { IMPLICIT } from "./store"
|
|
3
|
+
import type { Store } from "./internal/store"
|
|
4
|
+
import { IMPLICIT } from "./internal/store"
|
|
5
5
|
|
|
6
6
|
export type Logger = Pick<Console, `error` | `info` | `warn`>
|
|
7
7
|
export const LOG_LEVELS: ReadonlyArray<keyof Logger> = [
|
package/src/selector.ts
CHANGED
|
@@ -4,12 +4,12 @@ import type { Serializable } from "~/packages/anvl/src/json"
|
|
|
4
4
|
|
|
5
5
|
import type { ReadonlyValueToken, SelectorToken } from "."
|
|
6
6
|
import { selectorFamily__INTERNAL, selector__INTERNAL } from "./internal"
|
|
7
|
-
import type {
|
|
7
|
+
import type { Read, Write } from "./transaction"
|
|
8
8
|
|
|
9
9
|
export type SelectorOptions<T> = {
|
|
10
10
|
key: string
|
|
11
|
-
get: (
|
|
12
|
-
set: (
|
|
11
|
+
get: Read<() => T>
|
|
12
|
+
set: Write<(newValue: T) => void>
|
|
13
13
|
}
|
|
14
14
|
export type ReadonlySelectorOptions<T> = Omit<SelectorOptions<T>, `set`>
|
|
15
15
|
|
|
@@ -25,8 +25,8 @@ export function selector<T>(
|
|
|
25
25
|
|
|
26
26
|
export type SelectorFamilyOptions<T, K extends Serializable> = {
|
|
27
27
|
key: string
|
|
28
|
-
get: (key: K) => (
|
|
29
|
-
set: (key: K) => (
|
|
28
|
+
get: (key: K) => Read<() => T>
|
|
29
|
+
set: (key: K) => Write<(newValue: T) => void>
|
|
30
30
|
}
|
|
31
31
|
export type ReadonlySelectorFamilyOptions<T, K extends Serializable> = Omit<
|
|
32
32
|
SelectorFamilyOptions<T, K>,
|
package/src/subscribe.ts
CHANGED
|
@@ -14,7 +14,7 @@ export const subscribe = <T>(
|
|
|
14
14
|
const subscription = state.subject.subscribe(handleUpdate)
|
|
15
15
|
store.config.logger?.info(`👀 subscribe to "${state.key}"`)
|
|
16
16
|
const dependencySubscriptions =
|
|
17
|
-
`
|
|
17
|
+
state.type !== `atom` ? subscribeToRootAtoms(state, store) : null
|
|
18
18
|
|
|
19
19
|
const unsubscribe =
|
|
20
20
|
dependencySubscriptions === null
|
package/src/timeline.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import type { AtomFamily, AtomToken, ƒn } from "."
|
|
5
|
-
import { setState } from "."
|
|
6
|
-
import type { Store, KeyedStateUpdate, TransactionUpdate } from "./internal"
|
|
7
|
-
import { target, IMPLICIT, withdraw } from "./internal"
|
|
1
|
+
import type { AtomFamily, AtomToken } from "."
|
|
2
|
+
import { IMPLICIT } from "./internal"
|
|
8
3
|
import {
|
|
9
4
|
redo__INTERNAL,
|
|
10
5
|
timeline__INTERNAL,
|
package/src/transaction.ts
CHANGED
|
@@ -12,14 +12,19 @@ export type Transactors = {
|
|
|
12
12
|
}
|
|
13
13
|
export type ReadonlyTransactors = Pick<Transactors, `get`>
|
|
14
14
|
|
|
15
|
-
export type
|
|
15
|
+
export type Read<ƒ extends ƒn> = (
|
|
16
|
+
transactors: ReadonlyTransactors,
|
|
17
|
+
...parameters: Parameters<ƒ>
|
|
18
|
+
) => ReturnType<ƒ>
|
|
19
|
+
|
|
20
|
+
export type Write<ƒ extends ƒn> = (
|
|
16
21
|
transactors: Transactors,
|
|
17
22
|
...parameters: Parameters<ƒ>
|
|
18
23
|
) => ReturnType<ƒ>
|
|
19
24
|
|
|
20
25
|
export type TransactionOptions<ƒ extends ƒn> = {
|
|
21
26
|
key: string
|
|
22
|
-
do:
|
|
27
|
+
do: Write<ƒ>
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
export type Transaction<ƒ extends ƒn> = {
|