genji-core
Version:
The core lightweight library for genji, based on redux and redux-saga.
90 lines (81 loc) • 1.94 kB
JavaScript
import invariant from 'invariant';
import { isPlainObject } from './utils';
const hooks = [
'onError',
'onStateChange',
'onHmr',
'onMutation',
'onAction',
'extraMiddlewares',
'extraModels',
'extraEnhancers',
'extraReducers',
];
export function filterHooks(obj) {
return Object.keys(obj).reduce((memo, key) => {
if (hooks.indexOf(key) > -1) {
memo[key] = obj[key];
}
return memo;
}, {});
}
export default class Plugin {
constructor() {
this._handleActions = null;
this.hooks = hooks.reduce((memo, key) => {
memo[key] = [];
return memo;
}, {});
}
use(plugin) {
invariant(
isPlainObject(plugin),
'plugin.use: plugin should be plain object'
);
const hooks = this.hooks;
for (const key in plugin) {
if (Object.prototype.hasOwnProperty.call(plugin, key)) {
invariant(hooks[key], `plugin.use: unknown plugin property: ${key}`);
if (key === 'extraEnhancers') {
hooks[key] = plugin[key];
} else {
hooks[key].push(plugin[key]);
}
}
}
}
apply(key, defaultHandler) {
const hooks = this.hooks;
const validApplyHooks = ['onError', 'onHmr'];
invariant(
validApplyHooks.indexOf(key) > -1,
`plugin.apply: hook ${key} cannot be applied`
);
const fns = hooks[key];
return (...args) => {
if (fns.length) {
for (const fn of fns) {
fn(...args);
}
} else if (defaultHandler) {
defaultHandler(...args);
}
};
}
get(key) {
const hooks = this.hooks;
invariant(key in hooks, `plugin.get: hook ${key} cannot be got`);
if (key === 'extraReducers') {
return getExtraReducers(hooks[key]);
} else {
return hooks[key];
}
}
}
function getExtraReducers(hook) {
let ret = {};
for (const reducerObj of hook) {
ret = { ...ret, ...reducerObj };
}
return ret;
}