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); }