Created
May 25, 2018 03:15
-
-
Save bradennapier/f6b9bc41622d1a5ad27729497f924b32 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// TODO: Remove lodash as dependency | |
import _ from 'lodash'; | |
import toSnakeCase from 'to-redux-type'; | |
import { MODULE_NAME, SAGA_LIFECYCLES } from './context'; | |
function handleBoundAction(dispatch, pid, type, args, action, ...fnargs) { | |
const createdAction = { type, ...action }; | |
fnargs.forEach((arg, idx) => { | |
if (idx < args.length) { | |
createdAction[args[idx]] = arg; | |
} else if (typeof arg === 'object' && !Array.isArray(arg)) { | |
Object.assign(createdAction, arg); | |
} else { | |
throw new Error(`[${MODULE_NAME}] | ERROR | called action ${pid}.${type} with too many arguments - argument ${idx} and onward are invalid.`); | |
} | |
}); | |
return dispatch(createdAction); | |
} | |
function handleBuildState(priv, module, state) { | |
if (!state) { | |
console.warn(`[${MODULE_NAME}] | WARN | handleBuildState received empty state`); | |
return; | |
} | |
_.mergeWith(priv.state, state, (objValue, srcValue, key) => { | |
if (typeof srcValue !== 'object' && objValue !== undefined) { | |
// TODO : Output proper error formatting | |
console.error(objValue, srcValue, key); | |
throw new Error('ALREADY DEFINED'); | |
} | |
}); | |
} | |
export default function handleNewStateModule(priv, _module) { | |
let module = _module; | |
if (typeof _module === 'function') { | |
// TODO : Need to pass this function a configuration for the module. | |
module = _module(); | |
} | |
if (typeof module !== 'object') { | |
return; | |
} else if (typeof module.config !== 'object' || !module.config.pid) { | |
throw new Error(`[${MODULE_NAME}] | ERROR | Module didn't have a config or module.config.pid was not defined`); | |
} | |
const { pid } = module.config; | |
if (priv.modules.has(pid)) { | |
/* Only allow each pid to be registered once - using symbols for modules may be best? */ | |
throw new Error(`[${MODULE_NAME}] | ERROR | Module ${pid} has already been defined and may not be defined again`); | |
} | |
module.config.prefix = module.config.prefix ? `${toSnakeCase(module.config.prefix)}_` : ''; | |
priv.modules.set(pid, module); | |
const moduleDescriptor = { | |
pid, | |
}; | |
if (module.state) { | |
/* Module handles part of our state */ | |
module.reduces = Object.keys(module.state); | |
handleBuildState(priv, module, module.state); | |
} | |
if (module.reducers) { | |
const reducers = { ...module.reducers }; | |
// * Each key in schema indicates a piece of state we need to reduce. | |
Object.keys(reducers).forEach(_type => { | |
const type = `${module.config.prefix}${toSnakeCase(_type)}`; | |
const map = priv.reducers.get(type) || new Map(); | |
map.set(reducers[_type], moduleDescriptor); | |
priv.reducers.set(type, map); | |
}); | |
} | |
if (module.routes) { | |
const routes = { ...module.routes }; | |
/* Routes define all the sagas to execute when a given type executes */ | |
Object.keys(routes).forEach(_type => { | |
const type = `${module.config.prefix}${toSnakeCase(_type)}`; | |
const map = priv.routes.get(type) || new Map(); | |
const saga = module.sagas[routes[_type]]; | |
if (typeof saga !== 'function') { | |
console.warn(`[${MODULE_NAME}] | WARN | Route for ${module.config.pid} not found in sagas: ${_type}`); | |
return; | |
} | |
map.set(saga, moduleDescriptor); | |
priv.routes.set(type, map); | |
}); | |
} | |
if (module.sagas) { | |
/* If sagas are defined, check for lifecycle sagas */ | |
SAGA_LIFECYCLES.forEach(lifecycle => { | |
if (typeof module.sagas[lifecycle] === 'function') { | |
// TODO: Handle Lifecycles | |
} | |
}); | |
} | |
if (module.actions) { | |
const actions = { ...module.actions }; | |
if (!priv.actions[pid]) { | |
priv.actions[pid] = {}; | |
} | |
Object.keys(actions).forEach(_type => { | |
const type = `${module.config.prefix}${toSnakeCase(_type)}`; | |
const args = actions[_type] || []; | |
const action = typeof args[0] === 'object' ? { ...args[0] } : {}; | |
priv.actions[pid][_type] = (...fnargs) => | |
handleBoundAction(priv.context.dispatch, pid, type, args, action, ...fnargs); | |
}); | |
} | |
if (module.selectors) { | |
Object.assign(priv.selectors, module.selectors); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment