skypager-project
Version:
skypager project framework
119 lines (94 loc) • 3.1 kB
JavaScript
import stringify from "./stringify";
import { pluralize } from 'skypager-util/lib/string'
import mapKeys from 'lodash/mapKeys'
import mapValues from 'lodash/mapValues'
import reduce from 'lodash/reduce'
import isUndefined from 'lodash/isUndefined'
const featuresReq = require.context('./features', false, /\.js$/)
const reducersReq = require.context('./reducers', false, /\.js$/)
const es6 = (mod) => mod.default ? mod.default : mod
export const defaultFeatures = featuresReq
.keys()
.reduce((memo, key) => ({
...memo,
[key.replace(/\.\//,'').replace(/\.js$/,'')]: es6(featuresReq(key)),
}), {})
export const defaultReducers = reducersReq
.keys()
.reduce((memo, key) => ({
...memo,
[key.replace(/\.\//,'').replace(/\.js$/,'')]: es6(reducersReq(key)),
}), {})
export function api(options = {}) {
let { history = [], scope = this, features = {}, reducers = {}, keyFn = pluralize } = options
features = mapValues({ ...defaultFeatures, ...features }, (fn) => fn.bind ? fn.bind(scope) : fn);
reducers = mapValues({ ...defaultReducers, ...reducers }, (fn) => fn.bind ? fn.bind(scope) : fn);
const getState = () => {
const initialState = reduce(features, (acc, feature, name) => {
const defaultValue = feature();
if (isUndefined(defaultValue)) {
return acc;
}
return {
...acc,
[name]: defaultValue,
};
}, {});
const state = history.reduce((acc, { name, args }) => {
const featureState = acc[name];
const feature = features[name];
return {
...acc,
[name]: feature(featureState, ...args),
};
}, initialState);
Object.defineProperty(state, "toString", {
value: () => stringify(state),
});
return state;
};
const getConfig = (tap = options.tap) => {
const state = getState();
let config = reduce(reducers, (config, reducer, name) => {
const reduced = reducer(state);
if (isUndefined(reduced)) {
return config;
}
return {
...config,
[name]: reducer(state),
};
}, {});
if (typeof tap === 'function') {
config = tap.call(scope, config, options)
}
Object.defineProperty(config, "toString", {
value: () => stringify(config),
});
return config;
};
const when = (env, configure) => {
const envs = Array.isArray(env) ? env : [env];
const { NODE_ENV = "development" } = process.env;
if (env === true || envs.indexOf(NODE_ENV) !== -1) {
return configure(api({features,reducers,history}));
} else if (typeof env === 'function' && env(getState(), getConfig)) {
return configure({features, reducers, history})
}
return api({features, reducers, history});
};
return reduce(features, (acc, feature, name) => ({
...acc,
[name]: (...args) => api({
features,
reducers,
history: history.concat({ args, name }),
}),
}), {
getConfig: (...args) => mapKeys(getConfig(...args),(v,k) => keyFn(k)),
getState,
history,
when,
});
}
export default api