{"version":3,"sources":["../src/index.ts","../src/utils.ts"],"sourcesContent":["import type { Patch, Draft } from \"immer\";\nimport {\n  nothing,\n  enablePatches,\n  applyPatches,\n  produceWithPatches,\n} from \"immer\";\nimport { ensureCurrent, makeStateOperator } from \"./utils\";\nimport type { MaybeDraft } from \"./utils\";\n\ntype ValidRecipeReturnType<State> =\n  | State\n  | Draft<State>\n  // eslint-disable-next-line @typescript-eslint/no-invalid-void-type\n  | void\n  | undefined\n  | (State extends undefined ? typeof nothing : never);\n\nexport type ImmerRecipe<Data, Args extends Array<any>> = (\n  draft: Draft<Data>,\n  ...args: Args\n) => ValidRecipeReturnType<Data>;\n\nexport type DataFromRecipe<Recipe extends ImmerRecipe<any, any>> =\n  Recipe extends ImmerRecipe<infer T, any> ? T : never;\n\nexport interface BaseHistoryState<Data, HistoryEntry> {\n  past: Array<HistoryEntry>;\n  present: Data;\n  future: Array<HistoryEntry>;\n  paused: boolean;\n}\n\ntype HistoryEntryType<State> = State extends BaseHistoryState<any, infer T>\n  ? T\n  : never;\n\nexport interface BaseHistoryAdapterConfig {\n  /**\n   * Maximum number of past states to keep.\n   * If limit is reached, the oldest state will be removed.\n   * If not provided, all states will be kept.\n   */\n  limit?: number;\n}\n\nexport interface BaseHistoryStateFn {\n  dataConstraint: unknown;\n  _rawData: unknown;\n  data: this[\"_rawData\"] extends this[\"dataConstraint\"]\n    ? this[\"_rawData\"]\n    : never;\n  state: BaseHistoryState<this[\"data\"], unknown>;\n  config: BaseHistoryAdapterConfig;\n}\n\nexport type GetStateType<\n  Data,\n  StateFn extends BaseHistoryStateFn,\n> = (StateFn & {\n  _rawData: Data;\n})[\"state\"];\n\nexport type GetConfigType<\n  Data,\n  StateFn extends BaseHistoryStateFn,\n> = (StateFn & {\n  _rawData: Data;\n})[\"config\"];\n\nexport interface WrapRecipeConfig<Args extends Array<any>> {\n  /**\n   * A function to extract from the arguments whether the action was undoable or not.\n   * If not provided (or if function returns undefined), defaults to true.\n   * Non-undoable actions will not be included in state history.\n   */\n  isUndoable?: (...args: Args) => boolean | undefined;\n}\n\nexport interface UndoableConfig<\n  Data,\n  Args extends Array<any>,\n  RootState,\n  State extends BaseHistoryState<unknown, unknown> = HistoryState<Data>,\n> extends WrapRecipeConfig<Args> {\n  /**\n   * A function to select the history state from the root state.\n   */\n  selectHistoryState?: (state: Draft<RootState>) => Draft<State>;\n}\n\nexport interface HistoryAdapter<\n  Data,\n  State extends BaseHistoryState<unknown, unknown> = HistoryState<Data>,\n> {\n  /**\n   * Construct an initial state with no history.\n   * @param initialData Data to include\n   * @returns State shape including data\n   */\n  getInitialState(initialData: Data): State;\n  /**\n   * Applies previous patch if available, and returns state.\n   * Will mutate directly if passed a draft, otherwise will return a new state immutably.\n   * @param state History state shape, with patches\n   */\n  undo<S extends MaybeDraft<State>>(state: S): S;\n  /**\n   * Applies next patch if available, and returns state.\n   * Will mutate directly if passed a draft, otherwise will return a new state immutably.\n   * @param state History state shape, with patches\n   */\n  redo<S extends MaybeDraft<State>>(state: S): S;\n  /**\n   * Moves the state back or forward in history by n steps.\n   * @param state History state shape, with patches\n   * @param n steps to move. Negative numbers move backwards.\n   */\n  jump<S extends MaybeDraft<State>>(state: S, n: number): S;\n  /**\n   * Clears past and present history.\n   * @param state History state shape, with patches\n   */\n  clearHistory<S extends MaybeDraft<State>>(state: S): S;\n  /**\n   * Wraps a function to automatically update patch history according to changes\n   * @param recipe An immer-style recipe, which can mutate the draft or return new state\n   * @param config Configuration for undoable action\n   */\n  undoable<Args extends Array<any>, RootState = State>(\n    recipe: ImmerRecipe<Data, Args>,\n    config?: UndoableConfig<Data, Args, RootState, State>,\n  ): <State extends MaybeDraft<RootState>>(\n    state: State,\n    ...args: Args\n  ) => State;\n  /**\n   * Pauses the history, preventing any new patches from being added.\n   * @param state History state shape, with patches\n   */\n  pause<S extends MaybeDraft<State>>(state: S): S;\n  /**\n   * Resumes the history, allowing new patches to be added.\n   * @param state History state shape, with patches\n   */\n  resume<S extends MaybeDraft<State>>(state: S): S;\n}\n\n/**\n * Construct an initial state with no history.\n * @param initialData Data to include\n * @returns State shape including data\n */\nexport function getInitialState<Data, HistoryEntry>(\n  initialData: Data,\n): BaseHistoryState<Data, HistoryEntry> {\n  return {\n    past: [],\n    present: initialData,\n    future: [],\n    paused: false,\n  };\n}\n\ntype GetInitialState<StateFn extends BaseHistoryStateFn> = <\n  Data extends StateFn[\"dataConstraint\"],\n>(\n  initialData: Data,\n) => GetStateType<Data, StateFn>;\n\ntype ApplyOp = \"undo\" | \"redo\";\n\nexport type BuildHistoryAdapterConfig<StateFn extends BaseHistoryStateFn> = {\n  /**\n   * Function to apply a history entry to the state.\n   * Should return a history entry to be added to the opposite stack (i.e. past or future).\n   *\n   * For example, when undoing, the entry is removed from the past stack, provided to `applyEntry`, and the result is added to the future stack.\n   */\n  applyEntry: <Data extends StateFn[\"dataConstraint\"]>(\n    state: GetStateType<Data, StateFn>,\n    historyEntry: HistoryEntryType<GetStateType<Data, StateFn>>,\n    op: ApplyOp,\n  ) => HistoryEntryType<GetStateType<Data, StateFn>>;\n  /**\n   * Function to wrap a recipe to automatically update patch history according to changes.\n   * Should return a function that receives the state and arguments, and returns a history entry to be added to the past stack.\n   */\n  wrapRecipe: <Data extends StateFn[\"dataConstraint\"], Args extends Array<any>>(\n    recipe: ImmerRecipe<Data, Args>,\n  ) => (\n    state: Draft<GetStateType<Data, StateFn>>,\n    ...args: Args\n  ) => HistoryEntryType<GetStateType<Data, StateFn>>;\n  /**\n   * A function to run when the adapter is created.\n   *\n   * Useful for setup such as enabling patches.\n   */\n  onCreate?: (\n    config?: GetConfigType<StateFn[\"dataConstraint\"], StateFn>,\n  ) => void;\n} & (BaseHistoryState<any, any> extends GetStateType<\n  StateFn[\"dataConstraint\"],\n  StateFn\n>\n  ? {\n      /**\n       * Function to construct an initial state with no history.\n       */\n      getInitialState?: GetInitialState<StateFn>;\n    }\n  : {\n      /**\n       * Function to construct an initial state with no history.\n       */\n      getInitialState: GetInitialState<StateFn>;\n    });\n\nexport type CreateHistoryAdapter<StateFn extends BaseHistoryStateFn> = <\n  Data extends StateFn[\"dataConstraint\"],\n>(\n  adapterConfig?: GetConfigType<Data, StateFn>,\n) => HistoryAdapter<Data, GetStateType<Data, StateFn>>;\n\nexport function buildCreateHistoryAdapter<StateFn extends BaseHistoryStateFn>({\n  applyEntry,\n  wrapRecipe,\n  onCreate,\n  getInitialState: getInitialStateCustom = getInitialState,\n}: BuildHistoryAdapterConfig<StateFn>): CreateHistoryAdapter<StateFn> {\n  function undoMutably(state: StateFn[\"state\"]) {\n    if (!state.past.length) return;\n    state.future.unshift(applyEntry(state, state.past.pop() as never, \"undo\"));\n  }\n  function redoMutably(state: StateFn[\"state\"]) {\n    if (!state.future.length) return;\n    state.past.push(applyEntry(state, state.future.shift() as never, \"redo\"));\n  }\n  return function createHistoryAdapter<Data extends StateFn[\"dataConstraint\"]>(\n    adapterConfig?: GetConfigType<Data, StateFn>,\n  ): HistoryAdapter<Data, GetStateType<Data, StateFn>> {\n    type State = GetStateType<Data, StateFn>;\n    onCreate?.(adapterConfig);\n    return {\n      getInitialState: getInitialStateCustom,\n      undo: makeStateOperator(undoMutably),\n      redo: makeStateOperator(redoMutably),\n      jump: makeStateOperator<State, [number]>((state, n) => {\n        if (n < 0) {\n          for (let i = 0; i < -n; i++) {\n            undoMutably(state);\n          }\n        } else {\n          for (let i = 0; i < n; i++) {\n            redoMutably(state);\n          }\n        }\n      }),\n      clearHistory: makeStateOperator<State>((state) => {\n        state.past = [];\n        state.future = [];\n      }),\n      pause: makeStateOperator<State>((state) => {\n        state.paused = true;\n      }),\n      resume: makeStateOperator<State>((state) => {\n        state.paused = false;\n      }),\n      undoable: <Args extends Array<any>, RootState>(\n        recipe: (\n          draft: Draft<Data>,\n          ...args: Args\n        ) => ValidRecipeReturnType<Data>,\n        config?: UndoableConfig<Data, Args, RootState, State>,\n      ) => {\n        const { selectHistoryState, isUndoable } = config ?? {};\n        const finalRecipe = wrapRecipe(recipe);\n        return makeStateOperator<RootState, Args>((rootState, ...args) => {\n          const state =\n            selectHistoryState?.(rootState as never) ??\n            (rootState as Draft<GetStateType<Data, StateFn>>);\n\n          const historyEntry = finalRecipe(state, ...args);\n\n          // if paused, don't add to history\n          if (state.paused) return;\n\n          const undoable = isUndoable?.(...args) ?? true;\n          if (undoable) {\n            const lengthWithoutFuture = state.past.length + 1;\n            if (\n              adapterConfig?.limit &&\n              lengthWithoutFuture > adapterConfig.limit\n            ) {\n              state.past.shift();\n            }\n            state.past.push(historyEntry);\n            state.future = [];\n          }\n        });\n      },\n    };\n  };\n}\n\nexport type HistoryState<Data> = BaseHistoryState<Data, Data>;\n\nexport interface HistoryStateFn extends BaseHistoryStateFn {\n  state: HistoryState<this[\"data\"]>;\n}\n\n/**\n * Calls a recipe with the present state and arguments, and applies the result to the state.\n *\n * Correctly handles immer's `nothing` and `undefined` return values.\n */\nexport const applyRecipe = <\n  Data,\n  Args extends Array<any>,\n  State extends MaybeDraft<BaseHistoryState<Data, unknown>>,\n>(\n  state: State,\n  recipe: (draft: Draft<Data>, ...args: Args) => ValidRecipeReturnType<Data>,\n  ...args: Args\n) => {\n  const result = recipe(state.present as Draft<Data>, ...args);\n  if (result === nothing) {\n    state.present = undefined as never;\n  } else if (typeof result !== \"undefined\") {\n    state.present = result as never;\n  }\n};\n\nexport const createHistoryAdapter =\n  /* @__PURE__ */ buildCreateHistoryAdapter<HistoryStateFn>({\n    applyEntry(state, historyEntry) {\n      const stateBefore = state.present;\n      state.present = historyEntry;\n      return stateBefore;\n    },\n    wrapRecipe:\n      (recipe) =>\n      (state, ...args) => {\n        // we need to get the present state before the recipe is applied\n        // and because the recipe might mutate it, we need the non-draft version\n        const before = ensureCurrent(state.present) as DataFromRecipe<\n          typeof recipe\n        >;\n\n        applyRecipe(state, recipe, ...args);\n\n        return before;\n      },\n  });\n\nexport type PatchState = Record<ApplyOp, Array<Patch>>;\n\nexport type PatchHistoryState<Data> = BaseHistoryState<Data, PatchState>;\n\nexport interface PatchHistoryStateFn extends BaseHistoryStateFn {\n  state: PatchHistoryState<this[\"data\"]>;\n}\n\nexport const createPatchHistoryAdapter =\n  /* @__PURE__ */ buildCreateHistoryAdapter<PatchHistoryStateFn>({\n    onCreate() {\n      enablePatches();\n    },\n    applyEntry(state, historyEntry, op) {\n      applyPatches(state, historyEntry[op]);\n      return historyEntry;\n    },\n    wrapRecipe:\n      (recipe) =>\n      (state, ...args) => {\n        const [{ present }, redo, undo] = produceWithPatches(state, (draft) => {\n          applyRecipe(draft as never, recipe, ...args);\n        });\n        state.present = present;\n\n        return { undo, redo };\n      },\n  });\n","import type { Draft } from \"immer\";\nimport { current, isDraft, produce } from \"immer\";\n\nexport type NoInfer<T> = [T][T extends any ? 0 : never];\n\nexport type IfMaybeUndefined<T, True, False> = [undefined] extends [T]\n  ? True\n  : False;\n\nexport type Compute<T> = { [K in keyof T]: T[K] } & unknown;\n\nexport type WithRequiredProp<T, K extends keyof T> = Omit<T, K> &\n  Required<Pick<T, K>>;\n\nexport type Overwrite<T, U> = Compute<Omit<T, keyof U> & U>;\n\nexport type MaybeDraft<T> = T | Draft<T>;\n\nconst isDraftTyped = isDraft as <T>(value: MaybeDraft<T>) => value is Draft<T>;\n\nexport const ensureCurrent = <T>(value: T) =>\n  isDraft(value) ? current(value) : value;\n\nexport function makeStateOperator<State, Args extends Array<any> = []>(\n  mutator: (state: Draft<State>, ...args: Args) => void,\n) {\n  return function operator<S extends State | Draft<State>>(\n    state: S,\n    ...args: Args\n  ): S {\n    if (isDraftTyped(state)) {\n      mutator(state as Draft<State>, ...args);\n      return state;\n    } else {\n      return produce(state, (draft) => {\n        mutator(draft as Draft<State>, ...args);\n      });\n    }\n  };\n}\n"],"mappings":"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","names":["import_immer","createHistoryAdapter"]}