UNPKG

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

460 lines (355 loc) 21.1 kB
'use strict'; exports.__esModule = true; exports.isActionTypeInCurrentState = exports.getNextState = exports.getCurrentState = exports.getDefaultStateForMachines = exports.getStateMachinesPropPath = exports.createMachines = exports.createMachineStates = exports.isTransitionPossible = exports.isEachTransitionAmongMachineStates = exports.areStateMachineInputsActionTypes = exports.areInputsAndTransitionsStrings = exports.areStateNamesStrings = exports.invalidStateMachineInputs = exports.getStateInputsForAllMachines = exports.getStateInputsForMachine = exports.getTransitionsForMachine = exports.addTransitionsToState = exports.noMachines = undefined; var _any = require('ramda/src/any'); var _any2 = _interopRequireDefault(_any); var _pair = require('ramda/src/pair'); var _pair2 = _interopRequireDefault(_pair); var _mergeDeepRight = require('ramda/src/mergeDeepRight'); var _mergeDeepRight2 = _interopRequireDefault(_mergeDeepRight); var _always = require('ramda/src/always'); var _always2 = _interopRequireDefault(_always); var _when = require('ramda/src/when'); var _when2 = _interopRequireDefault(_when); var _split = require('ramda/src/split'); var _split2 = _interopRequireDefault(_split); var _ifElse = require('ramda/src/ifElse'); var _ifElse2 = _interopRequireDefault(_ifElse); var _both = require('ramda/src/both'); var _both2 = _interopRequireDefault(_both); var _last = require('ramda/src/last'); var _last2 = _interopRequireDefault(_last); var _ = require('ramda/src/__'); var _2 = _interopRequireDefault(_); var _contains = require('ramda/src/contains'); var _contains2 = _interopRequireDefault(_contains); var _head = require('ramda/src/head'); var _head2 = _interopRequireDefault(_head); var _pick = require('ramda/src/pick'); var _pick2 = _interopRequireDefault(_pick); var _reduce = require('ramda/src/reduce'); var _reduce2 = _interopRequireDefault(_reduce); var _path = require('ramda/src/path'); var _path2 = _interopRequireDefault(_path); var _has = require('ramda/src/has'); var _has2 = _interopRequireDefault(_has); var _useWith = require('ramda/src/useWith'); var _useWith2 = _interopRequireDefault(_useWith); var _toPairs = require('ramda/src/toPairs'); var _toPairs2 = _interopRequireDefault(_toPairs); var _either = require('ramda/src/either'); var _either2 = _interopRequireDefault(_either); var _allPass = require('ramda/src/allPass'); var _allPass2 = _interopRequireDefault(_allPass); var _is = require('ramda/src/is'); var _is2 = _interopRequireDefault(_is); var _all = require('ramda/src/all'); var _all2 = _interopRequireDefault(_all); var _difference = require('ramda/src/difference'); var _difference2 = _interopRequireDefault(_difference); var _converge = require('ramda/src/converge'); var _converge2 = _interopRequireDefault(_converge); var _prop = require('ramda/src/prop'); var _prop2 = _interopRequireDefault(_prop); var _keys = require('ramda/src/keys'); var _keys2 = _interopRequireDefault(_keys); var _map = require('ramda/src/map'); var _map2 = _interopRequireDefault(_map); var _filter = require('ramda/src/filter'); var _filter2 = _interopRequireDefault(_filter); var _values = require('ramda/src/values'); var _values2 = _interopRequireDefault(_values); var _flatten = require('ramda/src/flatten'); var _flatten2 = _interopRequireDefault(_flatten); var _uniq = require('ramda/src/uniq'); var _uniq2 = _interopRequireDefault(_uniq); var _defaultTo = require('ramda/src/defaultTo'); var _defaultTo2 = _interopRequireDefault(_defaultTo); var _assocPath = require('ramda/src/assocPath'); var _assocPath2 = _interopRequireDefault(_assocPath); var _unless = require('ramda/src/unless'); var _unless2 = _interopRequireDefault(_unless); var _compose = require('ramda/src/compose'); var _compose2 = _interopRequireDefault(_compose); var _curry = require('ramda/src/curry'); var _curry2 = _interopRequireDefault(_curry); var _isEmpty = require('ramda/src/isEmpty'); var _isEmpty2 = _interopRequireDefault(_isEmpty); var _isNil = require('ramda/src/isNil'); var _isNil2 = _interopRequireDefault(_isNil); var _anyPass = require('ramda/src/anyPass'); var _anyPass2 = _interopRequireDefault(_anyPass); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _util = require('../util'); var _types = require('../types'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Simple check to see whether a given duck's machines is empty. * * @func * @sig {k: v} -> Boolean * @param {Object} machines A duck's collection of state machines * @returns {Boolean} whether or not the machines are empty */ var noMachines = exports.noMachines = (0, _anyPass2.default)([_isNil2.default, _isEmpty2.default]); /** * Adds an object containing the current state of all the state machines onto * a given section of the redux store * * @func * @sig {k: v} -> {k: v} -> {k: v} * @param {Object} duck A duck instance, containing the state machines and the * prop name/path to the section of the store where their state is tracked * @param {*} state The current state of this portion of the store * @returns {Object} original state (or initialState, if state is nil) plus * current state of all the state machines */ var addTransitionsToState = exports.addTransitionsToState = (0, _curry2.default)(function (state, _ref) { var _ref$initialState = _ref.initialState, initialState = _ref$initialState === undefined ? {} : _ref$initialState, _ref$stateMachinesPro = _ref.stateMachinesPropName, stateMachinesPropName = _ref$stateMachinesPro === undefined ? ['states'] : _ref$stateMachinesPro; return (0, _compose2.default)((0, _unless2.default)((0, _util.hasNestedProp)(stateMachinesPropName), (0, _assocPath2.default)(stateMachinesPropName, {})), (0, _defaultTo2.default)(initialState))(state); }); /** * Retrieves a unique list all the state transitions possible for a given machine. * State machines are objects whose keys are states and whose values are objects * inside of which the transition-to state is the value of each of its key/value pairs. * * @func * @sig {k: v} -> [String] * @param {Object} machine A single state machine * @returns {String[]} A list of unique state transitions for the provided machine */ var getTransitionsForMachine = exports.getTransitionsForMachine = (0, _compose2.default)(_uniq2.default, (0, _filter2.default)(_util.isStringieThingie), _flatten2.default, (0, _map2.default)(_values2.default), _values2.default); /** * Retrieves a unique list all the inputs for a given state machine (which correspond to Action Types). * State machines are objects whose keys are states and whose values are objects * inside of which the input value is the key of each of its key/value pairs. * * @func * @sig {k: v} -> [String] * @param {Object} machine A single state machine * @returns {String[]} A list of unique inputs to the provided state machine */ var getStateInputsForMachine = exports.getStateInputsForMachine = (0, _compose2.default)(_uniq2.default, (0, _filter2.default)(_util.isStringieThingie), _flatten2.default, (0, _map2.default)(_keys2.default), _values2.default); /** * Retrieves a unique list all the inputs for all of a given duck's state machines. * State machines are objects whose keys are states and whose values are objects * inside of which the input value is the key of each of its key/value pairs. * * @func * @sig {k: v} -> [String] * @param {Object} duck A duck containing one or more state machines * @returns {String[]} A list of unique inputs to all the state machines for the provided duck */ var getStateInputsForAllMachines = exports.getStateInputsForAllMachines = (0, _compose2.default)(_uniq2.default, _flatten2.default, (0, _map2.default)(getStateInputsForMachine), _values2.default, (0, _prop2.default)('machines')); /** * Retrieves any invalid inputs from a given duck's state machines. * State machines are objects whose keys are states and whose values are objects * inside of which the input value is the key of each of its key/value pairs. * * @func * @sig {k: v} -> [String] * @param {Object} duck A duck containing one or more state machines and action types * @returns {String[]} A list of any invalid inputs for the state machines of the provided duck */ var invalidStateMachineInputs = exports.invalidStateMachineInputs = (0, _converge2.default)(_difference2.default, [getStateInputsForAllMachines, _types.getTypes]); /** * Checks whether all a given state machine's states are string values. * State machines are objects whose keys are states and whose values are objects * inside of which the input value is the key of each of its key/value pairs. * * @func * @sig {k: v} -> Boolean * @param {Object} machine A single state machine * @returns {Boolean} whether or not the states for the state machine are strings */ var areStateNamesStrings = exports.areStateNamesStrings = (0, _compose2.default)((0, _all2.default)((0, _is2.default)(String)), _keys2.default); /** * Checks whether all a given state machine's inputs and transition names are string values. * State machines are objects whose keys are states and whose values are objects * inside of which the input value is the key and transition is the value of each of its key/value pairs. * * @func * @sig {k: v} -> Boolean * @param {Object} machine A single state machine * @returns {Boolean} whether or not the inputs and transitions for the state machine are strings */ var areInputsAndTransitionsStrings = exports.areInputsAndTransitionsStrings = (0, _compose2.default)((0, _all2.default)((0, _allPass2.default)([_util.isPlainObj, (0, _either2.default)(_isEmpty2.default, (0, _compose2.default)((0, _all2.default)((0, _all2.default)((0, _is2.default)(String))), _toPairs2.default))])), _values2.default); /** * Checks whether all the state machine inputs for a given duck correspond to its action types. * State machines are objects whose keys are states and whose values are objects * inside of which the input value is the key of each of its key/value pairs. * * @func * @sig {k: v} -> Boolean * @param {Object} duck A duck containing one or more state machines and action types * @returns {Boolean} whether or not all the inputs for the state machines are among the duck's action types */ var areStateMachineInputsActionTypes = exports.areStateMachineInputsActionTypes = (0, _compose2.default)((0, _all2.default)(_isEmpty2.default), invalidStateMachineInputs); /** * Checks if all a state machine's transitions are states in that machine. * State machines are objects whose keys are states and whose values are objects * inside of which the transition-to state is the value of each of its key/value pairs. * * @func * @sig {k: v} -> Boolean * @param {Object} machine A single state machine * @returns {Boolean} whether or not all the transition names are also states for a given state machine */ var isEachTransitionAmongMachineStates = exports.isEachTransitionAmongMachineStates = (0, _useWith2.default)(_difference2.default, [getTransitionsForMachine, _keys2.default]); /** * Checks to see whether a given machine allows for a given transition, provided its current state * * @func * @sig String -> String -> {k: v} -> Boolean * @param {String} transitionName A string value representing a potential state transition * @param {String} currentState A string value representing the current state * @param {Object} machine A state machine which contains the possible states and their associated transitions * @returns {Boolean} whether or not the transition is possible from the current state */ var isTransitionPossible = exports.isTransitionPossible = (0, _curry2.default)(function (transitionName, currentState, machine) { return (0, _compose2.default)((0, _has2.default)((0, _util.coerceToString)(transitionName)), (0, _defaultTo2.default)({}), (0, _path2.default)([(0, _util.coerceToString)(currentState)]), (0, _defaultTo2.default)({}))(machine); }); /** * Creates a "machine state" object, which can be combined with others to create a single state machine. * The keys for a machine state object (called inputs or input values) correspond to the names of redux action types. * The values for a machine state object (called transitions) are merely * the names of fellow machine state objects (also created by this function). * * @func * @sig {k: v} -> {k: v} -> {k: v} * @param {Object} machine A single state machine * @param {Object} types An object whose keys/values correspond * to redux actions and will be used to set up inputs for the state machine * @returns {Object} a validated, immutable state machine */ var createMachineStates = exports.createMachineStates = (0, _curry2.default)(function () { var machine = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var types = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; return (0, _compose2.default)(Object.freeze, (0, _reduce2.default)(_util.listOfPairsToOneObject, {}), (0, _map2.default)(function (_ref2) { var state = _ref2[0], transitions = _ref2[1]; return [state, (0, _pick2.default)((0, _compose2.default)((0, _map2.default)(_head2.default), (0, _filter2.default)((0, _compose2.default)((0, _contains2.default)(_2.default, (0, _values2.default)(types)), _head2.default)), (0, _filter2.default)((0, _compose2.default)((0, _has2.default)(_2.default, machine), _last2.default)), (0, _filter2.default)((0, _all2.default)((0, _is2.default)(String))), _toPairs2.default)(transitions), transitions)]; }), (0, _filter2.default)((0, _both2.default)((0, _compose2.default)((0, _is2.default)(String), _head2.default), (0, _compose2.default)(_util.isPlainObj, _last2.default))), _toPairs2.default)(machine); }); /** * Creates a frozen (immutable) object whose keys are all the possible "current state" * values for the machine and whose values are objects containing each action type that * may produce a transition to another state. * * @func * @sig {k: v} -> {k: v} -> {k: v} * @param {Object} machines An object full of one or more state machines * @param {Object} duck A duck instance * @returns {Object} an object of validated, immutable state machines */ var createMachines = exports.createMachines = (0, _curry2.default)(function (machines, duck) { return (0, _compose2.default)(Object.freeze, (0, _reduce2.default)(_util.listOfPairsToOneObject, {}), (0, _map2.default)(function (_ref3) { var name = _ref3[0], machine = _ref3[1]; return [name, createMachineStates(machine, duck.types)]; }), _toPairs2.default)(machines); }); /** * Creates an string path (array) that the state machine functions will use to * lookup and alter the current state of one or more of the state machines. * The path supplied to this function can be a single prop name (String) or * an Array of prop names that represent a nested prop's path. * And if a String is passed in, a dot-separated format is also supported. * * @func * @sig String -> [String] * @param {String|String[]} path The prop name or path to the section of the * store where the state machines current state is tracked. * @returns {String[]} an array of strings representing the nested path to the * prop where state machines current state is tracked in the redux store */ var getStateMachinesPropPath = exports.getStateMachinesPropPath = (0, _ifElse2.default)((0, _allPass2.default)([(0, _is2.default)(String), (0, _contains2.default)('.'), _util.isValidPropName]), (0, _split2.default)('.'), (0, _compose2.default)((0, _when2.default)(_isEmpty2.default, (0, _always2.default)(['states'])), (0, _filter2.default)(_util.isNotBlankString), (0, _when2.default)((0, _is2.default)(String), Array))); /** * Builds a flattened object where the keys are the names of each of the duck's state machines, * and the values are each set to 'initial'. * * @func * @sig {k: v} -> {k: v} * @param {Object} machines An object containing the definitions for one or more state machines * @returns {Object} a flattened object where the current state of each state machine will be tracked */ var getDefaultStateForMachines = exports.getDefaultStateForMachines = function getDefaultStateForMachines() { var machines = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return (0, _reduce2.default)(function (obj, key) { var _extends2; return _extends({}, obj, (_extends2 = {}, _extends2[key] = 'initial', _extends2)); }, {}, (0, _keys2.default)(machines || {})); }; /** * Retrieves the section of the redux store where the current state is being * tracked for one or more state machines. The shape of this section of the store * is usually just a flattened object with a single value for each named state * machine, representing its current state. Each possible state for any of those * is defined in the Ducks. * * @func * @sig {k: v} -> {k: v} -> {k: v} * @param {Object} duck A duck instance, containing the state machines and the * prop name/path to the section of the store where their state is tracked * @param {*} state The current state of this portion of the store * @returns {Object} A flattened Object containing the names of each state * machine (String) and its current state (String) as key/value pairs */ var getCurrentState = exports.getCurrentState = function getCurrentState() { var _ref4 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, _ref4$machines = _ref4.machines, machines = _ref4$machines === undefined ? {} : _ref4$machines, stateMachinesPropName = _ref4.stateMachinesPropName; return (0, _compose2.default)((0, _mergeDeepRight2.default)((0, _map2.default)((0, _always2.default)('initial'), machines)), (0, _pick2.default)((0, _keys2.default)(machines)), (0, _defaultTo2.default)({}), (0, _path2.default)((0, _util.coerceToArray)(stateMachinesPropName))); }; /** * Based on the current state of the machines (managed in the store itself) and * the rules defined for each state machine (in the ducks), an action is processed * and may cause one or more ore the state machines to transition. * * @func * @sig {k: v} -> {k: v} -> {k: v} * @param {Object|*} state The current state of this portion of the store * @param {Object} action A dispatched redux action * @param {Object} duck A duck instance, containing the state machines and the * prop name/path to the section of the store where their state is tracked * @returns {Object} A flattened Object containing the names of each state * machine (String) and its current state (String) as key/value pairs */ var getNextState = exports.getNextState = (0, _curry2.default)(function (state, action, _ref5) { var _ref5$machines = _ref5.machines, machines = _ref5$machines === undefined ? {} : _ref5$machines, stateMachinesPropName = _ref5.stateMachinesPropName; var currentState = getCurrentState({ machines: machines, stateMachinesPropName: stateMachinesPropName })(state); return (0, _compose2.default)((0, _reduce2.default)(_util.listOfPairsToOneObject, {}), (0, _map2.default)(function (_ref6) { var name = _ref6[0], machine = _ref6[1]; return (0, _compose2.default)((0, _pair2.default)(name), (0, _unless2.default)(_util.isNotNil, (0, _always2.default)(currentState[name])), (0, _prop2.default)(action.type), (0, _defaultTo2.default)({}), (0, _prop2.default)(currentState[name]))(machine); }), _toPairs2.default)(machines); }); /** * Checks whether a dispatched action's type is listed among the * current state's input values for one or more of the state machines. * * @func * @sig {k: v} -> {k: v} -> {k: v} -> Boolean * @param {Object|*} state The current state of this portion of the store * @param {Object} action A dispatch redux action * @param {Object} duck A duck, which contains both state machines and the * corresponding prop name/path in the redux store where their current state is tracked * @returns {Boolean} whether or not the dispatched action is listed as an input * value for the state machine(s) current state */ var isActionTypeInCurrentState = exports.isActionTypeInCurrentState = (0, _curry2.default)(function (state, action, _ref7) { var machines = _ref7.machines, stateMachinesPropName = _ref7.stateMachinesPropName; var currentState = getCurrentState({ machines: machines, stateMachinesPropName: stateMachinesPropName })(state); return (0, _compose2.default)((0, _any2.default)(function (_ref8) { var name = _ref8[0], machine = _ref8[1]; return (0, _compose2.default)(_util.isNotNil, (0, _prop2.default)(action.type), (0, _defaultTo2.default)({}), (0, _prop2.default)(_2.default, machine), (0, _prop2.default)(name))(currentState); }), _toPairs2.default)(machines); });