redux-loop
Version:
Sequence your effects naturally and purely by returning them from your reducers.
447 lines (357 loc) • 17.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isCmd = isCmd;
exports.executeCmd = executeCmd;
exports["default"] = void 0;
var _utils = require("./utils");
var _Object$freeze4;
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var isCmdSymbol = Symbol('isCmd');
var dispatchSymbol = Symbol('dispatch');
var getStateSymbol = Symbol('getState');
var cmdTypes = {
RUN: 'RUN',
ACTION: 'ACTION',
SET_TIMEOUT: 'SET_TIMEOUT',
SET_INTERVAL: 'SET_INTERVAL',
LIST: 'LIST',
MAP: 'MAP',
NONE: 'NONE'
};
function isCmd(object) {
return object ? !!object[isCmdSymbol] : false;
}
function getMappedCmdArgs() {
var args = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var dispatch = arguments.length > 1 ? arguments[1] : undefined;
var getState = arguments.length > 2 ? arguments[2] : undefined;
return args.map(function (arg) {
if (arg === dispatchSymbol) {
return dispatch;
} else if (arg === getStateSymbol) {
return getState;
} else {
return arg;
}
});
}
function handleRunCmd(cmd, context) {
var dispatch = context.dispatch,
getState = context.getState,
loopConfig = context.loopConfig;
var onSuccess = cmd.successActionCreator || function () {};
var onFail;
if (cmd.failActionCreator) {
onFail = function onFail(error) {
if (!loopConfig.DONT_LOG_ERRORS_ON_HANDLED_FAILURES) {
console.error(error);
}
return cmd.failActionCreator(error);
};
} else {
onFail = console.error;
}
try {
var result = cmd.func.apply( // Pass undefined so that 'this' will not point to our 'cmd' object.
undefined, getMappedCmdArgs(cmd.args, dispatch, getState));
if ((0, _utils.isPromiseLike)(result) && !cmd.forceSync) {
return result.then(onSuccess, onFail).then(function (action) {
return action ? [action] : [];
});
}
var resultAction = onSuccess(result);
return resultAction ? Promise.resolve([resultAction]) : null;
} catch (err) {
if (!cmd.failActionCreator) {
console.error(err);
throw err; //don't swallow errors if they are not handling them
}
var _resultAction = onFail(err);
return _resultAction ? Promise.resolve([_resultAction]) : null;
}
}
function handleParallelList(_ref, context) {
var cmds = _ref.cmds,
_ref$batch = _ref.batch,
batch = _ref$batch === void 0 ? false : _ref$batch;
var promises = cmds.map(function (nestedCmd) {
var possiblePromise = executeCmdInternal(nestedCmd, context);
if (!possiblePromise || batch) {
return possiblePromise;
}
return possiblePromise.then(function (result) {
return Promise.all(result.map(function (a) {
return context.wrappedDispatch(a);
}));
});
}).filter(function (x) {
return x;
});
if (promises.length === 0) {
return null;
}
return Promise.all(promises).then(_utils.flatten).then(function (actions) {
return batch ? actions : [];
});
}
function handleSequenceList(_ref2, context) {
var cmds = _ref2.cmds,
_ref2$batch = _ref2.batch,
batch = _ref2$batch === void 0 ? false : _ref2$batch;
var firstCmd = cmds.length ? cmds[0] : null;
if (!firstCmd) {
return null;
}
var result = new Promise(function (resolve) {
var firstPromise = executeCmdInternal(firstCmd, context);
firstPromise = firstPromise || Promise.resolve([]);
firstPromise.then(function (result) {
var executePromise;
if (!batch) {
executePromise = Promise.all(result.map(function (a) {
return context.wrappedDispatch(a);
}));
} else {
executePromise = Promise.resolve();
}
executePromise.then(function () {
var remainingSequence = list(cmds.slice(1), {
batch: batch,
sequence: true
});
var remainingPromise = executeCmdInternal(remainingSequence, context);
if (remainingPromise) {
remainingPromise.then(function (innerResult) {
resolve(result.concat(innerResult));
});
} else {
resolve(result);
}
});
});
}).then(_utils.flatten);
return batch ? result : result.then(function () {
return [];
});
}
function handleDelayCmd(cmd, context) {
var executeNestedCmd = function executeNestedCmd() {
var cmdPromise = executeCmdInternal(cmd.nestedCmd, context);
if (cmdPromise) {
cmdPromise.then(function (actions) {
actions.forEach(function (action) {
return context.wrappedDispatch(action);
});
});
}
};
var timerId;
if (cmd.type === cmdTypes.SET_INTERVAL) {
timerId = setInterval(executeNestedCmd, cmd.delayMs);
} else {
timerId = setTimeout(executeNestedCmd, cmd.delayMs);
}
if (cmd.scheduledActionCreator) {
return Promise.resolve([cmd.scheduledActionCreator(timerId)]);
} else {
return null;
}
}
function executeCmd(cmd, dispatch, getState) {
var loopConfig = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
return executeCmdInternal(cmd, {
dispatch: dispatch,
wrappedDispatch: dispatch,
getState: getState,
loopConfig: loopConfig
});
}
function executeCmdInternal(cmd, context) {
switch (cmd.type) {
case cmdTypes.RUN:
return handleRunCmd(cmd, context);
case cmdTypes.ACTION:
return Promise.resolve([cmd.actionToDispatch]);
case cmdTypes.SET_TIMEOUT:
case cmdTypes.SET_INTERVAL:
return handleDelayCmd(cmd, context);
case cmdTypes.LIST:
return cmd.sequence ? handleSequenceList(cmd, context) : handleParallelList(cmd, context);
case cmdTypes.MAP:
{
var possiblePromise = executeCmdInternal(cmd.nestedCmd, _objectSpread(_objectSpread({}, context), {}, {
wrappedDispatch: function wrappedDispatch(action) {
return context.wrappedDispatch(cmd.tagger.apply(cmd, _toConsumableArray(cmd.args).concat([action])));
}
}));
if (!possiblePromise) {
return null;
}
return possiblePromise.then(function (actions) {
return actions.map(function (action) {
return cmd.tagger.apply(cmd, _toConsumableArray(cmd.args).concat([action]));
});
});
}
case cmdTypes.NONE:
return null;
default:
throw new Error("Invalid Cmd type ".concat(cmd.type));
}
}
function simulateRun(_ref3) {
var result = _ref3.result,
success = _ref3.success;
if (success && this.successActionCreator) {
return this.successActionCreator(result);
} else if (!success && this.failActionCreator) {
return this.failActionCreator(result);
}
return null;
}
function run(func) {
var _objectSpread2;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (process.env.NODE_ENV !== 'production') {
if (!options.testInvariants) {
(0, _utils.throwInvariant)(typeof func === 'function', 'Cmd.run: first argument to Cmd.run must be a function');
(0, _utils.throwInvariant)(_typeof(options) === 'object', 'Cmd.run: second argument to Cmd.run must be an options object');
(0, _utils.throwInvariant)(!options.successActionCreator || typeof options.successActionCreator === 'function', 'Cmd.run: successActionCreator option must be a function if specified');
(0, _utils.throwInvariant)(!options.failActionCreator || typeof options.failActionCreator === 'function', 'Cmd.run: failActionCreator option must be a function if specified');
(0, _utils.throwInvariant)(!options.args || options.args.constructor === Array, 'Cmd.run: args option must be an array if specified');
}
} else if (options.testInvariants) {
throw Error("Redux Loop: Detected usage of Cmd.run's testInvariants option in production code. This should only be used in tests.");
}
var testInvariants = options.testInvariants,
rest = _objectWithoutProperties(options, ["testInvariants"]);
return Object.freeze(_objectSpread((_objectSpread2 = {}, _defineProperty(_objectSpread2, isCmdSymbol, true), _defineProperty(_objectSpread2, "type", cmdTypes.RUN), _defineProperty(_objectSpread2, "func", func), _defineProperty(_objectSpread2, "simulate", simulateRun), _objectSpread2), rest));
}
function simulateAction() {
return this.actionToDispatch;
}
function action(actionToDispatch) {
var _Object$freeze;
if (process.env.NODE_ENV !== 'production') {
(0, _utils.throwInvariant)(_typeof(actionToDispatch) === 'object' && actionToDispatch !== null && typeof actionToDispatch.type !== 'undefined', 'Cmd.action: first argument and only argument to Cmd.action must be an action');
}
return Object.freeze((_Object$freeze = {}, _defineProperty(_Object$freeze, isCmdSymbol, true), _defineProperty(_Object$freeze, "type", cmdTypes.ACTION), _defineProperty(_Object$freeze, "actionToDispatch", actionToDispatch), _defineProperty(_Object$freeze, "simulate", simulateAction), _Object$freeze));
}
function clearTimeoutCmd(timerId) {
return run(clearTimeout, {
args: [timerId]
});
}
function clearIntervalCmd(timerId) {
return run(clearInterval, {
args: [timerId]
});
}
function setTimeoutCmd(nestedCmd, delayMs) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
return delay(nestedCmd, delayMs, options, cmdTypes.SET_TIMEOUT, 'Cmd.setTimeout');
}
function setIntervalCmd(nestedCmd, delayMs) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
return delay(nestedCmd, delayMs, options, cmdTypes.SET_INTERVAL, 'Cmd.setInterval');
}
function delay(nestedCmd, delayMs, options, cmdType, funcName) {
var _Object$freeze2;
if (process.env.NODE_ENV !== 'production') {
(0, _utils.throwInvariant)(isCmd(nestedCmd), "".concat(funcName, ": first argument must be another Cmd"));
(0, _utils.throwInvariant)(typeof delayMs === 'number', "".concat(funcName, ": second argument must be a number"));
(0, _utils.throwInvariant)(_typeof(options) === 'object', "".concat(funcName, ": third argument must be an options object"));
(0, _utils.throwInvariant)(options.scheduledActionCreator === undefined || typeof options.scheduledActionCreator === 'function', "".concat(funcName, ": scheduledActionCreator option must be a function if specified"));
}
return Object.freeze((_Object$freeze2 = {}, _defineProperty(_Object$freeze2, isCmdSymbol, true), _defineProperty(_Object$freeze2, "type", cmdType), _defineProperty(_Object$freeze2, "nestedCmd", nestedCmd), _defineProperty(_Object$freeze2, "delayMs", delayMs), _defineProperty(_Object$freeze2, "scheduledActionCreator", options.scheduledActionCreator), _defineProperty(_Object$freeze2, "simulate", simulateDelay), _Object$freeze2));
}
function simulateDelay(timerId, nestedSimulation) {
var result = this.nestedCmd.simulate(nestedSimulation);
var nestedActions = null;
if (Array.isArray(result)) {
nestedActions = result;
} else if (result) {
nestedActions = [result];
}
if (this.scheduledActionCreator) {
return [this.scheduledActionCreator(timerId)].concat(nestedActions);
} else {
return nestedActions;
}
}
function simulateList(simulations) {
return (0, _utils.flatten)(this.cmds.map(function (cmd, i) {
return cmd.simulate(simulations[i]);
}).filter(function (a) {
return a;
}));
}
function list(cmds) {
var _objectSpread3;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (process.env.NODE_ENV !== 'production') {
if (!options.testInvariants) {
(0, _utils.throwInvariant)(Array.isArray(cmds) && cmds.every(isCmd), 'Cmd.list: first argument to Cmd.list must be an array of other Cmds');
(0, _utils.throwInvariant)(_typeof(options) === 'object', 'Cmd.list: second argument to Cmd.list must be an options object');
}
} else if (options.testInvariants) {
throw Error("Redux Loop: Detected usage of Cmd.list's testInvariants option in production code. This should only be used in tests.");
}
var testInvariants = options.testInvariants,
rest = _objectWithoutProperties(options, ["testInvariants"]);
return Object.freeze(_objectSpread((_objectSpread3 = {}, _defineProperty(_objectSpread3, isCmdSymbol, true), _defineProperty(_objectSpread3, "type", cmdTypes.LIST), _defineProperty(_objectSpread3, "cmds", cmds), _defineProperty(_objectSpread3, "simulate", simulateList), _objectSpread3), rest));
}
function simulateMap(simulation) {
var _this = this;
var result = this.nestedCmd.simulate(simulation);
if (Array.isArray(result)) {
return result.map(function (action) {
return _this.tagger.apply(_this, _toConsumableArray(_this.args).concat([action]));
});
} else if (result) {
return this.tagger.apply(this, _toConsumableArray(this.args).concat([result]));
} else {
return null;
}
}
function map(nestedCmd, tagger) {
var _Object$freeze3;
if (process.env.NODE_ENV !== 'production') {
(0, _utils.throwInvariant)(isCmd(nestedCmd), 'Cmd.map: first argument to Cmd.map must be another Cmd');
(0, _utils.throwInvariant)(typeof tagger === 'function', 'Cmd.map: second argument to Cmd.map must be a function that returns an action');
}
for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
args[_key - 2] = arguments[_key];
}
return Object.freeze((_Object$freeze3 = {}, _defineProperty(_Object$freeze3, isCmdSymbol, true), _defineProperty(_Object$freeze3, "type", cmdTypes.MAP), _defineProperty(_Object$freeze3, "tagger", tagger), _defineProperty(_Object$freeze3, "nestedCmd", nestedCmd), _defineProperty(_Object$freeze3, "args", args), _defineProperty(_Object$freeze3, "simulate", simulateMap), _Object$freeze3));
}
var none = Object.freeze((_Object$freeze4 = {}, _defineProperty(_Object$freeze4, isCmdSymbol, true), _defineProperty(_Object$freeze4, "type", cmdTypes.NONE), _defineProperty(_Object$freeze4, "simulate", function simulate() {
return null;
}), _Object$freeze4));
var _default = {
run: run,
action: action,
setTimeout: setTimeoutCmd,
setInterval: setIntervalCmd,
clearTimeout: clearTimeoutCmd,
clearInterval: clearIntervalCmd,
list: list,
map: map,
none: none,
dispatch: dispatchSymbol,
getState: getStateSymbol
};
exports["default"] = _default;