import { combineEpics, Epic, ofType, StateObservable } from "redux-observable"; import { EMPTY, Observable } from "rxjs"; import { filter, map, mergeMap, withLatestFrom } from "rxjs/operators"; import { EpicFuncDefinition, Myth, MythDefinition, MythicAction, Myths, RootState } from "./types"; const makeEpic = < PKG extends string, NAME extends string, STATE, PROPS, >( pkg: PKG, myth: Myth, dispatch: EpicFuncDefinition, filterBy: (source: Observable) => Observable ) => ( action$: Observable, state$: StateObservable>, ) => action$.pipe( filterBy, withLatestFrom(state$.pipe(map(state => state.__private__[pkg]))), mergeMap(([action, state]) => dispatch(action, state, myth) ?? EMPTY), ); export const makeEpics = < PKG extends string, NAME extends string, STATE, PROPS, >( pkg: PKG, myth: Myth, definition: MythDefinition, ) => { const epics: Epic[] = []; for (const { when, dispatch } of definition.andAlso ?? []) { epics.push(makeEpic(pkg, myth, dispatch, filter(when))); } for (const dispatch of definition.thenDispatch ?? []) { epics.push(makeEpic(pkg, myth, dispatch, ofType(myth.type))); } return epics; }; export const makeMakeRootEpic = ( myths: Myths, ) => () => combineEpics( ...Object.values(myths).map(myth => combineEpics(...myth.epics)) );