Source: reducer.js

/**
 * @module reducer
 */

/**
 * return set reducer with auto-reset logic
 * @param  {Object}   initialState initial state for reducer
 * @return {Function}              set reducer
 */
export function getSetReducer(initialState) {
  return function set(state, action) {
    if (action.reset) {
      return { ...initialState, ...action.state }
    }
    return { ...state, ...action.state }
  }
}

/**
 * return reset reduser, for reset state
 * @param  {Object}   initialState initial state for reducer
 * @return {Function}              reset reducer
 */
export function getResetReducer(initialState) {
  return function reset() {
    return initialState;
  }
}

/**
 * Create reducer by types hash
 * ...
 * createReducer({
 *   '@@user/ADD_PHOTO': function(state, action) {
 *     return { ...state, photo: action.photo }
 *   },
 *   //...
 * }, initialUserState);
 * ...
 * createReducer({
 *   [TYPES.ADD_PHOTO](state, action) {
 *     return { ...state, photo: action.photo }
 *   },
 *   //...
 * }, initialUserState, null, { set: TYPES.SET });
 *
 * @param  {Object} switches            hash with type => reducer values
 * @param  {Mixed}  [initialState=null] initial state
 * @param  {Object} [extentions=null]   sub hash with field name => reducer values for inner fields reducing
 * @param  {Object} [options=null]      options, set: SET_TYPE, reset: RESET_TYPE for auto create SET and RESET reducers
 * @return {Function}                   reducer
 */
export function createReducer(switches, initialState = null, extentions = null, options = null) {
  if (options && options.set && initialState) {
    switches[options.set] = getSetReducer(initialState);
  }
  if (options && options.reset && initialState) {
    switches[options.reset] = getResetReducer(initialState);
  }
  return function(state = initialState, action) {
    let nextState = state;
    if (switches[action.type]) {
      //TODO: add isFunction check
      nextState = switches[action.type](state, action);
    }
    if (extentions) {
      let extState = {};
      Object.keys(extentions).forEach(function(key) {
        const ext = extentions[key];
        if (nextState[key] && ext) {
          //TODO: add isFunction check
          extState[key] = ext(nextState[key], action);
        }
      });
      nextState = {
        ...nextState,
        ...extState
      }
    }
    return nextState;
  }
}

export default createReducer;