redux-motive
Version:
Simplify writing action creators, reducers and effects - without breaking redux.
216 lines (208 loc) • 8.93 kB
JavaScript
;
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;