UNPKG

@sigi/core

Version:
234 lines 10.2 kB
import { produce } from 'immer'; import { merge } from 'rxjs'; import { map, filter, ignoreElements } from 'rxjs/operators'; import { hmrEnabled, hmrInstanceCache } from './hmr'; import { getDecoratedActions, getActionsToSkip } from './metadata'; import { Store } from './store'; import { NOOP_ACTION_TYPE_SYMBOL, GLOBAL_KEY_SYMBOL, TERMINATE_ACTION_TYPE_SYMBOL, RESET_ACTION_TYPE_SYMBOL, RETRY_ACTION_TYPE_SYMBOL, RETRY_KEY_SYMBOL, } from './symbols'; const _globalThis = typeof globalThis === 'undefined' ? typeof window === 'undefined' ? global : window : globalThis; const DEFAULT_STATE_KEY = 'defaultState'; export class EffectModule { get state$() { return this.store.state$; } get action$() { return this.store.action$; } get state() { return this.store.state; } constructor() { this.actionStreams = {}; this.retryActionsCreator = {}; this.actionNames = []; this.restoredFromSSR = false; this.createNoopAction = () => { return this.noop(); }; this.terminate = () => { return { type: TERMINATE_ACTION_TYPE_SYMBOL, payload: null, store: this.store }; }; this.reset = () => { return { type: RESET_ACTION_TYPE_SYMBOL, payload: null, store: this.store }; }; this.moduleName = Object.getPrototypeOf(this).moduleName; const reducer = this.combineReducers(); const definedActions = this.combineDefineActions(); const epic = this.combineEffects(); this.store = new Store(this.moduleName, reducer, epic); for (const name of definedActions) { ; this[name] = this.store.action$.pipe(filter(({ type }) => type === name), map(({ payload }) => payload)); } this.actions = { reset: this.reset, terminate: this.terminate, noop: this.noop, }; this.dispatchers = { reset: () => { this.store.dispatch(this.reset()); }, terminate: () => { this.store.dispatch(this.terminate()); }, noop: () => { this.store.dispatch(this.noop()); }, }; for (const name of this.actionNames) { const actionCreator = (payload) => ({ type: name, payload, store: this.store }); this.actions[name] = actionCreator; this.dispatchers[name] = (payload) => { this.store.dispatch(actionCreator(payload)); }; this.actionStreams[name] = this.store.action$.pipe(filter(({ type }) => type === name), map(({ payload }) => payload)); } if (typeof Proxy !== 'undefined') { const context = this; return new Proxy(this, { defineProperty(target, p, attr) { var _a; if (p === DEFAULT_STATE_KEY) { if (attr.set) { const rawSetter = attr.set; attr.set = function (value) { var _a; context.internalDefaultState = value; if (!context.store.ready) { context.store.setup(context.getDefaultState()); context.actionsToRetry = new Set(((_a = _globalThis[RETRY_KEY_SYMBOL]) === null || _a === void 0 ? void 0 : _a[this.moduleName]) || []); context.actionsToSkip = new Set(context.restoredFromSSR ? getActionsToSkip(context.constructor.prototype) || [] : []); } return rawSetter.call(this, value); }; } else if ('value' in attr) { context.internalDefaultState = attr.value; if (!context.store.ready) { context.store.setup(context.getDefaultState()); context.actionsToRetry = new Set(((_a = _globalThis[RETRY_KEY_SYMBOL]) === null || _a === void 0 ? void 0 : _a[context.moduleName]) || []); context.actionsToSkip = new Set(context.restoredFromSSR ? getActionsToSkip(context.constructor.prototype) || [] : []); } } } return Reflect.defineProperty(target, p, attr); }, set(target, p, value, receiver) { var _a; if (p === DEFAULT_STATE_KEY) { context.internalDefaultState = value; if (!context.store.ready) { context.store.setup(context.getDefaultState()); context.actionsToRetry = new Set(((_a = _globalThis[RETRY_KEY_SYMBOL]) === null || _a === void 0 ? void 0 : _a[context.moduleName]) || []); context.actionsToSkip = new Set(context.restoredFromSSR ? getActionsToSkip(context.constructor.prototype) || [] : []); } } return Reflect.set(target, p, value, receiver); }, }); } else { Object.defineProperty(this, DEFAULT_STATE_KEY, { set: (value) => { var _a; this.internalDefaultState = value; if (!this.store.ready) { this.store.setup(this.getDefaultState()); this.actionsToRetry = new Set(((_a = _globalThis[RETRY_KEY_SYMBOL]) === null || _a === void 0 ? void 0 : _a[this.moduleName]) || []); this.actionsToSkip = new Set(this.restoredFromSSR ? getActionsToSkip(this.constructor.prototype) || [] : []); } }, get: () => { return this.getDefaultState(); }, }); } } getActions() { return this.actions; } getAction$() { return this.actionStreams; } retryOnClient() { return this.retryActionsCreator; } noop() { return { type: NOOP_ACTION_TYPE_SYMBOL, payload: null, store: this.store }; } getDefaultState() { var _a, _b; return (_b = (_a = this.tryReadHmrState()) !== null && _a !== void 0 ? _a : this.tryReadSSRState()) !== null && _b !== void 0 ? _b : this.internalDefaultState; } tryReadSSRState() { const ssrCache = _globalThis[GLOBAL_KEY_SYMBOL]; if (ssrCache === null || ssrCache === void 0 ? void 0 : ssrCache[this.moduleName]) { this.restoredFromSSR = true; return ssrCache[this.moduleName]; } } tryReadHmrState() { if (hmrEnabled) { const hmrCache = hmrInstanceCache.get(this.moduleName); if (hmrCache) { const cachedState = hmrCache.state; hmrCache.dispose(); return cachedState; } } } combineEffects() { const effectKeys = getDecoratedActions(this.constructor.prototype, 'Effect'); if (!effectKeys || effectKeys.length === 0) { return (action$) => action$.pipe(ignoreElements()); } this.actionNames.push(...effectKeys); return (action$) => { return merge(...effectKeys.map((name) => { const effect = this[name]; const payload$ = action$.pipe(filter(({ type }) => type === name), filter((_, index) => { var _a; const skipCount = !this.actionsToRetry.has(name) && ((_a = this.actionsToSkip) === null || _a === void 0 ? void 0 : _a.has(name)) ? 1 : 0; return skipCount <= index; }), map(({ payload }) => payload)); this.retryActionsCreator[name] = () => ({ type: RETRY_ACTION_TYPE_SYMBOL, payload: { module: this, name, }, store: this.store, }); return effect.call(this, payload$); })); }; } combineReducers() { const reducerKeys = getDecoratedActions(this.constructor.prototype, 'Reducer', []); const immerReducerKeys = getDecoratedActions(this.constructor.prototype, 'ImmerReducer', []); this.actionNames.push(...reducerKeys, ...immerReducerKeys); const immerReducers = immerReducerKeys.reduce((acc, property) => { acc[property] = this[property].bind(this); return acc; }, {}); const reducers = reducerKeys.reduce((acc, property) => { acc[property] = this[property].bind(this); return acc; }, {}); return (prevState, action) => { const { type } = action; if (type === RESET_ACTION_TYPE_SYMBOL) { return this.getDefaultState(); } else { if (reducers[type]) { return reducers[type](prevState, action.payload); } else if (immerReducers[type]) { return produce(prevState, (draft) => immerReducers[type](draft, action.payload)); } } return prevState; }; } combineDefineActions() { const defineActionKeys = getDecoratedActions(this.constructor.prototype, 'DefineAction', []); this.actionNames.push(...defineActionKeys); return defineActionKeys; } } //# sourceMappingURL=module.js.map