UNPKG

typedux

Version:

Slightly adjusted Redux (awesome by default) for TS

236 lines 8.93 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ObservableStore = exports.processLeafReducersAndStates = void 0; const logger_proxy_1 = require("@3fv/logger-proxy"); const RootReducer_1 = __importDefault(require("../reducers/RootReducer")); // Vendor const redux_1 = require("redux"); require("symbol-observable"); const guard_1 = require("@3fv/guard"); const util_1 = require("../util"); const actions_1 = require("../actions"); const StateObserver_1 = __importDefault(require("./StateObserver")); const DefaultLeafReducer_1 = require("../reducers/DefaultLeafReducer"); const constants_1 = require("../constants"); const InternalState_1 = require("../internal/InternalState"); const DumbReducer_1 = __importDefault(require("../reducers/DumbReducer")); const selectors_1 = require("../selectors"); const get_1 = __importDefault(require("lodash/get")); const prelude_ts_1 = require("@3fv/prelude-ts"); const dev_1 = require("../dev"); const log = logger_proxy_1.getLogger(__filename); function processLeafReducersAndStates(leafReducersOrStates) { const leafReducers = leafReducersOrStates.filter(it => util_1.isFunction(guard_1.getValue(() => it.leaf))), leafStates = leafReducersOrStates.filter(it => !util_1.isFunction(guard_1.getValue(() => it.leaf)) && util_1.isString(guard_1.getValue(() => it.type))), otherReducers = leafReducersOrStates.filter(it => util_1.isFunction(it)); return [ ...otherReducers, ...leafReducers, ...leafStates.map(state => new DumbReducer_1.default(state)) ]; } exports.processLeafReducersAndStates = processLeafReducersAndStates; /** * Manage the redux store for RADS */ class ObservableStore { constructor(leafReducersOrStates, enhancer = undefined, rootStateType = undefined, defaultStateValue = undefined) { this.rootStateType = rootStateType; this.defaultStateValue = defaultStateValue; this.observers = []; this.actionFactories = new Map(); this.observable = () => { const store = this; return { /** * The minimal observable subscription method. * @param {Object} observer Any object that can be used as an observer. * The observer object should have a `next` method. * @returns {subscription} An object with an `unsubscribe` method that can * be used to unsubscribe the observable from the store, and prevent further * emission of values from the observable. */ subscribe(observer) { if (typeof observer !== "object" || observer === null) { throw new TypeError("Expected the observer to be an object."); } function observeState() { if (observer.next) { observer.next(store.getState()); } } observeState(); const unsubscribe = store.subscribe(observeState); return { unsubscribe }; }, [Symbol.observable]: store.observable }; }; this[Symbol.observable] = this.observable; this.actionContainer = new actions_1.ActionContainer(this); this.createRootReducer(ObservableStore.createInternalReducer(), ...processLeafReducersAndStates(leafReducersOrStates)); this.store = redux_1.createStore(this.rootReducerFn, this.rootReducer.defaultState(defaultStateValue), enhancer !== null && enhancer !== void 0 ? enhancer : (next => next)); this.subscribe(() => this.scheduleNotification()); } /** * Factory method for creating a new observable store * * @param enhancer * @returns {ObservableStore<S>} * @param rootStateType * @param defaultStateValue * @param leafReducersOrStates */ static createObservableStore(leafReducersOrStates, enhancer = undefined, rootStateType = undefined, defaultStateValue = undefined) { return new ObservableStore(leafReducersOrStates, enhancer, rootStateType, defaultStateValue); } /** * Create simple reducers * * @param {string | State} statesOrKeys * @returns {Array<State>} */ static makeSimpleReducers(...statesOrKeys) { return statesOrKeys .map(state => (util_1.isString(state) ? { type: state } : state)) .map(state => new DumbReducer_1.default(state)); } /** * Create a internal reducer * * @returns {DefaultLeafReducer<InternalState, ActionMessage<InternalState>>} */ static createInternalReducer() { return DefaultLeafReducer_1.DefaultLeafReducer.create(constants_1.INTERNAL_KEY, InternalState_1.InternalState); } setOnError(onError) { var _a; (_a = this.rootReducer) === null || _a === void 0 ? void 0 : _a.setOnError(onError); return this; } /** * Get a prepared set of actions * * @param keyOrCtor - class name of class constructor to search for */ getActions(keyOrCtor) { const key = util_1.isString(keyOrCtor) ? keyOrCtor : keyOrCtor.name; return prelude_ts_1.Option.ofNullable(this.actionFactories.get(key)).getOrCall(() => { if (util_1.isString(keyOrCtor)) { throw Error(`No registered actions with key: ${keyOrCtor}`); } const actions = new keyOrCtor(this); this.actionFactories.set(key, actions); return actions; }); } /** * Create a new root reducer * * @param leafReducers * @returns {any} */ createRootReducer(...leafReducers) { this.rootReducer = new RootReducer_1.default(this, this.rootStateType, ...leafReducers); this.rootReducerFn = this.rootReducer.makeGenericHandler(); return this.rootReducerFn; } /** * Retrieve the redux store under everything * * @returns {any} */ getReduxStore() { return this.store; } /** * Update the reducers */ replaceReducers(...leafReducers) { const rootReducerFn = this.createRootReducer(ObservableStore.createInternalReducer(), ...leafReducers); this.store.replaceReducer(rootReducerFn); } subscribe(listener) { return this.getReduxStore().subscribe(listener); } replaceReducer(nextReducer) { throw new Error("We don't play with no regular reducers ;)"); } /** * Retrieve the current state * @returns {*} */ getState() { return this.getReduxStore().getState(); } getInternalState() { return this.getState()[constants_1.INTERNAL_KEY]; } /** * Dispatch typed message * * @param action * @returns {A|undefined|IAction} */ dispatch(action) { return this.getReduxStore().dispatch(action); } /** * Schedule notifications to go out on next tick */ scheduleNotification() { let state = this.getState(); this.observers.forEach(listener => listener.onChange(state)); } /** * */ onChange() { this.scheduleNotification(); } /** * Create a new selector from the store's state */ selector() { return selectors_1.selectorChain(this, null); } observe(pathOrSelector, handler) { let selector; if (util_1.isString(pathOrSelector) || Array.isArray(pathOrSelector)) { const keyPath = pathOrSelector ? Array.isArray(pathOrSelector) ? pathOrSelector : pathOrSelector.split(".") : []; selector = ((state) => this.getValueAtPath(state, keyPath)); } else { selector = pathOrSelector; } let observer = new StateObserver_1.default(selector, handler); this.observers.push(observer); return () => { if (observer.removed) { if (log.isDebugEnabled() && dev_1.isDev) { log.debug("Already removed this observer", observer); } return; } this.observers.find((it, index) => { if (observer === it) { this.observers.splice(index, 1); return true; } return false; }); observer.removed = true; }; } getValueAtPath(state, keyPath) { return get_1.default(state, keyPath); } } exports.ObservableStore = ObservableStore; //# sourceMappingURL=ObservableStore.js.map