atom.io 0.9.9 → 0.9.10
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/internal/dist/index.d.mts +23 -7
- package/internal/dist/index.d.ts +23 -7
- package/internal/dist/index.js +223 -228
- package/internal/dist/index.js.map +1 -1
- package/internal/dist/index.mjs +219 -227
- package/internal/dist/index.mjs.map +1 -1
- package/internal/src/atom/is-default.ts +2 -2
- package/internal/src/caching.ts +6 -4
- package/internal/src/index.ts +1 -0
- package/internal/src/keys.ts +30 -0
- package/internal/src/selector/get-selector-dependency-keys.ts +20 -0
- package/internal/src/selector/index.ts +1 -1
- package/internal/src/selector/trace-selector-atoms.ts +26 -26
- package/internal/src/selector/update-selector-atoms.ts +4 -4
- package/internal/src/store/index.ts +0 -1
- package/internal/src/subscribe/subscribe-to-root-atoms.ts +4 -5
- package/package.json +2 -2
- package/internal/src/selector/lookup-selector-sources.ts +0 -20
- package/internal/src/store/lookup.ts +0 -26
|
@@ -32,6 +32,6 @@ export const isSelectorDefault = (
|
|
|
32
32
|
key: string,
|
|
33
33
|
store: Store = IMPLICIT.STORE,
|
|
34
34
|
): boolean => {
|
|
35
|
-
const
|
|
36
|
-
return
|
|
35
|
+
const rootKeys = traceAllSelectorAtoms(key, store)
|
|
36
|
+
return rootKeys.every((rootKey) => isAtomDefault(rootKey, store))
|
|
37
37
|
}
|
package/internal/src/caching.ts
CHANGED
|
@@ -27,10 +27,12 @@ export const cacheValue = (
|
|
|
27
27
|
subject.next({ newValue: value, oldValue: value })
|
|
28
28
|
})
|
|
29
29
|
.catch((error) => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
if (error !== `canceled`) {
|
|
31
|
+
store.config.logger?.error(
|
|
32
|
+
`Promised value for "${key}" rejected:`,
|
|
33
|
+
error,
|
|
34
|
+
)
|
|
35
|
+
}
|
|
34
36
|
})
|
|
35
37
|
} else {
|
|
36
38
|
target(store).valueMap.set(key, value)
|
package/internal/src/index.ts
CHANGED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Store } from "./store"
|
|
2
|
+
import { target } from "./transaction"
|
|
3
|
+
|
|
4
|
+
export type AtomKey<T> = string & { __atomKey?: never; __brand?: T }
|
|
5
|
+
export type SelectorKey<T> = string & { __selectorKey?: never; __brand?: T }
|
|
6
|
+
export type ReadonlySelectorKey<T> = string & {
|
|
7
|
+
__readonlySelectorKey?: never
|
|
8
|
+
__brand?: T
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const isAtomKey = (key: string, store: Store): key is AtomKey<unknown> =>
|
|
12
|
+
target(store).atoms.has(key)
|
|
13
|
+
export const isSelectorKey = (
|
|
14
|
+
key: string,
|
|
15
|
+
store: Store,
|
|
16
|
+
): key is SelectorKey<unknown> => target(store).selectors.has(key)
|
|
17
|
+
export const isReadonlySelectorKey = (
|
|
18
|
+
key: string,
|
|
19
|
+
store: Store,
|
|
20
|
+
): key is ReadonlySelectorKey<unknown> =>
|
|
21
|
+
target(store).readonlySelectors.has(key)
|
|
22
|
+
|
|
23
|
+
export type StateKey<T> = AtomKey<T> | ReadonlySelectorKey<T> | SelectorKey<T>
|
|
24
|
+
export const isStateKey = (
|
|
25
|
+
key: string,
|
|
26
|
+
store: Store,
|
|
27
|
+
): key is StateKey<unknown> =>
|
|
28
|
+
isAtomKey(key, store) ||
|
|
29
|
+
isSelectorKey(key, store) ||
|
|
30
|
+
isReadonlySelectorKey(key, store)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AtomKey, ReadonlySelectorKey, SelectorKey } from "../keys"
|
|
2
|
+
import { isStateKey } from "../keys"
|
|
3
|
+
import type { Store } from "../store"
|
|
4
|
+
import { target } from "../transaction"
|
|
5
|
+
|
|
6
|
+
export const getSelectorDependencyKeys = (
|
|
7
|
+
key: string,
|
|
8
|
+
store: Store,
|
|
9
|
+
): (
|
|
10
|
+
| AtomKey<unknown>
|
|
11
|
+
| ReadonlySelectorKey<unknown>
|
|
12
|
+
| SelectorKey<unknown>
|
|
13
|
+
)[] => {
|
|
14
|
+
const sources = target(store)
|
|
15
|
+
.selectorGraph.getRelationEntries({ downstreamSelectorKey: key })
|
|
16
|
+
.filter(([_, { source }]) => source !== key)
|
|
17
|
+
.map(([_, { source }]) => source)
|
|
18
|
+
.filter((source) => isStateKey(source, store))
|
|
19
|
+
return sources
|
|
20
|
+
}
|
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
import type { AtomToken, ReadonlySelectorToken, StateToken } from "atom.io"
|
|
2
|
-
|
|
3
1
|
import type { Store } from ".."
|
|
4
|
-
import {
|
|
2
|
+
import type { AtomKey, StateKey } from "../keys"
|
|
3
|
+
import { isAtomKey } from "../keys"
|
|
4
|
+
import { getSelectorDependencyKeys } from "./get-selector-dependency-keys"
|
|
5
5
|
|
|
6
6
|
export const traceSelectorAtoms = (
|
|
7
7
|
selectorKey: string,
|
|
8
|
-
|
|
8
|
+
directDependencyKey: StateKey<unknown>,
|
|
9
9
|
store: Store,
|
|
10
|
-
):
|
|
11
|
-
const
|
|
10
|
+
): AtomKey<unknown>[] => {
|
|
11
|
+
const rootKeys: AtomKey<unknown>[] = []
|
|
12
12
|
|
|
13
|
-
const
|
|
13
|
+
const indirectDependencyKeys = getSelectorDependencyKeys(
|
|
14
|
+
directDependencyKey,
|
|
15
|
+
store,
|
|
16
|
+
)
|
|
14
17
|
let depth = 0
|
|
15
|
-
while (
|
|
18
|
+
while (indirectDependencyKeys.length > 0) {
|
|
16
19
|
// biome-ignore lint/style/noNonNullAssertion: just checked length ^^^
|
|
17
|
-
const
|
|
20
|
+
const indirectDependencyKey = indirectDependencyKeys.shift()!
|
|
18
21
|
++depth
|
|
19
|
-
if (depth > 999) {
|
|
20
|
-
store.config.logger?.warn(
|
|
21
|
-
`Maximum selector dependency depth exceeded 999 in selector "${selectorKey}".`,
|
|
22
|
-
)
|
|
23
|
-
}
|
|
24
22
|
if (depth > 99999) {
|
|
25
23
|
throw new Error(
|
|
26
|
-
`Maximum selector dependency depth exceeded in selector "${selectorKey}".`,
|
|
24
|
+
`Maximum selector dependency depth exceeded (> 99999) in selector "${selectorKey}". This is likely due to a circular dependency.`,
|
|
27
25
|
)
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
if (
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
if (!isAtomKey(indirectDependencyKey, store)) {
|
|
29
|
+
indirectDependencyKeys.push(
|
|
30
|
+
...getSelectorDependencyKeys(indirectDependencyKey, store),
|
|
31
|
+
)
|
|
32
|
+
} else if (!rootKeys.includes(indirectDependencyKey)) {
|
|
33
|
+
rootKeys.push(indirectDependencyKey)
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
return
|
|
37
|
+
return rootKeys
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export const traceAllSelectorAtoms = (
|
|
41
41
|
selectorKey: string,
|
|
42
42
|
store: Store,
|
|
43
|
-
):
|
|
44
|
-
const
|
|
45
|
-
return
|
|
46
|
-
|
|
47
|
-
?
|
|
48
|
-
: traceSelectorAtoms(selectorKey,
|
|
43
|
+
): AtomKey<unknown>[] => {
|
|
44
|
+
const directDependencyKeys = getSelectorDependencyKeys(selectorKey, store)
|
|
45
|
+
return directDependencyKeys.flatMap((depKey) =>
|
|
46
|
+
isAtomKey(depKey, store)
|
|
47
|
+
? depKey
|
|
48
|
+
: traceSelectorAtoms(selectorKey, depKey, store),
|
|
49
49
|
)
|
|
50
50
|
}
|
|
@@ -20,15 +20,15 @@ export const updateSelectorAtoms = (
|
|
|
20
20
|
)
|
|
21
21
|
return
|
|
22
22
|
}
|
|
23
|
-
const
|
|
23
|
+
const rootKeys = traceSelectorAtoms(selectorKey, dependency.key, store)
|
|
24
24
|
store.config.logger?.info(
|
|
25
25
|
` || adding roots for "${selectorKey}":`,
|
|
26
|
-
|
|
26
|
+
rootKeys.map((r) => r),
|
|
27
27
|
)
|
|
28
|
-
for (const
|
|
28
|
+
for (const atomKey of rootKeys) {
|
|
29
29
|
core.selectorAtoms = core.selectorAtoms.set({
|
|
30
30
|
selectorKey,
|
|
31
|
-
atomKey
|
|
31
|
+
atomKey,
|
|
32
32
|
})
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -2,7 +2,6 @@ import { getState__INTERNAL } from "../get-state-internal"
|
|
|
2
2
|
import type { ReadonlySelector, Selector } from "../selector"
|
|
3
3
|
import { traceAllSelectorAtoms } from "../selector"
|
|
4
4
|
import type { Store } from "../store"
|
|
5
|
-
import { withdraw } from "../store"
|
|
6
5
|
import { recallState } from "./recall-state"
|
|
7
6
|
|
|
8
7
|
export const subscribeToRootAtoms = <T>(
|
|
@@ -12,18 +11,18 @@ export const subscribeToRootAtoms = <T>(
|
|
|
12
11
|
const dependencySubscriptions =
|
|
13
12
|
`default` in state
|
|
14
13
|
? null
|
|
15
|
-
: traceAllSelectorAtoms(state.key, store).map((
|
|
16
|
-
const atom =
|
|
14
|
+
: traceAllSelectorAtoms(state.key, store).map((atomKey) => {
|
|
15
|
+
const atom = store.atoms.get(atomKey)
|
|
17
16
|
if (atom === undefined) {
|
|
18
17
|
throw new Error(
|
|
19
|
-
`Atom "${
|
|
18
|
+
`Atom "${atomKey}", a dependency of selector "${state.key}", not found in store "${store.config.name}".`,
|
|
20
19
|
)
|
|
21
20
|
}
|
|
22
21
|
return atom.subject.subscribe(
|
|
23
22
|
`${state.type}:${state.key}`,
|
|
24
23
|
(atomChange) => {
|
|
25
24
|
store.config.logger?.info(
|
|
26
|
-
`📢 selector "${state.key}" saw root "${
|
|
25
|
+
`📢 selector "${state.key}" saw root "${atomKey}" go (`,
|
|
27
26
|
atomChange.oldValue,
|
|
28
27
|
`->`,
|
|
29
28
|
atomChange.newValue,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "atom.io",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.10",
|
|
4
4
|
"description": "Composable and testable reactive data library.",
|
|
5
5
|
"homepage": "https://atom.io.fyi",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"@types/tmp": "0.2.6",
|
|
56
56
|
"@vitest/coverage-v8": "0.34.6",
|
|
57
57
|
"concurrently": "8.2.2",
|
|
58
|
-
"eslint": "8.
|
|
58
|
+
"eslint": "8.54.0",
|
|
59
59
|
"framer-motion": "10.16.5",
|
|
60
60
|
"happy-dom": "12.10.3",
|
|
61
61
|
"npmlog": "7.0.1",
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { AtomToken, ReadonlySelectorToken, SelectorToken } from "atom.io"
|
|
2
|
-
|
|
3
|
-
import type { Store } from "../store"
|
|
4
|
-
import { lookup } from "../store"
|
|
5
|
-
import { target } from "../transaction"
|
|
6
|
-
|
|
7
|
-
export const lookupSelectorSources = (
|
|
8
|
-
key: string,
|
|
9
|
-
store: Store,
|
|
10
|
-
): (
|
|
11
|
-
| AtomToken<unknown>
|
|
12
|
-
| ReadonlySelectorToken<unknown>
|
|
13
|
-
| SelectorToken<unknown>
|
|
14
|
-
)[] => {
|
|
15
|
-
const sources = target(store)
|
|
16
|
-
.selectorGraph.getRelationEntries({ downstreamSelectorKey: key })
|
|
17
|
-
.filter(([_, { source }]) => source !== key)
|
|
18
|
-
.map(([_, { source }]) => lookup(source, store))
|
|
19
|
-
return sources
|
|
20
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { AtomToken, ReadonlySelectorToken, SelectorToken } from "atom.io"
|
|
2
|
-
|
|
3
|
-
import { target } from "../transaction"
|
|
4
|
-
import type { Store } from "./store"
|
|
5
|
-
|
|
6
|
-
export function lookup(
|
|
7
|
-
key: string,
|
|
8
|
-
store: Store,
|
|
9
|
-
): AtomToken<unknown> | ReadonlySelectorToken<unknown> | SelectorToken<unknown> {
|
|
10
|
-
const core = target(store)
|
|
11
|
-
let type: string = core.atoms.has(key)
|
|
12
|
-
? `atom`
|
|
13
|
-
: core.selectors.has(key)
|
|
14
|
-
? `selector`
|
|
15
|
-
: core.readonlySelectors.has(key)
|
|
16
|
-
? `readonly_selector`
|
|
17
|
-
: ``
|
|
18
|
-
if (!type) {
|
|
19
|
-
const errorId = Math.random().toString(36)
|
|
20
|
-
type = `🚨 This state could not be found by lookup! Check the console for "${errorId}"`
|
|
21
|
-
store.config.logger?.error(
|
|
22
|
-
`${errorId}: Key "${key}" does not exist in the store.`,
|
|
23
|
-
)
|
|
24
|
-
}
|
|
25
|
-
return { key, type } as any
|
|
26
|
-
}
|