atom.io 0.2.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 +8 -15
- package/dist/index.d.ts +507 -4
- package/dist/index.js +924 -368
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +913 -364
- package/dist/index.mjs.map +1 -1
- package/package.json +24 -6
- package/{dist/react → react/dist}/index.d.ts +2 -5
- package/react/dist/index.js +68 -0
- package/react/dist/index.js.map +1 -0
- package/react/dist/index.mjs +44 -0
- package/react/dist/index.mjs.map +1 -0
- package/react/package.json +12 -3
- package/src/atom.ts +18 -53
- package/src/index.ts +29 -37
- package/src/internal/atom-internal.ts +50 -0
- package/src/internal/families-internal.ts +142 -0
- package/src/internal/get.ts +41 -43
- package/src/internal/index.ts +5 -17
- package/src/internal/is-default.ts +20 -4
- package/src/internal/operation.ts +111 -16
- package/src/internal/selector-internal.ts +116 -15
- package/src/internal/set.ts +31 -17
- package/src/internal/store.ts +57 -45
- package/src/internal/subscribe-internal.ts +55 -11
- package/src/internal/timeline-internal.ts +293 -0
- package/src/internal/transaction-internal.ts +157 -16
- package/src/logger.ts +46 -0
- package/src/react/index.ts +5 -6
- package/src/selector.ts +34 -104
- package/src/subscribe.ts +55 -0
- package/src/timeline.ts +29 -0
- package/src/transaction.ts +29 -36
- package/dist/index-9d9f5a05.d.ts +0 -293
- package/dist/react/index.js +0 -909
- package/dist/react/index.js.map +0 -1
- package/dist/react/index.mjs +0 -880
- package/dist/react/index.mjs.map +0 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// ../src/react/index.ts
|
|
20
|
+
var react_exports = {};
|
|
21
|
+
__export(react_exports, {
|
|
22
|
+
composeStoreHooks: () => composeStoreHooks
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(react_exports);
|
|
25
|
+
var import_atom = require("atom.io");
|
|
26
|
+
var composeStoreHooks = ({
|
|
27
|
+
useState,
|
|
28
|
+
useEffect,
|
|
29
|
+
store = import_atom.__INTERNAL__.IMPLICIT.STORE
|
|
30
|
+
}) => {
|
|
31
|
+
function useI(token) {
|
|
32
|
+
const updateState = (next) => (0, import_atom.setState)(token, next, store);
|
|
33
|
+
return updateState;
|
|
34
|
+
}
|
|
35
|
+
function useO(token) {
|
|
36
|
+
const state = import_atom.__INTERNAL__.withdraw(token, store);
|
|
37
|
+
const initialValue = import_atom.__INTERNAL__.getState__INTERNAL(state, store);
|
|
38
|
+
const [current, dispatch] = useState(initialValue);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const unsubscribe = (0, import_atom.subscribe)(
|
|
41
|
+
token,
|
|
42
|
+
({ newValue, oldValue }) => {
|
|
43
|
+
if (oldValue !== newValue) {
|
|
44
|
+
dispatch(newValue);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
store
|
|
48
|
+
);
|
|
49
|
+
return unsubscribe;
|
|
50
|
+
}, []);
|
|
51
|
+
return current;
|
|
52
|
+
}
|
|
53
|
+
function useIO(token) {
|
|
54
|
+
return [useO(token), useI(token)];
|
|
55
|
+
}
|
|
56
|
+
function useStore(token) {
|
|
57
|
+
if (token.type === `readonly_selector`) {
|
|
58
|
+
return useO(token);
|
|
59
|
+
}
|
|
60
|
+
return useIO(token);
|
|
61
|
+
}
|
|
62
|
+
return { useI, useO, useIO, useStore };
|
|
63
|
+
};
|
|
64
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
65
|
+
0 && (module.exports = {
|
|
66
|
+
composeStoreHooks
|
|
67
|
+
});
|
|
68
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/react/index.ts"],"sourcesContent":["import type Preact from \"preact/hooks\"\n\nimport type React from \"react\"\n\nimport { subscribe, setState, __INTERNAL__ } from \"atom.io\"\nimport type { ReadonlyValueToken, StateToken } from \"atom.io\"\n\nimport type { Modifier } from \"~/packages/anvl/src/function\"\n\nexport type AtomStoreReactConfig = {\n useState: typeof Preact.useState | typeof React.useState\n useEffect: typeof Preact.useEffect | typeof React.useEffect\n store?: __INTERNAL__.Store\n}\n\n/* eslint-disable @typescript-eslint/explicit-module-boundary-types */\nexport const composeStoreHooks = ({\n useState,\n useEffect,\n store = __INTERNAL__.IMPLICIT.STORE,\n}: AtomStoreReactConfig) => {\n function useI<T>(token: StateToken<T>): (next: Modifier<T> | T) => void {\n const updateState = (next: Modifier<T> | T) => setState(token, next, store)\n return updateState\n }\n\n function useO<T>(token: ReadonlyValueToken<T> | StateToken<T>): T {\n const state = __INTERNAL__.withdraw(token, store)\n const initialValue = __INTERNAL__.getState__INTERNAL(state, store)\n const [current, dispatch] = useState(initialValue)\n useEffect(() => {\n const unsubscribe = subscribe(\n token,\n ({ newValue, oldValue }) => {\n if (oldValue !== newValue) {\n dispatch(newValue)\n }\n },\n store\n )\n return unsubscribe\n }, [])\n\n return current\n }\n\n function useIO<T>(token: StateToken<T>): [T, (next: Modifier<T> | T) => void] {\n return [useO(token), useI(token)]\n }\n\n function useStore<T>(\n token: StateToken<T>\n ): [T, (next: Modifier<T> | T) => void]\n function useStore<T>(token: ReadonlyValueToken<T>): T\n function useStore<T>(\n token: ReadonlyValueToken<T> | StateToken<T>\n ): T | [T, (next: Modifier<T> | T) => void] {\n if (token.type === `readonly_selector`) {\n return useO(token)\n }\n return useIO(token)\n }\n return { useI, useO, useIO, useStore }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,kBAAkD;AAY3C,IAAM,oBAAoB,CAAC;AAAA,EAChC;AAAA,EACA;AAAA,EACA,QAAQ,yBAAa,SAAS;AAChC,MAA4B;AAC1B,WAAS,KAAQ,OAAuD;AACtE,UAAM,cAAc,CAAC,aAA0B,sBAAS,OAAO,MAAM,KAAK;AAC1E,WAAO;AAAA,EACT;AAEA,WAAS,KAAQ,OAAiD;AAChE,UAAM,QAAQ,yBAAa,SAAS,OAAO,KAAK;AAChD,UAAM,eAAe,yBAAa,mBAAmB,OAAO,KAAK;AACjE,UAAM,CAAC,SAAS,QAAQ,IAAI,SAAS,YAAY;AACjD,cAAU,MAAM;AACd,YAAM,kBAAc;AAAA,QAClB;AAAA,QACA,CAAC,EAAE,UAAU,SAAS,MAAM;AAC1B,cAAI,aAAa,UAAU;AACzB,qBAAS,QAAQ;AAAA,UACnB;AAAA,QACF;AAAA,QACA;AAAA,MACF;AACA,aAAO;AAAA,IACT,GAAG,CAAC,CAAC;AAEL,WAAO;AAAA,EACT;AAEA,WAAS,MAAS,OAA4D;AAC5E,WAAO,CAAC,KAAK,KAAK,GAAG,KAAK,KAAK,CAAC;AAAA,EAClC;AAMA,WAAS,SACP,OAC0C;AAC1C,QAAI,MAAM,SAAS,qBAAqB;AACtC,aAAO,KAAK,KAAK;AAAA,IACnB;AACA,WAAO,MAAM,KAAK;AAAA,EACpB;AACA,SAAO,EAAE,MAAM,MAAM,OAAO,SAAS;AACvC;","names":[]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// ../src/react/index.ts
|
|
2
|
+
import { subscribe, setState, __INTERNAL__ } from "atom.io";
|
|
3
|
+
var composeStoreHooks = ({
|
|
4
|
+
useState,
|
|
5
|
+
useEffect,
|
|
6
|
+
store = __INTERNAL__.IMPLICIT.STORE
|
|
7
|
+
}) => {
|
|
8
|
+
function useI(token) {
|
|
9
|
+
const updateState = (next) => setState(token, next, store);
|
|
10
|
+
return updateState;
|
|
11
|
+
}
|
|
12
|
+
function useO(token) {
|
|
13
|
+
const state = __INTERNAL__.withdraw(token, store);
|
|
14
|
+
const initialValue = __INTERNAL__.getState__INTERNAL(state, store);
|
|
15
|
+
const [current, dispatch] = useState(initialValue);
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const unsubscribe = subscribe(
|
|
18
|
+
token,
|
|
19
|
+
({ newValue, oldValue }) => {
|
|
20
|
+
if (oldValue !== newValue) {
|
|
21
|
+
dispatch(newValue);
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
store
|
|
25
|
+
);
|
|
26
|
+
return unsubscribe;
|
|
27
|
+
}, []);
|
|
28
|
+
return current;
|
|
29
|
+
}
|
|
30
|
+
function useIO(token) {
|
|
31
|
+
return [useO(token), useI(token)];
|
|
32
|
+
}
|
|
33
|
+
function useStore(token) {
|
|
34
|
+
if (token.type === `readonly_selector`) {
|
|
35
|
+
return useO(token);
|
|
36
|
+
}
|
|
37
|
+
return useIO(token);
|
|
38
|
+
}
|
|
39
|
+
return { useI, useO, useIO, useStore };
|
|
40
|
+
};
|
|
41
|
+
export {
|
|
42
|
+
composeStoreHooks
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/react/index.ts"],"sourcesContent":["import type Preact from \"preact/hooks\"\n\nimport type React from \"react\"\n\nimport { subscribe, setState, __INTERNAL__ } from \"atom.io\"\nimport type { ReadonlyValueToken, StateToken } from \"atom.io\"\n\nimport type { Modifier } from \"~/packages/anvl/src/function\"\n\nexport type AtomStoreReactConfig = {\n useState: typeof Preact.useState | typeof React.useState\n useEffect: typeof Preact.useEffect | typeof React.useEffect\n store?: __INTERNAL__.Store\n}\n\n/* eslint-disable @typescript-eslint/explicit-module-boundary-types */\nexport const composeStoreHooks = ({\n useState,\n useEffect,\n store = __INTERNAL__.IMPLICIT.STORE,\n}: AtomStoreReactConfig) => {\n function useI<T>(token: StateToken<T>): (next: Modifier<T> | T) => void {\n const updateState = (next: Modifier<T> | T) => setState(token, next, store)\n return updateState\n }\n\n function useO<T>(token: ReadonlyValueToken<T> | StateToken<T>): T {\n const state = __INTERNAL__.withdraw(token, store)\n const initialValue = __INTERNAL__.getState__INTERNAL(state, store)\n const [current, dispatch] = useState(initialValue)\n useEffect(() => {\n const unsubscribe = subscribe(\n token,\n ({ newValue, oldValue }) => {\n if (oldValue !== newValue) {\n dispatch(newValue)\n }\n },\n store\n )\n return unsubscribe\n }, [])\n\n return current\n }\n\n function useIO<T>(token: StateToken<T>): [T, (next: Modifier<T> | T) => void] {\n return [useO(token), useI(token)]\n }\n\n function useStore<T>(\n token: StateToken<T>\n ): [T, (next: Modifier<T> | T) => void]\n function useStore<T>(token: ReadonlyValueToken<T>): T\n function useStore<T>(\n token: ReadonlyValueToken<T> | StateToken<T>\n ): T | [T, (next: Modifier<T> | T) => void] {\n if (token.type === `readonly_selector`) {\n return useO(token)\n }\n return useIO(token)\n }\n return { useI, useO, useIO, useStore }\n}\n"],"mappings":";AAIA,SAAS,WAAW,UAAU,oBAAoB;AAY3C,IAAM,oBAAoB,CAAC;AAAA,EAChC;AAAA,EACA;AAAA,EACA,QAAQ,aAAa,SAAS;AAChC,MAA4B;AAC1B,WAAS,KAAQ,OAAuD;AACtE,UAAM,cAAc,CAAC,SAA0B,SAAS,OAAO,MAAM,KAAK;AAC1E,WAAO;AAAA,EACT;AAEA,WAAS,KAAQ,OAAiD;AAChE,UAAM,QAAQ,aAAa,SAAS,OAAO,KAAK;AAChD,UAAM,eAAe,aAAa,mBAAmB,OAAO,KAAK;AACjE,UAAM,CAAC,SAAS,QAAQ,IAAI,SAAS,YAAY;AACjD,cAAU,MAAM;AACd,YAAM,cAAc;AAAA,QAClB;AAAA,QACA,CAAC,EAAE,UAAU,SAAS,MAAM;AAC1B,cAAI,aAAa,UAAU;AACzB,qBAAS,QAAQ;AAAA,UACnB;AAAA,QACF;AAAA,QACA;AAAA,MACF;AACA,aAAO;AAAA,IACT,GAAG,CAAC,CAAC;AAEL,WAAO;AAAA,EACT;AAEA,WAAS,MAAS,OAA4D;AAC5E,WAAO,CAAC,KAAK,KAAK,GAAG,KAAK,KAAK,CAAC;AAAA,EAClC;AAMA,WAAS,SACP,OAC0C;AAC1C,QAAI,MAAM,SAAS,qBAAqB;AACtC,aAAO,KAAK,KAAK;AAAA,IACnB;AACA,WAAO,MAAM,KAAK;AAAA,EACpB;AACA,SAAO,EAAE,MAAM,MAAM,OAAO,SAAS;AACvC;","names":[]}
|
package/react/package.json
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "atom.io-react",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"private": true,
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"browser": "./dist/index.mjs",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
6
15
|
}
|
package/src/atom.ts
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as Rx from "rxjs"
|
|
1
|
+
import type * as Rx from "rxjs"
|
|
3
2
|
|
|
4
3
|
import type { Serializable } from "~/packages/anvl/src/json"
|
|
5
|
-
import { stringifyJson } from "~/packages/anvl/src/json"
|
|
6
4
|
|
|
7
|
-
import type { AtomToken
|
|
8
|
-
import {
|
|
9
|
-
import { deposit } from "./internal"
|
|
10
|
-
import type { Store } from "./internal/store"
|
|
11
|
-
import { IMPLICIT } from "./internal/store"
|
|
5
|
+
import type { AtomToken } from "."
|
|
6
|
+
import { atomFamily__INTERNAL, atom__INTERNAL } from "./internal"
|
|
12
7
|
|
|
13
8
|
export type Effectors<T> = {
|
|
14
9
|
setSelf: <V extends T>(next: V | ((oldValue: T) => V)) => void
|
|
@@ -23,28 +18,8 @@ export type AtomOptions<T> = {
|
|
|
23
18
|
effects?: AtomEffect<T>[]
|
|
24
19
|
}
|
|
25
20
|
|
|
26
|
-
export
|
|
27
|
-
|
|
28
|
-
store: Store = IMPLICIT.STORE
|
|
29
|
-
): AtomToken<T> => {
|
|
30
|
-
if (HAMT.has(options.key, store.atoms)) {
|
|
31
|
-
store.config.logger?.error?.(
|
|
32
|
-
`Key "${options.key}" already exists in the store.`
|
|
33
|
-
)
|
|
34
|
-
return deposit(store.atoms.get(options.key))
|
|
35
|
-
}
|
|
36
|
-
const subject = new Rx.Subject<{ newValue: T; oldValue: T }>()
|
|
37
|
-
const newAtom = { ...options, subject }
|
|
38
|
-
const initialValue =
|
|
39
|
-
options.default instanceof Function ? options.default() : options.default
|
|
40
|
-
store.atoms = HAMT.set(options.key, newAtom, store.atoms)
|
|
41
|
-
store.atomsAreDefault = HAMT.set(options.key, true, store.atomsAreDefault)
|
|
42
|
-
store.valueMap = HAMT.set(options.key, initialValue, store.valueMap)
|
|
43
|
-
const token = deposit(newAtom)
|
|
44
|
-
const setSelf = (next) => setState(token, next, store)
|
|
45
|
-
const onSet = (observe: ObserveState<T>) => subscribe(token, observe, store)
|
|
46
|
-
options.effects?.forEach((effect) => effect({ setSelf, onSet }))
|
|
47
|
-
return token
|
|
21
|
+
export function atom<T>(options: AtomOptions<T>): AtomToken<T> {
|
|
22
|
+
return atom__INTERNAL<T>(options)
|
|
48
23
|
}
|
|
49
24
|
|
|
50
25
|
export type AtomFamilyOptions<T, K extends Serializable> = {
|
|
@@ -53,26 +28,16 @@ export type AtomFamilyOptions<T, K extends Serializable> = {
|
|
|
53
28
|
effects?: (key: K) => AtomEffect<T>[]
|
|
54
29
|
}
|
|
55
30
|
|
|
56
|
-
export
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
key: fullKey,
|
|
70
|
-
default:
|
|
71
|
-
options.default instanceof Function
|
|
72
|
-
? options.default(key)
|
|
73
|
-
: options.default,
|
|
74
|
-
effects: options.effects?.(key),
|
|
75
|
-
},
|
|
76
|
-
store
|
|
77
|
-
)
|
|
78
|
-
}
|
|
31
|
+
export type AtomFamily<T, K extends Serializable = Serializable> = ((
|
|
32
|
+
key: K
|
|
33
|
+
) => AtomToken<T>) & {
|
|
34
|
+
key: string
|
|
35
|
+
type: `atom_family`
|
|
36
|
+
subject: Rx.Subject<AtomToken<T>>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function atomFamily<T, K extends Serializable>(
|
|
40
|
+
options: AtomFamilyOptions<T, K>
|
|
41
|
+
): AtomFamily<T, K> {
|
|
42
|
+
return atomFamily__INTERNAL<T, K>(options)
|
|
43
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,36 +1,51 @@
|
|
|
1
1
|
import {
|
|
2
2
|
IMPLICIT,
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
closeOperation,
|
|
4
|
+
openOperation,
|
|
5
5
|
getState__INTERNAL,
|
|
6
6
|
setState__INTERNAL,
|
|
7
7
|
isAtomDefault,
|
|
8
8
|
isSelectorDefault,
|
|
9
|
-
startAction,
|
|
10
|
-
subscribeToRootAtoms,
|
|
11
9
|
withdraw,
|
|
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
|
+
export * from "./timeline"
|
|
18
19
|
export * from "./transaction"
|
|
19
|
-
export { __INTERNAL__
|
|
20
|
+
export { __INTERNAL__ }
|
|
21
|
+
export type { Serializable } from "~/packages/anvl/src/json"
|
|
20
22
|
|
|
21
23
|
export type AtomToken<_> = {
|
|
22
24
|
key: string
|
|
23
25
|
type: `atom`
|
|
26
|
+
family?: FamilyMetadata
|
|
24
27
|
}
|
|
25
28
|
export type SelectorToken<_> = {
|
|
26
29
|
key: string
|
|
27
30
|
type: `selector`
|
|
31
|
+
family?: FamilyMetadata
|
|
28
32
|
}
|
|
29
33
|
export type StateToken<T> = AtomToken<T> | SelectorToken<T>
|
|
30
34
|
|
|
31
35
|
export type ReadonlyValueToken<_> = {
|
|
32
36
|
key: string
|
|
33
37
|
type: `readonly_selector`
|
|
38
|
+
family?: FamilyMetadata
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type FamilyMetadata = {
|
|
42
|
+
key: string
|
|
43
|
+
subKey: string
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type TransactionToken<_> = {
|
|
47
|
+
key: string
|
|
48
|
+
type: `transaction`
|
|
34
49
|
}
|
|
35
50
|
|
|
36
51
|
export const getState = <T>(
|
|
@@ -46,10 +61,17 @@ export const setState = <T, New extends T>(
|
|
|
46
61
|
value: New | ((oldValue: T) => New),
|
|
47
62
|
store: Store = IMPLICIT.STORE
|
|
48
63
|
): void => {
|
|
49
|
-
|
|
64
|
+
try {
|
|
65
|
+
openOperation(token, store)
|
|
66
|
+
} catch (thrown) {
|
|
67
|
+
if (!(typeof thrown === `symbol`)) {
|
|
68
|
+
throw thrown
|
|
69
|
+
}
|
|
70
|
+
return
|
|
71
|
+
}
|
|
50
72
|
const state = withdraw(token, store)
|
|
51
73
|
setState__INTERNAL(state, value, store)
|
|
52
|
-
|
|
74
|
+
closeOperation(store)
|
|
53
75
|
}
|
|
54
76
|
|
|
55
77
|
export const isDefault = (
|
|
@@ -59,33 +81,3 @@ export const isDefault = (
|
|
|
59
81
|
token.type === `atom`
|
|
60
82
|
? isAtomDefault(token.key, store)
|
|
61
83
|
: isSelectorDefault(token.key, store)
|
|
62
|
-
|
|
63
|
-
export type ObserveState<T> = (change: { newValue: T; oldValue: T }) => void
|
|
64
|
-
|
|
65
|
-
export const subscribe = <T>(
|
|
66
|
-
token: ReadonlyValueToken<T> | StateToken<T>,
|
|
67
|
-
observe: ObserveState<T>,
|
|
68
|
-
store: Store = IMPLICIT.STORE
|
|
69
|
-
): (() => void) => {
|
|
70
|
-
const state = withdraw<T>(token, store)
|
|
71
|
-
const subscription = state.subject.subscribe(observe)
|
|
72
|
-
store.config.logger?.info(`👀 subscribe to "${state.key}"`)
|
|
73
|
-
const dependencySubscriptions = subscribeToRootAtoms(state, store)
|
|
74
|
-
const unsubscribe =
|
|
75
|
-
dependencySubscriptions === null
|
|
76
|
-
? () => {
|
|
77
|
-
store.config.logger?.info(`🙈 unsubscribe from "${state.key}"`)
|
|
78
|
-
subscription.unsubscribe()
|
|
79
|
-
}
|
|
80
|
-
: () => {
|
|
81
|
-
store.config.logger?.info(
|
|
82
|
-
`🙈 unsubscribe from "${state.key}" and its dependencies`
|
|
83
|
-
)
|
|
84
|
-
subscription.unsubscribe()
|
|
85
|
-
for (const dependencySubscription of dependencySubscriptions) {
|
|
86
|
-
dependencySubscription.unsubscribe()
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return unsubscribe
|
|
91
|
-
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as Rx from "rxjs"
|
|
2
|
+
|
|
3
|
+
import { deposit } from "./get"
|
|
4
|
+
import { markAtomAsDefault } from "./is-default"
|
|
5
|
+
import { cacheValue, hasKeyBeenUsed, storeAtom } from "./operation"
|
|
6
|
+
import type { Store } from "./store"
|
|
7
|
+
import { IMPLICIT } from "./store"
|
|
8
|
+
import { target } from "./transaction-internal"
|
|
9
|
+
import type { AtomToken, FamilyMetadata, UpdateHandler } from ".."
|
|
10
|
+
import { setState, subscribe } from ".."
|
|
11
|
+
import type { AtomOptions } from "../atom"
|
|
12
|
+
|
|
13
|
+
export type Atom<T> = {
|
|
14
|
+
key: string
|
|
15
|
+
type: `atom`
|
|
16
|
+
family?: FamilyMetadata
|
|
17
|
+
subject: Rx.Subject<{ newValue: T; oldValue: T }>
|
|
18
|
+
default: T
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function atom__INTERNAL<T>(
|
|
22
|
+
options: AtomOptions<T>,
|
|
23
|
+
family?: FamilyMetadata,
|
|
24
|
+
store: Store = IMPLICIT.STORE
|
|
25
|
+
): AtomToken<T> {
|
|
26
|
+
const core = target(store)
|
|
27
|
+
if (hasKeyBeenUsed(options.key, store)) {
|
|
28
|
+
store.config.logger?.error?.(
|
|
29
|
+
`Key "${options.key}" already exists in the store.`
|
|
30
|
+
)
|
|
31
|
+
return deposit(core.atoms.get(options.key))
|
|
32
|
+
}
|
|
33
|
+
const subject = new Rx.Subject<{ newValue: T; oldValue: T }>()
|
|
34
|
+
const newAtom = {
|
|
35
|
+
...options,
|
|
36
|
+
subject,
|
|
37
|
+
type: `atom`,
|
|
38
|
+
...(family && { family }),
|
|
39
|
+
} as const
|
|
40
|
+
const initialValue =
|
|
41
|
+
options.default instanceof Function ? options.default() : options.default
|
|
42
|
+
storeAtom(newAtom, store)
|
|
43
|
+
markAtomAsDefault(options.key, store)
|
|
44
|
+
cacheValue(options.key, initialValue, store)
|
|
45
|
+
const token = deposit(newAtom)
|
|
46
|
+
const setSelf = (next) => setState(token, next, store)
|
|
47
|
+
const onSet = (handle: UpdateHandler<T>) => subscribe(token, handle, store)
|
|
48
|
+
options.effects?.forEach((effect) => effect({ setSelf, onSet }))
|
|
49
|
+
return token
|
|
50
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import * as Rx from "rxjs"
|
|
2
|
+
|
|
3
|
+
import type { Serializable } from "~/packages/anvl/src/json"
|
|
4
|
+
import { stringifyJson } from "~/packages/anvl/src/json"
|
|
5
|
+
|
|
6
|
+
import type { Store } from "."
|
|
7
|
+
import {
|
|
8
|
+
atom__INTERNAL,
|
|
9
|
+
withdraw,
|
|
10
|
+
selector__INTERNAL,
|
|
11
|
+
target,
|
|
12
|
+
deposit,
|
|
13
|
+
IMPLICIT,
|
|
14
|
+
} from "."
|
|
15
|
+
import type {
|
|
16
|
+
AtomFamily,
|
|
17
|
+
AtomFamilyOptions,
|
|
18
|
+
AtomToken,
|
|
19
|
+
FamilyMetadata,
|
|
20
|
+
ReadonlySelectorFamily,
|
|
21
|
+
ReadonlySelectorFamilyOptions,
|
|
22
|
+
ReadonlyValueToken,
|
|
23
|
+
SelectorFamily,
|
|
24
|
+
SelectorFamilyOptions,
|
|
25
|
+
SelectorToken,
|
|
26
|
+
} from ".."
|
|
27
|
+
|
|
28
|
+
export function atomFamily__INTERNAL<T, K extends Serializable>(
|
|
29
|
+
options: AtomFamilyOptions<T, K>,
|
|
30
|
+
store: Store = IMPLICIT.STORE
|
|
31
|
+
): AtomFamily<T, K> {
|
|
32
|
+
const subject = new Rx.Subject<AtomToken<T>>()
|
|
33
|
+
return Object.assign(
|
|
34
|
+
(key: K): AtomToken<T> => {
|
|
35
|
+
const subKey = stringifyJson(key)
|
|
36
|
+
const family: FamilyMetadata = { key: options.key, subKey }
|
|
37
|
+
const fullKey = `${options.key}(${subKey})`
|
|
38
|
+
const existing = withdraw({ key: fullKey, type: `atom` }, store)
|
|
39
|
+
const token = existing
|
|
40
|
+
? deposit(existing)
|
|
41
|
+
: atom__INTERNAL<T>(
|
|
42
|
+
{
|
|
43
|
+
key: fullKey,
|
|
44
|
+
default:
|
|
45
|
+
options.default instanceof Function
|
|
46
|
+
? options.default(key)
|
|
47
|
+
: options.default,
|
|
48
|
+
effects: options.effects?.(key),
|
|
49
|
+
},
|
|
50
|
+
family,
|
|
51
|
+
store
|
|
52
|
+
)
|
|
53
|
+
subject.next(token)
|
|
54
|
+
return token
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
key: options.key,
|
|
58
|
+
type: `atom_family`,
|
|
59
|
+
subject,
|
|
60
|
+
} as const
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function readonlySelectorFamily__INTERNAL<T, K extends Serializable>(
|
|
65
|
+
options: SelectorFamilyOptions<T, K>,
|
|
66
|
+
store?: Store
|
|
67
|
+
): ReadonlySelectorFamily<T, K> {
|
|
68
|
+
const core = target(store)
|
|
69
|
+
const subject = new Rx.Subject<ReadonlyValueToken<T>>()
|
|
70
|
+
return Object.assign(
|
|
71
|
+
(key: K): ReadonlyValueToken<T> => {
|
|
72
|
+
const subKey = stringifyJson(key)
|
|
73
|
+
const family: FamilyMetadata = { key: options.key, subKey }
|
|
74
|
+
const fullKey = `${options.key}(${subKey})`
|
|
75
|
+
const existing = core.readonlySelectors.get(fullKey)
|
|
76
|
+
if (existing) {
|
|
77
|
+
return deposit(existing)
|
|
78
|
+
}
|
|
79
|
+
return selector__INTERNAL<T>(
|
|
80
|
+
{
|
|
81
|
+
key: fullKey,
|
|
82
|
+
get: options.get(key),
|
|
83
|
+
},
|
|
84
|
+
family,
|
|
85
|
+
store
|
|
86
|
+
) as ReadonlyValueToken<T>
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
key: options.key,
|
|
90
|
+
type: `readonly_selector_family`,
|
|
91
|
+
subject,
|
|
92
|
+
} as const
|
|
93
|
+
) as ReadonlySelectorFamily<T, K>
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function selectorFamily__INTERNAL<T, K extends Serializable>(
|
|
97
|
+
options: SelectorFamilyOptions<T, K>,
|
|
98
|
+
store?: Store
|
|
99
|
+
): SelectorFamily<T, K>
|
|
100
|
+
export function selectorFamily__INTERNAL<T, K extends Serializable>(
|
|
101
|
+
options: ReadonlySelectorFamilyOptions<T, K>,
|
|
102
|
+
store?: Store
|
|
103
|
+
): ReadonlySelectorFamily<T, K>
|
|
104
|
+
export function selectorFamily__INTERNAL<T, K extends Serializable>(
|
|
105
|
+
options: ReadonlySelectorFamilyOptions<T, K> | SelectorFamilyOptions<T, K>,
|
|
106
|
+
store: Store = IMPLICIT.STORE
|
|
107
|
+
): ReadonlySelectorFamily<T, K> | SelectorFamily<T, K> {
|
|
108
|
+
const isReadonly = !(`set` in options)
|
|
109
|
+
|
|
110
|
+
if (isReadonly) {
|
|
111
|
+
return readonlySelectorFamily__INTERNAL(options as any, store)
|
|
112
|
+
}
|
|
113
|
+
const core = target(store)
|
|
114
|
+
const subject = new Rx.Subject<SelectorToken<T>>()
|
|
115
|
+
|
|
116
|
+
return Object.assign(
|
|
117
|
+
(key: K): SelectorToken<T> => {
|
|
118
|
+
const subKey = stringifyJson(key)
|
|
119
|
+
const family: FamilyMetadata = { key: options.key, subKey }
|
|
120
|
+
const fullKey = `${options.key}(${subKey})`
|
|
121
|
+
const existing = core.selectors.get(fullKey)
|
|
122
|
+
if (existing) {
|
|
123
|
+
return deposit(existing)
|
|
124
|
+
}
|
|
125
|
+
const token = selector__INTERNAL<T>(
|
|
126
|
+
{
|
|
127
|
+
key: fullKey,
|
|
128
|
+
get: options.get(key),
|
|
129
|
+
set: options.set(key),
|
|
130
|
+
},
|
|
131
|
+
family,
|
|
132
|
+
store
|
|
133
|
+
)
|
|
134
|
+
subject.next(token)
|
|
135
|
+
return token
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
key: options.key,
|
|
139
|
+
type: `selector_family`,
|
|
140
|
+
} as const
|
|
141
|
+
) as SelectorFamily<T, K>
|
|
142
|
+
}
|
package/src/internal/get.ts
CHANGED
|
@@ -1,36 +1,18 @@
|
|
|
1
|
-
import { pipe } from "fp-ts/function"
|
|
2
1
|
import HAMT from "hamt_plus"
|
|
3
2
|
|
|
4
|
-
import type { Atom, ReadonlySelector, Selector } from "."
|
|
5
|
-
import
|
|
6
|
-
import { IMPLICIT } from "./store"
|
|
3
|
+
import type { Atom, ReadonlySelector, Selector, Store } from "."
|
|
4
|
+
import { target, isValueCached, readCachedValue, IMPLICIT } from "."
|
|
7
5
|
import type {
|
|
8
6
|
AtomToken,
|
|
9
7
|
ReadonlyValueToken,
|
|
10
8
|
SelectorToken,
|
|
11
9
|
StateToken,
|
|
10
|
+
Transaction,
|
|
11
|
+
TransactionToken,
|
|
12
|
+
ƒn,
|
|
12
13
|
} from ".."
|
|
13
14
|
|
|
14
|
-
export const
|
|
15
|
-
state: Atom<T> | ReadonlySelector<T> | Selector<T>,
|
|
16
|
-
store: Store = IMPLICIT.STORE
|
|
17
|
-
): T => {
|
|
18
|
-
const path = []
|
|
19
|
-
if (`default` in state) {
|
|
20
|
-
const atomKey = state.key
|
|
21
|
-
store.selectorAtoms = pipe(store.selectorAtoms, (oldValue) => {
|
|
22
|
-
let newValue = oldValue
|
|
23
|
-
for (const selectorKey of path) {
|
|
24
|
-
newValue = newValue.set(selectorKey, atomKey)
|
|
25
|
-
}
|
|
26
|
-
return newValue
|
|
27
|
-
})
|
|
28
|
-
}
|
|
29
|
-
const value = HAMT.get(state.key, store.valueMap)
|
|
30
|
-
return value
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export const getSelectorState = <T>(
|
|
15
|
+
export const computeSelectorState = <T>(
|
|
34
16
|
selector: ReadonlySelector<T> | Selector<T>
|
|
35
17
|
): T => selector.get()
|
|
36
18
|
|
|
@@ -38,9 +20,10 @@ export function lookup(
|
|
|
38
20
|
key: string,
|
|
39
21
|
store: Store
|
|
40
22
|
): AtomToken<unknown> | ReadonlyValueToken<unknown> | SelectorToken<unknown> {
|
|
41
|
-
const
|
|
23
|
+
const core = target(store)
|
|
24
|
+
const type = HAMT.has(key, core.atoms)
|
|
42
25
|
? `atom`
|
|
43
|
-
: HAMT.has(key,
|
|
26
|
+
: HAMT.has(key, core.selectors)
|
|
44
27
|
? `selector`
|
|
45
28
|
: `readonly_selector`
|
|
46
29
|
return { key, type }
|
|
@@ -56,18 +39,28 @@ export function withdraw<T>(
|
|
|
56
39
|
token: ReadonlyValueToken<T>,
|
|
57
40
|
store: Store
|
|
58
41
|
): ReadonlySelector<T>
|
|
42
|
+
export function withdraw<T>(
|
|
43
|
+
token: TransactionToken<T>,
|
|
44
|
+
store: Store
|
|
45
|
+
): Transaction<T extends ƒn ? T : never>
|
|
59
46
|
export function withdraw<T>(
|
|
60
47
|
token: ReadonlyValueToken<T> | StateToken<T>,
|
|
61
48
|
store: Store
|
|
62
49
|
): Atom<T> | ReadonlySelector<T> | Selector<T>
|
|
63
50
|
export function withdraw<T>(
|
|
64
|
-
token: ReadonlyValueToken<T> | StateToken<T>,
|
|
51
|
+
token: ReadonlyValueToken<T> | StateToken<T> | TransactionToken<T>,
|
|
65
52
|
store: Store
|
|
66
|
-
):
|
|
53
|
+
):
|
|
54
|
+
| Atom<T>
|
|
55
|
+
| ReadonlySelector<T>
|
|
56
|
+
| Selector<T>
|
|
57
|
+
| Transaction<T extends ƒn ? T : never> {
|
|
58
|
+
const core = target(store)
|
|
67
59
|
return (
|
|
68
|
-
HAMT.get(token.key,
|
|
69
|
-
HAMT.get(token.key,
|
|
70
|
-
HAMT.get(token.key,
|
|
60
|
+
HAMT.get(token.key, core.atoms) ??
|
|
61
|
+
HAMT.get(token.key, core.selectors) ??
|
|
62
|
+
HAMT.get(token.key, core.readonlySelectors) ??
|
|
63
|
+
HAMT.get(token.key, core.transactions)
|
|
71
64
|
)
|
|
72
65
|
}
|
|
73
66
|
|
|
@@ -75,32 +68,37 @@ export function deposit<T>(state: Atom<T>): AtomToken<T>
|
|
|
75
68
|
export function deposit<T>(state: Selector<T>): SelectorToken<T>
|
|
76
69
|
export function deposit<T>(state: Atom<T> | Selector<T>): StateToken<T>
|
|
77
70
|
export function deposit<T>(state: ReadonlySelector<T>): ReadonlyValueToken<T>
|
|
71
|
+
export function deposit<T>(
|
|
72
|
+
state: Transaction<T extends ƒn ? T : never>
|
|
73
|
+
): TransactionToken<T>
|
|
78
74
|
export function deposit<T>(
|
|
79
75
|
state: Atom<T> | ReadonlySelector<T> | Selector<T>
|
|
80
76
|
): ReadonlyValueToken<T> | StateToken<T>
|
|
81
77
|
export function deposit<T>(
|
|
82
|
-
state:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
78
|
+
state:
|
|
79
|
+
| Atom<T>
|
|
80
|
+
| ReadonlySelector<T>
|
|
81
|
+
| Selector<T>
|
|
82
|
+
| Transaction<T extends ƒn ? T : never>
|
|
83
|
+
): ReadonlyValueToken<T> | StateToken<T> | TransactionToken<T> {
|
|
84
|
+
return {
|
|
85
|
+
key: state.key,
|
|
86
|
+
type: state.type,
|
|
87
|
+
...(`family` in state && { family: state.family }),
|
|
89
88
|
}
|
|
90
|
-
return { key: state.key, type: `atom` }
|
|
91
89
|
}
|
|
92
90
|
|
|
93
91
|
export const getState__INTERNAL = <T>(
|
|
94
92
|
state: Atom<T> | ReadonlySelector<T> | Selector<T>,
|
|
95
93
|
store: Store = IMPLICIT.STORE
|
|
96
94
|
): T => {
|
|
97
|
-
if (
|
|
95
|
+
if (isValueCached(state.key, store)) {
|
|
98
96
|
store.config.logger?.info(`>> read "${state.key}"`)
|
|
99
|
-
return
|
|
97
|
+
return readCachedValue(state.key, store)
|
|
100
98
|
}
|
|
101
|
-
if (`
|
|
99
|
+
if (state.type !== `atom`) {
|
|
102
100
|
store.config.logger?.info(`-> calc "${state.key}"`)
|
|
103
|
-
return
|
|
101
|
+
return computeSelectorState(state)
|
|
104
102
|
}
|
|
105
103
|
store.config.logger?.error(
|
|
106
104
|
`Attempted to get atom "${state.key}", which was never initialized in store "${store.config.name}".`
|