updux/src/buildMiddleware/index.ts

83 lines
2.0 KiB
TypeScript

import u from 'updeep';
import { mapValues, map, get } from 'lodash';
import { Updux } from '../Updux.js';
const middlewareFor = (type, middleware) => (api) => (next) => (action) => {
if (type !== '*' && action.type !== type) return next(action);
return middleware(api)(next)(action);
};
const sliceMw = (slice, mw) => (api) => {
const getSliceState = () => get(api.getState(), slice);
return mw({ ...api, getState: getSliceState });
};
export function augmentMiddlewareApi(api, actions, selectors) {
const getState = () => api.getState();
const dispatch = (action) => api.dispatch(action);
Object.assign(
getState,
mapValues(selectors, (selector) => {
return (...args) => {
let result = selector(api.getState());
if (typeof result === 'function') return result(...args);
return result;
};
})
);
Object.assign(
dispatch,
mapValues(actions, (action) => {
return (...args) => api.dispatch(action(...args));
})
);
return {
...api,
getState,
dispatch,
actions,
selectors,
};
}
export const effectToMiddleware = (effect, actions, selectors) => {
let mw = effect;
let action = '*';
if (Array.isArray(effect)) {
action = effect[0];
mw = effect[1];
mw = middlewareFor(action, mw);
}
return (api) => mw(augmentMiddlewareApi(api, actions, selectors));
};
const composeMw = (mws) => (api) => (original_next) =>
mws.reduceRight((next, mw) => mw(api)(next), original_next);
export function buildMiddleware(
effects = [],
actions = {},
selectors = {},
sub = {}
) {
let inner = map(sub, ({ middleware }, slice) =>
slice !== '*' && middleware ? sliceMw(slice, middleware) : undefined
).filter((x) => x);
const local = effects.map((effect) =>
effectToMiddleware(effect, actions, selectors)
);
const mws = [...local, ...inner];
return composeMw(mws);
}