atom.io 0.1.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.
- package/README.md +10 -15
- package/dist/index.d.ts +505 -4
- package/dist/index.js +890 -321
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +879 -316
- package/dist/index.mjs.map +1 -1
- package/package.json +42 -10
- package/react/dist/index.d.ts +22 -0
- 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 +15 -0
- package/src/atom.ts +43 -0
- package/src/index.ts +77 -0
- package/src/internal/atom-internal.ts +50 -0
- package/src/internal/families-internal.ts +142 -0
- package/src/internal/get.ts +107 -0
- package/src/internal/index.ts +12 -0
- package/src/internal/is-default.ts +35 -0
- package/src/internal/logger.ts +46 -0
- package/src/internal/operation.ts +132 -0
- package/src/internal/selector-internal.ts +227 -0
- package/src/internal/set.ts +102 -0
- package/src/internal/store.ts +97 -0
- package/src/internal/subscribe-internal.ts +77 -0
- package/src/internal/timeline-internal.ts +196 -0
- package/src/internal/transaction-internal.ts +175 -0
- package/src/react/index.ts +64 -0
- package/src/selector.ts +62 -0
- package/src/subscribe.ts +55 -0
- package/src/timeline.ts +34 -0
- package/src/transaction.ts +41 -0
- package/dist/index-3b5d305c.d.ts +0 -257
- package/dist/react/index.d.ts +0 -21
- package/dist/react/index.js +0 -780
- package/dist/react/index.js.map +0 -1
- package/dist/react/index.mjs +0 -751
- 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":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "atom.io-react",
|
|
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
|
+
}
|
|
15
|
+
}
|
package/src/atom.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type * as Rx from "rxjs"
|
|
2
|
+
|
|
3
|
+
import type { Serializable } from "~/packages/anvl/src/json"
|
|
4
|
+
|
|
5
|
+
import type { AtomToken } from "."
|
|
6
|
+
import { atomFamily__INTERNAL, atom__INTERNAL } from "./internal"
|
|
7
|
+
|
|
8
|
+
export type Effectors<T> = {
|
|
9
|
+
setSelf: <V extends T>(next: V | ((oldValue: T) => V)) => void
|
|
10
|
+
onSet: (callback: (options: { newValue: T; oldValue: T }) => void) => void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type AtomEffect<T> = (tools: Effectors<T>) => void
|
|
14
|
+
|
|
15
|
+
export type AtomOptions<T> = {
|
|
16
|
+
key: string
|
|
17
|
+
default: T | (() => T)
|
|
18
|
+
effects?: AtomEffect<T>[]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function atom<T>(options: AtomOptions<T>): AtomToken<T> {
|
|
22
|
+
return atom__INTERNAL<T>(options)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type AtomFamilyOptions<T, K extends Serializable> = {
|
|
26
|
+
key: string
|
|
27
|
+
default: T | ((key: K) => T)
|
|
28
|
+
effects?: (key: K) => AtomEffect<T>[]
|
|
29
|
+
}
|
|
30
|
+
|
|
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
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IMPLICIT,
|
|
3
|
+
closeOperation,
|
|
4
|
+
openOperation,
|
|
5
|
+
getState__INTERNAL,
|
|
6
|
+
setState__INTERNAL,
|
|
7
|
+
isAtomDefault,
|
|
8
|
+
isSelectorDefault,
|
|
9
|
+
withdraw,
|
|
10
|
+
setLogLevel,
|
|
11
|
+
useLogger,
|
|
12
|
+
} from "./internal"
|
|
13
|
+
import * as __INTERNAL__ from "./internal"
|
|
14
|
+
import type { Store } from "./internal/store"
|
|
15
|
+
|
|
16
|
+
export * from "./atom"
|
|
17
|
+
export * from "./selector"
|
|
18
|
+
export * from "./timeline"
|
|
19
|
+
export * from "./transaction"
|
|
20
|
+
export * from "./subscribe"
|
|
21
|
+
export { __INTERNAL__, setLogLevel, useLogger }
|
|
22
|
+
export type { Serializable } from "~/packages/anvl/src/json"
|
|
23
|
+
|
|
24
|
+
export type AtomToken<_> = {
|
|
25
|
+
key: string
|
|
26
|
+
type: `atom`
|
|
27
|
+
family?: FamilyMetadata
|
|
28
|
+
}
|
|
29
|
+
export type SelectorToken<_> = {
|
|
30
|
+
key: string
|
|
31
|
+
type: `selector`
|
|
32
|
+
family?: FamilyMetadata
|
|
33
|
+
}
|
|
34
|
+
export type StateToken<T> = AtomToken<T> | SelectorToken<T>
|
|
35
|
+
|
|
36
|
+
export type ReadonlyValueToken<_> = {
|
|
37
|
+
key: string
|
|
38
|
+
type: `readonly_selector`
|
|
39
|
+
family?: FamilyMetadata
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type FamilyMetadata = {
|
|
43
|
+
key: string
|
|
44
|
+
subKey: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type TransactionToken<_> = {
|
|
48
|
+
key: string
|
|
49
|
+
type: `transaction`
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const getState = <T>(
|
|
53
|
+
token: ReadonlyValueToken<T> | StateToken<T>,
|
|
54
|
+
store: Store = IMPLICIT.STORE
|
|
55
|
+
): T => {
|
|
56
|
+
const state = withdraw<T>(token, store)
|
|
57
|
+
return getState__INTERNAL(state, store)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const setState = <T, New extends T>(
|
|
61
|
+
token: StateToken<T>,
|
|
62
|
+
value: New | ((oldValue: T) => New),
|
|
63
|
+
store: Store = IMPLICIT.STORE
|
|
64
|
+
): void => {
|
|
65
|
+
openOperation(store)
|
|
66
|
+
const state = withdraw(token, store)
|
|
67
|
+
setState__INTERNAL(state, value, store)
|
|
68
|
+
closeOperation(store)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const isDefault = (
|
|
72
|
+
token: ReadonlyValueToken<unknown> | StateToken<unknown>,
|
|
73
|
+
store: Store = IMPLICIT.STORE
|
|
74
|
+
): boolean =>
|
|
75
|
+
token.type === `atom`
|
|
76
|
+
? isAtomDefault(token.key, store)
|
|
77
|
+
: isSelectorDefault(token.key, store)
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import HAMT from "hamt_plus"
|
|
2
|
+
|
|
3
|
+
import type { Atom, ReadonlySelector, Selector, Store } from "."
|
|
4
|
+
import { target, isValueCached, readCachedValue, IMPLICIT } from "."
|
|
5
|
+
import type {
|
|
6
|
+
AtomToken,
|
|
7
|
+
ReadonlyValueToken,
|
|
8
|
+
SelectorToken,
|
|
9
|
+
StateToken,
|
|
10
|
+
Transaction,
|
|
11
|
+
TransactionToken,
|
|
12
|
+
ƒn,
|
|
13
|
+
} from ".."
|
|
14
|
+
|
|
15
|
+
export const computeSelectorState = <T>(
|
|
16
|
+
selector: ReadonlySelector<T> | Selector<T>
|
|
17
|
+
): T => selector.get()
|
|
18
|
+
|
|
19
|
+
export function lookup(
|
|
20
|
+
key: string,
|
|
21
|
+
store: Store
|
|
22
|
+
): AtomToken<unknown> | ReadonlyValueToken<unknown> | SelectorToken<unknown> {
|
|
23
|
+
const core = target(store)
|
|
24
|
+
const type = HAMT.has(key, core.atoms)
|
|
25
|
+
? `atom`
|
|
26
|
+
: HAMT.has(key, core.selectors)
|
|
27
|
+
? `selector`
|
|
28
|
+
: `readonly_selector`
|
|
29
|
+
return { key, type }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function withdraw<T>(token: AtomToken<T>, store: Store): Atom<T>
|
|
33
|
+
export function withdraw<T>(token: SelectorToken<T>, store: Store): Selector<T>
|
|
34
|
+
export function withdraw<T>(
|
|
35
|
+
token: StateToken<T>,
|
|
36
|
+
store: Store
|
|
37
|
+
): Atom<T> | Selector<T>
|
|
38
|
+
export function withdraw<T>(
|
|
39
|
+
token: ReadonlyValueToken<T>,
|
|
40
|
+
store: Store
|
|
41
|
+
): ReadonlySelector<T>
|
|
42
|
+
export function withdraw<T>(
|
|
43
|
+
token: TransactionToken<T>,
|
|
44
|
+
store: Store
|
|
45
|
+
): Transaction<T extends ƒn ? T : never>
|
|
46
|
+
export function withdraw<T>(
|
|
47
|
+
token: ReadonlyValueToken<T> | StateToken<T>,
|
|
48
|
+
store: Store
|
|
49
|
+
): Atom<T> | ReadonlySelector<T> | Selector<T>
|
|
50
|
+
export function withdraw<T>(
|
|
51
|
+
token: ReadonlyValueToken<T> | StateToken<T> | TransactionToken<T>,
|
|
52
|
+
store: Store
|
|
53
|
+
):
|
|
54
|
+
| Atom<T>
|
|
55
|
+
| ReadonlySelector<T>
|
|
56
|
+
| Selector<T>
|
|
57
|
+
| Transaction<T extends ƒn ? T : never> {
|
|
58
|
+
const core = target(store)
|
|
59
|
+
return (
|
|
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)
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function deposit<T>(state: Atom<T>): AtomToken<T>
|
|
68
|
+
export function deposit<T>(state: Selector<T>): SelectorToken<T>
|
|
69
|
+
export function deposit<T>(state: Atom<T> | Selector<T>): StateToken<T>
|
|
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>
|
|
74
|
+
export function deposit<T>(
|
|
75
|
+
state: Atom<T> | ReadonlySelector<T> | Selector<T>
|
|
76
|
+
): ReadonlyValueToken<T> | StateToken<T>
|
|
77
|
+
export function deposit<T>(
|
|
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 }),
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const getState__INTERNAL = <T>(
|
|
92
|
+
state: Atom<T> | ReadonlySelector<T> | Selector<T>,
|
|
93
|
+
store: Store = IMPLICIT.STORE
|
|
94
|
+
): T => {
|
|
95
|
+
if (isValueCached(state.key, store)) {
|
|
96
|
+
store.config.logger?.info(`>> read "${state.key}"`)
|
|
97
|
+
return readCachedValue(state.key, store)
|
|
98
|
+
}
|
|
99
|
+
if (`get` in state) {
|
|
100
|
+
store.config.logger?.info(`-> calc "${state.key}"`)
|
|
101
|
+
return computeSelectorState(state)
|
|
102
|
+
}
|
|
103
|
+
store.config.logger?.error(
|
|
104
|
+
`Attempted to get atom "${state.key}", which was never initialized in store "${store.config.name}".`
|
|
105
|
+
)
|
|
106
|
+
return state.default
|
|
107
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from "./atom-internal"
|
|
2
|
+
export * from "./families-internal"
|
|
3
|
+
export * from "./get"
|
|
4
|
+
export * from "./is-default"
|
|
5
|
+
export * from "./logger"
|
|
6
|
+
export * from "./operation"
|
|
7
|
+
export * from "./selector-internal"
|
|
8
|
+
export * from "./set"
|
|
9
|
+
export * from "./store"
|
|
10
|
+
export * from "./subscribe-internal"
|
|
11
|
+
export * from "./timeline-internal"
|
|
12
|
+
export * from "./transaction-internal"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Store } from "."
|
|
2
|
+
import { target, IMPLICIT, traceAllSelectorAtoms } from "."
|
|
3
|
+
|
|
4
|
+
export const isAtomDefault = (
|
|
5
|
+
key: string,
|
|
6
|
+
store: Store = IMPLICIT.STORE
|
|
7
|
+
): boolean => {
|
|
8
|
+
const core = target(store)
|
|
9
|
+
return core.atomsThatAreDefault.has(key)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const markAtomAsDefault = (
|
|
13
|
+
key: string,
|
|
14
|
+
store: Store = IMPLICIT.STORE
|
|
15
|
+
): void => {
|
|
16
|
+
const core = target(store)
|
|
17
|
+
core.atomsThatAreDefault = new Set(core.atomsThatAreDefault).add(key)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const markAtomAsNotDefault = (
|
|
21
|
+
key: string,
|
|
22
|
+
store: Store = IMPLICIT.STORE
|
|
23
|
+
): void => {
|
|
24
|
+
const core = target(store)
|
|
25
|
+
core.atomsThatAreDefault = new Set(target(store).atomsThatAreDefault)
|
|
26
|
+
core.atomsThatAreDefault.delete(key)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const isSelectorDefault = (
|
|
30
|
+
key: string,
|
|
31
|
+
store: Store = IMPLICIT.STORE
|
|
32
|
+
): boolean => {
|
|
33
|
+
const roots = traceAllSelectorAtoms(key, store)
|
|
34
|
+
return roots.every((root) => isAtomDefault(root.key, store))
|
|
35
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { doNothing } from "~/packages/anvl/src/function"
|
|
2
|
+
|
|
3
|
+
import type { Store } from "./store"
|
|
4
|
+
import { IMPLICIT } from "./store"
|
|
5
|
+
|
|
6
|
+
export type Logger = Pick<Console, `error` | `info` | `warn`>
|
|
7
|
+
export const LOG_LEVELS: ReadonlyArray<keyof Logger> = [
|
|
8
|
+
`info`,
|
|
9
|
+
`warn`,
|
|
10
|
+
`error`,
|
|
11
|
+
] as const
|
|
12
|
+
|
|
13
|
+
export const setLogLevel = (
|
|
14
|
+
preferredLevel: `error` | `info` | `warn` | null,
|
|
15
|
+
store: Store = IMPLICIT.STORE
|
|
16
|
+
): void => {
|
|
17
|
+
const { logger__INTERNAL } = store.config
|
|
18
|
+
if (preferredLevel === null) {
|
|
19
|
+
store.config.logger = null
|
|
20
|
+
} else {
|
|
21
|
+
store.config.logger = { ...console }
|
|
22
|
+
LOG_LEVELS.forEach((logLevel) => {
|
|
23
|
+
if (LOG_LEVELS.indexOf(logLevel) < LOG_LEVELS.indexOf(preferredLevel)) {
|
|
24
|
+
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */
|
|
25
|
+
store.config.logger![logLevel] = doNothing
|
|
26
|
+
} else {
|
|
27
|
+
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */
|
|
28
|
+
store.config.logger![logLevel] = logger__INTERNAL[logLevel]
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const useLogger = (
|
|
35
|
+
logger: Logger,
|
|
36
|
+
store: Store = IMPLICIT.STORE
|
|
37
|
+
): void => {
|
|
38
|
+
const currentLogLevel =
|
|
39
|
+
store.config.logger === null
|
|
40
|
+
? null
|
|
41
|
+
: LOG_LEVELS.find(
|
|
42
|
+
(logLevel) => store.config.logger?.[logLevel] !== doNothing
|
|
43
|
+
) ?? null
|
|
44
|
+
store.config.logger__INTERNAL = { ...logger }
|
|
45
|
+
setLogLevel(currentLogLevel, store)
|
|
46
|
+
}
|