UNPKG

typedux

Version:

Slightly adjusted Redux (awesome by default) for TS

383 lines 17.8 kB
var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spread = (this && this.__spread) || function () { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; (function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "immutable", "@3fv/logger-proxy", "../util", "shallowequal", "lodash/get", "lodash/clone", "../constants", "@3fv/prelude-ts", "../dev", "@3fv/guard", "../actions"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RootReducer = void 0; var Immutable = __importStar(require("immutable")); var logger_proxy_1 = require("@3fv/logger-proxy"); var util_1 = require("../util"); // import {getGlobalStateProvider} from '../actions/Actions' var shallowequal_1 = __importDefault(require("shallowequal")); var get_1 = __importDefault(require("lodash/get")); var clone_1 = __importDefault(require("lodash/clone")); var constants_1 = require("../constants"); var prelude_ts_1 = require("@3fv/prelude-ts"); var dev_1 = require("../dev"); var guard_1 = require("@3fv/guard"); var actions_1 = require("../actions"); var ActionIdCacheMax = 500, log = logger_proxy_1.getLogger(__filename); /** * Get leaf value *} * @param rootValue * @param leaf * @return {any} */ function getLeafValue(rootValue, leaf) { if (Immutable.Map.isMap(rootValue)) { return rootValue.get(leaf); } else { return get_1.default(rootValue, leaf); } } /** * RootReducer for typedux apps * * Maps leaf reducers and decorated reducers * to the appropriate state functions */ var RootReducer = /** @class */ (function () { /** * Create reducer * * @param rootStateType - type of root state, must be immutable map or record * @param reducers - list of all child reducers * @param store */ function RootReducer(store, rootStateType) { var _this = this; if (rootStateType === void 0) { rootStateType = null; } var reducers = []; for (var _i = 2; _i < arguments.length; _i++) { reducers[_i - 2] = arguments[_i]; } this.store = store; this.rootStateType = rootStateType; // Internal list of all leaf reducers this.reducers = []; // handled actions ids to avoid duplication this.handledActionIds = []; var leafs = []; reducers .filter(function (reducer) { return util_1.isFunction(reducer.leaf); }) .forEach(function (reducer) { var leaf = reducer.leaf(); if (leafs.includes(leaf)) { return; } leafs.push(leaf); _this.reducers.push(reducer); }); reducers .filter(function (reducer) { return !util_1.isFunction(reducer.leaf); }) .forEach(function (reducer) { return _this.reducers.push(reducer); }); } RootReducer.prototype.setOnError = function (onError) { this.onError = onError; return this; }; /** * Create default state * * @param defaultStateValue - if provided then its used as base for inflation * @returns {State} */ RootReducer.prototype.defaultState = function (defaultStateValue) { if (defaultStateValue === void 0) { defaultStateValue = null; } // LOAD THE STATE AND VERIFY IT IS Immutable.Map/Record var state = defaultStateValue || { type: "ROOT" }; // ITERATE REDUCERS & CREATE LEAF STATES this.reducers .filter(function (reducer) { return util_1.isFunction(reducer.leaf); }) .forEach(function (reducer) { var _a; var leaf = reducer.leaf(), leafDefaultState = getLeafValue(defaultStateValue, leaf); state = __assign(__assign({}, state), (_a = {}, _a[leaf] = reducer.defaultState(leafDefaultState || {}), _a)); }); return state; }; /** * Create a generic handler for dispatches * * @returns {(state:S, action:ReduxAction)=>S} */ RootReducer.prototype.makeGenericHandler = function () { var _this = this; return function (state, action) { return _this.handle(state, action); }; }; /** * Handle action message * * @param state * @param action * @returns {State} */ RootReducer.prototype.handle = function (state, action) { var e_1, _a; var _b, _c; // Check if action has already been processed if (action.id && this.handledActionIds.includes(action.id)) { if (typeof console !== "undefined" && console.trace) { console.trace("Duplicate action received: " + action.leaf + "/" + action.type + ", " + action.id, action); } return state; } // Push action id to the handled list else if (action.id) { this.handledActionIds.unshift(action.id); if (this.handledActionIds.length > ActionIdCacheMax) { this.handledActionIds.length = ActionIdCacheMax; } } try { /** * Tracks whether the overall state has changed */ var hasChanged_1 = false; // Guard state type as immutable if (!state) { state = this.defaultState(state); hasChanged_1 = true; } /** * Create a change detector func that evaluates * a leaf for changes and updates (and sets changed flags) * as need for tracking * * @param leaf * @param currentState * @param updateState * @param changed */ var createChangeDetector_1 = function (leaf, currentState, updateState, changed) { return function (newReducerState) { if (!newReducerState) { throw new Error("New reducer state is null for leaf " + leaf); } var noMatch = !shallowequal_1.default(currentState, newReducerState); if (noMatch) { changed.set(); updateState(clone_1.default(newReducerState)); } }; }; // Store a ref to the original state object var stateMap = state; // Hold the interim state in `tempState` var tempState_1 = __assign({}, stateMap); // Find the action registration var actionReg_1 = (_c = (_b = this.store) === null || _b === void 0 ? void 0 : _b.actionContainer) === null || _c === void 0 ? void 0 : _c.getAction(action.leaf, action.type); // Is the reg invalid, i.e. reg not found and leaf + type set var actionRegInvalid = !actionReg_1 && [action.leaf, action.type].every(guard_1.isString); if (dev_1.isDev && log.isDebugEnabled() && actionRegInvalid) { log.warn("Unable to find action registration for: " + actions_1.createLeafActionType(action.leaf, action.type), action); } if (util_1.isFunction(actionReg_1 === null || actionReg_1 === void 0 ? void 0 : actionReg_1.action)) { prelude_ts_1.Option.ofNullable(tempState_1[action.leaf]).ifSome(function (reducerState) { var _a; var leaf = action.leaf, changed = new util_1.Flag(), checkReducerStateChange = createChangeDetector_1(leaf, reducerState, function (newState) { var _a; tempState_1 = __assign(__assign({}, tempState_1), (_a = {}, _a[leaf] = newState, _a)); hasChanged_1 = true; }, changed); // ActionMessage.reducers PROVIDED if (log.isDebugEnabled() && dev_1.isDev) { log.debug("Action type supported", action.leaf, action.type); } if (action.stateType && reducerState instanceof action.stateType) { get_1.default(action, "reducers", []).forEach(function (actionReducer) { return checkReducerStateChange(actionReducer(reducerState, action)); }); } // IF @ActionReducer REGISTERED if (((_a = actionReg_1 === null || actionReg_1 === void 0 ? void 0 : actionReg_1.options) === null || _a === void 0 ? void 0 : _a.isReducer) === true) { prelude_ts_1.Option.ofNullable(actionReg_1.action.apply(actionReg_1, __spread([null], action.args))) .filter(util_1.isFunction) .match({ None: function () { throw new Error("Action reducer did not return a function: " + actionReg_1.type); }, Some: function (reducerFn) { if (log.isDebugEnabled() && dev_1.isDev) { log.debug("Calling action reducer: " + actionReg_1.fullName); } checkReducerStateChange(reducerFn(reducerState, tempState_1)); } }); } }); } var _loop_1 = function (reducer) { var _a; if (util_1.isFunction(reducer)) { var simpleReducer = reducer; var simpleState = simpleReducer(tempState_1, action); if (simpleState !== tempState_1) { tempState_1 = simpleState; hasChanged_1 = true; } return "continue"; } var // Get the reducer leaf leaf = reducer.leaf(), // Get Current RAW state rawLeafState = tempState_1[leaf], // Shape it for the reducer startReducerState = rawLeafState, stateChangeDetected = new util_1.Flag(); var reducerState = startReducerState; try { /** * Check the returned state from every handler for changes * * @param newReducerState */ var checkReducerStateChange = createChangeDetector_1(leaf, reducerState, function (newState) { reducerState = newState; }, stateChangeDetected); // Check internal actions if (constants_1.INTERNAL_ACTIONS.includes(action.type)) { if (log.isDebugEnabled() && dev_1.isDev) { log.debug("Sending init event to " + leaf + " - internal action received " + action.type); } if (constants_1.INTERNAL_ACTION.INIT === action.type && reducer.init) { checkReducerStateChange(reducer.init(startReducerState)); } } // Check leaf of reducer and action to see if this reducer handles the supplied action if (action.leaf && action.leaf !== leaf) { return "continue"; } // CHECK REDUCER.HANDLE if (reducer.handle) { checkReducerStateChange(reducer.handle(reducerState, action)); } // CHECK ACTUAL REDUCER FOR SUPPORT if (util_1.isFunction(reducer[action.type])) { checkReducerStateChange(reducer[action.type].apply(reducer, __spread([reducerState], action.args))); } } catch (err) { log.error("Error occurred on reducer leaf " + leaf, err); if (reducer.handleError) { reducer.handleError(startReducerState, action, err); } this_1.onError && this_1.onError(err, reducer); } if (stateChangeDetected) { tempState_1 = __assign(__assign({}, tempState_1), (_a = {}, _a[leaf] = reducerState, _a)); hasChanged_1 = true; } }; var this_1 = this; try { // Iterate leaves and execute actions for (var _d = __values(this.reducers), _e = _d.next(); !_e.done; _e = _d.next()) { var reducer = _e.value; _loop_1(reducer); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_e && !_e.done && (_a = _d.return)) _a.call(_d); } finally { if (e_1) throw e_1.error; } } if (log.isDebugEnabled() && dev_1.isDev) { log.debug("Has changed after all reducers", hasChanged_1, "states equal", shallowequal_1.default(tempState_1, state)); } return (hasChanged_1 ? tempState_1 : state); } catch (err) { log.error("Error bubbled to root reducer", err); // If error handler exists then use it if (this.onError) { this.onError && this.onError(err); return state; } // Otherwise throw throw err; } }; return RootReducer; }()); exports.RootReducer = RootReducer; // Export the RootReducer class as the default exports.default = RootReducer; }); // export default (state:any,action:any):any => { // return rootReducer.handle(state as DefaultStateType, action as ActionMessage<any>) // } //# sourceMappingURL=RootReducer.js.map