diff --git a/modules/eslint-plugin/schematics/ng-add/schema.json b/modules/eslint-plugin/schematics/ng-add/schema.json index 924cd9df70..10d311a45b 100644 --- a/modules/eslint-plugin/schematics/ng-add/schema.json +++ b/modules/eslint-plugin/schematics/ng-add/schema.json @@ -10,10 +10,13 @@ "default": "all", "enum": [ "all", + "allTypedChecked", "component-store", "effects", + "effectsTypedChecked", "operators", "signals", + "signalsTypedChecked", "store" ], "x-prompt": { @@ -24,6 +27,10 @@ "value": "all", "label": "all" }, + { + "value": "allTypedChecked", + "label": "allTypedChecked" + }, { "value": "component-store", "label": "component-store" @@ -32,6 +39,10 @@ "value": "effects", "label": "effects" }, + { + "value": "effectsTypedChecked", + "label": "effectsTypedChecked" + }, { "value": "operators", "label": "operators" @@ -40,6 +51,10 @@ "value": "signals", "label": "signals" }, + { + "value": "signalsTypedChecked", + "label": "signalsTypedChecked" + }, { "value": "store", "label": "store" diff --git a/modules/eslint-plugin/scripts/generate-config.ts b/modules/eslint-plugin/scripts/generate-config.ts index de1e1b92d3..764ace494c 100644 --- a/modules/eslint-plugin/scripts/generate-config.ts +++ b/modules/eslint-plugin/scripts/generate-config.ts @@ -9,27 +9,52 @@ import { NgRxRule } from '../src/rule-creator'; const RULE_MODULE = '@ngrx'; const CONFIG_DIRECTORY = './modules/eslint-plugin/src/configs/'; - writeConfig('all', (_rule) => true); - writeConfig('store', (rule) => rule.meta.docs?.ngrxModule === 'store'); - writeConfig('effects', (rule) => rule.meta.docs?.ngrxModule === 'effects'); + const isModule = (rule: NgRxRule, moduleName: string) => + rule.meta.docs?.ngrxModule === moduleName; + const isTypeChecked = (rule: NgRxRule) => + rule.meta.docs?.requiresTypeChecking === true; + + writeConfig('all', (rule) => !isTypeChecked(rule)); + writeConfig('allTypeChecked', (_rule) => true); + + writeConfig( + 'store', + (rule) => isModule(rule, 'store') && !isTypeChecked(rule) + ); + + writeConfig( + 'effects', + (rule) => isModule(rule, 'effects') && !isTypeChecked(rule) + ); + writeConfig('effectsTypeChecked', (rule) => isModule(rule, 'effects')); + writeConfig( 'component-store', - (rule) => rule.meta.docs?.ngrxModule === 'component-store' + (rule) => isModule(rule, 'component-store') && !isTypeChecked(rule) ); + writeConfig( 'operators', - (rule) => rule.meta.docs?.ngrxModule === 'operators' + (rule) => isModule(rule, 'operators') && !isTypeChecked(rule) + ); + + writeConfig( + 'signals', + (rule) => isModule(rule, 'signals') && !isTypeChecked(rule) ); - writeConfig('signals', (rule) => rule.meta.docs?.ngrxModule === 'signals'); + writeConfig('signalsTypeChecked', (rule) => isModule(rule, 'signals')); async function writeConfig( configName: | 'all' + | 'allTypeChecked' | 'store' | 'effects' + | 'effectsTypeChecked' | 'component-store' | 'operators' - | 'signals', + | 'signals' + | 'signalsTypeChecked', predicate: (rule: NgRxRule) => boolean ) { const rulesForConfig = Object.entries(rulesForGenerate).filter( @@ -42,14 +67,6 @@ import { NgRxRule } from '../src/rule-creator'; }, {} ); - const requireParserOptions: null | Record = - rulesForConfig.some(([_, rule]) => rule.meta.docs?.requiresTypeChecking) - ? { - ecmaVersion: 2020, - sourceType: 'module', - project: './tsconfig.json', - } - : null; const tsCode = ` /** @@ -67,7 +84,6 @@ import { NgRxRule } from '../src/rule-creator'; name: 'ngrx/base', languageOptions: { parser, - sourceType: 'module', }, plugins: { '@ngrx': plugin, @@ -77,15 +93,6 @@ import { NgRxRule } from '../src/rule-creator'; name: 'ngrx/${configName}', languageOptions: { parser, - ${ - requireParserOptions - ? `parserOptions: ${JSON.stringify( - requireParserOptions, - null, - 2 - )},` - : '' - } }, rules: ${JSON.stringify(configRules, null, 2)} }, @@ -104,13 +111,6 @@ import { NgRxRule } from '../src/rule-creator'; plugins: ['@ngrx'], rules: configRules, }; - if (requireParserOptions) { - jsonConfig.parserOptions = { - ecmaVersion: 2020, - sourceType: 'module', - project: './tsconfig.json', - }; - } const jsonConfigFormatted = await format( JSON.stringify(jsonConfig, null, 2), { diff --git a/modules/eslint-plugin/spec/exported-rules.spec.ts b/modules/eslint-plugin/spec/exported-rules.spec.ts index 74ee253e73..beaa758225 100644 --- a/modules/eslint-plugin/spec/exported-rules.spec.ts +++ b/modules/eslint-plugin/spec/exported-rules.spec.ts @@ -22,18 +22,23 @@ describe('ESLint V8', () => { }); test('exports all configurations', () => { const configs = getAllConfigs(); - expect(configs.length).toBe(6); + expect(configs.length).toBe(9); }); }); describe('ESLint V9', () => { test('exports all rules ', () => { const rules = getAllRules(); - expect(Object.keys((configs.all[1] as any).rules).length).toBe( + expect(Object.keys((configs.allTypeChecked[1] as any).rules).length).toBe( rules.length ); }); + test('there is a difference between typed checke rules ', () => { + expect( + Object.keys((configs.allTypeChecked[1] as any).rules).length + ).toBeGreaterThan(Object.keys((configs.all[1] as any).rules).length); + }); test('exports all configurations', () => { - expect(Object.keys(configs).length).toBe(6); + expect(Object.keys(configs).length).toBe(9); }); }); diff --git a/modules/eslint-plugin/spec/rules/component-store/avoid-combining-component-store-selectors.spec.ts b/modules/eslint-plugin/spec/rules/component-store/avoid-combining-component-store-selectors.spec.ts index ac465b5d6a..1c4c489c21 100644 --- a/modules/eslint-plugin/spec/rules/component-store/avoid-combining-component-store-selectors.spec.ts +++ b/modules/eslint-plugin/spec/rules/component-store/avoid-combining-component-store-selectors.spec.ts @@ -49,7 +49,7 @@ class Ok { constructor(customStore: ComponentStore) { const movies = customStore.select((state) => state.movies); const selectedId = this.customStore.select((state) => state.selectedId); - + this.movie$ = this.customStore.select( this.movies$, this.selectedId$, @@ -208,7 +208,11 @@ class NotOk { }`), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: [...validConstructor(), ...validInject()], - invalid: [...invalidConstructor(), ...invalidInject()], -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: [...validConstructor(), ...validInject()], + invalid: [...invalidConstructor(), ...invalidInject()], + } +); diff --git a/modules/eslint-plugin/spec/rules/component-store/avoid-mapping-component-store-selectors.spec.ts b/modules/eslint-plugin/spec/rules/component-store/avoid-mapping-component-store-selectors.spec.ts index 01b6cfb316..e536c7c10c 100644 --- a/modules/eslint-plugin/spec/rules/component-store/avoid-mapping-component-store-selectors.spec.ts +++ b/modules/eslint-plugin/spec/rules/component-store/avoid-mapping-component-store-selectors.spec.ts @@ -43,7 +43,7 @@ class Ok { constructor(private customStore: ComponentStore) { const movies = customStore.select((state) => state.movies); this.firstMovie$ = customStore.select(movies, (movies) => movies[0]); - + this.movies$ = this.customStore.select((state) => state.movies); this.firstMovie$ = this.customStore.select(this.movies$, (movies) => movies[0]); } @@ -87,7 +87,7 @@ import { ComponentStore } from '@ngrx/component-store' class NotOk { readonly movies$ = this.customStore.select((state) => state.movies).pipe( - filter(Boolean), + filter(Boolean), map((movies) => movies) ~~~~~~~~~~~~~~~~~~~~~~~ [${messageId}] ) @@ -133,7 +133,11 @@ const invalidInject: () => InvalidTestCase[] = () => [ }`), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: [...validConstructor(), ...validInject()], - invalid: [...invalidConstructor(), ...invalidInject()], -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: [...validConstructor(), ...validInject()], + invalid: [...invalidConstructor(), ...invalidInject()], + } +); diff --git a/modules/eslint-plugin/spec/rules/component-store/require-super-ondestroy.spec.ts b/modules/eslint-plugin/spec/rules/component-store/require-super-ondestroy.spec.ts index 0805b03d3b..e3a5735468 100644 --- a/modules/eslint-plugin/spec/rules/component-store/require-super-ondestroy.spec.ts +++ b/modules/eslint-plugin/spec/rules/component-store/require-super-ondestroy.spec.ts @@ -115,7 +115,11 @@ class BooksStore extends ComponentStore implements OnDestroy { }`), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/component-store/updater-explicit-return-type.spec.ts b/modules/eslint-plugin/spec/rules/component-store/updater-explicit-return-type.spec.ts index cb89bc9cdf..4ee9de511a 100644 --- a/modules/eslint-plugin/spec/rules/component-store/updater-explicit-return-type.spec.ts +++ b/modules/eslint-plugin/spec/rules/component-store/updater-explicit-return-type.spec.ts @@ -212,7 +212,11 @@ class NotOk6 { }`), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: [...validConstructor(), ...validInject()], - invalid: [...invalidConstructor(), ...invalidInject()], -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: [...validConstructor(), ...validInject()], + invalid: [...invalidConstructor(), ...invalidInject()], + } +); diff --git a/modules/eslint-plugin/spec/rules/effects/avoid-cyclic-effects.spec.ts b/modules/eslint-plugin/spec/rules/effects/avoid-cyclic-effects.spec.ts index 9ad4eb9fa5..19e6e7c8c4 100644 --- a/modules/eslint-plugin/spec/rules/effects/avoid-cyclic-effects.spec.ts +++ b/modules/eslint-plugin/spec/rules/effects/avoid-cyclic-effects.spec.ts @@ -455,7 +455,11 @@ class Effect { }`), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: [...validConstructor(), ...validInject()], - invalid: [...invalidConstructor(), ...invalidInject()], -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: [...validConstructor(), ...validInject()], + invalid: [...invalidConstructor(), ...invalidInject()], + } +); diff --git a/modules/eslint-plugin/spec/rules/effects/no-dispatch-in-effects.spec.ts b/modules/eslint-plugin/spec/rules/effects/no-dispatch-in-effects.spec.ts index 82bb30ad20..930f6fb658 100644 --- a/modules/eslint-plugin/spec/rules/effects/no-dispatch-in-effects.spec.ts +++ b/modules/eslint-plugin/spec/rules/effects/no-dispatch-in-effects.spec.ts @@ -16,27 +16,27 @@ type Options = ESLintUtils.InferOptionsTypeFromRule; const validConstructor: () => (string | ValidTestCase)[] = () => [ ` import { Store } from '@ngrx/store' - + class Ok { readonly effect = somethingOutside(); }`, ` import { Store } from '@ngrx/store' - + class Ok1 { effect = createEffect(() => this.actions.pipe( ofType('PING'), tap(() => ({ type: 'PONG' })) )) - + constructor(private actions: Actions, private store: Store) {} }`, ` import { Store } from '@ngrx/store' - + class Ok2 { readonly effect: CreateEffectMetadata - + constructor(private actions: Actions, private store$: Store) { this.effect = createEffect( () => ({ scheduler = asyncScheduler } = {}) => @@ -591,7 +591,11 @@ class NotOk7 { ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: [...validConstructor(), ...validInject()], - invalid: [...invalidConstructor(), ...invalidInject()], -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: [...validConstructor(), ...validInject()], + invalid: [...invalidConstructor(), ...invalidInject()], + } +); diff --git a/modules/eslint-plugin/spec/rules/effects/no-effects-in-providers.spec.ts b/modules/eslint-plugin/spec/rules/effects/no-effects-in-providers.spec.ts index f9ee69ee43..e88c537599 100644 --- a/modules/eslint-plugin/spec/rules/effects/no-effects-in-providers.spec.ts +++ b/modules/eslint-plugin/spec/rules/effects/no-effects-in-providers.spec.ts @@ -191,7 +191,11 @@ export class AppModule {}`, ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/effects/no-multiple-actions-in-effects.spec.ts b/modules/eslint-plugin/spec/rules/effects/no-multiple-actions-in-effects.spec.ts index f23e8d7a48..34abb9b0bd 100644 --- a/modules/eslint-plugin/spec/rules/effects/no-multiple-actions-in-effects.spec.ts +++ b/modules/eslint-plugin/spec/rules/effects/no-multiple-actions-in-effects.spec.ts @@ -225,7 +225,11 @@ export class Effects { ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/effects/prefer-effect-callback-in-block-statement.spec.ts b/modules/eslint-plugin/spec/rules/effects/prefer-effect-callback-in-block-statement.spec.ts index a01ebf8e5b..d4a1f1cbd9 100644 --- a/modules/eslint-plugin/spec/rules/effects/prefer-effect-callback-in-block-statement.spec.ts +++ b/modules/eslint-plugin/spec/rules/effects/prefer-effect-callback-in-block-statement.spec.ts @@ -163,7 +163,11 @@ class Effect { ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/effects/use-effects-lifecycle-interface.spec.ts b/modules/eslint-plugin/spec/rules/effects/use-effects-lifecycle-interface.spec.ts index 7e412e2d26..f2f7f087bc 100644 --- a/modules/eslint-plugin/spec/rules/effects/use-effects-lifecycle-interface.spec.ts +++ b/modules/eslint-plugin/spec/rules/effects/use-effects-lifecycle-interface.spec.ts @@ -193,7 +193,11 @@ export class Effects implements OnRunEffects { ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/operators/prefer-concat-latest-from.spec.ts b/modules/eslint-plugin/spec/rules/operators/prefer-concat-latest-from.spec.ts index 7921f88c57..2d0cde35ee 100644 --- a/modules/eslint-plugin/spec/rules/operators/prefer-concat-latest-from.spec.ts +++ b/modules/eslint-plugin/spec/rules/operators/prefer-concat-latest-from.spec.ts @@ -409,7 +409,11 @@ class NotOk5 { ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/signals/enforce-type-call.spec.ts b/modules/eslint-plugin/spec/rules/signals/enforce-type-call.spec.ts index 686af931d0..6ae597e662 100644 --- a/modules/eslint-plugin/spec/rules/signals/enforce-type-call.spec.ts +++ b/modules/eslint-plugin/spec/rules/signals/enforce-type-call.spec.ts @@ -68,7 +68,11 @@ const invalid: () => InvalidTestCase[] = () => [ }, ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/signals/prefer-protected-state.spec.ts b/modules/eslint-plugin/spec/rules/signals/prefer-protected-state.spec.ts index d940fece07..edecff7860 100644 --- a/modules/eslint-plugin/spec/rules/signals/prefer-protected-state.spec.ts +++ b/modules/eslint-plugin/spec/rules/signals/prefer-protected-state.spec.ts @@ -79,7 +79,11 @@ const mySignalStore = signalStore({ providedIn: 'root' });`, ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/signals/signal-state-no-arrays-at-root-level.spec.ts b/modules/eslint-plugin/spec/rules/signals/signal-state-no-arrays-at-root-level.spec.ts index 743bb588a4..57dce5f944 100644 --- a/modules/eslint-plugin/spec/rules/signals/signal-state-no-arrays-at-root-level.spec.ts +++ b/modules/eslint-plugin/spec/rules/signals/signal-state-no-arrays-at-root-level.spec.ts @@ -31,7 +31,11 @@ const state = signalState([]); ~~ [${messageId}]`), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/signals/signal-store-feature-should-use-generic-type.spec.ts b/modules/eslint-plugin/spec/rules/signals/signal-store-feature-should-use-generic-type.spec.ts index 059c91ea5f..711d6adff6 100644 --- a/modules/eslint-plugin/spec/rules/signals/signal-store-feature-should-use-generic-type.spec.ts +++ b/modules/eslint-plugin/spec/rules/signals/signal-store-feature-should-use-generic-type.spec.ts @@ -97,7 +97,11 @@ function withY<_>() { ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/signals/with-state-no-arrays-at-root-level.spec.ts b/modules/eslint-plugin/spec/rules/signals/with-state-no-arrays-at-root-level.spec.ts index 97e71ea4d1..9552d778e8 100644 --- a/modules/eslint-plugin/spec/rules/signals/with-state-no-arrays-at-root-level.spec.ts +++ b/modules/eslint-plugin/spec/rules/signals/with-state-no-arrays-at-root-level.spec.ts @@ -39,7 +39,11 @@ const store = withState([]); ~~~~~~~~~~~~ [${messageId}]`), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/store/avoid-combining-selectors.spec.ts b/modules/eslint-plugin/spec/rules/store/avoid-combining-selectors.spec.ts index 5f13e22d5e..27246b4f96 100644 --- a/modules/eslint-plugin/spec/rules/store/avoid-combining-selectors.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/avoid-combining-selectors.spec.ts @@ -15,43 +15,43 @@ type Options = ESLintUtils.InferOptionsTypeFromRule; const validConstructor: () => (string | ValidTestCase)[] = () => [ ` import { Store } from '@ngrx/store' - + class Ok { readonly test$ = somethingOutside(); }`, ` import { Store } from '@ngrx/store' - + class Ok1 { readonly vm$: Observable - + constructor(store: Store) { this.vm$ = store.select(selectItems) } }`, ` import { Store, select } from '@ngrx/store' - + class Ok2 { vm$ = this.store.pipe(select(selectItems)) - + constructor(private store: Store) {} }`, ` import { Store } from '@ngrx/store' - + class Ok3 { vm$ = combineLatest(this.store$.select(selectItems), this.somethingElse()) - + constructor(private store$: Store) {} }`, ` import { Store } from '@ngrx/store' - + @Pipe() class Ok4 { vm$ = combineLatest(this.somethingElse(), this.store.select(selectItems)) - + constructor(private readonly store: Store) {} }`, ]; @@ -359,7 +359,11 @@ class NotOk11 { ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: [...validConstructor(), ...validInject()], - invalid: [...invalidConstructor(), ...invalidInject()], -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: [...validConstructor(), ...validInject()], + invalid: [...invalidConstructor(), ...invalidInject()], + } +); diff --git a/modules/eslint-plugin/spec/rules/store/avoid-dispatching-multiple-actions-sequentially.spec.ts b/modules/eslint-plugin/spec/rules/store/avoid-dispatching-multiple-actions-sequentially.spec.ts index b885027d1a..65f145c1cc 100644 --- a/modules/eslint-plugin/spec/rules/store/avoid-dispatching-multiple-actions-sequentially.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/avoid-dispatching-multiple-actions-sequentially.spec.ts @@ -15,7 +15,7 @@ type Options = ESLintUtils.InferOptionsTypeFromRule; const validConstructor: () => (string | ValidTestCase)[] = () => [ ` import { Store } from '@ngrx/store' - + class Ok { ngOnInit() { this.dispatch(UserActions.add()) @@ -23,10 +23,10 @@ const validConstructor: () => (string | ValidTestCase)[] = () => [ }`, ` import { Store } from '@ngrx/store' - + class Ok1 { constructor(private store: Store) {} - + ping() { this.store.dispatch(GameActions.ping()) } @@ -34,10 +34,10 @@ const validConstructor: () => (string | ValidTestCase)[] = () => [ // https://github.com/timdeschryver/eslint-plugin-ngrx/issues/47 ` import { Store } from '@ngrx/store' - + class Ok2 { constructor(private store: Store) {} - + pingPong() { if (condition) { this.store.dispatch(GameActions.ping()) @@ -49,10 +49,10 @@ const validConstructor: () => (string | ValidTestCase)[] = () => [ // https://github.com/timdeschryver/eslint-plugin-ngrx/issues/86 ` import { Store } from '@ngrx/store' - + class Ok3 { constructor(private store: Store) {} - + ngOnInit() { this.store.subscribe(() => { this.store.dispatch(one()); @@ -65,13 +65,13 @@ const validConstructor: () => (string | ValidTestCase)[] = () => [ // https://github.com/ngrx/platform/issues/3513 ` import { Store } from '@ngrx/store' - + class Ok4 { constructor(private store: Store) {} - + ngOnInit() { this.store.dispatch(one()); - + this.store.subscribe(() => { this.store.dispatch(anotherOne()); }); @@ -80,13 +80,13 @@ const validConstructor: () => (string | ValidTestCase)[] = () => [ // https://github.com/ngrx/platform/issues/3513 ` import { Store } from '@ngrx/store' - + class Ok5 { constructor(private store: Store) {} - + ngOnInit() { this.store.dispatch(anotherOne()); - + this.store.subscribe(() => { this.store.dispatch(one()); }); @@ -172,10 +172,10 @@ ngOnInit() { const invalidConstructor: () => InvalidTestCase[] = () => [ fromFixture(` import { Store } from '@ngrx/store' - + class NotOk { constructor(private store: Store) {} - + pingPong() { this.store.dispatch(GameActions.ping()) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [${messageId}] @@ -185,7 +185,7 @@ const invalidConstructor: () => InvalidTestCase[] = () => [ }`), fromFixture(` import { Store } from '@ngrx/store' - + class NotOk1 { constructor(store: Store, private readonly store$: Store) { store.dispatch(GameActions.ping()) @@ -198,10 +198,10 @@ const invalidConstructor: () => InvalidTestCase[] = () => [ }`), fromFixture(` import { Store } from '@ngrx/store' - + class NotOk2 { constructor(private store: Store) {} - + pingPongPong() { this.store.dispatch(GameActions.ping()) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [${messageId}] @@ -214,14 +214,14 @@ const invalidConstructor: () => InvalidTestCase[] = () => [ // https://github.com/timdeschryver/eslint-plugin-ngrx/issues/44 fromFixture(` import { Store } from '@ngrx/store' - + class NotOk3 { constructor(private customName: Store) {} - + ngOnInit() { customName.dispatch() } - + pingPong() { this.customName.dispatch(GameActions.ping()) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [${messageId}] @@ -298,7 +298,11 @@ pingPong() { }`), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: [...validConstructor(), ...validInject()], - invalid: [...invalidConstructor(), ...invalidInject()], -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: [...validConstructor(), ...validInject()], + invalid: [...invalidConstructor(), ...invalidInject()], + } +); diff --git a/modules/eslint-plugin/spec/rules/store/avoid-duplicate-actions-in-reducer.spec.ts b/modules/eslint-plugin/spec/rules/store/avoid-duplicate-actions-in-reducer.spec.ts index 86ee707959..be78ac008b 100644 --- a/modules/eslint-plugin/spec/rules/store/avoid-duplicate-actions-in-reducer.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/avoid-duplicate-actions-in-reducer.spec.ts @@ -181,7 +181,11 @@ export const reducer = createReducer( }, ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/store/avoid-mapping-selectors.spec.ts b/modules/eslint-plugin/spec/rules/store/avoid-mapping-selectors.spec.ts index 4b5c6f2be8..7113b8404c 100644 --- a/modules/eslint-plugin/spec/rules/store/avoid-mapping-selectors.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/avoid-mapping-selectors.spec.ts @@ -252,7 +252,11 @@ class NotOk3 { `), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/store/good-action-hygiene.spec.ts b/modules/eslint-plugin/spec/rules/store/good-action-hygiene.spec.ts index 9a0e7b1269..039b5fbdd4 100644 --- a/modules/eslint-plugin/spec/rules/store/good-action-hygiene.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/good-action-hygiene.spec.ts @@ -27,7 +27,11 @@ const invalid: () => InvalidTestCase[] = () => [ ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/store/no-multiple-global-stores.spec.ts b/modules/eslint-plugin/spec/rules/store/no-multiple-global-stores.spec.ts index a808799361..45302efa80 100644 --- a/modules/eslint-plugin/spec/rules/store/no-multiple-global-stores.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/no-multiple-global-stores.spec.ts @@ -215,7 +215,11 @@ class NotOk2 { ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/store/no-reducer-in-key-names.spec.ts b/modules/eslint-plugin/spec/rules/store/no-reducer-in-key-names.spec.ts index 2269c193bf..b933d53ae5 100644 --- a/modules/eslint-plugin/spec/rules/store/no-reducer-in-key-names.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/no-reducer-in-key-names.spec.ts @@ -227,7 +227,11 @@ export const reducers: ActionReducerMap = { }, ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/store/no-store-subscription.spec.ts b/modules/eslint-plugin/spec/rules/store/no-store-subscription.spec.ts index e0ef6248c3..09ff359a53 100644 --- a/modules/eslint-plugin/spec/rules/store/no-store-subscription.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/no-store-subscription.spec.ts @@ -211,12 +211,16 @@ class NotOk10 { constructor() { store.pipe(select(selectItems)).subscribe() - ~~~~~~~~~ [${messageId}] + ~~~~~~~~~ [${messageId}] } }`), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/store/no-typed-global-store.spec.ts b/modules/eslint-plugin/spec/rules/store/no-typed-global-store.spec.ts index 08b20ce45b..a213f0ee02 100644 --- a/modules/eslint-plugin/spec/rules/store/no-typed-global-store.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/no-typed-global-store.spec.ts @@ -151,7 +151,7 @@ import { Store } from '@ngrx/store'; export class NotOk4 { store = inject(Store<{}>); - ~~~~ [${noTypedStore} suggest] + ~~~~ [${noTypedStore} suggest] }`, { suggestions: [ @@ -170,7 +170,11 @@ export class NotOk4 { ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: [...validConstructor(), ...validInject()], - invalid: [...invalidConstructor(), ...invalidInject()], -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: [...validConstructor(), ...validInject()], + invalid: [...invalidConstructor(), ...invalidInject()], + } +); diff --git a/modules/eslint-plugin/spec/rules/store/on-function-explicit-return-type.spec.ts b/modules/eslint-plugin/spec/rules/store/on-function-explicit-return-type.spec.ts index e10bd77efa..f261c51602 100644 --- a/modules/eslint-plugin/spec/rules/store/on-function-explicit-return-type.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/on-function-explicit-return-type.spec.ts @@ -232,7 +232,11 @@ const reducer = createReducer( }, ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/store/prefer-action-creator-in-dispatch.spec.ts b/modules/eslint-plugin/spec/rules/store/prefer-action-creator-in-dispatch.spec.ts index 7cfe2f888d..b0efd6c19b 100644 --- a/modules/eslint-plugin/spec/rules/store/prefer-action-creator-in-dispatch.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/prefer-action-creator-in-dispatch.spec.ts @@ -199,7 +199,11 @@ class NotOk7 { }`), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: [...validConstructor(), ...validInject()], - invalid: [...invalidConstructor(), ...invalidInject()], -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: [...validConstructor(), ...validInject()], + invalid: [...invalidConstructor(), ...invalidInject()], + } +); diff --git a/modules/eslint-plugin/spec/rules/store/prefer-action-creator-in-of-type.spec.ts b/modules/eslint-plugin/spec/rules/store/prefer-action-creator-in-of-type.spec.ts index 00bead2952..24c5e0a0b3 100644 --- a/modules/eslint-plugin/spec/rules/store/prefer-action-creator-in-of-type.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/prefer-action-creator-in-of-type.spec.ts @@ -78,7 +78,11 @@ class Test { ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/store/prefer-action-creator.spec.ts b/modules/eslint-plugin/spec/rules/store/prefer-action-creator.spec.ts index 75d779e7a3..cb2275bbbf 100644 --- a/modules/eslint-plugin/spec/rules/store/prefer-action-creator.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/prefer-action-creator.spec.ts @@ -48,7 +48,11 @@ class Test implements ngrx.Action { type = ActionTypes.success; constructor(read ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/store/prefer-inline-action-props.spec.ts b/modules/eslint-plugin/spec/rules/store/prefer-inline-action-props.spec.ts index d87626d381..7741796974 100644 --- a/modules/eslint-plugin/spec/rules/store/prefer-inline-action-props.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/prefer-inline-action-props.spec.ts @@ -99,7 +99,11 @@ const invalid: () => InvalidTestCase[] = () => [ }, ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/store/prefer-one-generic-in-create-for-feature-selector.spec.ts b/modules/eslint-plugin/spec/rules/store/prefer-one-generic-in-create-for-feature-selector.spec.ts index 9c4b57a7d5..daf6c05c09 100644 --- a/modules/eslint-plugin/spec/rules/store/prefer-one-generic-in-create-for-feature-selector.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/prefer-one-generic-in-create-for-feature-selector.spec.ts @@ -64,7 +64,11 @@ const featureNotOk2 = createFeatureSelector< StateA & StateB>('feature-state')`, ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/store/prefer-selector-in-select.spec.ts b/modules/eslint-plugin/spec/rules/store/prefer-selector-in-select.spec.ts index 1847ce8eae..35a103bbc3 100644 --- a/modules/eslint-plugin/spec/rules/store/prefer-selector-in-select.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/prefer-selector-in-select.spec.ts @@ -312,7 +312,11 @@ class NotOk15 { ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: [...validConstructor(), ...validInject()], - invalid: [...invalidConstructor(), ...invalidInject()], -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: [...validConstructor(), ...validInject()], + invalid: [...invalidConstructor(), ...invalidInject()], + } +); diff --git a/modules/eslint-plugin/spec/rules/store/prefix-selectors-with-select.spec.ts b/modules/eslint-plugin/spec/rules/store/prefix-selectors-with-select.spec.ts index ab74748c74..92cafa19c2 100644 --- a/modules/eslint-plugin/spec/rules/store/prefix-selectors-with-select.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/prefix-selectors-with-select.spec.ts @@ -299,7 +299,11 @@ const { selectEntitiesMap } = getSelectors(adapter);`, ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: valid(), - invalid: invalid(), -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: valid(), + invalid: invalid(), + } +); diff --git a/modules/eslint-plugin/spec/rules/store/select-style.spec.ts b/modules/eslint-plugin/spec/rules/store/select-style.spec.ts index 1f25b79e90..8856ff7f58 100644 --- a/modules/eslint-plugin/spec/rules/store/select-style.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/select-style.spec.ts @@ -503,7 +503,11 @@ class NotOk11 { ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: [...validConstructor(), ...validInject()], - invalid: [...invalidConstructor(), ...invalidInject()], -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: [...validConstructor(), ...validInject()], + invalid: [...invalidConstructor(), ...invalidInject()], + } +); diff --git a/modules/eslint-plugin/spec/rules/store/use-consistent-global-store-name.spec.ts b/modules/eslint-plugin/spec/rules/store/use-consistent-global-store-name.spec.ts index 1265db954a..18a405e357 100644 --- a/modules/eslint-plugin/spec/rules/store/use-consistent-global-store-name.spec.ts +++ b/modules/eslint-plugin/spec/rules/store/use-consistent-global-store-name.spec.ts @@ -303,7 +303,11 @@ class NotOk7 { ), ]; -ruleTester().run(path.parse(__filename).name, rule, { - valid: [...validConstructor(), ...validInject()], - invalid: [...invalidConstructor(), ...invalidInject()], -}); +ruleTester(rule.meta.docs?.requiresTypeChecking).run( + path.parse(__filename).name, + rule, + { + valid: [...validConstructor(), ...validInject()], + invalid: [...invalidConstructor(), ...invalidInject()], + } +); diff --git a/modules/eslint-plugin/spec/utils/rule-tester.ts b/modules/eslint-plugin/spec/utils/rule-tester.ts index 8c91dadaa8..526565db75 100644 --- a/modules/eslint-plugin/spec/utils/rule-tester.ts +++ b/modules/eslint-plugin/spec/utils/rule-tester.ts @@ -1,13 +1,17 @@ import { RuleTester } from '@typescript-eslint/rule-tester'; import { resolve } from 'path'; -export function ruleTester() { +export function ruleTester(requiresTypeChecking?: boolean) { + const languageOptions = + (requiresTypeChecking ?? false) + ? { + parserOptions: { + tsconfigRootDir: resolve('./modules/eslint-plugin/spec/fixtures'), + project: './tsconfig.json', + }, + } + : undefined; return new RuleTester({ - languageOptions: { - parserOptions: { - tsconfigRootDir: resolve('./modules/eslint-plugin/spec/fixtures'), - project: './tsconfig.json', - }, - }, + languageOptions, }); } diff --git a/modules/eslint-plugin/src/configs/all.json b/modules/eslint-plugin/src/configs/all.json index e5dca896ed..10d3ca5faa 100644 --- a/modules/eslint-plugin/src/configs/all.json +++ b/modules/eslint-plugin/src/configs/all.json @@ -6,10 +6,8 @@ "@ngrx/avoid-mapping-component-store-selectors": "error", "@ngrx/require-super-ondestroy": "error", "@ngrx/updater-explicit-return-type": "error", - "@ngrx/avoid-cyclic-effects": "error", "@ngrx/no-dispatch-in-effects": "error", "@ngrx/no-effects-in-providers": "error", - "@ngrx/no-multiple-actions-in-effects": "error", "@ngrx/prefer-action-creator-in-of-type": "error", "@ngrx/prefer-effect-callback-in-block-statement": "error", "@ngrx/use-effects-lifecycle-interface": "error", @@ -18,7 +16,6 @@ "@ngrx/prefer-protected-state": "error", "@ngrx/signal-state-no-arrays-at-root-level": "error", "@ngrx/signal-store-feature-should-use-generic-type": "error", - "@ngrx/with-state-no-arrays-at-root-level": "error", "@ngrx/avoid-combining-selectors": "error", "@ngrx/avoid-dispatching-multiple-actions-sequentially": "error", "@ngrx/avoid-duplicate-actions-in-reducer": "error", @@ -37,10 +34,5 @@ "@ngrx/prefix-selectors-with-select": "error", "@ngrx/select-style": "error", "@ngrx/use-consistent-global-store-name": "error" - }, - "parserOptions": { - "ecmaVersion": 2020, - "sourceType": "module", - "project": "./tsconfig.json" } } diff --git a/modules/eslint-plugin/src/configs/all.ts b/modules/eslint-plugin/src/configs/all.ts index e2df99897b..e363fb246f 100644 --- a/modules/eslint-plugin/src/configs/all.ts +++ b/modules/eslint-plugin/src/configs/all.ts @@ -13,7 +13,6 @@ export default ( name: 'ngrx/base', languageOptions: { parser, - sourceType: 'module', }, plugins: { '@ngrx': plugin, @@ -23,21 +22,14 @@ export default ( name: 'ngrx/all', languageOptions: { parser, - parserOptions: { - ecmaVersion: 2020, - sourceType: 'module', - project: './tsconfig.json', - }, }, rules: { '@ngrx/avoid-combining-component-store-selectors': 'error', '@ngrx/avoid-mapping-component-store-selectors': 'error', '@ngrx/require-super-ondestroy': 'error', '@ngrx/updater-explicit-return-type': 'error', - '@ngrx/avoid-cyclic-effects': 'error', '@ngrx/no-dispatch-in-effects': 'error', '@ngrx/no-effects-in-providers': 'error', - '@ngrx/no-multiple-actions-in-effects': 'error', '@ngrx/prefer-action-creator-in-of-type': 'error', '@ngrx/prefer-effect-callback-in-block-statement': 'error', '@ngrx/use-effects-lifecycle-interface': 'error', @@ -46,7 +38,6 @@ export default ( '@ngrx/prefer-protected-state': 'error', '@ngrx/signal-state-no-arrays-at-root-level': 'error', '@ngrx/signal-store-feature-should-use-generic-type': 'error', - '@ngrx/with-state-no-arrays-at-root-level': 'error', '@ngrx/avoid-combining-selectors': 'error', '@ngrx/avoid-dispatching-multiple-actions-sequentially': 'error', '@ngrx/avoid-duplicate-actions-in-reducer': 'error', diff --git a/modules/eslint-plugin/src/configs/allTypeChecked.json b/modules/eslint-plugin/src/configs/allTypeChecked.json new file mode 100644 index 0000000000..62cf71345c --- /dev/null +++ b/modules/eslint-plugin/src/configs/allTypeChecked.json @@ -0,0 +1,41 @@ +{ + "parser": "@typescript-eslint/parser", + "plugins": ["@ngrx"], + "rules": { + "@ngrx/avoid-combining-component-store-selectors": "error", + "@ngrx/avoid-mapping-component-store-selectors": "error", + "@ngrx/require-super-ondestroy": "error", + "@ngrx/updater-explicit-return-type": "error", + "@ngrx/avoid-cyclic-effects": "error", + "@ngrx/no-dispatch-in-effects": "error", + "@ngrx/no-effects-in-providers": "error", + "@ngrx/no-multiple-actions-in-effects": "error", + "@ngrx/prefer-action-creator-in-of-type": "error", + "@ngrx/prefer-effect-callback-in-block-statement": "error", + "@ngrx/use-effects-lifecycle-interface": "error", + "@ngrx/prefer-concat-latest-from": "error", + "@ngrx/enforce-type-call": "error", + "@ngrx/prefer-protected-state": "error", + "@ngrx/signal-state-no-arrays-at-root-level": "error", + "@ngrx/signal-store-feature-should-use-generic-type": "error", + "@ngrx/with-state-no-arrays-at-root-level": "error", + "@ngrx/avoid-combining-selectors": "error", + "@ngrx/avoid-dispatching-multiple-actions-sequentially": "error", + "@ngrx/avoid-duplicate-actions-in-reducer": "error", + "@ngrx/avoid-mapping-selectors": "error", + "@ngrx/good-action-hygiene": "error", + "@ngrx/no-multiple-global-stores": "error", + "@ngrx/no-reducer-in-key-names": "error", + "@ngrx/no-store-subscription": "error", + "@ngrx/no-typed-global-store": "error", + "@ngrx/on-function-explicit-return-type": "error", + "@ngrx/prefer-action-creator-in-dispatch": "error", + "@ngrx/prefer-action-creator": "error", + "@ngrx/prefer-inline-action-props": "error", + "@ngrx/prefer-one-generic-in-create-for-feature-selector": "error", + "@ngrx/prefer-selector-in-select": "error", + "@ngrx/prefix-selectors-with-select": "error", + "@ngrx/select-style": "error", + "@ngrx/use-consistent-global-store-name": "error" + } +} diff --git a/modules/eslint-plugin/src/configs/allTypeChecked.ts b/modules/eslint-plugin/src/configs/allTypeChecked.ts new file mode 100644 index 0000000000..e85fd58274 --- /dev/null +++ b/modules/eslint-plugin/src/configs/allTypeChecked.ts @@ -0,0 +1,64 @@ +/** + * DO NOT EDIT + * This file is generated + */ + +import type { TSESLint } from '@typescript-eslint/utils'; + +export default ( + plugin: TSESLint.FlatConfig.Plugin, + parser: TSESLint.FlatConfig.Parser +): TSESLint.FlatConfig.ConfigArray => [ + { + name: 'ngrx/base', + languageOptions: { + parser, + }, + plugins: { + '@ngrx': plugin, + }, + }, + { + name: 'ngrx/allTypeChecked', + languageOptions: { + parser, + }, + rules: { + '@ngrx/avoid-combining-component-store-selectors': 'error', + '@ngrx/avoid-mapping-component-store-selectors': 'error', + '@ngrx/require-super-ondestroy': 'error', + '@ngrx/updater-explicit-return-type': 'error', + '@ngrx/avoid-cyclic-effects': 'error', + '@ngrx/no-dispatch-in-effects': 'error', + '@ngrx/no-effects-in-providers': 'error', + '@ngrx/no-multiple-actions-in-effects': 'error', + '@ngrx/prefer-action-creator-in-of-type': 'error', + '@ngrx/prefer-effect-callback-in-block-statement': 'error', + '@ngrx/use-effects-lifecycle-interface': 'error', + '@ngrx/prefer-concat-latest-from': 'error', + '@ngrx/enforce-type-call': 'error', + '@ngrx/prefer-protected-state': 'error', + '@ngrx/signal-state-no-arrays-at-root-level': 'error', + '@ngrx/signal-store-feature-should-use-generic-type': 'error', + '@ngrx/with-state-no-arrays-at-root-level': 'error', + '@ngrx/avoid-combining-selectors': 'error', + '@ngrx/avoid-dispatching-multiple-actions-sequentially': 'error', + '@ngrx/avoid-duplicate-actions-in-reducer': 'error', + '@ngrx/avoid-mapping-selectors': 'error', + '@ngrx/good-action-hygiene': 'error', + '@ngrx/no-multiple-global-stores': 'error', + '@ngrx/no-reducer-in-key-names': 'error', + '@ngrx/no-store-subscription': 'error', + '@ngrx/no-typed-global-store': 'error', + '@ngrx/on-function-explicit-return-type': 'error', + '@ngrx/prefer-action-creator-in-dispatch': 'error', + '@ngrx/prefer-action-creator': 'error', + '@ngrx/prefer-inline-action-props': 'error', + '@ngrx/prefer-one-generic-in-create-for-feature-selector': 'error', + '@ngrx/prefer-selector-in-select': 'error', + '@ngrx/prefix-selectors-with-select': 'error', + '@ngrx/select-style': 'error', + '@ngrx/use-consistent-global-store-name': 'error', + }, + }, +]; diff --git a/modules/eslint-plugin/src/configs/component-store.ts b/modules/eslint-plugin/src/configs/component-store.ts index 210b9e0ffc..d233093879 100644 --- a/modules/eslint-plugin/src/configs/component-store.ts +++ b/modules/eslint-plugin/src/configs/component-store.ts @@ -13,7 +13,6 @@ export default ( name: 'ngrx/base', languageOptions: { parser, - sourceType: 'module', }, plugins: { '@ngrx': plugin, diff --git a/modules/eslint-plugin/src/configs/effects.json b/modules/eslint-plugin/src/configs/effects.json index c34abc383e..28dc17386a 100644 --- a/modules/eslint-plugin/src/configs/effects.json +++ b/modules/eslint-plugin/src/configs/effects.json @@ -2,17 +2,10 @@ "parser": "@typescript-eslint/parser", "plugins": ["@ngrx"], "rules": { - "@ngrx/avoid-cyclic-effects": "error", "@ngrx/no-dispatch-in-effects": "error", "@ngrx/no-effects-in-providers": "error", - "@ngrx/no-multiple-actions-in-effects": "error", "@ngrx/prefer-action-creator-in-of-type": "error", "@ngrx/prefer-effect-callback-in-block-statement": "error", "@ngrx/use-effects-lifecycle-interface": "error" - }, - "parserOptions": { - "ecmaVersion": 2020, - "sourceType": "module", - "project": "./tsconfig.json" } } diff --git a/modules/eslint-plugin/src/configs/effects.ts b/modules/eslint-plugin/src/configs/effects.ts index c3b386f40b..3c826cd58f 100644 --- a/modules/eslint-plugin/src/configs/effects.ts +++ b/modules/eslint-plugin/src/configs/effects.ts @@ -13,7 +13,6 @@ export default ( name: 'ngrx/base', languageOptions: { parser, - sourceType: 'module', }, plugins: { '@ngrx': plugin, @@ -23,17 +22,10 @@ export default ( name: 'ngrx/effects', languageOptions: { parser, - parserOptions: { - ecmaVersion: 2020, - sourceType: 'module', - project: './tsconfig.json', - }, }, rules: { - '@ngrx/avoid-cyclic-effects': 'error', '@ngrx/no-dispatch-in-effects': 'error', '@ngrx/no-effects-in-providers': 'error', - '@ngrx/no-multiple-actions-in-effects': 'error', '@ngrx/prefer-action-creator-in-of-type': 'error', '@ngrx/prefer-effect-callback-in-block-statement': 'error', '@ngrx/use-effects-lifecycle-interface': 'error', diff --git a/modules/eslint-plugin/src/configs/effectsTypeChecked.json b/modules/eslint-plugin/src/configs/effectsTypeChecked.json new file mode 100644 index 0000000000..e8dfbaf7fe --- /dev/null +++ b/modules/eslint-plugin/src/configs/effectsTypeChecked.json @@ -0,0 +1,13 @@ +{ + "parser": "@typescript-eslint/parser", + "plugins": ["@ngrx"], + "rules": { + "@ngrx/avoid-cyclic-effects": "error", + "@ngrx/no-dispatch-in-effects": "error", + "@ngrx/no-effects-in-providers": "error", + "@ngrx/no-multiple-actions-in-effects": "error", + "@ngrx/prefer-action-creator-in-of-type": "error", + "@ngrx/prefer-effect-callback-in-block-statement": "error", + "@ngrx/use-effects-lifecycle-interface": "error" + } +} diff --git a/modules/eslint-plugin/src/configs/effectsTypeChecked.ts b/modules/eslint-plugin/src/configs/effectsTypeChecked.ts new file mode 100644 index 0000000000..43c56d2957 --- /dev/null +++ b/modules/eslint-plugin/src/configs/effectsTypeChecked.ts @@ -0,0 +1,36 @@ +/** + * DO NOT EDIT + * This file is generated + */ + +import type { TSESLint } from '@typescript-eslint/utils'; + +export default ( + plugin: TSESLint.FlatConfig.Plugin, + parser: TSESLint.FlatConfig.Parser +): TSESLint.FlatConfig.ConfigArray => [ + { + name: 'ngrx/base', + languageOptions: { + parser, + }, + plugins: { + '@ngrx': plugin, + }, + }, + { + name: 'ngrx/effectsTypeChecked', + languageOptions: { + parser, + }, + rules: { + '@ngrx/avoid-cyclic-effects': 'error', + '@ngrx/no-dispatch-in-effects': 'error', + '@ngrx/no-effects-in-providers': 'error', + '@ngrx/no-multiple-actions-in-effects': 'error', + '@ngrx/prefer-action-creator-in-of-type': 'error', + '@ngrx/prefer-effect-callback-in-block-statement': 'error', + '@ngrx/use-effects-lifecycle-interface': 'error', + }, + }, +]; diff --git a/modules/eslint-plugin/src/configs/operators.ts b/modules/eslint-plugin/src/configs/operators.ts index ea6cdbff06..17a02f9822 100644 --- a/modules/eslint-plugin/src/configs/operators.ts +++ b/modules/eslint-plugin/src/configs/operators.ts @@ -13,7 +13,6 @@ export default ( name: 'ngrx/base', languageOptions: { parser, - sourceType: 'module', }, plugins: { '@ngrx': plugin, diff --git a/modules/eslint-plugin/src/configs/signals.json b/modules/eslint-plugin/src/configs/signals.json index 67acc07b8e..ced089db66 100644 --- a/modules/eslint-plugin/src/configs/signals.json +++ b/modules/eslint-plugin/src/configs/signals.json @@ -5,12 +5,6 @@ "@ngrx/enforce-type-call": "error", "@ngrx/prefer-protected-state": "error", "@ngrx/signal-state-no-arrays-at-root-level": "error", - "@ngrx/signal-store-feature-should-use-generic-type": "error", - "@ngrx/with-state-no-arrays-at-root-level": "error" - }, - "parserOptions": { - "ecmaVersion": 2020, - "sourceType": "module", - "project": "./tsconfig.json" + "@ngrx/signal-store-feature-should-use-generic-type": "error" } } diff --git a/modules/eslint-plugin/src/configs/signals.ts b/modules/eslint-plugin/src/configs/signals.ts index 266dc66795..067934f9f8 100644 --- a/modules/eslint-plugin/src/configs/signals.ts +++ b/modules/eslint-plugin/src/configs/signals.ts @@ -13,7 +13,6 @@ export default ( name: 'ngrx/base', languageOptions: { parser, - sourceType: 'module', }, plugins: { '@ngrx': plugin, @@ -23,18 +22,12 @@ export default ( name: 'ngrx/signals', languageOptions: { parser, - parserOptions: { - ecmaVersion: 2020, - sourceType: 'module', - project: './tsconfig.json', - }, }, rules: { '@ngrx/enforce-type-call': 'error', '@ngrx/prefer-protected-state': 'error', '@ngrx/signal-state-no-arrays-at-root-level': 'error', '@ngrx/signal-store-feature-should-use-generic-type': 'error', - '@ngrx/with-state-no-arrays-at-root-level': 'error', }, }, ]; diff --git a/modules/eslint-plugin/src/configs/signalsTypeChecked.json b/modules/eslint-plugin/src/configs/signalsTypeChecked.json new file mode 100644 index 0000000000..f1f5303b91 --- /dev/null +++ b/modules/eslint-plugin/src/configs/signalsTypeChecked.json @@ -0,0 +1,11 @@ +{ + "parser": "@typescript-eslint/parser", + "plugins": ["@ngrx"], + "rules": { + "@ngrx/enforce-type-call": "error", + "@ngrx/prefer-protected-state": "error", + "@ngrx/signal-state-no-arrays-at-root-level": "error", + "@ngrx/signal-store-feature-should-use-generic-type": "error", + "@ngrx/with-state-no-arrays-at-root-level": "error" + } +} diff --git a/modules/eslint-plugin/src/configs/signalsTypeChecked.ts b/modules/eslint-plugin/src/configs/signalsTypeChecked.ts new file mode 100644 index 0000000000..ea468905e4 --- /dev/null +++ b/modules/eslint-plugin/src/configs/signalsTypeChecked.ts @@ -0,0 +1,34 @@ +/** + * DO NOT EDIT + * This file is generated + */ + +import type { TSESLint } from '@typescript-eslint/utils'; + +export default ( + plugin: TSESLint.FlatConfig.Plugin, + parser: TSESLint.FlatConfig.Parser +): TSESLint.FlatConfig.ConfigArray => [ + { + name: 'ngrx/base', + languageOptions: { + parser, + }, + plugins: { + '@ngrx': plugin, + }, + }, + { + name: 'ngrx/signalsTypeChecked', + languageOptions: { + parser, + }, + rules: { + '@ngrx/enforce-type-call': 'error', + '@ngrx/prefer-protected-state': 'error', + '@ngrx/signal-state-no-arrays-at-root-level': 'error', + '@ngrx/signal-store-feature-should-use-generic-type': 'error', + '@ngrx/with-state-no-arrays-at-root-level': 'error', + }, + }, +]; diff --git a/modules/eslint-plugin/src/configs/store.ts b/modules/eslint-plugin/src/configs/store.ts index 0543e60e13..7c0f2c89ce 100644 --- a/modules/eslint-plugin/src/configs/store.ts +++ b/modules/eslint-plugin/src/configs/store.ts @@ -13,7 +13,6 @@ export default ( name: 'ngrx/base', languageOptions: { parser, - sourceType: 'module', }, plugins: { '@ngrx': plugin, diff --git a/modules/eslint-plugin/v9/index.ts b/modules/eslint-plugin/v9/index.ts index abb59d7bf4..27ac341067 100644 --- a/modules/eslint-plugin/v9/index.ts +++ b/modules/eslint-plugin/v9/index.ts @@ -11,6 +11,9 @@ import effects from '../src/configs/effects'; import componentStore from '../src/configs/component-store'; import operators from '../src/configs/operators'; import signals from '../src/configs/signals'; +import allTypeChecked from '../src/configs/allTypeChecked'; +import effectsTypeChecked from '../src/configs/effectsTypeChecked'; +import signalsTypeChecked from '../src/configs/signalsTypeChecked'; const meta = { name: packageName, version: packageVersion }; @@ -20,16 +23,19 @@ const tsPlugin: TSESLint.FlatConfig.Plugin = { const configs = { all: all(tsPlugin, parser), + allTypeChecked: allTypeChecked(tsPlugin, parser), store: store(tsPlugin, parser), effects: effects(tsPlugin, parser), + effectsTypeChecked: effectsTypeChecked(tsPlugin, parser), componentStore: componentStore(tsPlugin, parser), operators: operators(tsPlugin, parser), signals: signals(tsPlugin, parser), + signalsTypeChecked: signalsTypeChecked(tsPlugin, parser), }; /* As the angular-eslint plugin we do both a default and named exports to allow people to use this package from -both CJS and ESM in very natural ways. +both CJS and ESM in very natural ways. */ export default { meta, diff --git a/projects/ngrx.io/content/guide/eslint-plugin/index.md b/projects/ngrx.io/content/guide/eslint-plugin/index.md index 4e641a33de..36a0ac5815 100644 --- a/projects/ngrx.io/content/guide/eslint-plugin/index.md +++ b/projects/ngrx.io/content/guide/eslint-plugin/index.md @@ -162,13 +162,16 @@ module.exports = tseslint.config({ -| Name | -| -------------------------------------------------------------------------------------------------------------------- | -| [all](https://github.com/ngrx/platform/blob/main/modules/eslint-plugin/src/configs/all.json) | -| [component-store](https://github.com/ngrx/platform/blob/main/modules/eslint-plugin/src/configs/component-store.json) | -| [effects](https://github.com/ngrx/platform/blob/main/modules/eslint-plugin/src/configs/effects.json) | -| [operators](https://github.com/ngrx/platform/blob/main/modules/eslint-plugin/src/configs/operators.json) | -| [signals](https://github.com/ngrx/platform/blob/main/modules/eslint-plugin/src/configs/signals.json) | -| [store](https://github.com/ngrx/platform/blob/main/modules/eslint-plugin/src/configs/store.json) | - - +| Name | +| -------------------------------------------------------------------------------------------------------------------------- | +| [all](https://github.com/ngrx/platform/blob/main/modules/eslint-plugin/src/configs/all.json) | +| [allTypeChecked](https://github.com/ngrx/platform/blob/main/modules/eslint-plugin/src/configs/allTypeChecked.json) | +| [component-store](https://github.com/ngrx/platform/blob/main/modules/eslint-plugin/src/configs/component-store.json) | +| [effects](https://github.com/ngrx/platform/blob/main/modules/eslint-plugin/src/configs/effects.json) | +| [effectsTypeChecked](https://github.com/ngrx/platform/blob/main/modules/eslint-plugin/src/configs/effectsTypeChecked.json) | +| [operators](https://github.com/ngrx/platform/blob/main/modules/eslint-plugin/src/configs/operators.json) | +| [signals](https://github.com/ngrx/platform/blob/main/modules/eslint-plugin/src/configs/signals.json) | +| [signalsTypeChecked](https://github.com/ngrx/platform/blob/main/modules/eslint-plugin/src/configs/signalsTypeChecked.json) | +| [store](https://github.com/ngrx/platform/blob/main/modules/eslint-plugin/src/configs/store.json) | + +