UNPKG

redux-motive

Version:

Simplify writing action creators, reducers and effects - without breaking redux.

216 lines (208 loc) 8.93 kB
'use strict'; function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } var arrayWithoutHoles = _arrayWithoutHoles; function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } var iterableToArray = _iterableToArray; function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } var nonIterableSpread = _nonIterableSpread; function _toConsumableArray(arr) { return arrayWithoutHoles(arr) || iterableToArray(arr) || nonIterableSpread(); } var toConsumableArray = _toConsumableArray; 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 defineProperty = _defineProperty; var _PROGRESSING, _INITIAL; var PROGRESS_STATE_PROP = 'progressing'; var ERROR_STATE_PROP = 'error'; var MOTIVE_PREFIX = '@@MOTIVE'; var FUNCOBJ_EFFECT_KEY = 'effect'; var META_MOTIVE_ASYNC = '@@motiveasync'; var META_MOTIVE_ARGS = '@@motiveargs'; var HANDLER_SUFFIXES = { START: 'START', END: 'END', ERROR: 'ERROR' }; var DEFAULT_STATES = { PROGRESSING: (_PROGRESSING = {}, defineProperty(_PROGRESSING, PROGRESS_STATE_PROP, true), defineProperty(_PROGRESSING, ERROR_STATE_PROP, null), _PROGRESSING), INITIAL: (_INITIAL = {}, defineProperty(_INITIAL, PROGRESS_STATE_PROP, false), defineProperty(_INITIAL, ERROR_STATE_PROP, null), _INITIAL) }; var DEFAULT_HANDLERS = { start: function start(state) { return Object.assign({}, state, DEFAULT_STATES.PROGRESSING); }, end: function end(state) { return Object.assign({}, state, DEFAULT_STATES.INITIAL); }, error: function error(state, _error) { var _Object$assign; return Object.assign({}, state, (_Object$assign = {}, defineProperty(_Object$assign, PROGRESS_STATE_PROP, false), defineProperty(_Object$assign, ERROR_STATE_PROP, _error), _Object$assign)); } }; function ReduxMotive(configuration) { if (!(this instanceof ReduxMotive)) { return new ReduxMotive(configuration); } var _configuration$config = configuration.config, config = _configuration$config === void 0 ? {} : _configuration$config, syncMotives = configuration.sync, asyncMotives = configuration.async; if (!(syncMotives || asyncMotives)) { throw new Error("Expected props 'sync' or 'async' to be defined for the Motive."); } var actionCreators = {}; var reducersMap = {}; var PREFIX = intentPrefix(config.prefix || ''); var defaultHandlers = config && config.handlers || DEFAULT_HANDLERS; var bindAsMotive = memoizeFirst(constructEffectMotive); function extractActionCreatorAndReducerFromSyncMotive(syncMotiveKey) { var ACTION_TYPE = "".concat(PREFIX, "/").concat(snakeCase(syncMotiveKey)); var syncMotiveFunc = syncMotives[syncMotiveKey]; function syncMotiveActionCreator() { return createMotiveAction(ACTION_TYPE, defineProperty({}, META_MOTIVE_ARGS, Array.prototype.slice.call(arguments))); } syncMotiveActionCreator.ACTION_TYPE = ACTION_TYPE; function syncMotiveReducer(state, action) { return syncMotiveFunc.apply(void 0, [state].concat(toConsumableArray(action.meta[META_MOTIVE_ARGS]))); } actionCreators[syncMotiveKey] = syncMotiveActionCreator; reducersMap[ACTION_TYPE] = syncMotiveReducer; } function extractActionCreatorsAndReducerFromAsyncMotive(asyncMotiveKey) { var _asyncMotiveReducers; var ACTION_TYPE = "".concat(PREFIX, "/").concat(snakeCase(asyncMotiveKey)); var ACTION_TYPE_START = "".concat(ACTION_TYPE, "/").concat(HANDLER_SUFFIXES.START); var ACTION_TYPE_END = "".concat(ACTION_TYPE, "/").concat(HANDLER_SUFFIXES.END); var ACTION_TYPE_ERROR = "".concat(ACTION_TYPE, "/").concat(HANDLER_SUFFIXES.ERROR); var asyncMotiveConfig = asyncMotives[asyncMotiveKey]; var asyncMotiveFunc; var asyncMotiveHandlers = defaultHandlers; var hitAsyncConfig = !(asyncMotiveConfig instanceof Function); if (hitAsyncConfig) { asyncMotiveHandlers = asyncMotiveConfig.handlers || asyncMotiveHandlers; asyncMotiveFunc = asyncMotiveConfig[FUNCOBJ_EFFECT_KEY]; } else { asyncMotiveFunc = asyncMotiveConfig; } function asyncMotiveActionCreator() { var args = Array.prototype.slice.call(arguments); return function asyncMotiveThunk(dispatch, getState) { var meta = defineProperty({}, META_MOTIVE_ARGS, args); dispatch(createAsyncAction(ACTION_TYPE_START, meta)); var boundMotive = bindAsMotive(actionCreators, dispatch, getState); asyncMotiveFunc.apply(void 0, [boundMotive].concat(toConsumableArray(args))).then(function () { dispatch(createAsyncAction(ACTION_TYPE_END, meta)); }).catch(function (err) { dispatch(createAsyncAction(ACTION_TYPE_ERROR, meta, err)); }); }; } asyncMotiveActionCreator.ACTION_TYPE_START = ACTION_TYPE_START; asyncMotiveActionCreator.ACTION_TYPE_END = ACTION_TYPE_END; asyncMotiveActionCreator.ACTION_TYPE_ERROR = ACTION_TYPE_ERROR; var asyncMotiveReducers = (_asyncMotiveReducers = {}, defineProperty(_asyncMotiveReducers, ACTION_TYPE_START, function (state, action) { var _asyncMotiveHandlers; return (_asyncMotiveHandlers = asyncMotiveHandlers).start.apply(_asyncMotiveHandlers, [state].concat(toConsumableArray(action.meta[META_MOTIVE_ARGS]))); }), defineProperty(_asyncMotiveReducers, ACTION_TYPE_END, function (state, action) { var _asyncMotiveHandlers2; return (_asyncMotiveHandlers2 = asyncMotiveHandlers).end.apply(_asyncMotiveHandlers2, [state].concat(toConsumableArray(action.meta[META_MOTIVE_ARGS]))); }), defineProperty(_asyncMotiveReducers, ACTION_TYPE_ERROR, function (state, action) { var _asyncMotiveHandlers3; return (_asyncMotiveHandlers3 = asyncMotiveHandlers).error.apply(_asyncMotiveHandlers3, [state, action.payload].concat(toConsumableArray(action.meta[META_MOTIVE_ARGS]))); }), _asyncMotiveReducers); actionCreators[asyncMotiveKey] = asyncMotiveActionCreator; reducersMap[ACTION_TYPE_START] = asyncMotiveReducers[ACTION_TYPE_START]; reducersMap[ACTION_TYPE_END] = asyncMotiveReducers[ACTION_TYPE_END]; reducersMap[ACTION_TYPE_ERROR] = asyncMotiveReducers[ACTION_TYPE_ERROR]; } syncMotives && Object.keys(syncMotives).forEach(extractActionCreatorAndReducerFromSyncMotive); asyncMotives && Object.keys(asyncMotives).forEach(extractActionCreatorsAndReducerFromAsyncMotive); var initialState = defaultHandlers === DEFAULT_HANDLERS ? Object.assign({}, DEFAULT_STATES.INITIAL, config.initialState) : config.initialState; function motiveReducer() { var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialState; var action = arguments.length > 1 ? arguments[1] : undefined; return reducersMap[action.type] ? reducersMap[action.type](state, action) : state; } var motive = Object.assign({}, actionCreators); Object.defineProperty(motive, 'reducer', { value: motiveReducer }); return motive; } function snakeCase(str) { return str.replace(/\W/g, '_').replace(/(?!^.)[A-Z]/g, function (c) { return '_' + c.toUpperCase(); }).replace(/\w/g, function (c) { return c.toUpperCase(); }); } function intentPrefix(name) { return "".concat(MOTIVE_PREFIX).concat(name ? '/' : '').concat(snakeCase(name)); } function createMotiveAction(type, meta, payload) { var action = { type: type, meta: meta }; if (payload) action.payload = payload; return action; } function createAsyncAction() { var action = createMotiveAction.apply(void 0, arguments); action.meta[META_MOTIVE_ASYNC] = true; return action; } function memoizeFirst(func) { var cache = new WeakMap(); return function (arg) { if (!cache.has(arg)) { cache.set(arg, func.apply(null, arguments)); } return cache.get(arg); }; } function constructEffectMotive(actionCreators, dispatch, getState) { var motive = {}; Object.defineProperty(motive, 'dispatch', { value: dispatch }); Object.defineProperty(motive, 'getState', { value: getState }); return bindDispatchToActionCreators(motive, actionCreators, dispatch); } function bindDispatchToActionCreator(func, dispatch) { return function () { return dispatch(func.apply(null, arguments)); }; } function bindDispatchToActionCreators(target, actionCreators, dispatch) { return Object.keys(actionCreators).reduce(function (target, funcName) { target[funcName] = bindDispatchToActionCreator(actionCreators[funcName], dispatch); return target; }, target); } module.exports = ReduxMotive;