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.
@@ -32,6 +32,6 @@ export const isSelectorDefault = (
32
32
  key: string,
33
33
  store: Store = IMPLICIT.STORE,
34
34
  ): boolean => {
35
- const roots = traceAllSelectorAtoms(key, store)
36
- return roots.every((root) => isAtomDefault(root.key, store))
35
+ const rootKeys = traceAllSelectorAtoms(key, store)
36
+ return rootKeys.every((rootKey) => isAtomDefault(rootKey, store))
37
37
  }
@@ -27,10 +27,12 @@ export const cacheValue = (
27
27
  subject.next({ newValue: value, oldValue: value })
28
28
  })
29
29
  .catch((error) => {
30
- store.config.logger?.error(
31
- `Promised value for "${key}" rejected:`,
32
- error,
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)
@@ -3,6 +3,7 @@ export * from "./caching"
3
3
  export * from "./families"
4
4
  export * from "./future"
5
5
  export * from "./get-state-internal"
6
+ export * from "./keys"
6
7
  export * from "./operation"
7
8
  export * from "./mutable"
8
9
  export * from "./selector"
@@ -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,4 +1,4 @@
1
- export * from "./lookup-selector-sources"
1
+ export * from "./get-selector-dependency-keys"
2
2
  export * from "./register-selector"
3
3
  export * from "./create-selector"
4
4
  export * from "./trace-selector-atoms"
@@ -1,50 +1,50 @@
1
- import type { AtomToken, ReadonlySelectorToken, StateToken } from "atom.io"
2
-
3
1
  import type { Store } from ".."
4
- import { lookupSelectorSources } from "./lookup-selector-sources"
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
- dependency: ReadonlySelectorToken<unknown> | StateToken<unknown>,
8
+ directDependencyKey: StateKey<unknown>,
9
9
  store: Store,
10
- ): AtomToken<unknown>[] => {
11
- const roots: AtomToken<unknown>[] = []
10
+ ): AtomKey<unknown>[] => {
11
+ const rootKeys: AtomKey<unknown>[] = []
12
12
 
13
- const sources = lookupSelectorSources(dependency.key, store)
13
+ const indirectDependencyKeys = getSelectorDependencyKeys(
14
+ directDependencyKey,
15
+ store,
16
+ )
14
17
  let depth = 0
15
- while (sources.length > 0) {
18
+ while (indirectDependencyKeys.length > 0) {
16
19
  // biome-ignore lint/style/noNonNullAssertion: just checked length ^^^
17
- const source = sources.shift()!
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 (source.type !== `atom`) {
31
- sources.push(...lookupSelectorSources(source.key, store))
32
- } else {
33
- roots.push(source)
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 roots
37
+ return rootKeys
38
38
  }
39
39
 
40
40
  export const traceAllSelectorAtoms = (
41
41
  selectorKey: string,
42
42
  store: Store,
43
- ): AtomToken<unknown>[] => {
44
- const sources = lookupSelectorSources(selectorKey, store)
45
- return sources.flatMap((source) =>
46
- source.type === `atom`
47
- ? source
48
- : traceSelectorAtoms(selectorKey, source, store),
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 roots = traceSelectorAtoms(selectorKey, dependency, store)
23
+ const rootKeys = traceSelectorAtoms(selectorKey, dependency.key, store)
24
24
  store.config.logger?.info(
25
25
  ` || adding roots for "${selectorKey}":`,
26
- roots.map((r) => r.key),
26
+ rootKeys.map((r) => r),
27
27
  )
28
- for (const root of roots) {
28
+ for (const atomKey of rootKeys) {
29
29
  core.selectorAtoms = core.selectorAtoms.set({
30
30
  selectorKey,
31
- atomKey: root.key,
31
+ atomKey,
32
32
  })
33
33
  }
34
34
  }
@@ -1,5 +1,4 @@
1
1
  export * from "./deposit"
2
- export * from "./lookup"
3
2
  export * from "./store"
4
3
  export * from "./withdraw"
5
4
  export * from "./withdraw-new-family-member"
@@ -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((atomToken) => {
16
- const atom = withdraw(atomToken, store)
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 "${atomToken.key}", a dependency of selector "${state.key}", not found in store "${store.config.name}".`,
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 "${atomToken.key}" go (`,
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.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.53.0",
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
- }