@sigi/core
Version:
Sigi core library
234 lines • 10.2 kB
JavaScript
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