updux/src/reducer.ts

92 lines
2.6 KiB
TypeScript
Raw Normal View History

2023-03-08 16:47:21 +00:00
import { Action, ActionCreator, createAction } from '@reduxjs/toolkit';
import { BaseActionCreator } from '@reduxjs/toolkit/dist/createAction.js';
import * as R from 'remeda';
import { Dux } from './types.js';
import { Mutation } from './Updux.js';
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(
initialState: any,
mutations: MutationCase[] = [],
2023-03-09 15:59:00 +00:00
defaultMutation?: Omit<MutationCase, 'matcher'>,
2023-03-08 16:47:21 +00:00
subduxes: Record<string, Dux> = {},
) {
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-08 16:47:21 +00:00
const reducer = (state = initialState, action: Action) => {
if (!action?.type)
throw new Error('upreducer called with a bad action');
let terminal = false;
let didSomething = false;
2023-03-09 15:41:15 +00:00
mutations
.filter(({ matcher }) => matcher(action))
.forEach(({ mutation, terminal: t }) => {
if (t) terminal = true;
2023-03-09 15:59:00 +00:00
didSomething = true;
2023-03-09 15:41:15 +00:00
//
// TODO wrap mutations in immer
state = mutation((action as any).payload, action)(state);
});
2023-03-08 16:47:21 +00:00
2023-03-09 15:59:00 +00:00
if (!didSomething && defaultMutation) {
if (defaultMutation.terminal) terminal = true;
state = defaultMutation.mutation(
(action as any).payload,
action,
)(state);
}
2023-03-08 16:47:21 +00:00
2023-03-09 20:13:13 +00:00
if (!terminal && Object.keys(subduxes).length > 0) {
// subduxes
state = R.merge(
state,
R.mapValues(subReducers, (reducer, slice) =>
(reducer as any)(state[slice], action),
),
);
}
2023-03-08 16:47:21 +00:00
return state;
};
return reducer;
/*
if (subReducers) {
if (subduxes['*']) {
newState = u.updateIn(
'*',
subduxes['*'].upreducer(action),
newState,
);
} else {
const update = mapValues(subReducers, (upReducer) =>
upReducer(action),
);
newState = u(update, newState);
}
}
const a = mutations[action.type] || mutations['+'];
if (!a) return newState;
return a(action.payload, action)(newState);
};
return wrapper ? wrapper(upreducer) : upreducer;
*/
}