ruddy
Version:
Modularized state-management tools for modern front-end applications. Manage dispatched messages in a clean and predictable way for either small or large scale projects
251 lines (177 loc) • 10.9 kB
JavaScript
'use strict';
exports.__esModule = true;
exports.createDuckExtender = exports.createExtendedOptions = exports.extendOptionsForDuck = exports.extendReducer = exports.createOptionsExtender = undefined;
var _uniq = require('ramda/src/uniq');
var _uniq2 = _interopRequireDefault(_uniq);
var _path = require('ramda/src/path');
var _path2 = _interopRequireDefault(_path);
var _ = require('ramda/src/__');
var _2 = _interopRequireDefault(_);
var _when = require('ramda/src/when');
var _when2 = _interopRequireDefault(_when);
var _mapAccum = require('ramda/src/mapAccum');
var _mapAccum2 = _interopRequireDefault(_mapAccum);
var _mergeAll = require('ramda/src/mergeAll');
var _mergeAll2 = _interopRequireDefault(_mergeAll);
var _applyTo = require('ramda/src/applyTo');
var _applyTo2 = _interopRequireDefault(_applyTo);
var _concat = require('ramda/src/concat');
var _concat2 = _interopRequireDefault(_concat);
var _reduce = require('ramda/src/reduce');
var _reduce2 = _interopRequireDefault(_reduce);
var _objOf = require('ramda/src/objOf');
var _objOf2 = _interopRequireDefault(_objOf);
var _mergeDeepRight = require('ramda/src/mergeDeepRight');
var _mergeDeepRight2 = _interopRequireDefault(_mergeDeepRight);
var _of = require('ramda/src/of');
var _of2 = _interopRequireDefault(_of);
var _find = require('ramda/src/find');
var _find2 = _interopRequireDefault(_find);
var _last = require('ramda/src/last');
var _last2 = _interopRequireDefault(_last);
var _has = require('ramda/src/has');
var _has2 = _interopRequireDefault(_has);
var _all = require('ramda/src/all');
var _all2 = _interopRequireDefault(_all);
var _ifElse = require('ramda/src/ifElse');
var _ifElse2 = _interopRequireDefault(_ifElse);
var _T = require('ramda/src/T');
var _T2 = _interopRequireDefault(_T);
var _isNil = require('ramda/src/isNil');
var _isNil2 = _interopRequireDefault(_isNil);
var _identity = require('ramda/src/identity');
var _identity2 = _interopRequireDefault(_identity);
var _mergeDeepWith = require('ramda/src/mergeDeepWith');
var _mergeDeepWith2 = _interopRequireDefault(_mergeDeepWith);
var _converge = require('ramda/src/converge');
var _converge2 = _interopRequireDefault(_converge);
var _always = require('ramda/src/always');
var _always2 = _interopRequireDefault(_always);
var _pair = require('ramda/src/pair');
var _pair2 = _interopRequireDefault(_pair);
var _prop = require('ramda/src/prop');
var _prop2 = _interopRequireDefault(_prop);
var _map = require('ramda/src/map');
var _map2 = _interopRequireDefault(_map);
var _is = require('ramda/src/is');
var _is2 = _interopRequireDefault(_is);
var _any = require('ramda/src/any');
var _any2 = _interopRequireDefault(_any);
var _compose = require('ramda/src/compose');
var _compose2 = _interopRequireDefault(_compose);
var _cond = require('ramda/src/cond');
var _cond2 = _interopRequireDefault(_cond);
var _curry = require('ramda/src/curry');
var _curry2 = _interopRequireDefault(_curry);
var _reducers = require('../reducers');
var _schema = require('./schema');
var _types = require('../types');
var _util = require('../util');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* A function that creates an "extender" function which will merges
* a portion of two duck together at a specified prop
*
* @func
* @sig {k: v} -> {k: v} -> String -> *
* @param {Object} childDuckOptions A set of options from which a duck can be built
* @param {Object} parentDuck A duck that has already been built and whose original constructor options will be re-invoked
* @param {String} key A key name from which to match child options to parent (same prop for both)
* @returns {Function} A function that takes the name of a prop on a duck, and
* will merge the parent and child together for that prop
*/
var createOptionsExtender = exports.createOptionsExtender = (0, _curry2.default)(function (childDuckOptions, _ref, key) {
var parentOptions = _ref.options;
return (0, _cond2.default)([
/* If the key at the child or parent is a function */
[(0, _compose2.default)((0, _any2.default)((0, _is2.default)(Function)), (0, _map2.default)((0, _prop2.default)(key)), (0, _pair2.default)(parentOptions)),
/**
* then they both need to be invoked
* (coerced to fn, if not already)
* and then their results are merged
*/
(0, _always2.default)((0, _converge2.default)((0, _mergeDeepWith2.default)(_util.simpleMergeStrategy), [(0, _util.coerceToFn)(parentOptions[key]), (0, _converge2.default)((0, _util.coerceToFn)(childDuckOptions[key]), [_identity2.default, (0, _util.coerceToFn)(parentOptions[key])])]))],
/* If the child doesn't have anything at that key, just return from the parent */
[(0, _compose2.default)(_isNil2.default, (0, _prop2.default)(key)), (0, _always2.default)(parentOptions[key])],
/* Otherwise, simply merge the parent and child together at that key */
[_T2.default, (0, _compose2.default)((0, _mergeDeepWith2.default)(_util.simpleMergeStrategy, parentOptions[key]), (0, _prop2.default)(key))]])(childDuckOptions);
});
/**
* Merges the reducer from an existing duck with a reducer inside of a set of configuration options (for a new duck).
* If a reducer doesn't exist in both sources, no merging is needed, otherwise the merged reducer
* will always invoke the parent's reducer and feed that result into the child's reducer as its 'state' argument.
* This way a chain of reducers will always be executed.
*
* @func
* @sig {k: v} -> {k: v} -> {k: v}
* @param {Object} duck An existing duck, which contains its original
* configuration options at its 'options' prop.
* @param {Object} options A set of configuration options for a new duck
* @returns {Object} A reducer function which is either a chain of reducers (parent first, then child)
* or one of the reducers (if a reducer wasn't present in both sets of config options)
*/
var extendReducer = exports.extendReducer = function extendReducer(_ref2) {
var parentOptions = _ref2.options;
return (0, _compose2.default)((0, _ifElse2.default)((0, _all2.default)((0, _has2.default)('reducer')), (0, _compose2.default)((0, _reducers.makeExtendedReducer)(parentOptions), _last2.default), (0, _compose2.default)((0, _find2.default)((0, _has2.default)('reducer')), (0, _pair2.default)(parentOptions))), (0, _pair2.default)(parentOptions));
};
/**
* Merges a set of configuration options (for a new duck) with those of an
* existing duck (along with defaults for any unsupplied, but required values).
*
* @func
* @sig {k: v} -> {k: v} -> {k: v}
* @param {Object} duck An existing duck, which contains its original
* configuration options at its 'options' prop.
* @param {Object} options A set of configuration options for a new duck
* @returns {Object} A set of configuration options where schema defaults are
* merged with the existing duck's configuration options and the new
* (to-be-built) duck's configuration options
*/
var extendOptionsForDuck = exports.extendOptionsForDuck = function extendOptionsForDuck(duck) {
return (0, _compose2.default)((0, _converge2.default)(_mergeDeepRight2.default, [_identity2.default, (0, _compose2.default)((0, _objOf2.default)('reducer'), extendReducer(duck))]), (0, _reduce2.default)(_mergeDeepRight2.default, {}), (0, _concat2.default)([_schema.duxDefaults, duck.options]), _of2.default, (0, _applyTo2.default)(duck), _util.coerceToFn);
};
/**
* Applies a set of evolvers, which are just transformations that are run against a given prop inside of an object.
* In this case the config options for a new duck are transformed and then
* those are merged with the same prop(s) inside of the config 'options' of the existing duck.
*
* @func
* @sig [[k: (a -> b)] -> {k: v} -> {k: v} -> {k: v}
* @param {Array} evolvers An array of arrays (which are key/value pairs whose
* key is a prop name on an options object and whose value is a function to
* execute against the corresponding value on the options object)
* @param {Object} duck An existing duck, which contains its original
* configuration options at its 'options' prop.
* @param {Object} options A set of configuration options for a new duck
* @returns {Object} The options from the original duck extended with the
* configuration options for a new (to-be-built) duck, according to the
* transformations defined in the evolvers.
*/
var createExtendedOptions = exports.createExtendedOptions = (0, _curry2.default)(function (evolvers, duck, options) {
return (0, _compose2.default)((0, _mergeDeepRight2.default)(options), _mergeAll2.default, _last2.default, (0, _mapAccum2.default)(function (mergedDuck, _ref3) {
var key = _ref3[0],
builder = _ref3[1];
var option = (0, _compose2.default)((0, _objOf2.default)(key), (0, _when2.default)((0, _is2.default)(Function), (0, _applyTo2.default)(key)), builder)(mergedDuck);
return [(0, _mergeDeepRight2.default)(mergedDuck, option), option];
}, duck))(evolvers);
});
/**
* Takes an already built duck and the options for building a new one and
* extends the new options onto the options and simple props of the already built duck.
* The combined object can be passed as options when creating a new duck.
*
* @func
* @sig {k: v} -> {k: v} -> {k: v}
* @param {Object} duck An existing duck from which a new duck will be based
* @param {Object} options A set of options to be merged with those of an
* existing duck (to be used together whenn creating a new duck)
* @returns {Object} a merged set of options to be fed into a new duck
*/
var createDuckExtender = exports.createDuckExtender = function createDuckExtender(duck) {
var extendOptions = extendOptionsForDuck(duck);
return function (options) {
var childOptions = extendOptions(options);
var optionBuilders = [['consts', (0, _compose2.default)((0, _mergeDeepWith2.default)(_types.concatOrReplace, _2.default, childOptions.consts), (0, _path2.default)(['options', 'consts']))], ['types', (0, _compose2.default)(_uniq2.default, (0, _concat2.default)(childOptions.types), (0, _path2.default)(['options', 'types']))], ['initialState', createOptionsExtender(childOptions)], ['machines', createOptionsExtender(childOptions)], ['creators', createOptionsExtender(childOptions)], ['selectors', createOptionsExtender(childOptions)], ['queries', createOptionsExtender(childOptions)], ['enhancers', createOptionsExtender(childOptions)], ['multipliers', createOptionsExtender(childOptions)], ['throttling', createOptionsExtender(childOptions)], ['debouncing', createOptionsExtender(childOptions)], ['effects', createOptionsExtender(childOptions)], ['validators', createOptionsExtender(childOptions)], ['workers', createOptionsExtender(childOptions)]];
return createExtendedOptions(optionBuilders, duck, childOptions);
};
};