diff --git a/modules/eslint-plugin/spec/rules/no-dispatch-in-effects.spec.ts b/modules/eslint-plugin/spec/rules/no-dispatch-in-effects.spec.ts index c740bdc4b4..fd6e05e226 100644 --- a/modules/eslint-plugin/spec/rules/no-dispatch-in-effects.spec.ts +++ b/modules/eslint-plugin/spec/rules/no-dispatch-in-effects.spec.ts @@ -51,6 +51,42 @@ class Ok2 { { dispatch: false }, ) } +}`, + ` +import { Store } from '@ngrx/store' +import { inject } from '@angular/core' + +class Ok3 { + private readonly actions = inject(Actions); + private readonly store = inject(Store); + + effect = createEffect(() => this.actions.pipe( + ofType('PING'), + tap(() => ({ type: 'PONG' })) + )) +}`, + ` +import { Store } from '@ngrx/store' +import { inject } from '@angular/core' + +class Ok4 { + readonly effect: CreateEffectMetadata + private readonly actions = inject(Actions); + private readonly store$ = inject(Store); + + constructor() { + this.effect = createEffect( + () => ({ scheduler = asyncScheduler } = {}) => + this.actions.pipe( + ofType(customerActions.remove), + tap(() => { + customObject.dispatch({ somethingElse: true }) + return customerActions.removeSuccess() + }), + ), + { dispatch: false }, + ) + } }`, ]; @@ -277,6 +313,258 @@ class NotOk3 { ) } + ngOnDestroy() { + store.dispatch() + } +}`, + }, + ], + } + ), + fromFixture( + ` +import { Store } from '@ngrx/store' +import { inject } from '@angular/core' + +class NotOk4 { + private actions = inject(Actions); + private store = inject(Store); + + effect = createEffect( + () => { + return this.actions.pipe( + ofType(someAction), + tap(() => this.store.dispatch(awesomeAction())), + ~~~~~~~~~~~~~~~~~~~ [${noDispatchInEffects} suggest] + ) + }, + { dispatch: false }, + ) +}`, + { + suggestions: [ + { + messageId: noDispatchInEffectsSuggest, + output: ` +import { Store } from '@ngrx/store' +import { inject } from '@angular/core' + +class NotOk4 { + private actions = inject(Actions); + private store = inject(Store); + + effect = createEffect( + () => { + return this.actions.pipe( + ofType(someAction), + tap(() => (awesomeAction())), + ) + }, + { dispatch: false }, + ) +}`, + }, + ], + } + ), + fromFixture( + ` +import { Store } from '@ngrx/store' +import { inject } from '@angular/core' + +class NotOk5 { + private readonly actions = inject(Actions); + private readonly store = inject(Store); + readonly effect = createEffect(() => condition ? this.actions.pipe( + ofType(userActions.add), + tap(() => { + return this.store.dispatch(userActions.addSuccess) + ~~~~~~~~~~~~~~~~~~~ [${noDispatchInEffects} suggest] + }) + ) : this.actions.pipe()) +}`, + { + suggestions: [ + { + messageId: noDispatchInEffectsSuggest, + output: ` +import { Store } from '@ngrx/store' +import { inject } from '@angular/core' + +class NotOk5 { + private readonly actions = inject(Actions); + private readonly store = inject(Store); + readonly effect = createEffect(() => condition ? this.actions.pipe( + ofType(userActions.add), + tap(() => { + return (userActions.addSuccess) + }) + ) : this.actions.pipe()) +}`, + }, + ], + } + ), + fromFixture( + ` +import { Store } from '@ngrx/store' +import { inject } from '@angular/core' + +class NotOk6 { + private readonly actions = inject(Actions); + private readonly store = inject(Store); + + effect = createEffect( + () => ({ debounce = 200 } = {}) => + this.actions.pipe( + ofType(actions.ping), + tap(() => { + return this.customName.dispatch(/* you shouldn't do this */ actions.pong()) + ~~~~~~~~~~~~~~~~~~~~~~~~ [${noDispatchInEffects} suggest] + }), + ), + ) +}`, + { + suggestions: [ + { + messageId: noDispatchInEffectsSuggest, + output: ` +import { Store } from '@ngrx/store' +import { inject } from '@angular/core' + +class NotOk6 + private readonly actions = inject(Actions); + private readonly store = inject(Store); + + effect = createEffect( + () => ({ debounce = 200 } = {}) => + this.actions.pipe( + ofType(actions.ping), + tap(() => { + return (/* you shouldn't do this */ actions.pong()) + }), + ), + ) +}`, + }, + ], + } + ), + fromFixture( + ` +import { Store } from '@ngrx/store' +import { inject } from '@angular/core' + +class NotOk7 { + readonly effect : CreateEffectMetadata + readonly effect : CreateEffectMetadata + private readonly actions = inject(Actions); + private readonly store = inject(Store); + private readonly store$ = inject(Store); + + constructor() { + this.effect = createEffect( + () => + this.actions.pipe( + ofType(bookActions.load), + map(() => { + this.store$.dispatch(bookActions.loadSuccess());// you shouldn't do this + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [${noDispatchInEffects} suggest 0] + return somethingElse() + }), + ), + { dispatch: true, useEffectsErrorHandler: false, ...options }, + ) + this.effect = createEffect( + () => + this.actions.pipe( + ofType(bookActions.load), + tap(() => store.dispatch(bookActions.loadSuccess())) + ~~~~~~~~~~~~~~ [${noDispatchInEffects} suggest 1] + ), + ) + } + + ngOnDestroy() { + store.dispatch() + } +}`, + { + suggestions: [ + { + messageId: noDispatchInEffectsSuggest, + output: ` +import { Store } from '@ngrx/store' +import { inject } from '@angular/core' + +class NotOk7 { + readonly effect : CreateEffectMetadata + readonly effect : CreateEffectMetadata + private readonly actions = inject(Actions); + private readonly store = inject(Store); + private readonly store$ = inject(Store); + + constructor() { + this.effect = createEffect( + () => + this.actions.pipe( + ofType(bookActions.load), + map(() => { + ;// you shouldn't do this + return somethingElse() + }), + ), + { dispatch: true, useEffectsErrorHandler: false, ...options }, + ) + this.effect = createEffect( + () => + this.actions.pipe( + ofType(bookActions.load), + tap(() => store.dispatch(bookActions.loadSuccess())) + ), + ) + } + + ngOnDestroy() { + store.dispatch() + } +}`, + }, + { + messageId: noDispatchInEffectsSuggest, + output: ` +import { Store } from '@ngrx/store' +import { inject } from '@angular/core' + +class NotOk7 { + readonly effect : CreateEffectMetadata + readonly effect : CreateEffectMetadata + private readonly actions = inject(Actions); + private readonly store = inject(Store); + private readonly store$ = inject(Store); + + constructor() { + this.effect = createEffect( + () => + this.actions.pipe( + ofType(bookActions.load), + map(() => { + this.store$.dispatch(bookActions.loadSuccess());// you shouldn't do this + return somethingElse() + }), + ), + { dispatch: true, useEffectsErrorHandler: false, ...options }, + ) + this.effect = createEffect( + () => + this.actions.pipe( + ofType(bookActions.load), + tap(() => (bookActions.loadSuccess())) + ), + ) + } + ngOnDestroy() { store.dispatch() }