import { Action } from '@reduxjs/toolkit'; import * as R from 'remeda'; import { DuxConfig } from './types.js'; import { Mutation } from './Updux.js'; import u from '@yanick/updeep-remeda'; export type MutationCase = { matcher: (action: Action) => boolean; mutation: Mutation; terminal: boolean; }; export function buildReducer( initialStateState: unknown, mutations: MutationCase[] = [], defaultMutation?: Omit, subduxes: Record = {}, ) { const subReducers = R.mapValues(subduxes, R.prop('reducer')); // TODO matcherMutation // TODO defaultMutation // const reducer = (state = initialStateState, action: Action) => { if (!action?.type) throw new Error('reducer called with a bad action'); let active = mutations.filter(({ matcher }) => matcher(action)); if (active.length === 0 && defaultMutation) active.push(defaultMutation as any); if ( !active.some(R.prop('terminal')) && Object.values(subReducers).length > 0 ) { active.push({ mutation: (payload, action) => (state) => { return u( state, R.mapValues( subReducers, (reducer, slice) => (state) => { return (reducer as any)(state, action); }, ), ); }, } as any); } // frozen objects don't play well with immer // if (Object.isFrozen(state)) { // state = { ...(state as any) }; // } return active.reduce( (state, { mutation }) => mutation((action as any).payload, action)(state), state, ); }; return reducer; }