UNPKG

@datorama/akita-ng-effects

Version:

A Reactive State Management extension dealing with side effects.

245 lines (233 loc) 8.36 kB
import { __rest } from 'tslib'; import { ɵɵdefineInjectable, Injectable, InjectionToken, ɵɵinject, Inject, Optional, SkipSelf, NgModule, Injector } from '@angular/core'; import { Subject } from 'rxjs'; import { logAction } from '@datorama/akita'; import { takeUntil } from 'rxjs/operators'; export { action as createAction, payload, props } from 'ts-action'; export { ofType } from 'ts-action-operators'; class Actions extends Subject { dispatch(value) { this.logAction(value); this.next(value); } logAction(value) { const { type } = value, props = __rest(value, ["type"]); const hasPayload = Object.getOwnPropertyNames(props).length > 0; logAction(type, null, hasPayload ? props : null); } } Actions.ɵprov = ɵɵdefineInjectable({ factory: function Actions_Factory() { return new Actions(); }, token: Actions, providedIn: "root" }); Actions.decorators = [ { type: Injectable, args: [{ providedIn: 'root', },] } ]; const _ROOT_EFFECTS = new InjectionToken('@datorama/akita Internal Root Effects'); const ROOT_EFFECT_INSTANCES = new InjectionToken('@datorama/akita Root Effects'); const _FEATURE_EFFECTS = new InjectionToken('@datorama/akita Internal Feature Effects'); const FEATURE_EFFECT_INSTANCES = new InjectionToken('@datorama/akita Feature Effects'); class ModuleManager { constructor(actions$) { this.actions$ = actions$; this.effectInstanceSources = new WeakSet(); this.destroyEffects$ = new Subject(); } subscribeToEffects(effectInstance) { for (let key in effectInstance) { const property = effectInstance[key]; if (property.isEffect === true) { property.pipe(takeUntil(this.destroyEffects$)).subscribe((actionOrSkip) => { this.dispatchAction(property, actionOrSkip); }); } } } has(effect) { return this.effectInstanceSources.has(effect); } add(effect) { this.effectInstanceSources.add(effect); } dispatchAction(property, actionOrSkip) { if (property.dispatchAction && this.checkAction(actionOrSkip)) { this.actions$.dispatch(actionOrSkip); } } checkAction(action) { if (action.type) { return true; } throw new TypeError('Make sure to provide a valid action type or set the option {dispatch: false}'); } ngOnDestroy() { // modules aren't supposed to be destroyed; might not be needed this.destroyEffects$.next(); this.effectInstanceSources = new WeakSet(); } } ModuleManager.ctorParameters = () => [ { type: Actions } ]; ModuleManager.ɵprov = ɵɵdefineInjectable({ factory: function ModuleManager_Factory() { return new ModuleManager(ɵɵinject(Actions)); }, token: ModuleManager, providedIn: "root" }); ModuleManager.decorators = [ { type: Injectable, args: [{ providedIn: 'root', },] } ]; ModuleManager.ctorParameters = () => [ { type: Actions } ]; class EffectsRootModule { constructor(moduleManager, actions, rootEffects, parentModule) { this.moduleManager = moduleManager; this.actions = actions; this.parentModule = parentModule; this.rootGuard(); rootEffects.forEach((effect) => this.moduleManager.subscribeToEffects(effect)); } rootGuard() { if (this.parentModule) { throw new Error('EffectsRootModule is already loaded. Import it in the AppModule only'); } } } EffectsRootModule.ctorParameters = () => [ { type: ModuleManager }, { type: Actions }, { type: Array, decorators: [{ type: Inject, args: [ROOT_EFFECT_INSTANCES,] }] }, { type: EffectsRootModule, decorators: [{ type: Optional }, { type: SkipSelf }] } ]; EffectsRootModule.decorators = [ { type: NgModule } ]; EffectsRootModule.ctorParameters = () => [ { type: ModuleManager }, { type: Actions }, { type: Array, decorators: [{ type: Inject, args: [ROOT_EFFECT_INSTANCES,] }] }, { type: EffectsRootModule, decorators: [{ type: Optional }, { type: SkipSelf }] } ]; class EffectsFeatureModule { constructor(moduleManager, featureEffects) { this.moduleManager = moduleManager; featureEffects.forEach((group) => group.forEach((effect) => { this.moduleManager.subscribeToEffects(effect); })); } } EffectsFeatureModule.ctorParameters = () => [ { type: ModuleManager }, { type: Array, decorators: [{ type: Inject, args: [FEATURE_EFFECT_INSTANCES,] }] } ]; EffectsFeatureModule.decorators = [ { type: NgModule } ]; EffectsFeatureModule.ctorParameters = () => [ { type: ModuleManager }, { type: Array, decorators: [{ type: Inject, args: [FEATURE_EFFECT_INSTANCES,] }] } ]; class AkitaNgEffectsModule { static forRoot(rootEffects = []) { return { ngModule: EffectsRootModule, providers: [ ModuleManager, Actions, rootEffects, { provide: _ROOT_EFFECTS, useValue: [rootEffects], }, { provide: ROOT_EFFECT_INSTANCES, useFactory: createEffectInstances, deps: [Injector, _ROOT_EFFECTS, ModuleManager], }, ], }; } static forFeature(featureEffects = []) { return { ngModule: EffectsFeatureModule, providers: [ featureEffects, { provide: _FEATURE_EFFECTS, useValue: featureEffects, multi: true, }, { provide: FEATURE_EFFECT_INSTANCES, multi: true, useFactory: createEffectInstances, deps: [Injector, _FEATURE_EFFECTS, ModuleManager], }, ], }; } } AkitaNgEffectsModule.decorators = [ { type: NgModule, args: [{},] } ]; function createEffectInstances(injector, effectGroups, moduleManager) { const mergedEffects = []; for (const effectGroup of effectGroups) { mergedEffects.push(...effectGroup); } // todo we shouldn't use a map to avoid registering the effects twice; // fix the underlying issue for feature is called twice const effectInstances = mergedEffects.reduce((acc, effect) => { if (!moduleManager.has(effect)) { moduleManager.add(effect); acc.push(injector.get(effect)); } return acc; }, []); return effectInstances; } function setMetadata(effect, propertyName, effectOptions) { Object.defineProperty(effect, 'isEffect', { enumerable: true, configurable: false, writable: false, value: true, }); Object.defineProperty(effect, 'name', { enumerable: true, configurable: false, writable: false, value: propertyName, }); Object.defineProperty(effect, 'dispatchAction', { enumerable: true, configurable: false, writable: false, value: effectOptions.dispatch, }); } function Effect(options) { options = Object.assign({ dispatch: false }, options); return function (classProto, propKey) { let returnValue; Object.defineProperty(classProto, propKey, { get: function () { return returnValue; }, set: function (value) { setMetadata(value, propKey, options); returnValue = value; }, enumerable: true, }); }; } function createEffect(actions$, options) { const effect = actions$(); options = Object.assign({ dispatch: false }, options); setMetadata(effect, null, options); return effect; } /** * Generated bundle index. Do not edit. */ export { Actions, AkitaNgEffectsModule, Effect, EffectsRootModule, createEffect, createEffectInstances as ɵa, _ROOT_EFFECTS as ɵb, ROOT_EFFECT_INSTANCES as ɵc, _FEATURE_EFFECTS as ɵd, FEATURE_EFFECT_INSTANCES as ɵe, ModuleManager as ɵf, EffectsFeatureModule as ɵg }; //# sourceMappingURL=datorama-akita-ng-effects.js.map