2023-09-06 19:09:45 +00:00
|
|
|
import { Action } from '@reduxjs/toolkit';
|
2023-03-08 16:47:21 +00:00
|
|
|
import * as R from 'remeda';
|
2023-09-06 19:09:45 +00:00
|
|
|
import { DuxConfig } from './types.js';
|
2023-03-08 16:47:21 +00:00
|
|
|
import { Mutation } from './Updux.js';
|
2023-03-22 16:04:07 +00:00
|
|
|
import u from '@yanick/updeep-remeda';
|
2023-03-08 16:47:21 +00:00
|
|
|
|
2023-03-09 15:41:15 +00:00
|
|
|
export type MutationCase = {
|
2023-03-08 16:47:21 +00:00
|
|
|
matcher: (action: Action) => boolean;
|
|
|
|
mutation: Mutation;
|
|
|
|
terminal: boolean;
|
|
|
|
};
|
|
|
|
|
|
|
|
export function buildReducer(
|
2023-09-06 19:09:45 +00:00
|
|
|
initialStateState: unknown,
|
2023-03-08 16:47:21 +00:00
|
|
|
mutations: MutationCase[] = [],
|
2023-03-09 15:59:00 +00:00
|
|
|
defaultMutation?: Omit<MutationCase, 'matcher'>,
|
2023-09-06 19:09:45 +00:00
|
|
|
subduxes: Record<string, DuxConfig> = {},
|
2023-03-08 16:47:21 +00:00
|
|
|
) {
|
2023-03-09 20:13:13 +00:00
|
|
|
const subReducers = R.mapValues(subduxes, R.prop('reducer'));
|
2023-03-08 16:47:21 +00:00
|
|
|
|
|
|
|
// TODO matcherMutation
|
|
|
|
// TODO defaultMutation
|
2023-03-09 15:41:15 +00:00
|
|
|
//
|
2023-03-23 22:15:32 +00:00
|
|
|
const reducer = (state = initialStateState, action: Action) => {
|
2023-09-06 19:09:45 +00:00
|
|
|
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<any, any>('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);
|
2023-03-09 20:13:13 +00:00
|
|
|
}
|
|
|
|
|
2023-09-06 19:09:45 +00:00
|
|
|
// 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,
|
|
|
|
);
|
2023-03-08 16:47:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
return reducer;
|
|
|
|
}
|