updux/src/reducer.ts

67 lines
2.1 KiB
TypeScript
Raw Normal View History

2023-03-08 16:47:21 +00:00
import * as R from 'remeda';
2023-03-22 16:04:07 +00:00
import u from '@yanick/updeep-remeda';
2024-08-09 14:27:41 +00:00
import * as rtk from '@reduxjs/toolkit';
2024-08-08 13:28:44 +00:00
import { DuxConfig, Mutation } from './types.js';
import { D } from '@mobily/ts-belt';
import Updux from './Updux.js';
2024-08-10 13:07:23 +00:00
import { AnyAction } from '@reduxjs/toolkit';
2023-03-08 16:47:21 +00:00
2023-03-09 15:41:15 +00:00
export type MutationCase = {
2024-08-09 14:27:41 +00:00
matcher: (action: rtk.AnyAction) => boolean;
2023-03-08 16:47:21 +00:00
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'>,
2024-08-08 13:28:44 +00:00
subduxes: Record<string, Updux<any>> = {},
2024-08-10 13:07:23 +00:00
inheritedReducer?: (state: any, action: AnyAction) => any,
2023-03-08 16:47:21 +00:00
) {
2024-08-08 13:28:44 +00:00
const subReducers = D.map(subduxes, D.getUnsafe('reducer'));
2023-03-08 16:47:21 +00:00
2024-08-09 14:27:41 +00:00
const reducer = (state = initialStateState, action: rtk.AnyAction) => {
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);
2024-08-10 13:07:23 +00:00
if (!active.some(R.prop<any, any>('terminal')) && inheritedReducer) {
active.push({
mutation: (_payload, action) => (state) => {
return u(state, inheritedReducer(state, action));
},
} as any);
}
2023-09-06 19:09:45 +00:00
if (
!active.some(R.prop<any, any>('terminal')) &&
2024-08-08 13:28:44 +00:00
D.values(subReducers).length > 0
2023-09-06 19:09:45 +00:00
) {
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
return active.reduce(
(state, { mutation }) =>
mutation((action as any).payload, action)(state),
state,
);
2023-03-08 16:47:21 +00:00
};
return reducer;
}