UNPKG

@gongt/ts-stl-client

Version:
201 lines 7.96 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const check_environment_1 = require("@gongt/ts-stl-library/check-environment"); const create_logger_1 = require("@gongt/ts-stl-library/debug/create-logger"); const levels_1 = require("@gongt/ts-stl-library/debug/levels"); function callAll(reducers) { return function callAllWrapper(part, state, action) { let changed = false; for (const reducer of reducers) { debug('[all] call reducer (%s): %s', reducers.length, reducer.displayName || reducer.name); const r = reducer(part, state, action); if (r) { debug(' state changed.'); changed = true; } } return changed; }; } function callOnlyOne(reducers, storeName) { return function callOneWrapper(part, state, action) { for (const reducer of reducers) { debug('[one] call reducer: %s -> %s', storeName, reducer.displayName || reducer.name); const ret = reducer(state[storeName], action.payload, action); if (ret) { debug(' action handled: %O', ret); if (state[storeName] !== ret) { state[storeName] = ret; } return true; } } return false; }; } function combineAll(reducers) { const ret = {}; debugStart('Init Actions'); const debugEnd = debugStart.enabled ? console.groupEnd.bind(console) : () => null; const statics = []; for (const act of Object.keys(reducers)) { ret[act] = {}; const allCallbackCurrentAct = []; for (const sto of Object.keys(reducers[act])) { const globals = reducers[act][sto].global; const locals = reducers[act][sto].local; if (locals.length) { ret[act][sto] = callOnlyOne(locals, sto); if (debugStart.enabled) { statics.push({ action: act, store: sto, type: 'local', listeners: locals.length, }); } } if (globals.length) { allCallbackCurrentAct.push(callOnlyOne(globals, sto)); if (debugStart.enabled) { statics.push({ action: act, store: sto, type: 'global', listeners: globals.length, }); } } } if (allCallbackCurrentAct.length) { ret[act]['*'] = callAll(allCallbackCurrentAct); if (debugStart.enabled) { statics.push({ action: act, store: '*', type: 'global', listeners: allCallbackCurrentAct.length, }); } } } if (debugStart.enabled) { console.table(statics); } debugEnd(); return ret; } function createStructure(reducers) { const data = {}; for (const info of reducers) { const { actionName: act, storeName: sto } = info; if (!data[act]) { data[act] = {}; } if (!data[act][sto]) { data[act][sto] = { local: [], global: [] }; } const mod = info.global ? 'global' : 'local'; data[act][sto][mod].push(info.callback); } return data; } function reducerFromNative(native) { if (native['__wrappedNativeReducer']) { return native; } const nativeReducerWrapper = function (state, action, rawAction) { debug('call native reducer: %s[%O]', native['displayName'] || native.name, native); const ret = native(state, rawAction); if (ret === state) { return undefined; } return ret; }; nativeReducerWrapper['displayName'] = `nativeReduce(${native['displayName'] || native.name})`; nativeReducerWrapper['__wrappedNativeReducer'] = true; return nativeReducerWrapper; } exports.reducerFromNative = reducerFromNative; const debugStart = create_logger_1.createLogger(levels_1.LOG_LEVEL.DEBUG, 'reducer'); if (check_environment_1.IS_CLIENT) { debugStart.fn = console.groupCollapsed.bind(console); } const debug = create_logger_1.createLogger(levels_1.LOG_LEVEL.INFO, 'reducer'); function MyCombineReducers(reducers, toplevel) { for (const item of reducers) { if (!item.actionName || !item.storeName || !item.callback) { console.error(item); throw new TypeError('final check: invalid reducer. more info see console.'); } } const reducersData = createStructure(reducers); const reducersCombine = combineAll(reducersData); // const storeList = reducers.map(info => info.storeName); return (state, action) => { if (!action || !action.type) { throw new TypeError('dispatching action without type.'); } debugStart('action: %s @ %s', action.type, action.virtualStorage || 'Nil'); const debugEnd = debugStart.enabled ? console.groupEnd.bind(console) : () => null; debug(action); try { if (toplevel) { // topLevel: original redux top level style reducer const newState = toplevel(state, action); if (state !== newState) { debug('handled by top level reducer - finish'); debugEnd(); return newState; } } let { type: actionType, virtualStorage: store, payload } = action; if (!reducersCombine[actionType]) { debug('unknown action - finish'); debugEnd(); return state; } if (!action.hasOwnProperty('payload')) { debug('action has no payload'); debugEnd(); return state; // this is normal action } let changed = false; const currentReducers = reducersCombine[actionType]; const storeName = store; debug('sub store name: %s', storeName); /** * global reducers: * only call reducer witch: * 1. action is watching by reducer * if any reducer modified the state: * NO any more reducer will called within this virtual store * every action may or may-not call multiple global reducer. * every action will call at most only one global reducer on each virtual store */ const global = currentReducers['*']; if (global) { // global: call any store's reducer, but debug(' -> call global reducers'); const thisChanged = global(storeName, state, action); changed = thisChanged || changed; } else { debug(' -> no global reducer'); } /** * local reducers: * only call reducer witch: * 1. action is watching by reducer * 2. action.store equals to reducer.store * if any reducer modified the state: * NO any more reducer will called * every action will only call one local reducer. */ const local = currentReducers[store]; if (local) { debug(' -> call local reducers'); const thisChanged = local(storeName, state, action); changed = thisChanged || changed; } else { debug(' -> no local reducer'); } debug('state %s', changed ? 'changed' : 'NOT changed'); debugEnd(); return changed ? Object.assign({}, state) : state; } catch (e) { debugEnd(); debugEnd(); debugEnd(); debug('error while processing action: %s', e ? e.message : 'no info'); throw e; } }; } exports.MyCombineReducers = MyCombineReducers; //# sourceMappingURL=combine-reducers.js.map