| 1 | import { createNextState, isDraft } from '../immerImports'
|
|---|
| 2 | import type { Draft } from 'immer'
|
|---|
| 3 | import type { EntityId, DraftableEntityState, PreventAny } from './models'
|
|---|
| 4 | import type { PayloadAction } from '../createAction'
|
|---|
| 5 | import { isFSA } from '../createAction'
|
|---|
| 6 |
|
|---|
| 7 | export const isDraftTyped = isDraft as <T>(
|
|---|
| 8 | value: T | Draft<T>,
|
|---|
| 9 | ) => value is Draft<T>
|
|---|
| 10 |
|
|---|
| 11 | export function createSingleArgumentStateOperator<T, Id extends EntityId>(
|
|---|
| 12 | mutator: (state: DraftableEntityState<T, Id>) => void,
|
|---|
| 13 | ) {
|
|---|
| 14 | const operator = createStateOperator(
|
|---|
| 15 | (_: undefined, state: DraftableEntityState<T, Id>) => mutator(state),
|
|---|
| 16 | )
|
|---|
| 17 |
|
|---|
| 18 | return function operation<S extends DraftableEntityState<T, Id>>(
|
|---|
| 19 | state: PreventAny<S, T, Id>,
|
|---|
| 20 | ): S {
|
|---|
| 21 | return operator(state as S, undefined)
|
|---|
| 22 | }
|
|---|
| 23 | }
|
|---|
| 24 |
|
|---|
| 25 | export function createStateOperator<T, Id extends EntityId, R>(
|
|---|
| 26 | mutator: (arg: R, state: DraftableEntityState<T, Id>) => void,
|
|---|
| 27 | ) {
|
|---|
| 28 | return function operation<S extends DraftableEntityState<T, Id>>(
|
|---|
| 29 | state: S,
|
|---|
| 30 | arg: R | PayloadAction<R>,
|
|---|
| 31 | ): S {
|
|---|
| 32 | function isPayloadActionArgument(
|
|---|
| 33 | arg: R | PayloadAction<R>,
|
|---|
| 34 | ): arg is PayloadAction<R> {
|
|---|
| 35 | return isFSA(arg)
|
|---|
| 36 | }
|
|---|
| 37 |
|
|---|
| 38 | const runMutator = (draft: DraftableEntityState<T, Id>) => {
|
|---|
| 39 | if (isPayloadActionArgument(arg)) {
|
|---|
| 40 | mutator(arg.payload, draft)
|
|---|
| 41 | } else {
|
|---|
| 42 | mutator(arg, draft)
|
|---|
| 43 | }
|
|---|
| 44 | }
|
|---|
| 45 |
|
|---|
| 46 | if (isDraftTyped<DraftableEntityState<T, Id>>(state)) {
|
|---|
| 47 | // we must already be inside a `createNextState` call, likely because
|
|---|
| 48 | // this is being wrapped in `createReducer` or `createSlice`.
|
|---|
| 49 | // It's safe to just pass the draft to the mutator.
|
|---|
| 50 | runMutator(state)
|
|---|
| 51 |
|
|---|
| 52 | // since it's a draft, we'll just return it
|
|---|
| 53 | return state
|
|---|
| 54 | }
|
|---|
| 55 |
|
|---|
| 56 | return createNextState(state, runMutator)
|
|---|
| 57 | }
|
|---|
| 58 | }
|
|---|