{"version":3,"file":"derived.cjs","sources":["../../src/derived.ts"],"sourcesContent":["import { Store } from './store'\nimport { __derivedToStore, __storeToDerived } from './scheduler'\nimport type { Listener } from './types'\n\nexport type UnwrapDerivedOrStore<T> =\n  T extends Derived<infer InnerD>\n    ? InnerD\n    : T extends Store<infer InnerS>\n      ? InnerS\n      : never\n\ntype UnwrapReadonlyDerivedOrStoreArray<\n  TArr extends ReadonlyArray<Derived<any> | Store<any>>,\n> = TArr extends readonly [infer Head, ...infer Tail]\n  ? Head extends Derived<any> | Store<any>\n    ? Tail extends ReadonlyArray<Derived<any> | Store<any>>\n      ? [UnwrapDerivedOrStore<Head>, ...UnwrapReadonlyDerivedOrStoreArray<Tail>]\n      : []\n    : []\n  : []\n\n// Can't have currVal, as it's being evaluated from the current derived fn\nexport interface DerivedFnProps<\n  TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>,\n  TUnwrappedArr extends\n    UnwrapReadonlyDerivedOrStoreArray<TArr> = UnwrapReadonlyDerivedOrStoreArray<TArr>,\n> {\n  // `undefined` if it's the first run\n  /**\n   * `undefined` if it's the first run\n   * @privateRemarks this also cannot be typed as TState, as it breaks the inferencing of the function's return type when an argument is used - even with `NoInfer` usage\n   */\n  prevVal: unknown | undefined\n  prevDepVals: TUnwrappedArr | undefined\n  currDepVals: TUnwrappedArr\n}\n\nexport interface DerivedOptions<\n  TState,\n  TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>,\n> {\n  onSubscribe?: (\n    listener: Listener<TState>,\n    derived: Derived<TState>,\n  ) => () => void\n  onUpdate?: () => void\n  deps: TArr\n  /**\n   * Values of the `deps` from before and after the current invocation of `fn`\n   */\n  fn: (props: DerivedFnProps<TArr>) => TState\n}\n\nexport class Derived<\n  TState,\n  const TArr extends ReadonlyArray<\n    Derived<any> | Store<any>\n  > = ReadonlyArray<any>,\n> {\n  listeners = new Set<Listener<TState>>()\n  state: TState\n  prevState: TState | undefined\n  options: DerivedOptions<TState, TArr>\n\n  /**\n   * Functions representing the subscriptions. Call a function to cleanup\n   * @private\n   */\n  _subscriptions: Array<() => void> = []\n\n  lastSeenDepValues: Array<unknown> = []\n  getDepVals = () => {\n    const prevDepVals = [] as Array<unknown>\n    const currDepVals = [] as Array<unknown>\n    for (const dep of this.options.deps) {\n      prevDepVals.push(dep.prevState)\n      currDepVals.push(dep.state)\n    }\n    this.lastSeenDepValues = currDepVals\n    return {\n      prevDepVals,\n      currDepVals,\n      prevVal: this.prevState ?? undefined,\n    }\n  }\n\n  constructor(options: DerivedOptions<TState, TArr>) {\n    this.options = options\n    this.state = options.fn({\n      prevDepVals: undefined,\n      prevVal: undefined,\n      currDepVals: this.getDepVals().currDepVals as never,\n    })\n  }\n\n  registerOnGraph(\n    deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps,\n  ) {\n    for (const dep of deps) {\n      if (dep instanceof Derived) {\n        // First register the intermediate derived value if it's not already registered\n        dep.registerOnGraph()\n        // Then register this derived with the dep's underlying stores\n        this.registerOnGraph(dep.options.deps)\n      } else if (dep instanceof Store) {\n        // Register the derived as related derived to the store\n        let relatedLinkedDerivedVals = __storeToDerived.get(dep)\n        if (!relatedLinkedDerivedVals) {\n          relatedLinkedDerivedVals = new Set()\n          __storeToDerived.set(dep, relatedLinkedDerivedVals)\n        }\n        relatedLinkedDerivedVals.add(this as never)\n\n        // Register the store as a related store to this derived\n        let relatedStores = __derivedToStore.get(this as never)\n        if (!relatedStores) {\n          relatedStores = new Set()\n          __derivedToStore.set(this as never, relatedStores)\n        }\n        relatedStores.add(dep)\n      }\n    }\n  }\n\n  unregisterFromGraph(\n    deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps,\n  ) {\n    for (const dep of deps) {\n      if (dep instanceof Derived) {\n        this.unregisterFromGraph(dep.options.deps)\n      } else if (dep instanceof Store) {\n        const relatedLinkedDerivedVals = __storeToDerived.get(dep)\n        if (relatedLinkedDerivedVals) {\n          relatedLinkedDerivedVals.delete(this as never)\n        }\n\n        const relatedStores = __derivedToStore.get(this as never)\n        if (relatedStores) {\n          relatedStores.delete(dep)\n        }\n      }\n    }\n  }\n\n  recompute = () => {\n    this.prevState = this.state\n    const { prevDepVals, currDepVals, prevVal } = this.getDepVals()\n    this.state = this.options.fn({\n      prevDepVals: prevDepVals as never,\n      currDepVals: currDepVals as never,\n      prevVal,\n    })\n\n    this.options.onUpdate?.()\n  }\n\n  checkIfRecalculationNeededDeeply = () => {\n    for (const dep of this.options.deps) {\n      if (dep instanceof Derived) {\n        dep.checkIfRecalculationNeededDeeply()\n      }\n    }\n    let shouldRecompute = false\n    const lastSeenDepValues = this.lastSeenDepValues\n    const { currDepVals } = this.getDepVals()\n    for (let i = 0; i < currDepVals.length; i++) {\n      if (currDepVals[i] !== lastSeenDepValues[i]) {\n        shouldRecompute = true\n        break\n      }\n    }\n\n    if (shouldRecompute) {\n      this.recompute()\n    }\n  }\n\n  mount = () => {\n    this.registerOnGraph()\n    this.checkIfRecalculationNeededDeeply()\n\n    return () => {\n      this.unregisterFromGraph()\n      for (const cleanup of this._subscriptions) {\n        cleanup()\n      }\n    }\n  }\n\n  subscribe = (listener: Listener<TState>) => {\n    this.listeners.add(listener)\n    const unsub = this.options.onSubscribe?.(listener, this)\n    return () => {\n      this.listeners.delete(listener)\n      unsub?.()\n    }\n  }\n}\n"],"names":["Store","__storeToDerived","__derivedToStore"],"mappings":"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"}