@paprika/seducer
Version:
Seducer (simple reducer) is a wrapper on top of React.useReducer, making it easier to use
128 lines (109 loc) • 5.39 kB
JavaScript
;
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = exports.reducer = void 0;
var _logger = _interopRequireDefault(require("./logger"));
/**
* Summary: Reducer controls all actions and reduce them to create the nextState
*
* Description. Curry function execute (actions, hasLogger, interceptors) and returns nextState
*
* (actions, hasLogger, interceptors) =>
* @param {{[key]:(state: any, payload: any)=> any}} actions An object with {key: value} format that define an action of an state
* @param {boolean} hasLogger Allowed to print a friendly log with the previous and next action
* @param {{[key]:(state, payload)=> any}} interceptors An object with {key: value} which allows inversion of control by extending the actions object
*
* @return (state: any, action: {[key]: string, () => any}) => {...}
*
* @param any state The current state of the useReducer state can be anything
* @param {{key: {type:string, payload:any}}} action The action to be handle by the reducer and redirected to the their respective actions
*
* @return {any} nextState
*/
var reducer = function reducer(actions, hasLogger) {
var interceptors = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
return function (state, action) {
var isAValidAction = "type" in action && ([action.type] in actions || interceptors && [action.type] in interceptors);
if (isAValidAction) {
var nextState = function nextState() {
return actions[action.type](state, action.payload);
};
if (interceptors && [action.type] in interceptors) {
return handleInterceptors({
action: action,
actions: actions,
hasLogger: hasLogger,
interceptors: interceptors,
nextState: nextState,
state: state
});
}
return handleRegularRegularReducerFlow({
action: action,
hasLogger: hasLogger,
nextState: nextState,
state: state
});
}
throw new Error("The type \"".concat(action.type, "\" lacks of an action implementation, did you forget to add it: \n").concat(action.type, "(state, payload) { \n return state;\n} \n\nto your action object"));
};
};
/**
* Summary: Seducer permits to implement inversion of control without exposing the internal reducer and instead allowing the consumer to
* extend its current action object, this has three benefits:
*
* First: Abstract the concept of a reducer so the developer doesn't have to deal with
*
* Second: Is quite simple to understand the concept of function and it's easy to explain to another developer that to override a function
* has to declare another function with the same name, this is pretty common to do in OOP.
*
* Third: In order to achieve inversion of control the library doesn't requires to export their internal reducer to the consumer
* instead is transparent to them by simply overriding the already created actions.
* In case duplication exists a third parameter will be sent to the action (state, payload, nextState) is
* which is a function that the consumer can executed to generate the default nextState value that the component would generate
* if wouldn't be intercepted.
*
*
* @param {{ [key: string], () => any }} action
* @param {{[key]:(state, payload)=> nextState}} actions
* @param {boolean} hasLogger
* @param {{[key]:(state, payload)=> nextState}} interceptors
* @param {any} nextState A function that when its call generate the nextState for a giving action.
* @param {any} state
*/
exports.reducer = reducer;
function handleInterceptors(_ref) {
var action = _ref.action,
actions = _ref.actions,
hasLogger = _ref.hasLogger,
interceptors = _ref.interceptors,
nextState = _ref.nextState,
state = _ref.state;
// if the interceptor action is overriding and original action
if (action.type in actions) {
var nextInterceptorState = interceptors[action.type](state, action.payload, nextState);
return hasLogger ? (0, _logger["default"])(state, nextInterceptorState, action, true) : nextInterceptorState;
} // if the action has been added as a new action
var nextInterceptorStateWithoutOverride = interceptors[action.type](state, action.payload);
return hasLogger ? (0, _logger["default"])(state, nextInterceptorStateWithoutOverride, action, true) : nextInterceptorStateWithoutOverride;
}
/**
* Summary: A regular call to get the nextState for the reducer depending on the action that has been pass down by the consumer
*
*
* @param {{ action: () => any, hasLogger: boolean, nextState: any, state: any}} options
* @return {any} the next state value
*/
function handleRegularRegularReducerFlow(_ref2) {
var action = _ref2.action,
hasLogger = _ref2.hasLogger,
nextState = _ref2.nextState,
state = _ref2.state;
return hasLogger ? (0, _logger["default"])(state, nextState(), action) : nextState();
}
var _default = reducer;
exports["default"] = _default;
//# sourceMappingURL=reducer.js.map