atom.io 0.6.1 → 0.6.3
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/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -2
- package/dist/index.mjs.map +1 -1
- package/json/dist/index.js.map +1 -1
- package/json/dist/index.mjs.map +1 -1
- package/package.json +13 -3
- package/react/dist/index.js.map +1 -1
- package/react/dist/index.mjs.map +1 -1
- package/react-devtools/dist/index.js +32 -18
- package/react-devtools/dist/index.js.map +1 -1
- package/react-devtools/dist/index.mjs +32 -18
- package/react-devtools/dist/index.mjs.map +1 -1
- package/realtime/dist/index.js.map +1 -1
- package/realtime/dist/index.mjs.map +1 -1
- package/realtime-react/dist/index.js.map +1 -1
- package/realtime-react/dist/index.mjs.map +1 -1
- package/realtime-testing/dist/index.d.mts +49 -0
- package/realtime-testing/dist/index.d.ts +49 -0
- package/realtime-testing/dist/index.js +153 -0
- package/realtime-testing/dist/index.js.map +1 -0
- package/realtime-testing/dist/index.mjs +117 -0
- package/realtime-testing/dist/index.mjs.map +1 -0
- package/realtime-testing/package.json +15 -0
- package/src/atom.ts +15 -15
- package/src/index.ts +59 -59
- package/src/internal/atom-internal.ts +36 -36
- package/src/internal/families-internal.ts +114 -114
- package/src/internal/get.ts +83 -83
- package/src/internal/is-default.ts +17 -17
- package/src/internal/meta/attach-meta.ts +7 -7
- package/src/internal/meta/meta-state.ts +115 -115
- package/src/internal/operation.ts +93 -93
- package/src/internal/selector/create-read-write-selector.ts +46 -46
- package/src/internal/selector/create-readonly-selector.ts +37 -37
- package/src/internal/selector/lookup-selector-sources.ts +9 -9
- package/src/internal/selector/register-selector.ts +44 -44
- package/src/internal/selector/trace-selector-atoms.ts +30 -30
- package/src/internal/selector/update-selector-atoms.ts +25 -25
- package/src/internal/selector-internal.ts +37 -37
- package/src/internal/set.ts +78 -78
- package/src/internal/store.ts +118 -118
- package/src/internal/subscribe-internal.ts +62 -62
- package/src/internal/time-travel-internal.ts +76 -76
- package/src/internal/timeline/add-atom-to-timeline.ts +158 -153
- package/src/internal/timeline-internal.ts +80 -80
- package/src/internal/transaction/abort-transaction.ts +8 -8
- package/src/internal/transaction/apply-transaction.ts +41 -41
- package/src/internal/transaction/build-transaction.ts +28 -28
- package/src/internal/transaction/index.ts +7 -7
- package/src/internal/transaction/redo-transaction.ts +13 -13
- package/src/internal/transaction/undo-transaction.ts +13 -13
- package/src/internal/transaction-internal.ts +48 -48
- package/src/json/select-json.ts +12 -12
- package/src/logger.ts +30 -30
- package/src/react/store-context.tsx +4 -4
- package/src/react/store-hooks.ts +18 -18
- package/src/react-devtools/AtomIODevtools.tsx +83 -82
- package/src/react-devtools/StateEditor.tsx +53 -53
- package/src/react-devtools/TokenList.tsx +47 -42
- package/src/react-explorer/AtomIOExplorer.tsx +197 -185
- package/src/react-explorer/explorer-effects.ts +11 -11
- package/src/react-explorer/explorer-states.ts +186 -193
- package/src/react-explorer/index.ts +11 -11
- package/src/react-explorer/space-states.ts +48 -50
- package/src/react-explorer/view-states.ts +25 -25
- package/src/realtime/hook-composition/expose-family.ts +81 -81
- package/src/realtime/hook-composition/expose-single.ts +26 -26
- package/src/realtime/hook-composition/expose-timeline.ts +60 -0
- package/src/realtime/hook-composition/index.ts +2 -2
- package/src/realtime/hook-composition/receive-state.ts +18 -18
- package/src/realtime/hook-composition/receive-transaction.ts +8 -8
- package/src/realtime-react/realtime-context.tsx +17 -17
- package/src/realtime-react/realtime-hooks.ts +17 -17
- package/src/realtime-react/realtime-state.ts +4 -4
- package/src/realtime-react/use-pull-family-member.ts +15 -15
- package/src/realtime-react/use-pull-family.ts +13 -13
- package/src/realtime-react/use-pull.ts +12 -12
- package/src/realtime-react/use-push.ts +15 -15
- package/src/realtime-react/use-server-action.ts +21 -21
- package/src/realtime-testing/index.ts +1 -0
- package/src/realtime-testing/setup-realtime-test.tsx +160 -0
- package/src/selector.ts +25 -25
- package/src/silo.ts +38 -38
- package/src/subscribe.ts +68 -68
- package/src/timeline.ts +13 -13
- package/src/transaction.ts +28 -28
- package/src/web-effects/storage.ts +17 -17
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/realtime-testing/setup-realtime-test.tsx"],"sourcesContent":["import * as http from \"http\"\n\nimport * as React from \"react\"\n\nimport { prettyDOM, render, type RenderResult } from \"@testing-library/react\"\nimport * as AtomIO from \"atom.io\"\nimport * as AR from \"atom.io/react\"\nimport * as RTC from \"atom.io/realtime-react\"\nimport * as RR from \"fp-ts/ReadonlyRecord\"\nimport * as Happy from \"happy-dom\"\nimport * as SocketIO from \"socket.io\"\nimport type { Socket as ClientSocket } from \"socket.io-client\"\nimport { io } from \"socket.io-client\"\n\nexport type TestSetupOptions = {\n\tserver: (tools: { socket: SocketIO.Socket; silo: AtomIO.Silo }) => void\n}\nexport type TestSetupOptions__SingleClient = TestSetupOptions & {\n\tclient: React.FC\n}\nexport type TestSetupOptions__MultiClient<ClientNames extends string> =\n\tTestSetupOptions & {\n\t\tclients: {\n\t\t\t[K in ClientNames]: React.FC\n\t\t}\n\t}\n\nexport type RealtimeTestTools = {\n\tname: string\n\tsilo: AtomIO.Silo\n\tdispose: () => void\n}\nexport type RealtimeTestClient = RealtimeTestTools & {\n\trenderResult: RenderResult\n\tprettyPrint: () => void\n\treconnect: () => void\n\tdisconnect: () => void\n}\nexport type RealtimeTestServer = RealtimeTestTools & {\n\tport: number\n}\n\nexport type RealtimeTestAPI = {\n\tserver: RealtimeTestServer\n\tteardown: () => void\n}\nexport type RealtimeTestAPI__SingleClient = RealtimeTestAPI & {\n\tclient: RealtimeTestClient\n}\nexport type RealtimeTestAPI__MultiClient<ClientNames extends string> =\n\tRealtimeTestAPI & {\n\t\tclients: Record<ClientNames, RealtimeTestClient>\n\t}\n\nexport const setupRealtimeTestServer = (\n\toptions: TestSetupOptions,\n): RealtimeTestServer => {\n\tconst httpServer = http.createServer((_, res) => res.end(`Hello World!`))\n\tconst address = httpServer.listen().address()\n\tconst port =\n\t\ttypeof address === `string` ? 80 : address === null ? null : address.port\n\tif (port === null) throw new Error(`Could not determine port for test server`)\n\tconst server = new SocketIO.Server(httpServer)\n\tconst silo = AtomIO.silo(`SERVER`, AtomIO.__INTERNAL__.IMPLICIT.STORE)\n\n\tserver.on(`connection`, (socket: SocketIO.Socket) => {\n\t\toptions.server({ socket, silo })\n\t})\n\n\tconst dispose = () => {\n\t\tserver.close()\n\t\tAtomIO.__INTERNAL__.clearStore(silo.store)\n\t}\n\n\treturn {\n\t\tname: `SERVER`,\n\t\tsilo,\n\t\tdispose,\n\t\tport,\n\t}\n}\nexport const setupRealtimeTestClient = (\n\toptions: TestSetupOptions__SingleClient,\n\tname: string,\n\tport: number,\n): RealtimeTestClient => {\n\tconst socket: ClientSocket = io(`http://localhost:${port}/`)\n\tconst silo = AtomIO.silo(name, AtomIO.__INTERNAL__.IMPLICIT.STORE)\n\n\tconst { document } = new Happy.Window()\n\tdocument.body.innerHTML = `<div id=\"app\"></div>`\n\tconst renderResult = render(\n\t\t<AR.StoreProvider store={silo.store}>\n\t\t\t<RTC.RealtimeProvider socket={socket}>\n\t\t\t\t<options.client />\n\t\t\t</RTC.RealtimeProvider>\n\t\t</AR.StoreProvider>,\n\t\t{\n\t\t\tcontainer: document.querySelector(`#app`) as unknown as HTMLElement,\n\t\t},\n\t)\n\n\tconst prettyPrint = () => console.log(prettyDOM(renderResult.container))\n\n\tconst disconnect = () => socket.disconnect()\n\tconst reconnect = () => socket.connect()\n\n\tconst dispose = () => {\n\t\tsocket.disconnect()\n\t\tAtomIO.__INTERNAL__.clearStore(silo.store)\n\t}\n\n\treturn {\n\t\tname,\n\t\tsilo,\n\t\trenderResult,\n\t\tprettyPrint,\n\t\tdisconnect,\n\t\treconnect,\n\t\tdispose,\n\t}\n}\n\nexport const singleClient = (\n\toptions: TestSetupOptions__SingleClient,\n): RealtimeTestAPI__SingleClient => {\n\tconst server = setupRealtimeTestServer(options)\n\tconst client = setupRealtimeTestClient(options, `CLIENT`, server.port)\n\n\treturn {\n\t\tclient,\n\t\tserver,\n\t\tteardown: () => {\n\t\t\tclient.dispose()\n\t\t\tserver.dispose()\n\t\t},\n\t}\n}\n\nexport const multiClient = <ClientNames extends string>(\n\toptions: TestSetupOptions__MultiClient<ClientNames>,\n): RealtimeTestAPI__MultiClient<ClientNames> => {\n\tconst server = setupRealtimeTestServer(options)\n\tconst clients = RR.toEntries(options.clients).reduce(\n\t\t(clients, [name, client]) => ({\n\t\t\t...clients,\n\t\t\t[name]: setupRealtimeTestClient({ ...options, client }, name, server.port),\n\t\t}),\n\t\t{} as Record<ClientNames, RealtimeTestClient>,\n\t)\n\n\treturn {\n\t\tclients,\n\t\tserver,\n\t\tteardown: () => {\n\t\t\tRR.toEntries(clients).forEach(([, client]) => client.dispose())\n\t\t\tserver.dispose()\n\t\t},\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA,YAAY,UAAU;AAItB,SAAS,WAAW,cAAiC;AACrD,YAAY,YAAY;AACxB,YAAY,QAAQ;AACpB,YAAY,SAAS;AACrB,YAAY,QAAQ;AACpB,YAAY,WAAW;AACvB,YAAY,cAAc;AAE1B,SAAS,UAAU;AAkFf;AAxCG,IAAM,0BAA0B,CACtC,YACwB;AACxB,QAAM,aAAkB,kBAAa,CAAC,GAAG,QAAQ,IAAI,IAAI,cAAc,CAAC;AACxE,QAAM,UAAU,WAAW,OAAO,EAAE,QAAQ;AAC5C,QAAM,OACL,OAAO,YAAY,WAAW,KAAK,YAAY,OAAO,OAAO,QAAQ;AACtE,MAAI,SAAS;AAAM,UAAM,IAAI,MAAM,0CAA0C;AAC7E,QAAM,SAAS,IAAa,gBAAO,UAAU;AAC7C,QAAMA,QAAc,YAAK,UAAiB,oBAAa,SAAS,KAAK;AAErE,SAAO,GAAG,cAAc,CAAC,WAA4B;AACpD,YAAQ,OAAO,EAAE,QAAQ,MAAAA,MAAK,CAAC;AAAA,EAChC,CAAC;AAED,QAAM,UAAU,MAAM;AACrB,WAAO,MAAM;AACb,IAAO,oBAAa,WAAWA,MAAK,KAAK;AAAA,EAC1C;AAEA,SAAO;AAAA,IACN,MAAM;AAAA,IACN,MAAAA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;AACO,IAAM,0BAA0B,CACtC,SACA,MACA,SACwB;AACxB,QAAM,SAAuB,GAAG,oBAAoB,IAAI,GAAG;AAC3D,QAAMA,QAAc,YAAK,MAAa,oBAAa,SAAS,KAAK;AAEjE,QAAM,EAAE,SAAS,IAAI,IAAU,aAAO;AACtC,WAAS,KAAK,YAAY;AAC1B,QAAM,eAAe;AAAA,IACpB,oBAAI,kBAAH,EAAiB,OAAOA,MAAK,OAC7B,8BAAK,sBAAJ,EAAqB,QACrB,8BAAC,QAAQ,QAAR,EAAe,GACjB,GACD;AAAA,IACA;AAAA,MACC,WAAW,SAAS,cAAc,MAAM;AAAA,IACzC;AAAA,EACD;AAEA,QAAM,cAAc,MAAM,QAAQ,IAAI,UAAU,aAAa,SAAS,CAAC;AAEvE,QAAM,aAAa,MAAM,OAAO,WAAW;AAC3C,QAAM,YAAY,MAAM,OAAO,QAAQ;AAEvC,QAAM,UAAU,MAAM;AACrB,WAAO,WAAW;AAClB,IAAO,oBAAa,WAAWA,MAAK,KAAK;AAAA,EAC1C;AAEA,SAAO;AAAA,IACN;AAAA,IACA,MAAAA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;AAEO,IAAM,eAAe,CAC3B,YACmC;AACnC,QAAM,SAAS,wBAAwB,OAAO;AAC9C,QAAM,SAAS,wBAAwB,SAAS,UAAU,OAAO,IAAI;AAErE,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA,UAAU,MAAM;AACf,aAAO,QAAQ;AACf,aAAO,QAAQ;AAAA,IAChB;AAAA,EACD;AACD;AAEO,IAAM,cAAc,CAC1B,YAC+C;AAC/C,QAAM,SAAS,wBAAwB,OAAO;AAC9C,QAAM,UAAa,aAAU,QAAQ,OAAO,EAAE;AAAA,IAC7C,CAACC,UAAS,CAAC,MAAM,MAAM,MAAO,iCAC1BA,WAD0B;AAAA,MAE7B,CAAC,IAAI,GAAG,wBAAwB,iCAAK,UAAL,EAAc,OAAO,IAAG,MAAM,OAAO,IAAI;AAAA,IAC1E;AAAA,IACA,CAAC;AAAA,EACF;AAEA,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA,UAAU,MAAM;AACf,MAAG,aAAU,OAAO,EAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,MAAM,OAAO,QAAQ,CAAC;AAC9D,aAAO,QAAQ;AAAA,IAChB;AAAA,EACD;AACD;","names":["silo","clients"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "atom.io-realtime-testing",
|
|
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
CHANGED
|
@@ -6,38 +6,38 @@ import type { AtomToken } from "."
|
|
|
6
6
|
import { atomFamily__INTERNAL, atom__INTERNAL } from "./internal"
|
|
7
7
|
|
|
8
8
|
export type Effectors<T> = {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
setSelf: <V extends T>(next: V | ((oldValue: T) => V)) => void
|
|
10
|
+
onSet: (callback: (options: { newValue: T; oldValue: T }) => void) => void
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export type AtomEffect<T> = (tools: Effectors<T>) => void
|
|
14
14
|
|
|
15
15
|
export type AtomOptions<T> = {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
key: string
|
|
17
|
+
default: T | (() => T)
|
|
18
|
+
effects?: AtomEffect<T>[]
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export function atom<T>(options: AtomOptions<T>): AtomToken<T> {
|
|
22
|
-
|
|
22
|
+
return atom__INTERNAL<T>(options)
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export type AtomFamilyOptions<T, K extends Serializable> = {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
key: string
|
|
27
|
+
default: T | ((key: K) => T)
|
|
28
|
+
effects?: (key: K) => AtomEffect<T>[]
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export type AtomFamily<T, K extends Serializable = Serializable> = ((
|
|
32
|
-
|
|
32
|
+
key: K,
|
|
33
33
|
) => AtomToken<T>) & {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
key: string
|
|
35
|
+
type: `atom_family`
|
|
36
|
+
subject: Rx.Subject<AtomToken<T>>
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export function atomFamily<T, K extends Serializable>(
|
|
40
|
-
|
|
40
|
+
options: AtomFamilyOptions<T, K>,
|
|
41
41
|
): AtomFamily<T, K> {
|
|
42
|
-
|
|
42
|
+
return atomFamily__INTERNAL<T, K>(options)
|
|
43
43
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { capitalize } from "~/packages/anvl/src/string/capitalize"
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
IMPLICIT,
|
|
5
|
+
closeOperation,
|
|
6
|
+
openOperation,
|
|
7
|
+
getState__INTERNAL,
|
|
8
|
+
setState__INTERNAL,
|
|
9
|
+
isAtomDefault,
|
|
10
|
+
isSelectorDefault,
|
|
11
|
+
withdraw,
|
|
12
12
|
} from "./internal"
|
|
13
13
|
import * as __INTERNAL__ from "./internal"
|
|
14
14
|
import type { Store } from "./internal/store"
|
|
@@ -25,75 +25,75 @@ export type { Store } from "./internal/store"
|
|
|
25
25
|
export type { Serializable } from "~/packages/anvl/src/json"
|
|
26
26
|
|
|
27
27
|
export type AtomToken<_> = {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
key: string
|
|
29
|
+
type: `atom`
|
|
30
|
+
family?: FamilyMetadata
|
|
31
|
+
__brand?: _
|
|
32
32
|
}
|
|
33
33
|
export type SelectorToken<_> = {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
key: string
|
|
35
|
+
type: `selector`
|
|
36
|
+
family?: FamilyMetadata
|
|
37
|
+
__brand?: _
|
|
38
38
|
}
|
|
39
39
|
export type StateToken<T> = AtomToken<T> | SelectorToken<T>
|
|
40
40
|
|
|
41
41
|
export type ReadonlySelectorToken<_> = {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
key: string
|
|
43
|
+
type: `readonly_selector`
|
|
44
|
+
family?: FamilyMetadata
|
|
45
|
+
__brand?: _
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
export type FamilyMetadata = {
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
key: string
|
|
50
|
+
subKey: string
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export const getState = <T>(
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
token: ReadonlySelectorToken<T> | StateToken<T>,
|
|
55
|
+
store: Store = IMPLICIT.STORE,
|
|
56
56
|
): T => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
57
|
+
const state = withdraw<T>(token, store)
|
|
58
|
+
if (state === null) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`${capitalize(token.type)} "${token.key}" not found in store "${
|
|
61
|
+
store.config.name
|
|
62
|
+
}".`,
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
return getState__INTERNAL(state, store)
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
export const setState = <T, New extends T>(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
token: StateToken<T>,
|
|
70
|
+
value: New | ((oldValue: T) => New),
|
|
71
|
+
store: Store = IMPLICIT.STORE,
|
|
72
72
|
): void => {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
73
|
+
try {
|
|
74
|
+
openOperation(token, store)
|
|
75
|
+
} catch (thrown) {
|
|
76
|
+
if (!(typeof thrown === `symbol`)) {
|
|
77
|
+
throw thrown
|
|
78
|
+
}
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
const state = withdraw(token, store)
|
|
82
|
+
if (state === null) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`${capitalize(token.type)} "${token.key}" not found in store "${
|
|
85
|
+
store.config.name
|
|
86
|
+
}".`,
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
setState__INTERNAL(state, value, store)
|
|
90
|
+
closeOperation(store)
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
export const isDefault = (
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
token: ReadonlySelectorToken<unknown> | StateToken<unknown>,
|
|
95
|
+
store: Store = IMPLICIT.STORE,
|
|
96
96
|
): boolean =>
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
token.type === `atom`
|
|
98
|
+
? isAtomDefault(token.key, store)
|
|
99
|
+
: isSelectorDefault(token.key, store)
|
|
@@ -12,44 +12,44 @@ import { setState, subscribe } from ".."
|
|
|
12
12
|
import type { AtomOptions } from "../atom"
|
|
13
13
|
|
|
14
14
|
export type Atom<T> = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
key: string
|
|
16
|
+
type: `atom`
|
|
17
|
+
family?: FamilyMetadata
|
|
18
|
+
subject: Rx.Subject<{ newValue: T; oldValue: T }>
|
|
19
|
+
default: T
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export function atom__INTERNAL<T>(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
options: AtomOptions<T>,
|
|
24
|
+
family?: FamilyMetadata,
|
|
25
|
+
store: Store = IMPLICIT.STORE,
|
|
26
26
|
): AtomToken<T> {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
27
|
+
const core = target(store)
|
|
28
|
+
if (hasKeyBeenUsed(options.key, store)) {
|
|
29
|
+
store.config.logger?.error?.(
|
|
30
|
+
`Key "${options.key}" already exists in the store.`,
|
|
31
|
+
)
|
|
32
|
+
return deposit(core.atoms.get(options.key))
|
|
33
|
+
}
|
|
34
|
+
const subject = new Rx.Subject<{ newValue: T; oldValue: T }>()
|
|
35
|
+
const newAtom = {
|
|
36
|
+
...options,
|
|
37
|
+
subject,
|
|
38
|
+
type: `atom`,
|
|
39
|
+
...(family && { family }),
|
|
40
|
+
} as const
|
|
41
|
+
const initialValue =
|
|
42
|
+
options.default instanceof Function ? options.default() : options.default
|
|
43
|
+
core.atoms = HAMT.set(newAtom.key, newAtom, core.atoms)
|
|
44
|
+
markAtomAsDefault(options.key, store)
|
|
45
|
+
cacheValue(options.key, initialValue, store)
|
|
46
|
+
const token = deposit(newAtom)
|
|
47
|
+
options.effects?.forEach((effect) =>
|
|
48
|
+
effect({
|
|
49
|
+
setSelf: (next) => setState(token, next, store),
|
|
50
|
+
onSet: (handle: UpdateHandler<T>) => subscribe(token, handle, store),
|
|
51
|
+
}),
|
|
52
|
+
)
|
|
53
|
+
store.subject.atomCreation.next(token)
|
|
54
|
+
return token as AtomToken<T>
|
|
55
55
|
}
|
|
@@ -5,138 +5,138 @@ import { stringifyJson } from "~/packages/anvl/src/json"
|
|
|
5
5
|
|
|
6
6
|
import type { Store } from "."
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
atom__INTERNAL,
|
|
9
|
+
withdraw,
|
|
10
|
+
selector__INTERNAL,
|
|
11
|
+
target,
|
|
12
|
+
deposit,
|
|
13
|
+
IMPLICIT,
|
|
14
14
|
} from "."
|
|
15
15
|
import type {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
AtomFamily,
|
|
17
|
+
AtomFamilyOptions,
|
|
18
|
+
AtomToken,
|
|
19
|
+
FamilyMetadata,
|
|
20
|
+
ReadonlySelectorFamily,
|
|
21
|
+
ReadonlySelectorFamilyOptions,
|
|
22
|
+
ReadonlySelectorToken,
|
|
23
|
+
SelectorFamily,
|
|
24
|
+
SelectorFamilyOptions,
|
|
25
|
+
SelectorToken,
|
|
26
26
|
} from ".."
|
|
27
27
|
|
|
28
28
|
export function atomFamily__INTERNAL<T, K extends Serializable>(
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
options: AtomFamilyOptions<T, K>,
|
|
30
|
+
store: Store = IMPLICIT.STORE,
|
|
31
31
|
): AtomFamily<T, K> {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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: AtomToken<any> = 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
62
|
}
|
|
63
63
|
|
|
64
64
|
export function readonlySelectorFamily__INTERNAL<T, K extends Serializable>(
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
options: ReadonlySelectorFamilyOptions<T, K>,
|
|
66
|
+
store?: Store,
|
|
67
67
|
): ReadonlySelectorFamily<T, K> {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
68
|
+
const core = target(store)
|
|
69
|
+
const subject = new Rx.Subject<ReadonlySelectorToken<T>>()
|
|
70
|
+
return Object.assign(
|
|
71
|
+
(key: K): ReadonlySelectorToken<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 ReadonlySelectorToken<T>
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
key: options.key,
|
|
90
|
+
type: `readonly_selector_family`,
|
|
91
|
+
subject,
|
|
92
|
+
} as const,
|
|
93
|
+
) as ReadonlySelectorFamily<T, K>
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
export function selectorFamily__INTERNAL<T, K extends Serializable>(
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
options: SelectorFamilyOptions<T, K>,
|
|
98
|
+
store?: Store,
|
|
99
99
|
): SelectorFamily<T, K>
|
|
100
100
|
export function selectorFamily__INTERNAL<T, K extends Serializable>(
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
options: ReadonlySelectorFamilyOptions<T, K>,
|
|
102
|
+
store?: Store,
|
|
103
103
|
): ReadonlySelectorFamily<T, K>
|
|
104
104
|
export function selectorFamily__INTERNAL<T, K extends Serializable>(
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
options: ReadonlySelectorFamilyOptions<T, K> | SelectorFamilyOptions<T, K>,
|
|
106
|
+
store: Store = IMPLICIT.STORE,
|
|
107
107
|
): ReadonlySelectorFamily<T, K> | SelectorFamily<T, K> {
|
|
108
|
-
|
|
108
|
+
const isReadonly = !(`set` in options)
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
if (isReadonly) {
|
|
111
|
+
return readonlySelectorFamily__INTERNAL(options, store)
|
|
112
|
+
}
|
|
113
|
+
const core = target(store)
|
|
114
|
+
const subject = new Rx.Subject<SelectorToken<T>>()
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
142
|
}
|