import * as R from 'remeda'; import u from '@yanick/updeep-remeda'; import * as rtk from '@reduxjs/toolkit'; import { DuxConfig, Mutation } from './types.js'; import { D } from '@mobily/ts-belt'; import Updux from './Updux.js'; import { AnyAction } from '@reduxjs/toolkit'; export type MutationCase = { matcher: (action: rtk.AnyAction) => boolean; mutation: Mutation; terminal: boolean; }; export function buildReducer( initialStateState: unknown, mutations: MutationCase[] = [], defaultMutation?: Omit, subduxes: Record> = {}, inheritedReducer?: (state: any, action: AnyAction) => any, ) { const subReducers = D.map(subduxes, D.getUnsafe('reducer')); const reducer = (state = initialStateState, action: rtk.AnyAction) => { 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')) && inheritedReducer) { active.push({ mutation: (_payload, action) => (state) => { return u(state, inheritedReducer(state, action)); }, } as any); } if ( !active.some(R.prop('terminal')) && D.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); } return active.reduce( (state, { mutation }) => mutation((action as any).payload, action)(state), state, ); }; return reducer; }