@jbt/ng-rx
Version:
Configurable ngrx
817 lines (792 loc) • 21.3 kB
JavaScript
import { Subscriber, merge, isObservable, of } from 'rxjs';
import { mergeAll, filter, concatMap, concatAll, mergeMap, map } from 'rxjs/operators';
import { Repository, ObjectUtils } from '@jbt/utils';
import { combineReducers, createSelector, select, StoreModule, Store } from '@ngrx/store';
import { NgModule } from '@angular/core';
import { EffectsModule, Actions, EffectSources } from '@ngrx/effects';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @enum {string} */
const EFFECT_TYPE = {
ACTION: 'action',
SEQUENCE: 'sequence',
PARALLEL: 'parallel',
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const ERRORS = {
HEADER: `
MergeHotStreamHandlerArraySubscriber Error.
`,
NOT_A_FUNCTION: `
Supplied handler ignored: It is not a function
`,
NOT_AN_OBSERVABLE: `
Supplied handler ignored: It does not return an observable
`
};
class MergeHotStreamHandlerArraySubscriber extends Subscriber {
/**
* @param {?} sub
* @param {?} effects
*/
constructor(sub, effects) {
super(sub);
this._handlers = [];
this._handlers = effects || this._handlers;
}
/**
* @param {?} value
* @return {?}
*/
_next(value) {
/** @type {?} */
const inner$ = merge(this._handlers
.filter((/**
* @param {?} handler
* @return {?}
*/
(handler) => {
/** @type {?} */
const condition = typeof handler === 'function';
if (!condition) {
console.warn(ERRORS.HEADER + ERRORS.NOT_A_FUNCTION, handler);
}
return condition;
}))
.filter((/**
* @param {?} handler
* @return {?}
*/
(handler) => {
/** @type {?} */
const condition = isObservable(handler(value));
if (!condition) {
console.warn(ERRORS.HEADER + ERRORS.NOT_AN_OBSERVABLE, handler);
}
return condition;
}))
.map((/**
* @param {?} handler
* @return {?}
*/
(handler) => {
return handler(value);
}))).pipe(mergeAll());
inner$.subscribe({
next: (/**
* @param {?} v
* @return {?}
*/
(v) => {
this.destination.next(v);
})
});
}
}
if (false) {
/**
* @type {?}
* @private
*/
MergeHotStreamHandlerArraySubscriber.prototype._handlers;
}
/** @type {?} */
const mergeHotStreamHandlerArray = (/**
* @param {?} handlers
* @return {?}
*/
handlers => (/**
* @param {?} source
* @return {?}
*/
source => source.lift({
/**
* @param {?} sub
* @param {?} s
* @return {?}
*/
call(sub, s) {
s.subscribe(new MergeHotStreamHandlerArraySubscriber(sub, handlers));
}
})));
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* ***************************************************
*
* EffectsConfigurator
*
* ****************************************************
*/
class EffectsConfigurator {
/**
* @param {?} effectsRepository
* @param {?} actions$
* @param {?} store
*/
constructor(effectsRepository, actions$, store) {
this._setupMethodMap = {
[EFFECT_TYPE.SEQUENCE]: this._setUpSequentialEffect,
[EFFECT_TYPE.PARALLEL]: this._setUpParallelEffect,
[EFFECT_TYPE.ACTION]: this._setUpActionEffect
};
this._effects = [];
this._effectsRepository = effectsRepository;
this._effect = actions$.pipe(mergeHotStreamHandlerArray(this._effects), filter((/**
* @param {?} action
* @return {?}
*/
action => this._isAction(action))));
this._effect.subscribe((/**
* @param {?} action
* @return {?}
*/
(action) => {
store.dispatch(action);
}));
}
/**
* @param {?=} effectsConfig
* @return {?}
*/
addEffects(effectsConfig = []) {
effectsConfig.forEach((/**
* @param {?} config
* @return {?}
*/
config => {
/** @type {?} */
const method = this._setupMethodMap[config.type].call(this, config);
this._effects.push(method);
}));
}
/**
* @private
* @param {?} action
* @return {?}
*/
_isAction(action) {
return action && action.type && (typeof action.type === 'string');
}
/**
* @private
* @param {?} config
* @return {?}
*/
_setUpSequentialEffect(config) {
return (/**
* @param {?} action
* @return {?}
*/
(action) => of(action).pipe(filter((/**
* @param {?} action
* @return {?}
*/
action => this._filterAction(action, config))), concatMap((/**
* @param {?} action
* @return {?}
*/
action => config.handlers.map((/**
* @param {?} handler
* @return {?}
*/
handler => {
/** @type {?} */
const handlerFn = this._getHandler(handler, config);
return handlerFn(action, config);
})))), concatAll()));
}
/**
* @private
* @param {?} config
* @return {?}
*/
_setUpParallelEffect(config) {
return (/**
* @param {?} action
* @return {?}
*/
action => of(action).pipe(filter((/**
* @param {?} action
* @return {?}
*/
action => this._filterAction(action, config))), mergeMap((/**
* @param {?} action
* @return {?}
*/
action => config.handlers.map((/**
* @param {?} handler
* @return {?}
*/
handler => {
/** @type {?} */
const handlerFn = this._getHandler(handler, config);
return handlerFn(action, config);
})))), mergeAll()));
}
/**
* @private
* @param {?} config
* @return {?}
*/
_setUpActionEffect(config) {
return (/**
* @param {?} action
* @return {?}
*/
action => of(action).pipe(filter((/**
* @param {?} action
* @return {?}
*/
action => this._filterAction(action, config))), map((/**
* @param {?} action
* @return {?}
*/
action => {
return {
type: config.result,
payload: action['payload']
};
}))));
}
/**
* @private
* @param {?} action
* @param {?} effectsConfig
* @return {?}
*/
_filterAction(action, effectsConfig) {
/** @type {?} */
const isCause = effectsConfig.causes.indexOf(action.type) > -1;
/** @type {?} */
const isWildcard = effectsConfig.causes.indexOf('*') > -1;
return isWildcard || isCause;
}
/**
* @private
* @param {?} handler
* @param {?} config
* @return {?}
*/
_getHandler(handler, config) {
return (typeof handler === 'function')
? handler
: this._effectsRepository.get(handler);
}
}
if (false) {
/**
* @type {?}
* @private
*/
EffectsConfigurator.prototype._setupMethodMap;
/**
* @type {?}
* @private
*/
EffectsConfigurator.prototype._effectsRepository;
/**
* @type {?}
* @private
*/
EffectsConfigurator.prototype._effect;
/**
* @type {?}
* @private
*/
EffectsConfigurator.prototype._effects;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class EffectsRepository extends Repository {
constructor() {
super({
id: 'EffectsRepository',
fallbackKey: 'default'
});
this.addByMap({
default: (/**
* @return {?}
*/
() => of({ type: 'VOID' }))
});
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @record
*/
function ReducerSingleConfiguration() { }
if (false) {
/** @type {?} */
ReducerSingleConfiguration.prototype.id;
/** @type {?|undefined} */
ReducerSingleConfiguration.prototype.initialState;
/** @type {?|undefined} */
ReducerSingleConfiguration.prototype.handlers;
}
/**
* @record
*/
function ReducerGroupConfiguration() { }
if (false) {
/** @type {?} */
ReducerGroupConfiguration.prototype.id;
/** @type {?} */
ReducerGroupConfiguration.prototype.children;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class ReducersRepository extends Repository {
constructor() {
super({
id: 'ReducersRepository',
fallbackKey: 'default'
});
this.addByMap({
default: (/**
* @param {?} state
* @return {?}
*/
state => state)
});
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class ReducersConfigurator {
/**
* @param {?} store
* @param {?} reducersRepository
*/
constructor(store, reducersRepository) {
this._config = {};
this._store = store;
this._reducersRepository = reducersRepository;
}
/**
* @param {?} config
* @return {?}
*/
addReducers(config) {
this._config[config.id] = (this._config[config.id])
? ObjectUtils.mergeTrees(this._config[config.id], config)
: config;
Object.keys(this._config).forEach((/**
* @param {?} key
* @return {?}
*/
key => this._addReducer(this._config[key])));
}
/**
* @private
* @param {?} reducerConfig
* @return {?}
*/
_addReducer(reducerConfig) {
this._store.addReducer(reducerConfig.id, this._createReducerFn(reducerConfig));
}
/**
* @private
* @param {?} config
* @return {?}
*/
_createReducerFn(config) {
return (config.children)
? this._createReducersByConfig(config.children)
: (/**
* @param {?} state
* @param {?} action
* @return {?}
*/
(state, action) => this._mainReducer(state, action, config));
}
/**
* @private
* @param {?=} config
* @return {?}
*/
_createReducersByConfig(config = []) {
/** @type {?} */
const self = this;
return combineReducers(config.reduce((/**
* @param {?} reducers
* @param {?} item
* @return {?}
*/
(reducers, item) => {
reducers[item.id] = self._createReducerFn(item);
return reducers;
}), {}));
}
/**
* @param {?} state
* @param {?} action
* @param {?} config
* @return {?}
*/
_mainReducer(state, action, config) {
if (!state) {
return config.initialState;
}
config.handlers = config.handlers || {};
/** @type {?} */
const handler = this._getReducerHandlers(config.handlers[action.type]);
return handler(state, action);
}
/**
* @private
* @param {?} handler
* @return {?}
*/
_getReducerHandlers(handler) {
return (typeof handler === 'function')
? handler
: this._reducersRepository.get(handler);
}
}
if (false) {
/**
* @type {?}
* @private
*/
ReducersConfigurator.prototype._store;
/**
* @type {?}
* @private
*/
ReducersConfigurator.prototype._reducersRepository;
/**
* @type {?}
* @private
*/
ReducersConfigurator.prototype._config;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class DefaultReducerHandlers {
/**
* @param {?} state
* @param {?} action
* @return {?}
*/
static set(state, action) {
return action.payload;
}
/**
* @param {?} state
* @param {?} action
* @return {?}
*/
static override(state, action) {
return Object.assign({}, state, action.payload);
}
/**
* @param {?} state
* @param {?} action
* @return {?}
*/
static noop(state, action) {
return state;
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class Selector {
/**
* @param {?} path
* @return {?}
*/
static selectByPath(path) {
/** @type {?} */
const slices = path.split('.');
/** @type {?} */
const sel = slices
.slice(1)
.reduce((/**
* @param {?} acc
* @param {?} current
* @return {?}
*/
(acc, current) => createSelector(acc, (/**
* @param {?} state
* @return {?}
*/
state => state[current]))), createSelector((/**
* @param {?} state
* @return {?}
*/
state => state[slices[0]]), (/**
* @param {?} state
* @return {?}
*/
state => state)));
return select(sel);
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class State {
/**
* @param {?} store
* @param {?} reducersConfigurator
* @param {?} effectsConfigurator
* @param {?} reducersRepository
* @param {?} effectsRepository
*/
constructor(store, reducersConfigurator, effectsConfigurator, reducersRepository, effectsRepository) {
this._store = store;
this._reducersConfigurator = reducersConfigurator;
this._effectsConfigurator = effectsConfigurator;
this._reducersRepository = reducersRepository;
this._effectsRepository = effectsRepository;
}
/**
* @param {?} config
* @return {?}
*/
configure(config) {
if (config.state) {
this.configureReducers(config.state);
}
if (config.effects) {
this.configureEffects(config.effects);
}
}
/**
* @param {?} config
* @return {?}
*/
configureReducers(config) {
this._reducersConfigurator.addReducers(config);
}
/**
* @param {?} config
* @return {?}
*/
configureEffects(config) {
this._effectsConfigurator.addEffects(config);
}
/**
* @param {?} reducersMap
* @return {?}
*/
addReducerHandlers(reducersMap) {
this._reducersRepository.addByMap(reducersMap);
}
/**
* @param {?} effectsMap
* @return {?}
*/
addEffectHandlers(effectsMap) {
this._effectsRepository.addByMap(effectsMap);
}
/**
* @param {?} type
* @param {?=} payload
* @return {?}
*/
dispatch(type, payload) {
this._store.dispatch({
type: type,
payload: payload
});
}
/**
* @param {?} path
* @return {?}
*/
select(path) {
return this._store.pipe(Selector.selectByPath(path));
}
}
if (false) {
/**
* @type {?}
* @private
*/
State.prototype._store;
/**
* @type {?}
* @private
*/
State.prototype._reducersConfigurator;
/**
* @type {?}
* @private
*/
State.prototype._reducersRepository;
/**
* @type {?}
* @private
*/
State.prototype._effectsConfigurator;
/**
* @type {?}
* @private
*/
State.prototype._effectsRepository;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class ProviderFactory {
/**
* @param {?} store
* @param {?} reducersRepository
* @return {?}
*/
static createReducersConfigurator(store, reducersRepository) {
return new ReducersConfigurator(store, reducersRepository);
}
/**
* @param {?} effectsRepository
* @param {?} actions$
* @param {?} store
* @return {?}
*/
static createEffectsConfigurator(effectsRepository, actions$, store) {
return new EffectsConfigurator(effectsRepository, actions$, store);
}
}
class InternalsModule {
}
InternalsModule.decorators = [
{ type: NgModule, args: [{
imports: [
StoreModule.forRoot({}),
EffectsModule.forRoot([])
],
providers: [{
provide: ReducersConfigurator,
useFactory: ProviderFactory.createReducersConfigurator,
deps: [
Store,
ReducersRepository
]
}, {
provide: EffectsConfigurator,
useFactory: ProviderFactory.createEffectsConfigurator,
deps: [
EffectsRepository,
Actions,
Store,
EffectSources,
]
},
EffectsRepository,
ReducersRepository,
],
exports: [
StoreModule
]
},] }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} store
* @param {?} reducer
* @param {?} effects
* @param {?} reducersRepository
* @param {?} effectsRepository
* @return {?}
*/
function createState(store, reducer, effects, reducersRepository, effectsRepository) {
return new State(store, reducer, effects, reducersRepository, effectsRepository);
}
class StateModule {
/**
* @return {?}
*/
static forRoot() {
return {
ngModule: StateModule,
providers: [{
provide: State,
useFactory: createState,
deps: [
Store,
ReducersConfigurator,
EffectsConfigurator,
ReducersRepository,
EffectsRepository
]
}]
};
}
/**
* @return {?}
*/
static forChild() {
return {
ngModule: StateModule,
providers: []
};
}
}
StateModule.decorators = [
{ type: NgModule, args: [{
imports: [InternalsModule],
},] }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
export { EFFECT_TYPE, State, StateModule, createState as ɵa, EffectsConfigurator as ɵb, EffectsRepository as ɵc, ReducersRepository as ɵd, ReducersConfigurator as ɵe, ProviderFactory as ɵf, InternalsModule as ɵg };
//# sourceMappingURL=jbt-ng-rx.js.map