atom.io 0.1.0 → 0.2.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.
- package/README.md +11 -11
- package/dist/{index-3b5d305c.d.ts → index-9d9f5a05.d.ts} +66 -30
- package/dist/index.d.ts +1 -1
- package/dist/index.js +206 -100
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +205 -99
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.ts +11 -7
- package/dist/react/index.js +222 -93
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +221 -92
- package/dist/react/index.mjs.map +1 -1
- package/package.json +21 -7
- package/react/package.json +6 -0
- package/src/atom.ts +78 -0
- package/src/index.ts +91 -0
- package/src/internal/get.ts +109 -0
- package/src/internal/index.ts +23 -0
- package/src/internal/is-default.ts +19 -0
- package/src/internal/operation.ts +49 -0
- package/src/internal/selector-internal.ts +127 -0
- package/src/internal/set.ts +88 -0
- package/src/internal/store.ts +84 -0
- package/src/internal/subscribe-internal.ts +33 -0
- package/src/internal/transaction-internal.ts +34 -0
- package/src/react/index.ts +65 -0
- package/src/selector.ts +132 -0
- package/src/transaction.ts +53 -0
package/src/selector.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import HAMT from "hamt_plus"
|
|
2
|
+
import * as Rx from "rxjs"
|
|
3
|
+
|
|
4
|
+
import { become } from "~/packages/anvl/src/function"
|
|
5
|
+
import type { Serializable } from "~/packages/anvl/src/json"
|
|
6
|
+
import { stringifyJson } from "~/packages/anvl/src/json"
|
|
7
|
+
|
|
8
|
+
import type { ReadonlyValueToken, SelectorToken } from "."
|
|
9
|
+
import type { Selector, Store } from "./internal"
|
|
10
|
+
import { IMPLICIT, markDone, deposit, registerSelector } from "./internal"
|
|
11
|
+
import type { ReadonlyTransactors, Transactors } from "./transaction"
|
|
12
|
+
|
|
13
|
+
export type SelectorOptions<T> = {
|
|
14
|
+
key: string
|
|
15
|
+
get: (readonlyTransactors: ReadonlyTransactors) => T
|
|
16
|
+
set: (transactors: Transactors, newValue: T) => void
|
|
17
|
+
}
|
|
18
|
+
export type ReadonlySelectorOptions<T> = Omit<SelectorOptions<T>, `set`>
|
|
19
|
+
|
|
20
|
+
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
|
|
27
|
+
): ReadonlyValueToken<T>
|
|
28
|
+
export function selector<T>(
|
|
29
|
+
options: ReadonlySelectorOptions<T> | SelectorOptions<T>,
|
|
30
|
+
store: Store = IMPLICIT.STORE
|
|
31
|
+
): 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` }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export type SelectorFamilyOptions<T, K extends Serializable> = {
|
|
84
|
+
key: string
|
|
85
|
+
get: (key: K) => (readonlyTransactors: ReadonlyTransactors) => T
|
|
86
|
+
set: (key: K) => (transactors: Transactors, newValue: T) => void
|
|
87
|
+
}
|
|
88
|
+
export type ReadonlySelectorFamilyOptions<T, K extends Serializable> = Omit<
|
|
89
|
+
SelectorFamilyOptions<T, K>,
|
|
90
|
+
`set`
|
|
91
|
+
>
|
|
92
|
+
|
|
93
|
+
export function selectorFamily<T, K extends Serializable>(
|
|
94
|
+
options: SelectorFamilyOptions<T, K>,
|
|
95
|
+
store?: Store
|
|
96
|
+
): (key: K) => SelectorToken<T>
|
|
97
|
+
export function selectorFamily<T, K extends Serializable>(
|
|
98
|
+
options: ReadonlySelectorFamilyOptions<T, K>,
|
|
99
|
+
store?: Store
|
|
100
|
+
): (key: K) => ReadonlyValueToken<T>
|
|
101
|
+
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
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ReadonlyValueToken, StateToken } from "."
|
|
2
|
+
import { getState, setState } from "."
|
|
3
|
+
import type { Store } from "./internal"
|
|
4
|
+
import { IMPLICIT } from "./internal"
|
|
5
|
+
import {
|
|
6
|
+
abortTransaction,
|
|
7
|
+
finishTransaction,
|
|
8
|
+
startTransaction,
|
|
9
|
+
} from "./internal/transaction-internal"
|
|
10
|
+
|
|
11
|
+
export type ƒn = (...parameters: any[]) => any
|
|
12
|
+
|
|
13
|
+
export type Transactors = {
|
|
14
|
+
get: <S>(state: ReadonlyValueToken<S> | StateToken<S>) => S
|
|
15
|
+
set: <S>(state: StateToken<S>, newValue: S | ((oldValue: S) => S)) => void
|
|
16
|
+
}
|
|
17
|
+
export type ReadonlyTransactors = Pick<Transactors, `get`>
|
|
18
|
+
|
|
19
|
+
export type Action<ƒ extends ƒn> = (
|
|
20
|
+
transactors: Transactors,
|
|
21
|
+
...parameters: Parameters<ƒ>
|
|
22
|
+
) => ReturnType<ƒ>
|
|
23
|
+
|
|
24
|
+
export type TransactionOptions<ƒ extends ƒn> = {
|
|
25
|
+
key: string
|
|
26
|
+
do: Action<ƒ>
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const transaction = <ƒ extends ƒn>(
|
|
30
|
+
options: TransactionOptions<ƒ>,
|
|
31
|
+
store: Store = IMPLICIT.STORE
|
|
32
|
+
): ((...parameters: Parameters<ƒ>) => ReturnType<ƒ>) & { key: string } =>
|
|
33
|
+
Object.assign(
|
|
34
|
+
(...parameters: Parameters<ƒ>) => {
|
|
35
|
+
startTransaction(store)
|
|
36
|
+
try {
|
|
37
|
+
const result = options.do(
|
|
38
|
+
{
|
|
39
|
+
get: (token) => getState(token, store),
|
|
40
|
+
set: (token, value) => setState(token, value, store),
|
|
41
|
+
},
|
|
42
|
+
...parameters
|
|
43
|
+
)
|
|
44
|
+
finishTransaction(store)
|
|
45
|
+
return result
|
|
46
|
+
} catch (thrown) {
|
|
47
|
+
abortTransaction(store)
|
|
48
|
+
store.config.logger?.error(`Transaction ${options.key} failed`, thrown)
|
|
49
|
+
throw thrown
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
{ key: options.key }
|
|
53
|
+
)
|