updux/src/middleware.js

86 lines
2.1 KiB
JavaScript

import R from 'remeda';
const composeMw = (mws) => (api) => (original_next) =>
mws.reduceRight((next, mw) => mw(api)(next), original_next);
export function augmentMiddlewareApi(api, actions, selectors) {
const getState = () => api.getState();
const dispatch = (action) => api.dispatch(action);
Object.assign(
getState,
R.mapValues(selectors, (selector) => {
return (...args) => {
let result = selector(api.getState());
if (typeof result === 'function') return result(...args);
return result;
};
}),
);
Object.assign(
dispatch,
R.mapValues(actions, (action) => {
return (...args) => api.dispatch(action(...args));
}),
);
return {
...api,
getState,
dispatch,
actions,
selectors,
};
}
const sliceMw = (slice, mw) => (api) => {
const getSliceState = () => api.getState()[slice];
return mw({ ...api, getState: getSliceState });
};
const middlewareFor = (type, middleware) => (api) => (next) => (action) => {
if (type !== '*' && action.type !== type) return next(action);
return middleware(api)(next)(action);
};
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));
};
export function buildMiddleware(
effects = [],
actions = {},
selectors = {},
subduxes = {},
wrapper = undefined,
) {
let inner = R.compact(
Object.entries(subduxes).map(([slice, { middleware }]) =>
((slice !== '*' && middleware) ? sliceMw(slice, middleware) : null),
),
);
const local = effects.map((effect) =>
effectToMiddleware(effect, actions, selectors),
);
let mws = [...local, ...inner];
if( wrapper ) mws = wrapper(mws);
return composeMw(mws);
}