UNPKG

attadux

Version:

Implementation of the redux-modular-ducks, forked from the extensible-duck implementation and extended to include spected validators, state machines, helpers, web workers, effect handling, action multipliers, action enhancers, action throttling/debouncing

427 lines (309 loc) 24 kB
'use strict'; exports.__esModule = true; exports.createValidationMiddlewareHelpers = exports.createDuckReducer = exports.createDuckActionCreators = exports.createDuckActionMultipliers = exports.makeMultipliers = exports.createDuckActionEnhancers = exports.makeEnhancers = exports.createDuckSelectors = exports.createDuckInitialState = exports.createDuckMachines = exports.createDuckWorkers = exports.createDuckQueries = exports.createDuckDebouncers = exports.createDuckThrottlers = exports.createDuckEffects = exports.createDuckValidators = exports.createDuckMetadata = exports.createDuckLookup = exports.createRow = undefined; var _applySpec = require('ramda/src/applySpec'); var _applySpec2 = _interopRequireDefault(_applySpec); var _juxt = require('ramda/src/juxt'); var _juxt2 = _interopRequireDefault(_juxt); var _assocPath = require('ramda/src/assocPath'); var _assocPath2 = _interopRequireDefault(_assocPath); var _applyTo = require('ramda/src/applyTo'); var _applyTo2 = _interopRequireDefault(_applyTo); var _isEmpty = require('ramda/src/isEmpty'); var _isEmpty2 = _interopRequireDefault(_isEmpty); var _propSatisfies = require('ramda/src/propSatisfies'); var _propSatisfies2 = _interopRequireDefault(_propSatisfies); var _not = require('ramda/src/not'); var _not2 = _interopRequireDefault(_not); var _anyPass = require('ramda/src/anyPass'); var _anyPass2 = _interopRequireDefault(_anyPass); var _allPass = require('ramda/src/allPass'); var _allPass2 = _interopRequireDefault(_allPass); var _call = require('ramda/src/call'); var _call2 = _interopRequireDefault(_call); var _isNil = require('ramda/src/isNil'); var _isNil2 = _interopRequireDefault(_isNil); var _pathSatisfies = require('ramda/src/pathSatisfies'); var _pathSatisfies2 = _interopRequireDefault(_pathSatisfies); var _ifElse = require('ramda/src/ifElse'); var _ifElse2 = _interopRequireDefault(_ifElse); var _map = require('ramda/src/map'); var _map2 = _interopRequireDefault(_map); var _propEq = require('ramda/src/propEq'); var _propEq2 = _interopRequireDefault(_propEq); var _keys = require('ramda/src/keys'); var _keys2 = _interopRequireDefault(_keys); var _pick = require('ramda/src/pick'); var _pick2 = _interopRequireDefault(_pick); var _evolve = require('ramda/src/evolve'); var _evolve2 = _interopRequireDefault(_evolve); var _mergeDeepRight = require('ramda/src/mergeDeepRight'); var _mergeDeepRight2 = _interopRequireDefault(_mergeDeepRight); var _converge = require('ramda/src/converge'); var _converge2 = _interopRequireDefault(_converge); var _objOf = require('ramda/src/objOf'); var _objOf2 = _interopRequireDefault(_objOf); var _ap = require('ramda/src/ap'); var _ap2 = _interopRequireDefault(_ap); var _of = require('ramda/src/of'); var _of2 = _interopRequireDefault(_of); var _mergeAll = require('ramda/src/mergeAll'); var _mergeAll2 = _interopRequireDefault(_mergeAll); var _path = require('ramda/src/path'); var _path2 = _interopRequireDefault(_path); var _split = require('ramda/src/split'); var _split2 = _interopRequireDefault(_split); var _nth = require('ramda/src/nth'); var _nth2 = _interopRequireDefault(_nth); var _head = require('ramda/src/head'); var _head2 = _interopRequireDefault(_head); var _either = require('ramda/src/either'); var _either2 = _interopRequireDefault(_either); var _is = require('ramda/src/is'); var _is2 = _interopRequireDefault(_is); var _ = require('ramda/src/__'); var _2 = _interopRequireDefault(_); var _prop = require('ramda/src/prop'); var _prop2 = _interopRequireDefault(_prop); var _when = require('ramda/src/when'); var _when2 = _interopRequireDefault(_when); var _always = require('ramda/src/always'); var _always2 = _interopRequireDefault(_always); var _unless = require('ramda/src/unless'); var _unless2 = _interopRequireDefault(_unless); var _curry = require('ramda/src/curry'); var _curry2 = _interopRequireDefault(_curry); var _identity = require('ramda/src/identity'); var _identity2 = _interopRequireDefault(_identity); var _unapply = require('ramda/src/unapply'); var _unapply2 = _interopRequireDefault(_unapply); var _filter = require('ramda/src/filter'); var _filter2 = _interopRequireDefault(_filter); var _assoc = require('ramda/src/assoc'); var _assoc2 = _interopRequireDefault(_assoc); var _reduce = require('ramda/src/reduce'); var _reduce2 = _interopRequireDefault(_reduce); var _compose = require('ramda/src/compose'); var _compose2 = _interopRequireDefault(_compose); var _spected = require('spected'); var _spected2 = _interopRequireDefault(_spected); var _shapey = require('shapey'); var _machines = require('../machines'); var _reducers = require('../reducers'); var _selectors = require('../selectors'); var _workers = require('../workers'); var _queries = require('../queries'); var _schema = require('./schema'); var _types = require('../types'); var _util = require('../util'); var _validate = require('./validate'); var _effects = require('../effects'); var _validators = require('../validators'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } /** * Merges multiple ducks into one flattened Object (row). * * @func * @sig ({k: v}...) -> {k: v} * @param {...Object} ducks One or more ducks to merge into one row * @returns {Object} A single object composed of many ducks */ var createRow = exports.createRow = (0, _compose2['default'])((0, _reduce2['default'])(function (row, duck) { return (0, _assoc2['default'])(duck.store, duck, row); }, {}), (0, _filter2['default'])(_schema.isDux), (0, _unapply2['default'])(_identity2['default'])); /** * A function which takes an Object of one or more ducks and finds the duck * which matches a (potentially) namespaced Redux action * * @func * @sig {k: v} -> {k: v} -> {k: v} * @param {Object} row An Object containing one or more ducks * @param {Object} action An dispatch Redux action (if belonging to this lib, * should have a namespaced action type) * @returns {Object} A single duck that corresponds to the dispatched action * (defaults to an empty object if none found) */ var createDuckLookup = exports.createDuckLookup = (0, _curry2['default'])(function (row, action) { return (0, _compose2['default'])((0, _unless2['default'])(_util.isPlainObj, (0, _always2['default'])({})), (0, _when2['default'])(_util.isStringieThingie, (0, _prop2['default'])(_2['default'], (0, _filter2['default'])(_schema.isDux, row))), (0, _when2['default'])((0, _is2['default'])(String), (0, _compose2['default'])((0, _either2['default'])((0, _nth2['default'])(1), _head2['default']), (0, _split2['default'])('/'))), (0, _path2['default'])(['type']))(action); }); /** * Validates and applies the configuration options for a new Duck, also * performing final formatting for many of the duck's simpler props * (consts, types, validationLevel, namespace, store, etc.). * * @func * @sig {k: v} -> {k: v} * @param {Object} options All the configuration options to be passed into the duck constructor * @returns {Object} An object containing all the validated configuration options for the new Duck */ var createDuckMetadata = exports.createDuckMetadata = (0, _compose2['default'])(_mergeAll2['default'], (0, _ap2['default'])([(0, _compose2['default'])((0, _objOf2['default'])('stateMachinesPropName'), (0, _always2['default'])(['states'])), (0, _compose2['default'])((0, _converge2['default'])(_mergeDeepRight2['default'], [(0, _compose2['default'])((0, _evolve2['default'])(_schema.metadataEvolvers), (0, _pick2['default'])((0, _keys2['default'])(_schema.metadataEvolvers)), _queries.copyRawQueriesToConsts), (0, _compose2['default'])((0, _objOf2['default'])('types'), (0, _converge2['default'])(_types.createTypes, [_identity2['default'], (0, _prop2['default'])('types')]))]), (0, _prop2['default'])('validatedOptions')), (0, _compose2['default'])((0, _when2['default'])(_util.isNotEmpty, (0, _objOf2['default'])('invalidOptions')), _validators.pruneValidatedFields, (0, _prop2['default'])('validationsResult')), (0, _compose2['default'])((0, _objOf2['default'])('options'), (0, _prop2['default'])('validatedOptions'))]), _of2['default'], _validate.createDuckSchemaValidator); /** * Creates the Duck's validators (if they are present inside of its 'options' prop). * * @func * @sig {k: v} -> {k: v} * @param {Object} duck A duck which (may) contain validators (inside of its 'options') * @returns {Object} A clone of the duck, but now with validators (if they were found inside of 'options'). */ var createDuckValidators = exports.createDuckValidators = (0, _compose2['default'])((0, _unless2['default'])((0, _propEq2['default'])('validationLevel', 'PRUNE'), (0, _evolve2['default'])({ validators: (0, _map2['default'])(function (validator) { return (0, _compose2['default'])(_validators.pruneValidatedFields, validator); }) })), (0, _converge2['default'])(_mergeDeepRight2['default'], [_identity2['default'], (0, _ifElse2['default'])((0, _pathSatisfies2['default'])(_isNil2['default'], ['options', 'validators']), (0, _always2['default'])({}), (0, _compose2['default'])((0, _objOf2['default'])('validators'), (0, _map2['default'])(_spected2['default']), (0, _converge2['default'])(_call2['default'], [(0, _compose2['default'])(_util.coerceToFn, (0, _path2['default'])(['options', 'validators'])), _identity2['default']])))])); /** * Creates the Duck's effect handlers (if they are present inside of its 'options' prop). * * @func * @sig {k: v} -> {k: v} * @param {Object} duck A duck which (may) contain effect handlers (inside of its 'options') * @returns {Object} A clone of the duck, but now with effect handlers (if they were found inside of 'options'). */ var createDuckEffects = exports.createDuckEffects = (0, _converge2['default'])(_mergeDeepRight2['default'], [_identity2['default'], (0, _ifElse2['default'])((0, _pathSatisfies2['default'])(_isNil2['default'], ['options', 'effects']), (0, _always2['default'])([]), (0, _compose2['default'])((0, _objOf2['default'])('effects'), (0, _map2['default'])(function (_ref) { var pattern = _ref[0]; var effectHandler = _ref[1]; var successHandler = _ref[2]; var errorHandler = _ref[3]; return (0, _effects.createEffectHandler)(pattern, effectHandler || _identity2['default'], (0, _effects.makeResponseHandler)(_effects.defaultSuccessHandler, successHandler), (0, _effects.makeResponseHandler)(_effects.defaultErrorHandler, errorHandler)); }), (0, _filter2['default'])((0, _allPass2['default'])([(0, _is2['default'])(Array), (0, _pathSatisfies2['default'])((0, _anyPass2['default'])([(0, _is2['default'])(String), (0, _is2['default'])(RegExp), (0, _is2['default'])(Function)]), [0]), (0, _pathSatisfies2['default'])((0, _is2['default'])(Function), [1]), (0, _pathSatisfies2['default'])((0, _anyPass2['default'])([_isNil2['default'], _util.isPlainObj, (0, _is2['default'])(Function), (0, _is2['default'])(String)]), [2]), (0, _pathSatisfies2['default'])((0, _anyPass2['default'])([_isNil2['default'], _util.isPlainObj, (0, _is2['default'])(Function), (0, _is2['default'])(String)]), [3])])), (0, _converge2['default'])(_call2['default'], [(0, _compose2['default'])(_util.coerceToFn, (0, _path2['default'])(['options', 'effects'])), _identity2['default']])))]); /** * Creates the Duck's throttlers (if they are present inside of its 'options' prop). * * @func * @sig {k: v} -> {k: v} * @param {Object} duck A duck which (may) contain throttlers (inside of its 'options') * @returns {Object} A clone of the duck, but now with throttlers (if they were found inside of 'options'). */ var createDuckThrottlers = exports.createDuckThrottlers = (0, _converge2['default'])(_mergeDeepRight2['default'], [_identity2['default'], (0, _ifElse2['default'])((0, _pathSatisfies2['default'])(_isNil2['default'], ['options', 'throttling']), (0, _always2['default'])([]), (0, _compose2['default'])((0, _objOf2['default'])('throttling'), (0, _map2['default'])(function (_ref2) { var pattern = _ref2[0]; var milliseconds = _ref2[1]; return [pattern, Number(milliseconds)]; }), (0, _filter2['default'])((0, _allPass2['default'])([(0, _is2['default'])(Array), (0, _pathSatisfies2['default'])((0, _anyPass2['default'])([(0, _is2['default'])(String), (0, _is2['default'])(RegExp), (0, _is2['default'])(Function)]), [0]), (0, _pathSatisfies2['default'])((0, _compose2['default'])(_not2['default'], isNaN, Number), [1])])), (0, _converge2['default'])(_call2['default'], [(0, _compose2['default'])(_util.coerceToFn, (0, _path2['default'])(['options', 'throttling'])), _identity2['default']])))]); /** * Creates the Duck's debouncers (if they are present inside of its 'options' prop). * * @func * @sig {k: v} -> {k: v} * @param {Object} duck A duck which (may) contain debouncers (inside of its 'options') * @returns {Object} A clone of the duck, but now with debouncers (if they were found inside of 'options'). */ var createDuckDebouncers = exports.createDuckDebouncers = (0, _converge2['default'])(_mergeDeepRight2['default'], [_identity2['default'], (0, _ifElse2['default'])((0, _pathSatisfies2['default'])(_isNil2['default'], ['options', 'debouncing']), (0, _always2['default'])([]), (0, _compose2['default'])((0, _objOf2['default'])('debouncing'), (0, _map2['default'])(function (_ref3) { var pattern = _ref3[0]; var milliseconds = _ref3[1]; return [pattern, Number(milliseconds)]; }), (0, _filter2['default'])((0, _allPass2['default'])([(0, _is2['default'])(Array), (0, _pathSatisfies2['default'])((0, _anyPass2['default'])([(0, _is2['default'])(String), (0, _is2['default'])(RegExp), (0, _is2['default'])(Function)]), [0]), (0, _pathSatisfies2['default'])((0, _compose2['default'])(_not2['default'], isNaN, Number), [1])])), (0, _converge2['default'])(_call2['default'], [(0, _compose2['default'])(_util.coerceToFn, (0, _path2['default'])(['options', 'debouncing'])), _identity2['default']])))]); /** * Creates the Duck's queries (if they are present inside of its 'options' prop). * * @func * @sig {k: v} -> {k: v} * @param {Object} duck A duck which (may) contain queries (inside of its 'options') * @returns {Object} A clone of the duck, but now with queries (if they were found inside of 'options'). */ var createDuckQueries = exports.createDuckQueries = (0, _converge2['default'])(_mergeDeepRight2['default'], [_identity2['default'], (0, _ifElse2['default'])((0, _pathSatisfies2['default'])(_isNil2['default'], ['options', 'queries']), (0, _always2['default'])({}), (0, _compose2['default'])((0, _objOf2['default'])('queries'), _queries.makeQueries))]); /** * Creates the Duck's workers (if they are present inside of its 'options' prop). * * @func * @sig {k: v} -> {k: v} * @param {Object} duck A duck which (may) contain workers (inside of its 'options') * @returns {Object} A clone of the duck, but now with workers (if they were found inside of 'options'). */ var createDuckWorkers = exports.createDuckWorkers = (0, _converge2['default'])(_mergeDeepRight2['default'], [_identity2['default'], (0, _ifElse2['default'])((0, _pathSatisfies2['default'])(_isNil2['default'], ['options', 'workers']), (0, _always2['default'])({}), (0, _compose2['default'])((0, _objOf2['default'])('workers'), _workers.makeWorkers))]); /** * Creates the Duck's state machines (if they are present inside of its 'options' prop). * * @func * @sig {k: v} -> {k: v} * @param {Object} duck A duck which (may) contain state machines (inside of its 'options') * @returns {Object} A clone of the duck, but now with state machines (if they were found inside of 'options'). */ var createDuckMachines = exports.createDuckMachines = (0, _converge2['default'])(_mergeDeepRight2['default'], [_identity2['default'], (0, _ifElse2['default'])((0, _pathSatisfies2['default'])(_isNil2['default'], ['options', 'machines']), (0, _always2['default'])({}), (0, _compose2['default'])((0, _objOf2['default'])('machines'), (0, _converge2['default'])(_machines.createMachines, [(0, _converge2['default'])(_call2['default'], [(0, _compose2['default'])(_util.coerceToFn, (0, _path2['default'])(['options', 'machines'])), _identity2['default']]), _identity2['default']])))]); /** * Creates the Duck's initial state for the section of the store that affects this duck. * * @func * @sig {k: v} -> {k: v} * @param {Object} duck A duck which (may) contain initialState (inside of its 'options') * @returns {Object} A clone of the duck, but now with initialState (if it was found inside of 'options'). */ var createDuckInitialState = exports.createDuckInitialState = (0, _converge2['default'])(_mergeDeepRight2['default'], [_identity2['default'], (0, _compose2['default'])((0, _objOf2['default'])('initialState'), (0, _converge2['default'])(_mergeDeepRight2['default'], [(0, _converge2['default'])(_call2['default'], [(0, _compose2['default'])(_util.coerceToFn, (0, _path2['default'])(['options', 'initialState'])), _identity2['default']]), (0, _ifElse2['default'])((0, _propSatisfies2['default'])(_isEmpty2['default'], 'machines'), (0, _always2['default'])({}), (0, _compose2['default'])((0, _applyTo2['default'])({}), (0, _converge2['default'])(_assocPath2['default'], [(0, _prop2['default'])('stateMachinesPropName'), (0, _compose2['default'])(_machines.getDefaultStateForMachines, (0, _prop2['default'])('machines'))])))]))]); /** * Creates the Duck's selectors (if they are present inside of its 'options' prop). * * @func * @sig {k: v} -> {k: v} * @param {Object} duck A duck which (may) contain selectors (inside of its 'options') * @returns {Object} A clone of the duck, but now with selectors (if they were found inside of 'options'). */ var createDuckSelectors = exports.createDuckSelectors = (0, _converge2['default'])(_mergeDeepRight2['default'], [_identity2['default'], (0, _ifElse2['default'])((0, _pathSatisfies2['default'])(_isNil2['default'], ['options', 'selectors']), (0, _always2['default'])({}), (0, _compose2['default'])((0, _objOf2['default'])('selectors'), _selectors.deriveSelectors, (0, _converge2['default'])(_call2['default'], [(0, _compose2['default'])(_util.coerceToFn, (0, _path2['default'])(['options', 'selectors'])), _identity2['default']])))]); /** * Creates an Object of enhancement functions out of an Object of spec objects * (or arrays of spec objects). * * @func * @sig {k: [({k: v} -> {k: v}), ({k: v} -> {k: v}), ...]|({k: v} -> {k: v}) } -> {k: ({k: v} -> {k: v}) } * @param {Object[]|Object} enhancements A single enhancement spec or an Array of enhancement specs * @returns {Object} An object of enhancer functions, each ready to receive an * input object and apply their single or chain of enhancer functions to it. */ var makeEnhancers = exports.makeEnhancers = (0, _ifElse2['default'])((0, _is2['default'])(Array), _shapey.shapeline, _shapey.makeShaper); /** * Creates the Duck's action enhancers (if they are present inside of its 'options' prop). * * @func * @sig {k: v} -> {k: v} * @param {Object} duck A duck which (may) contain action enhancers (inside of its 'options') * @returns {Object} A clone of the duck, but now with action enhancers (if they were found inside of 'options'). */ var createDuckActionEnhancers = exports.createDuckActionEnhancers = (0, _converge2['default'])(_mergeDeepRight2['default'], [_identity2['default'], (0, _ifElse2['default'])((0, _pathSatisfies2['default'])(_isNil2['default'], ['options', 'enhancers']), (0, _always2['default'])({}), (0, _compose2['default'])((0, _objOf2['default'])('enhancers'), (0, _map2['default'])(makeEnhancers), (0, _converge2['default'])(_call2['default'], [(0, _compose2['default'])(_util.coerceToFn, (0, _path2['default'])(['options', 'enhancers'])), _identity2['default']])))]); /** * Creates an Object of multiplier functions out of an Object of spec objects * (or arrays of spec objects). * * @func * @sig {k: [({k: v} -> {k: v}), ({k: v} -> {k: v}), ...]|({k: v} -> {k: v}) } -> {k: ({k: v} -> {k: v}) } * @param {Object[]|Object} multipliers A single multiplier spec or an Array of multipler specs * @returns {Object} An object of multipler functions, each ready to receive an * input object and apply their single or many multipler functions to it. */ var makeMultipliers = exports.makeMultipliers = (0, _compose2['default'])(_juxt2['default'], (0, _map2['default'])(_shapey.makeShaper), (0, _unless2['default'])((0, _is2['default'])(Array), _of2['default'])); /** * Creates the Duck's action multipliers (if they are present inside of its 'options' prop). * * @func * @sig {k: v} -> {k: v} * @param {Object} duck A duck which (may) contain action multipliers (inside of its 'options') * @returns {Object} A clone of the duck, but now with action multipliers (if they were found inside of 'options'). */ var createDuckActionMultipliers = exports.createDuckActionMultipliers = (0, _converge2['default'])(_mergeDeepRight2['default'], [_identity2['default'], (0, _ifElse2['default'])((0, _pathSatisfies2['default'])(_isNil2['default'], ['options', 'multipliers']), (0, _always2['default'])({}), (0, _compose2['default'])((0, _objOf2['default'])('multipliers'), (0, _map2['default'])(makeMultipliers), (0, _converge2['default'])(_call2['default'], [(0, _compose2['default'])(_util.coerceToFn, (0, _path2['default'])(['options', 'multipliers'])), _identity2['default']])))]); /** * Creates the Duck's action creators (if they are present inside of its 'options' prop). * * @func * @sig {k: v} -> {k: v} * @param {Object} duck A duck which (may) contain action creators (inside of its 'options') * @returns {Object} A clone of the duck, but now with action creators (if they were found inside of 'options'). */ var createDuckActionCreators = exports.createDuckActionCreators = (0, _converge2['default'])(_mergeDeepRight2['default'], [_identity2['default'], (0, _ifElse2['default'])((0, _pathSatisfies2['default'])(_isNil2['default'], ['options', 'creators']), (0, _always2['default'])({}), (0, _compose2['default'])((0, _objOf2['default'])('creators'), (0, _converge2['default'])(_call2['default'], [(0, _compose2['default'])(_util.coerceToFn, (0, _path2['default'])(['options', 'creators'])), _identity2['default']])))]); /** * Creates the Duck's reducer (if it was present inside of its 'options' prop). * * @func * @sig {k: v} -> {k: v} * @param {Object} duck A duck which (may) contain a reducer (inside of its 'options') * @returns {Object} A clone of the duck, but now with a reducer (if it was found inside of 'options'). */ var createDuckReducer = exports.createDuckReducer = (0, _converge2['default'])(_mergeDeepRight2['default'], [_identity2['default'], (0, _ifElse2['default'])((0, _either2['default'])((0, _pathSatisfies2['default'])(_isNil2['default'], ['options', 'reducer']), (0, _propSatisfies2['default'])(_isEmpty2['default'], 'machines')), (0, _compose2['default'])((0, _objOf2['default'])('reducer'), _reducers.createReducer), (0, _compose2['default'])((0, _objOf2['default'])('reducer'), _reducers.createTransitionsPostReducer))]); /** * Creates validation helpers for a given Duck, to be used in the middleware chain. * * @func * @sig {k: v} -> {k: v} * @param {Object} duck A duck which (may) contain validators (inside of its 'options') * @returns {Object} A clone of the duck, but now with validator helpers (if validators were found inside of 'options'). */ var createValidationMiddlewareHelpers = exports.createValidationMiddlewareHelpers = (0, _converge2['default'])(_mergeDeepRight2['default'], [_identity2['default'], (0, _ifElse2['default'])((0, _propSatisfies2['default'])(_isNil2['default'], 'validators'), (0, _always2['default'])({}), (0, _compose2['default'])((0, _applySpec2['default'])({ isPayloadValid: _validators.createPayloadValidator, getValidationErrors: _validators.createPayloadValidationsLogger, pruneInvalidFields: _validators.createPayloadPruner }), (0, _prop2['default'])('validators')))]);