{"version":3,"file":"atom.cjs","names":["ReactiveFlags"],"sources":["../src/atom.ts"],"sourcesContent":["import { ReactiveFlags, createReactiveSystem } 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\nlet batchDepth = 0\n\nexport function batch(fn: () => void) {\n  try {\n    ++batchDepth\n    fn()\n  } finally {\n    if (!--batchDepth) {\n      flush()\n    }\n  }\n}\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 (batchDepth > 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      if (isComputed) {\n        activeSub = atom\n        ++cycle\n        atom.depsTail = undefined\n      } else if (getValue === undefined) {\n        // Mutable atoms can be marked dirty by the reactive graph, but they should\n        // never be recomputed without an explicit value/updater.\n        return false\n      }\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"],"mappings":"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"}