@tanstack/store
Version:
Framework agnostic type-safe store w/ reactive framework adapters
1 lines • 12.5 kB
Source Map (JSON)
{"version":3,"file":"atom.cjs","sources":["../../src/atom.ts"],"sourcesContent":["import { ReactiveFlags, createReactiveSystem, getBatchDepth } from './alien'\n\nimport type { ReactiveNode } from './alien'\nimport type {\n Atom,\n AtomOptions,\n Observer,\n ReadonlyAtom,\n Subscription,\n} from './types'\n\nexport function toObserver<T>(\n nextHandler?: Observer<T> | ((value: T) => void),\n errorHandler?: (error: any) => void,\n completionHandler?: () => void,\n): Observer<T> {\n const isObserver = typeof nextHandler === 'object'\n const self = isObserver ? nextHandler : undefined\n\n return {\n next: (isObserver ? nextHandler.next : nextHandler)?.bind(self),\n error: (isObserver ? nextHandler.error : errorHandler)?.bind(self),\n complete: (isObserver ? nextHandler.complete : completionHandler)?.bind(\n self,\n ),\n }\n}\n\ninterface InternalAtom<T> extends ReactiveNode {\n _snapshot: T\n _update: (getValue?: T | ((snapshot: T) => T)) => boolean\n get: () => T\n subscribe: (observerOrFn: Observer<T> | ((value: T) => void)) => Subscription\n}\n\nconst queuedEffects: Array<Effect | undefined> = []\nlet cycle = 0\nconst { link, unlink, propagate, checkDirty, shallowPropagate } =\n createReactiveSystem({\n update(atom: InternalAtom<any>): boolean {\n return atom._update()\n },\n // eslint-disable-next-line no-shadow\n notify(effect: Effect): void {\n queuedEffects[queuedEffectsLength++] = effect\n effect.flags &= ~ReactiveFlags.Watching\n },\n unwatched(atom: InternalAtom<any>): void {\n if (atom.depsTail !== undefined) {\n atom.depsTail = undefined\n atom.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty\n purgeDeps(atom)\n }\n },\n })\n\nlet notifyIndex = 0\nlet queuedEffectsLength = 0\nlet activeSub: ReactiveNode | undefined\n\nfunction purgeDeps(sub: ReactiveNode) {\n const depsTail = sub.depsTail\n let dep = depsTail !== undefined ? depsTail.nextDep : sub.deps\n while (dep !== undefined) {\n dep = unlink(dep, sub)\n }\n}\n\nexport function flush(): void {\n if (getBatchDepth() > 0) {\n return\n }\n while (notifyIndex < queuedEffectsLength) {\n // eslint-disable-next-line no-shadow\n const effect = queuedEffects[notifyIndex]!\n queuedEffects[notifyIndex++] = undefined\n effect.notify()\n }\n notifyIndex = 0\n queuedEffectsLength = 0\n}\n\ntype AsyncAtomState<TData, TError = unknown> =\n | { status: 'pending' }\n | { status: 'done'; data: TData }\n | { status: 'error'; error: TError }\n\nexport function createAsyncAtom<T>(\n getValue: () => Promise<T>,\n options?: AtomOptions<AsyncAtomState<T>>,\n): ReadonlyAtom<AsyncAtomState<T>> {\n const ref: { current?: InternalAtom<AsyncAtomState<T>> } = {}\n const atom = createAtom<AsyncAtomState<T>>(() => {\n getValue().then(\n (data) => {\n const internalAtom = ref.current!\n if (internalAtom._update({ status: 'done', data })) {\n const subs = internalAtom.subs\n if (subs !== undefined) {\n propagate(subs)\n shallowPropagate(subs)\n flush()\n }\n }\n },\n (error) => {\n const internalAtom = ref.current!\n if (internalAtom._update({ status: 'error', error })) {\n const subs = internalAtom.subs\n if (subs !== undefined) {\n propagate(subs)\n shallowPropagate(subs)\n flush()\n }\n }\n },\n )\n\n return { status: 'pending' }\n }, options)\n ref.current = atom as unknown as InternalAtom<AsyncAtomState<T>>\n\n return atom\n}\n\nexport function createAtom<T>(\n getValue: (prev?: NoInfer<T>) => T,\n options?: AtomOptions<T>,\n): ReadonlyAtom<T>\nexport function createAtom<T>(\n initialValue: T,\n options?: AtomOptions<T>,\n): Atom<T>\nexport function createAtom<T>(\n valueOrFn: T | ((prev?: T) => T),\n options?: AtomOptions<T>,\n): Atom<T> | ReadonlyAtom<T> {\n const isComputed = typeof valueOrFn === 'function'\n const getter = valueOrFn as (prev?: T) => T\n\n // Create plain object atom\n const atom: InternalAtom<T> = {\n _snapshot: isComputed ? undefined! : valueOrFn,\n\n subs: undefined,\n subsTail: undefined,\n deps: undefined,\n depsTail: undefined,\n flags: isComputed ? ReactiveFlags.None : ReactiveFlags.Mutable,\n\n get(): T {\n if (activeSub !== undefined) {\n link(atom, activeSub, cycle)\n }\n return atom._snapshot\n },\n\n subscribe(observerOrFn: Observer<T> | ((value: T) => void)) {\n const obs = toObserver(observerOrFn)\n const observed = { current: false }\n const e = effect(() => {\n atom.get()\n if (!observed.current) {\n observed.current = true\n } else {\n obs.next?.(atom._snapshot)\n }\n })\n\n return {\n unsubscribe: () => {\n e.stop()\n },\n }\n },\n _update(getValue?: T | ((snapshot: T) => T)): boolean {\n const prevSub = activeSub\n const compare = options?.compare ?? Object.is\n activeSub = atom\n ++cycle\n atom.depsTail = undefined\n if (isComputed) {\n atom.flags = ReactiveFlags.Mutable | ReactiveFlags.RecursedCheck\n }\n try {\n const oldValue = atom._snapshot\n const newValue =\n typeof getValue === 'function'\n ? (getValue as (snapshot: T) => T)(oldValue)\n : getValue === undefined && isComputed\n ? getter(oldValue)\n : getValue!\n if (oldValue === undefined || !compare(oldValue, newValue)) {\n atom._snapshot = newValue\n return true\n }\n return false\n } finally {\n activeSub = prevSub\n if (isComputed) {\n atom.flags &= ~ReactiveFlags.RecursedCheck\n }\n purgeDeps(atom)\n }\n },\n }\n\n if (isComputed) {\n atom.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty\n atom.get = function (): T {\n const flags = atom.flags\n if (\n flags & ReactiveFlags.Dirty ||\n (flags & ReactiveFlags.Pending && checkDirty(atom.deps!, atom))\n ) {\n if (atom._update()) {\n const subs = atom.subs\n if (subs !== undefined) {\n shallowPropagate(subs)\n }\n }\n } else if (flags & ReactiveFlags.Pending) {\n atom.flags = flags & ~ReactiveFlags.Pending\n }\n if (activeSub !== undefined) {\n link(atom, activeSub, cycle)\n }\n return atom._snapshot\n }\n } else {\n ;(atom as unknown as Atom<T>).set = function (\n // eslint-disable-next-line no-shadow\n valueOrFn: T | ((prev: T) => T),\n ): void {\n if (atom._update(valueOrFn)) {\n const subs = atom.subs\n if (subs !== undefined) {\n propagate(subs)\n shallowPropagate(subs)\n flush()\n }\n }\n }\n }\n\n return atom as unknown as Atom<T> | ReadonlyAtom<T>\n}\n\ninterface Effect extends ReactiveNode {\n notify: () => void\n stop: () => void\n}\n\nfunction effect<T>(fn: () => T): Effect {\n const run = (): T => {\n const prevSub = activeSub\n activeSub = effectObj\n ++cycle\n effectObj.depsTail = undefined\n effectObj.flags = ReactiveFlags.Watching | ReactiveFlags.RecursedCheck\n try {\n return fn()\n } finally {\n activeSub = prevSub\n effectObj.flags &= ~ReactiveFlags.RecursedCheck\n purgeDeps(effectObj)\n }\n }\n const effectObj: Effect = {\n deps: undefined,\n depsTail: undefined,\n subs: undefined,\n subsTail: undefined,\n flags: ReactiveFlags.Watching | ReactiveFlags.RecursedCheck,\n\n notify(): void {\n const flags = this.flags\n if (\n flags & ReactiveFlags.Dirty ||\n (flags & ReactiveFlags.Pending && checkDirty(this.deps!, this))\n ) {\n run()\n } else {\n this.flags = ReactiveFlags.Watching\n }\n },\n\n stop(): void {\n this.flags = ReactiveFlags.None\n this.depsTail = undefined\n purgeDeps(this)\n },\n }\n\n run()\n\n return effectObj\n}\n"],"names":["createReactiveSystem","effect","ReactiveFlags","getBatchDepth","valueOrFn"],"mappings":"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"}