updux/src/index.js

167 lines
4.2 KiB
JavaScript
Raw Normal View History

2019-10-17 15:15:10 +00:00
import fp from 'lodash/fp';
import u from 'updeep';
import { createStore, applyMiddleware } from 'redux';
function actionFor(type) {
return (payload = null, meta = null) => {
return fp.pickBy(v => v !== null)({type, payload, meta});
};
}
2019-10-19 17:11:30 +00:00
function buildInitial({initial = {}, subduxes = {}}) {
2019-10-17 15:15:10 +00:00
let state = initial;
if (fp.isPlainObject(initial)) {
initial = fp.mergeAll([
2019-10-19 17:11:30 +00:00
fp.mapValues(fp.getOr({}, 'initial'), subduxes),
2019-10-17 15:15:10 +00:00
initial,
]);
}
return initial;
}
2019-10-19 17:11:30 +00:00
function buildActions({mutations = {}, subduxes = {}}) {
let actions = fp.mergeAll(fp.map(fp.getOr({}, 'actions'), subduxes)) || {};
2019-10-17 15:15:10 +00:00
Object.keys(mutations).forEach(type => {
if (!actions[type]) {
actions[type] = actionFor(type);
}
});
return actions;
}
2019-10-19 17:11:30 +00:00
const composeMutations = (m1,m2) =>
(payload=null,action={}) => state => m2(payload,action)(
m1(payload,action)(state) );
2019-10-17 15:15:10 +00:00
2019-10-19 17:11:30 +00:00
function buildMutations({mutations = {}, subduxes = {}}) {
// we have to differentiate the subduxes with '*' than those
// without, as the root '*' is not the same as any sub-'*'
2019-10-17 15:15:10 +00:00
2019-10-19 17:11:30 +00:00
const actions = fp.uniq( Object.keys(mutations).concat(
...Object.values( subduxes ).map( ({mutations}) => Object.keys(mutations) )
) );
2019-10-17 15:15:10 +00:00
2019-10-19 17:11:30 +00:00
// let's seed with noops
let mergedMutations = {};
actions.forEach( action => {
mergedMutations[action] = () => state => state;
});
console.log(mergedMutations);
Object.entries( subduxes ).forEach( ([slice, {mutations,reducer}]) => {
if( mutations['*'] ) {
const localized = (payload=null,action={}) => u.updateIn( slice, mutations['*'](payload,action) );
console.log("b");
mergedMutations = fp.mapValues(
mutation => composeMutations(
(dummy,action) => u.updateIn(slice,
state => reducer(state,action)
), mutation )
)(mergedMutations);
return;
}
Object.entries(mutations).forEach(([type,mutation]) => {
const localized = (payload=null,action={}) => u.updateIn( slice, mutation(payload,action) );
if( type !== '*' ) {
console.log("a");
mergedMutations[type] = composeMutations(
localized, mergedMutations[type]
)
}
else {
}
})
});
console.log(mergedMutations);
Object.entries(mutations).forEach(([type,mutation]) => {
console.log(type,":",mutation,":",mergedMutations[type]);
mergedMutations[type] = composeMutations(
mergedMutations[type], mutation
)
});
return mergedMutations;
2019-10-17 15:15:10 +00:00
}
2019-10-19 17:11:30 +00:00
function buildMiddleware({effects={},subduxes={}},{actions}) {
2019-10-17 15:15:10 +00:00
return api => {
for ( let type in actions ) {
api.dispatch[type] = (...args) => api.dispatch( actions[type](...args) );
}
return original_next => {
return [
...fp.toPairs(effects).map(([type,effect])=> {
return api => next => action => {
if( action.type !== type ) return next(action);
return effect(api)(next)(action);
};
}),
2019-10-19 17:11:30 +00:00
...fp.map( 'middleware', subduxes )
2019-10-17 15:15:10 +00:00
].filter(x=>x).reduceRight( (next,mw) => mw(api)(next), original_next )
}}
}
function updux(config) {
const dux = {};
dux.actions = buildActions(config);
dux.initial = buildInitial(config);
dux.mutations = buildMutations(config);
2019-10-19 17:11:30 +00:00
dux.upreducer = (action={}) => state => {
2019-10-17 15:15:10 +00:00
if (state === null) state = dux.initial;
const a =
dux.mutations[action.type] ||
dux.mutations['*'] ||
(() => state => state);
return a(action.payload, action)(state);
};
dux.reducer = (state, action) => {
return dux.upreducer(action)(state);
};
dux.middleware = buildMiddleware(config,dux);
dux.createStore = () => {
const store = createStore( dux.reducer, dux.initial,
applyMiddleware( dux.middleware)
);
for ( let a in dux.actions ) {
store.dispatch[a] = (...args) => {
store.dispatch(dux.actions[a](...args))
};
}
return store;
}
return dux;
}
export default updux;