From 6db463ae69a1b864ae52feb0680315399bb2bfc5 Mon Sep 17 00:00:00 2001 From: Jason Weinzierl Date: Fri, 22 Nov 2024 09:04:17 -0600 Subject: [PATCH 01/12] style(recommended): newline for args --- src/configs/recommended.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/configs/recommended.ts b/src/configs/recommended.ts index 30faa9bf..91007f6d 100644 --- a/src/configs/recommended.ts +++ b/src/configs/recommended.ts @@ -1,6 +1,8 @@ import { TSESLint } from '@typescript-eslint/utils'; -export const createRecommendedConfig = (plugin: TSESLint.FlatConfig.Plugin) => ({ +export const createRecommendedConfig = ( + plugin: TSESLint.FlatConfig.Plugin, +) => ({ plugins: { 'rxjs-x': plugin, }, From b15b3892a8faa08c0425f32dc3972bcfb1313065 Mon Sep 17 00:00:00 2001 From: Jason Weinzierl Date: Fri, 22 Nov 2024 10:23:35 -0600 Subject: [PATCH 02/12] feat(strict): add strict config --- README.md | 92 ++++++++++++------------ docs/rules/no-async-subscribe.md | 2 +- docs/rules/no-create.md | 2 +- docs/rules/no-exposed-subjects.md | 2 + docs/rules/no-ignored-default-value.md | 2 + docs/rules/no-ignored-error.md | 2 + docs/rules/no-ignored-notifier.md | 2 +- docs/rules/no-ignored-replay-buffer.md | 2 +- docs/rules/no-ignored-takewhile-value.md | 2 +- docs/rules/no-implicit-any-catch.md | 2 +- docs/rules/no-index.md | 2 +- docs/rules/no-internal.md | 2 +- docs/rules/no-nested-subscribe.md | 2 +- docs/rules/no-redundant-notify.md | 2 +- docs/rules/no-sharereplay.md | 2 +- docs/rules/no-subject-unsubscribe.md | 2 +- docs/rules/no-topromise.md | 2 + docs/rules/no-unbound-methods.md | 2 +- docs/rules/no-unsafe-subject-next.md | 2 +- docs/rules/no-unsafe-takeuntil.md | 2 +- docs/rules/prefer-observer.md | 2 + docs/rules/prefer-root-operators.md | 2 + docs/rules/throw-error.md | 2 + src/configs/strict.ts | 33 +++++++++ src/index.ts | 2 + tests/configs/strict.test.ts | 19 +++++ 26 files changed, 130 insertions(+), 60 deletions(-) create mode 100644 src/configs/strict.ts create mode 100644 tests/configs/strict.test.ts diff --git a/README.md b/README.md index be928367..f4f59b5d 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ See [Linting with Type Information](https://typescript-eslint.io/getting-started | | Name | | :- | :------------ | | βœ… | `recommended` | +| πŸ”’ | `strict` | @@ -66,55 +67,56 @@ The package includes the following rules. πŸ’Ό Configurations enabled in.\ βœ… Set in the `recommended` configuration.\ +πŸ”’ Set in the `strict` configuration.\ πŸ”§ Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\ πŸ’‘ Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).\ πŸ’­ Requires [type information](https://typescript-eslint.io/linting/typed-linting).\ ❌ Deprecated. -| NameΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  | Description | πŸ’Ό | πŸ”§ | πŸ’‘ | πŸ’­ | ❌ | -| :--------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------- | :- | :- | :- | :- | :- | -| [ban-observables](docs/rules/ban-observables.md) | Disallow banned observable creators. | | | | | | -| [ban-operators](docs/rules/ban-operators.md) | Disallow banned operators. | | | | πŸ’­ | | -| [finnish](docs/rules/finnish.md) | Enforce Finnish notation. | | | | πŸ’­ | | -| [just](docs/rules/just.md) | Require the use of `just` instead of `of`. | | πŸ”§ | | | | -| [macro](docs/rules/macro.md) | Require the use of the RxJS Tools Babel macro. | | πŸ”§ | | | ❌ | -| [no-async-subscribe](docs/rules/no-async-subscribe.md) | Disallow passing `async` functions to `subscribe`. | βœ… | | | πŸ’­ | | -| [no-compat](docs/rules/no-compat.md) | Disallow the `rxjs-compat` package. | | | | | ❌ | -| [no-connectable](docs/rules/no-connectable.md) | Disallow operators that return connectable observables. | | | | πŸ’­ | | -| [no-create](docs/rules/no-create.md) | Disallow the static `Observable.create` function. | βœ… | | | πŸ’­ | | -| [no-cyclic-action](docs/rules/no-cyclic-action.md) | Disallow cyclic actions in effects and epics. | | | | πŸ’­ | | -| [no-explicit-generics](docs/rules/no-explicit-generics.md) | Disallow unnecessary explicit generic type arguments. | | | | | | -| [no-exposed-subjects](docs/rules/no-exposed-subjects.md) | Disallow public and protected subjects. | | | | πŸ’­ | | -| [no-finnish](docs/rules/no-finnish.md) | Disallow Finnish notation. | | | | πŸ’­ | | -| [no-ignored-default-value](docs/rules/no-ignored-default-value.md) | Disallow using `firstValueFrom`, `lastValueFrom`, `first`, and `last` without specifying a default value. | | | | πŸ’­ | | -| [no-ignored-error](docs/rules/no-ignored-error.md) | Disallow calling `subscribe` without specifying an error handler. | | | | πŸ’­ | | -| [no-ignored-notifier](docs/rules/no-ignored-notifier.md) | Disallow observables not composed from the `repeatWhen` or `retryWhen` notifier. | βœ… | | | πŸ’­ | | -| [no-ignored-observable](docs/rules/no-ignored-observable.md) | Disallow ignoring observables returned by functions. | | | | πŸ’­ | | -| [no-ignored-replay-buffer](docs/rules/no-ignored-replay-buffer.md) | Disallow using `ReplaySubject`, `publishReplay` or `shareReplay` without specifying the buffer size. | βœ… | | | | | -| [no-ignored-subscribe](docs/rules/no-ignored-subscribe.md) | Disallow calling `subscribe` without specifying arguments. | | | | πŸ’­ | | -| [no-ignored-subscription](docs/rules/no-ignored-subscription.md) | Disallow ignoring the subscription returned by `subscribe`. | | | | πŸ’­ | | -| [no-ignored-takewhile-value](docs/rules/no-ignored-takewhile-value.md) | Disallow ignoring the value within `takeWhile`. | βœ… | | | | | -| [no-implicit-any-catch](docs/rules/no-implicit-any-catch.md) | Disallow implicit `any` error parameters in `catchError` operators. | βœ… | πŸ”§ | πŸ’‘ | πŸ’­ | | -| [no-index](docs/rules/no-index.md) | Disallow importing index modules. | βœ… | | | | | -| [no-internal](docs/rules/no-internal.md) | Disallow importing internal modules. | βœ… | πŸ”§ | πŸ’‘ | | | -| [no-nested-subscribe](docs/rules/no-nested-subscribe.md) | Disallow calling `subscribe` within a `subscribe` callback. | βœ… | | | πŸ’­ | | -| [no-redundant-notify](docs/rules/no-redundant-notify.md) | Disallow sending redundant notifications from completed or errored observables. | βœ… | | | πŸ’­ | | -| [no-sharereplay](docs/rules/no-sharereplay.md) | Disallow unsafe `shareReplay` usage. | βœ… | | | | | -| [no-subclass](docs/rules/no-subclass.md) | Disallow subclassing RxJS classes. | | | | πŸ’­ | | -| [no-subject-unsubscribe](docs/rules/no-subject-unsubscribe.md) | Disallow calling the `unsubscribe` method of subjects. | βœ… | | | πŸ’­ | | -| [no-subject-value](docs/rules/no-subject-value.md) | Disallow accessing the `value` property of a `BehaviorSubject` instance. | | | | πŸ’­ | | -| [no-subscribe-handlers](docs/rules/no-subscribe-handlers.md) | Disallow passing handlers to `subscribe`. | | | | πŸ’­ | | -| [no-tap](docs/rules/no-tap.md) | Disallow the `tap` operator. | | | | | ❌ | -| [no-topromise](docs/rules/no-topromise.md) | Disallow use of the `toPromise` method. | | | πŸ’‘ | πŸ’­ | | -| [no-unbound-methods](docs/rules/no-unbound-methods.md) | Disallow passing unbound methods. | βœ… | | | πŸ’­ | | -| [no-unsafe-catch](docs/rules/no-unsafe-catch.md) | Disallow unsafe `catchError` usage in effects and epics. | | | | πŸ’­ | | -| [no-unsafe-first](docs/rules/no-unsafe-first.md) | Disallow unsafe `first`/`take` usage in effects and epics. | | | | πŸ’­ | | -| [no-unsafe-subject-next](docs/rules/no-unsafe-subject-next.md) | Disallow unsafe optional `next` calls. | βœ… | | | πŸ’­ | | -| [no-unsafe-switchmap](docs/rules/no-unsafe-switchmap.md) | Disallow unsafe `switchMap` usage in effects and epics. | | | | πŸ’­ | | -| [no-unsafe-takeuntil](docs/rules/no-unsafe-takeuntil.md) | Disallow applying operators after `takeUntil`. | βœ… | | | πŸ’­ | | -| [prefer-observer](docs/rules/prefer-observer.md) | Disallow passing separate handlers to `subscribe` and `tap`. | | πŸ”§ | πŸ’‘ | πŸ’­ | | -| [prefer-root-operators](docs/rules/prefer-root-operators.md) | Disallow importing operators from `rxjs/operators`. | | πŸ”§ | πŸ’‘ | | | -| [suffix-subjects](docs/rules/suffix-subjects.md) | Enforce the use of a suffix in subject identifiers. | | | | πŸ’­ | | -| [throw-error](docs/rules/throw-error.md) | Enforce passing only `Error` values to `throwError`. | | | | πŸ’­ | | +| NameΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  | Description | πŸ’Ό | πŸ”§ | πŸ’‘ | πŸ’­ | ❌ | +| :--------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------- | :--- | :- | :- | :- | :- | +| [ban-observables](docs/rules/ban-observables.md) | Disallow banned observable creators. | | | | | | +| [ban-operators](docs/rules/ban-operators.md) | Disallow banned operators. | | | | πŸ’­ | | +| [finnish](docs/rules/finnish.md) | Enforce Finnish notation. | | | | πŸ’­ | | +| [just](docs/rules/just.md) | Require the use of `just` instead of `of`. | | πŸ”§ | | | | +| [macro](docs/rules/macro.md) | Require the use of the RxJS Tools Babel macro. | | πŸ”§ | | | ❌ | +| [no-async-subscribe](docs/rules/no-async-subscribe.md) | Disallow passing `async` functions to `subscribe`. | βœ… πŸ”’ | | | πŸ’­ | | +| [no-compat](docs/rules/no-compat.md) | Disallow the `rxjs-compat` package. | | | | | ❌ | +| [no-connectable](docs/rules/no-connectable.md) | Disallow operators that return connectable observables. | | | | πŸ’­ | | +| [no-create](docs/rules/no-create.md) | Disallow the static `Observable.create` function. | βœ… πŸ”’ | | | πŸ’­ | | +| [no-cyclic-action](docs/rules/no-cyclic-action.md) | Disallow cyclic actions in effects and epics. | | | | πŸ’­ | | +| [no-explicit-generics](docs/rules/no-explicit-generics.md) | Disallow unnecessary explicit generic type arguments. | | | | | | +| [no-exposed-subjects](docs/rules/no-exposed-subjects.md) | Disallow public and protected subjects. | πŸ”’ | | | πŸ’­ | | +| [no-finnish](docs/rules/no-finnish.md) | Disallow Finnish notation. | | | | πŸ’­ | | +| [no-ignored-default-value](docs/rules/no-ignored-default-value.md) | Disallow using `firstValueFrom`, `lastValueFrom`, `first`, and `last` without specifying a default value. | πŸ”’ | | | πŸ’­ | | +| [no-ignored-error](docs/rules/no-ignored-error.md) | Disallow calling `subscribe` without specifying an error handler. | πŸ”’ | | | πŸ’­ | | +| [no-ignored-notifier](docs/rules/no-ignored-notifier.md) | Disallow observables not composed from the `repeatWhen` or `retryWhen` notifier. | βœ… πŸ”’ | | | πŸ’­ | | +| [no-ignored-observable](docs/rules/no-ignored-observable.md) | Disallow ignoring observables returned by functions. | | | | πŸ’­ | | +| [no-ignored-replay-buffer](docs/rules/no-ignored-replay-buffer.md) | Disallow using `ReplaySubject`, `publishReplay` or `shareReplay` without specifying the buffer size. | βœ… πŸ”’ | | | | | +| [no-ignored-subscribe](docs/rules/no-ignored-subscribe.md) | Disallow calling `subscribe` without specifying arguments. | | | | πŸ’­ | | +| [no-ignored-subscription](docs/rules/no-ignored-subscription.md) | Disallow ignoring the subscription returned by `subscribe`. | | | | πŸ’­ | | +| [no-ignored-takewhile-value](docs/rules/no-ignored-takewhile-value.md) | Disallow ignoring the value within `takeWhile`. | βœ… πŸ”’ | | | | | +| [no-implicit-any-catch](docs/rules/no-implicit-any-catch.md) | Disallow implicit `any` error parameters in `catchError` operators. | βœ… πŸ”’ | πŸ”§ | πŸ’‘ | πŸ’­ | | +| [no-index](docs/rules/no-index.md) | Disallow importing index modules. | βœ… πŸ”’ | | | | | +| [no-internal](docs/rules/no-internal.md) | Disallow importing internal modules. | βœ… πŸ”’ | πŸ”§ | πŸ’‘ | | | +| [no-nested-subscribe](docs/rules/no-nested-subscribe.md) | Disallow calling `subscribe` within a `subscribe` callback. | βœ… πŸ”’ | | | πŸ’­ | | +| [no-redundant-notify](docs/rules/no-redundant-notify.md) | Disallow sending redundant notifications from completed or errored observables. | βœ… πŸ”’ | | | πŸ’­ | | +| [no-sharereplay](docs/rules/no-sharereplay.md) | Disallow unsafe `shareReplay` usage. | βœ… πŸ”’ | | | | | +| [no-subclass](docs/rules/no-subclass.md) | Disallow subclassing RxJS classes. | | | | πŸ’­ | | +| [no-subject-unsubscribe](docs/rules/no-subject-unsubscribe.md) | Disallow calling the `unsubscribe` method of subjects. | βœ… πŸ”’ | | | πŸ’­ | | +| [no-subject-value](docs/rules/no-subject-value.md) | Disallow accessing the `value` property of a `BehaviorSubject` instance. | | | | πŸ’­ | | +| [no-subscribe-handlers](docs/rules/no-subscribe-handlers.md) | Disallow passing handlers to `subscribe`. | | | | πŸ’­ | | +| [no-tap](docs/rules/no-tap.md) | Disallow the `tap` operator. | | | | | ❌ | +| [no-topromise](docs/rules/no-topromise.md) | Disallow use of the `toPromise` method. | πŸ”’ | | πŸ’‘ | πŸ’­ | | +| [no-unbound-methods](docs/rules/no-unbound-methods.md) | Disallow passing unbound methods. | βœ… πŸ”’ | | | πŸ’­ | | +| [no-unsafe-catch](docs/rules/no-unsafe-catch.md) | Disallow unsafe `catchError` usage in effects and epics. | | | | πŸ’­ | | +| [no-unsafe-first](docs/rules/no-unsafe-first.md) | Disallow unsafe `first`/`take` usage in effects and epics. | | | | πŸ’­ | | +| [no-unsafe-subject-next](docs/rules/no-unsafe-subject-next.md) | Disallow unsafe optional `next` calls. | βœ… πŸ”’ | | | πŸ’­ | | +| [no-unsafe-switchmap](docs/rules/no-unsafe-switchmap.md) | Disallow unsafe `switchMap` usage in effects and epics. | | | | πŸ’­ | | +| [no-unsafe-takeuntil](docs/rules/no-unsafe-takeuntil.md) | Disallow applying operators after `takeUntil`. | βœ… πŸ”’ | | | πŸ’­ | | +| [prefer-observer](docs/rules/prefer-observer.md) | Disallow passing separate handlers to `subscribe` and `tap`. | πŸ”’ | πŸ”§ | πŸ’‘ | πŸ’­ | | +| [prefer-root-operators](docs/rules/prefer-root-operators.md) | Disallow importing operators from `rxjs/operators`. | πŸ”’ | πŸ”§ | πŸ’‘ | | | +| [suffix-subjects](docs/rules/suffix-subjects.md) | Enforce the use of a suffix in subject identifiers. | | | | πŸ’­ | | +| [throw-error](docs/rules/throw-error.md) | Enforce passing only `Error` values to `throwError`. | πŸ”’ | | | πŸ’­ | | diff --git a/docs/rules/no-async-subscribe.md b/docs/rules/no-async-subscribe.md index 08685f14..a18c37f4 100644 --- a/docs/rules/no-async-subscribe.md +++ b/docs/rules/no-async-subscribe.md @@ -1,6 +1,6 @@ # Disallow passing `async` functions to `subscribe` (`rxjs-x/no-async-subscribe`) -πŸ’Ό This rule is enabled in the βœ… `recommended` config. +πŸ’Ό This rule is enabled in the following configs: βœ… `recommended`, πŸ”’ `strict`. πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/docs/rules/no-create.md b/docs/rules/no-create.md index 3d6afe37..65aaa301 100644 --- a/docs/rules/no-create.md +++ b/docs/rules/no-create.md @@ -1,6 +1,6 @@ # Disallow the static `Observable.create` function (`rxjs-x/no-create`) -πŸ’Ό This rule is enabled in the βœ… `recommended` config. +πŸ’Ό This rule is enabled in the following configs: βœ… `recommended`, πŸ”’ `strict`. πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/docs/rules/no-exposed-subjects.md b/docs/rules/no-exposed-subjects.md index 4b2ed2d2..a86d5081 100644 --- a/docs/rules/no-exposed-subjects.md +++ b/docs/rules/no-exposed-subjects.md @@ -1,5 +1,7 @@ # Disallow public and protected subjects (`rxjs-x/no-exposed-subjects`) +πŸ’Ό This rule is enabled in the πŸ”’ `strict` config. + πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/docs/rules/no-ignored-default-value.md b/docs/rules/no-ignored-default-value.md index ca399502..0b82010d 100644 --- a/docs/rules/no-ignored-default-value.md +++ b/docs/rules/no-ignored-default-value.md @@ -1,5 +1,7 @@ # Disallow using `firstValueFrom`, `lastValueFrom`, `first`, and `last` without specifying a default value (`rxjs-x/no-ignored-default-value`) +πŸ’Ό This rule is enabled in the πŸ”’ `strict` config. + πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/docs/rules/no-ignored-error.md b/docs/rules/no-ignored-error.md index 09fe9bc0..040bf4a5 100644 --- a/docs/rules/no-ignored-error.md +++ b/docs/rules/no-ignored-error.md @@ -1,5 +1,7 @@ # Disallow calling `subscribe` without specifying an error handler (`rxjs-x/no-ignored-error`) +πŸ’Ό This rule is enabled in the πŸ”’ `strict` config. + πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/docs/rules/no-ignored-notifier.md b/docs/rules/no-ignored-notifier.md index 6c3529b2..06bd6202 100644 --- a/docs/rules/no-ignored-notifier.md +++ b/docs/rules/no-ignored-notifier.md @@ -1,6 +1,6 @@ # Disallow observables not composed from the `repeatWhen` or `retryWhen` notifier (`rxjs-x/no-ignored-notifier`) -πŸ’Ό This rule is enabled in the βœ… `recommended` config. +πŸ’Ό This rule is enabled in the following configs: βœ… `recommended`, πŸ”’ `strict`. πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/docs/rules/no-ignored-replay-buffer.md b/docs/rules/no-ignored-replay-buffer.md index 327d8eab..c53326bc 100644 --- a/docs/rules/no-ignored-replay-buffer.md +++ b/docs/rules/no-ignored-replay-buffer.md @@ -1,6 +1,6 @@ # Disallow using `ReplaySubject`, `publishReplay` or `shareReplay` without specifying the buffer size (`rxjs-x/no-ignored-replay-buffer`) -πŸ’Ό This rule is enabled in the βœ… `recommended` config. +πŸ’Ό This rule is enabled in the following configs: βœ… `recommended`, πŸ”’ `strict`. diff --git a/docs/rules/no-ignored-takewhile-value.md b/docs/rules/no-ignored-takewhile-value.md index cea5d850..8a6bc625 100644 --- a/docs/rules/no-ignored-takewhile-value.md +++ b/docs/rules/no-ignored-takewhile-value.md @@ -1,6 +1,6 @@ # Disallow ignoring the value within `takeWhile` (`rxjs-x/no-ignored-takewhile-value`) -πŸ’Ό This rule is enabled in the βœ… `recommended` config. +πŸ’Ό This rule is enabled in the following configs: βœ… `recommended`, πŸ”’ `strict`. diff --git a/docs/rules/no-implicit-any-catch.md b/docs/rules/no-implicit-any-catch.md index 059cbdef..9029a3cf 100644 --- a/docs/rules/no-implicit-any-catch.md +++ b/docs/rules/no-implicit-any-catch.md @@ -1,6 +1,6 @@ # Disallow implicit `any` error parameters in `catchError` operators (`rxjs-x/no-implicit-any-catch`) -πŸ’Ό This rule is enabled in the βœ… `recommended` config. +πŸ’Ό This rule is enabled in the following configs: βœ… `recommended`, πŸ”’ `strict`. πŸ”§πŸ’‘ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). diff --git a/docs/rules/no-index.md b/docs/rules/no-index.md index d1e96af0..123a6cee 100644 --- a/docs/rules/no-index.md +++ b/docs/rules/no-index.md @@ -1,6 +1,6 @@ # Disallow importing index modules (`rxjs-x/no-index`) -πŸ’Ό This rule is enabled in the βœ… `recommended` config. +πŸ’Ό This rule is enabled in the following configs: βœ… `recommended`, πŸ”’ `strict`. diff --git a/docs/rules/no-internal.md b/docs/rules/no-internal.md index 8c04bdb8..20a2d79d 100644 --- a/docs/rules/no-internal.md +++ b/docs/rules/no-internal.md @@ -1,6 +1,6 @@ # Disallow importing internal modules (`rxjs-x/no-internal`) -πŸ’Ό This rule is enabled in the βœ… `recommended` config. +πŸ’Ό This rule is enabled in the following configs: βœ… `recommended`, πŸ”’ `strict`. πŸ”§πŸ’‘ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). diff --git a/docs/rules/no-nested-subscribe.md b/docs/rules/no-nested-subscribe.md index cc948993..ad222a44 100644 --- a/docs/rules/no-nested-subscribe.md +++ b/docs/rules/no-nested-subscribe.md @@ -1,6 +1,6 @@ # Disallow calling `subscribe` within a `subscribe` callback (`rxjs-x/no-nested-subscribe`) -πŸ’Ό This rule is enabled in the βœ… `recommended` config. +πŸ’Ό This rule is enabled in the following configs: βœ… `recommended`, πŸ”’ `strict`. πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/docs/rules/no-redundant-notify.md b/docs/rules/no-redundant-notify.md index 081049bf..945ed49d 100644 --- a/docs/rules/no-redundant-notify.md +++ b/docs/rules/no-redundant-notify.md @@ -1,6 +1,6 @@ # Disallow sending redundant notifications from completed or errored observables (`rxjs-x/no-redundant-notify`) -πŸ’Ό This rule is enabled in the βœ… `recommended` config. +πŸ’Ό This rule is enabled in the following configs: βœ… `recommended`, πŸ”’ `strict`. πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/docs/rules/no-sharereplay.md b/docs/rules/no-sharereplay.md index e2e185e5..03042a55 100644 --- a/docs/rules/no-sharereplay.md +++ b/docs/rules/no-sharereplay.md @@ -1,6 +1,6 @@ # Disallow unsafe `shareReplay` usage (`rxjs-x/no-sharereplay`) -πŸ’Ό This rule is enabled in the βœ… `recommended` config. +πŸ’Ό This rule is enabled in the following configs: βœ… `recommended`, πŸ”’ `strict`. diff --git a/docs/rules/no-subject-unsubscribe.md b/docs/rules/no-subject-unsubscribe.md index dda9b824..fa11b86e 100644 --- a/docs/rules/no-subject-unsubscribe.md +++ b/docs/rules/no-subject-unsubscribe.md @@ -1,6 +1,6 @@ # Disallow calling the `unsubscribe` method of subjects (`rxjs-x/no-subject-unsubscribe`) -πŸ’Ό This rule is enabled in the βœ… `recommended` config. +πŸ’Ό This rule is enabled in the following configs: βœ… `recommended`, πŸ”’ `strict`. πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/docs/rules/no-topromise.md b/docs/rules/no-topromise.md index f88c565a..5359dce2 100644 --- a/docs/rules/no-topromise.md +++ b/docs/rules/no-topromise.md @@ -1,5 +1,7 @@ # Disallow use of the `toPromise` method (`rxjs-x/no-topromise`) +πŸ’Ό This rule is enabled in the πŸ”’ `strict` config. + πŸ’‘ This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/docs/rules/no-unbound-methods.md b/docs/rules/no-unbound-methods.md index f896809b..8ac596f1 100644 --- a/docs/rules/no-unbound-methods.md +++ b/docs/rules/no-unbound-methods.md @@ -1,6 +1,6 @@ # Disallow passing unbound methods (`rxjs-x/no-unbound-methods`) -πŸ’Ό This rule is enabled in the βœ… `recommended` config. +πŸ’Ό This rule is enabled in the following configs: βœ… `recommended`, πŸ”’ `strict`. πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/docs/rules/no-unsafe-subject-next.md b/docs/rules/no-unsafe-subject-next.md index ff51ddad..a3eccf23 100644 --- a/docs/rules/no-unsafe-subject-next.md +++ b/docs/rules/no-unsafe-subject-next.md @@ -1,6 +1,6 @@ # Disallow unsafe optional `next` calls (`rxjs-x/no-unsafe-subject-next`) -πŸ’Ό This rule is enabled in the βœ… `recommended` config. +πŸ’Ό This rule is enabled in the following configs: βœ… `recommended`, πŸ”’ `strict`. πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/docs/rules/no-unsafe-takeuntil.md b/docs/rules/no-unsafe-takeuntil.md index c45eec06..8a2dda6e 100644 --- a/docs/rules/no-unsafe-takeuntil.md +++ b/docs/rules/no-unsafe-takeuntil.md @@ -1,6 +1,6 @@ # Disallow applying operators after `takeUntil` (`rxjs-x/no-unsafe-takeuntil`) -πŸ’Ό This rule is enabled in the βœ… `recommended` config. +πŸ’Ό This rule is enabled in the following configs: βœ… `recommended`, πŸ”’ `strict`. πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/docs/rules/prefer-observer.md b/docs/rules/prefer-observer.md index 1da03859..6c231255 100644 --- a/docs/rules/prefer-observer.md +++ b/docs/rules/prefer-observer.md @@ -1,5 +1,7 @@ # Disallow passing separate handlers to `subscribe` and `tap` (`rxjs-x/prefer-observer`) +πŸ’Ό This rule is enabled in the πŸ”’ `strict` config. + πŸ”§πŸ’‘ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/docs/rules/prefer-root-operators.md b/docs/rules/prefer-root-operators.md index bfc205c6..8cff5fab 100644 --- a/docs/rules/prefer-root-operators.md +++ b/docs/rules/prefer-root-operators.md @@ -1,5 +1,7 @@ # Disallow importing operators from `rxjs/operators` (`rxjs-x/prefer-root-operators`) +πŸ’Ό This rule is enabled in the πŸ”’ `strict` config. + πŸ”§πŸ’‘ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). diff --git a/docs/rules/throw-error.md b/docs/rules/throw-error.md index 924b74f3..7c3a98b2 100644 --- a/docs/rules/throw-error.md +++ b/docs/rules/throw-error.md @@ -1,5 +1,7 @@ # Enforce passing only `Error` values to `throwError` (`rxjs-x/throw-error`) +πŸ’Ό This rule is enabled in the πŸ”’ `strict` config. + πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/src/configs/strict.ts b/src/configs/strict.ts new file mode 100644 index 00000000..80e2f4ec --- /dev/null +++ b/src/configs/strict.ts @@ -0,0 +1,33 @@ +import { TSESLint } from '@typescript-eslint/utils'; + +export const createStrictConfig = ( + plugin: TSESLint.FlatConfig.Plugin, +) => ({ + plugins: { + 'rxjs-x': plugin, + }, + rules: { + 'rxjs-x/no-async-subscribe': 'error', + 'rxjs-x/no-create': 'error', + 'rxjs-x/no-exposed-subjects': 'error', + 'rxjs-x/no-ignored-default-value': 'error', + 'rxjs-x/no-ignored-error': 'error', + 'rxjs-x/no-ignored-notifier': 'error', + 'rxjs-x/no-ignored-replay-buffer': 'error', + 'rxjs-x/no-ignored-takewhile-value': 'error', + 'rxjs-x/no-implicit-any-catch': ['error', { allowExplicitAny: false }], + 'rxjs-x/no-index': 'error', + 'rxjs-x/no-internal': 'error', + 'rxjs-x/no-nested-subscribe': 'error', + 'rxjs-x/no-redundant-notify': 'error', + 'rxjs-x/no-sharereplay': ['error', { allowConfig: true }], + 'rxjs-x/no-subject-unsubscribe': 'error', + 'rxjs-x/no-topromise': 'error', + 'rxjs-x/no-unbound-methods': 'error', + 'rxjs-x/no-unsafe-subject-next': 'error', + 'rxjs-x/no-unsafe-takeuntil': 'error', + 'rxjs-x/prefer-observer': ['error', { allowNext: false }], + 'rxjs-x/prefer-root-operators': 'error', + 'rxjs-x/throw-error': ['error', { allowThrowingAny: false, allowThrowingUnknown: false }], + }, +} satisfies TSESLint.FlatConfig.Config); diff --git a/src/index.ts b/src/index.ts index ab3491b5..d83cef9c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ import { TSESLint } from '@typescript-eslint/utils'; import { name, version } from '../package.json'; import { createRecommendedConfig } from './configs/recommended'; +import { createStrictConfig } from './configs/strict'; import { banObservablesRule } from './rules/ban-observables'; import { banOperatorsRule } from './rules/ban-operators'; @@ -99,6 +100,7 @@ const rxjsX = { ...plugin, configs: { recommended: createRecommendedConfig(plugin), + strict: createStrictConfig(plugin), }, } satisfies TSESLint.FlatConfig.Plugin; diff --git a/tests/configs/strict.test.ts b/tests/configs/strict.test.ts new file mode 100644 index 00000000..cd213fc4 --- /dev/null +++ b/tests/configs/strict.test.ts @@ -0,0 +1,19 @@ +import { createRecommendedConfig } from '../../src/configs/recommended'; +import { createStrictConfig } from '../../src/configs/strict'; + +describe('strict', () => { + const mockPlugin = {}; + const config = createStrictConfig(mockPlugin); + + it('should add the rxjs-x plugin', () => { + expect(config.plugins).toEqual({ 'rxjs-x': mockPlugin }); + }); + + it('should include the recommended rules', () => { + const recommendedConfig = createRecommendedConfig(mockPlugin); + + for (const rule of Object.keys(recommendedConfig.rules)) { + expect(config.rules).toHaveProperty(rule); + } + }); +}); From b5288436ef4ec772ee0be85165612211e07a53c4 Mon Sep 17 00:00:00 2001 From: Jason Weinzierl Date: Fri, 22 Nov 2024 10:38:17 -0600 Subject: [PATCH 03/12] refactor(strict): indicate strict or recommended in rules --- src/rules/no-async-subscribe.ts | 2 +- src/rules/no-create.ts | 2 +- src/rules/no-exposed-subjects.ts | 1 + src/rules/no-ignored-default-value.ts | 1 + src/rules/no-ignored-error.ts | 1 + src/rules/no-ignored-notifier.ts | 2 +- src/rules/no-ignored-replay-buffer.ts | 2 +- src/rules/no-ignored-takewhile-value.ts | 2 +- src/rules/no-implicit-any-catch.ts | 7 ++++++- src/rules/no-index.ts | 2 +- src/rules/no-internal.ts | 2 +- src/rules/no-nested-subscribe.ts | 2 +- src/rules/no-redundant-notify.ts | 2 +- src/rules/no-sharereplay.ts | 2 +- src/rules/no-subject-unsubscribe.ts | 2 +- src/rules/no-topromise.ts | 1 + src/rules/no-unbound-methods.ts | 2 +- src/rules/no-unsafe-subject-next.ts | 2 +- src/rules/no-unsafe-takeuntil.ts | 2 +- src/rules/prefer-observer.ts | 1 + src/rules/prefer-root-operators.ts | 1 + src/rules/throw-error.ts | 1 + src/utils.ts | 4 ++-- 23 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/rules/no-async-subscribe.ts b/src/rules/no-async-subscribe.ts index 522b72f7..89127af3 100644 --- a/src/rules/no-async-subscribe.ts +++ b/src/rules/no-async-subscribe.ts @@ -7,7 +7,7 @@ export const noAsyncSubscribeRule = ruleCreator({ meta: { docs: { description: 'Disallow passing `async` functions to `subscribe`.', - recommended: true, + recommended: 'recommended', requiresTypeChecking: true, }, messages: { diff --git a/src/rules/no-create.ts b/src/rules/no-create.ts index 5123f8da..c7a17f24 100644 --- a/src/rules/no-create.ts +++ b/src/rules/no-create.ts @@ -7,7 +7,7 @@ export const noCreateRule = ruleCreator({ meta: { docs: { description: 'Disallow the static `Observable.create` function.', - recommended: true, + recommended: 'recommended', requiresTypeChecking: true, }, messages: { diff --git a/src/rules/no-exposed-subjects.ts b/src/rules/no-exposed-subjects.ts index 5dd6964a..f32e6473 100644 --- a/src/rules/no-exposed-subjects.ts +++ b/src/rules/no-exposed-subjects.ts @@ -12,6 +12,7 @@ export const noExposedSubjectsRule = ruleCreator({ meta: { docs: { description: 'Disallow public and protected subjects.', + recommended: 'strict', requiresTypeChecking: true, }, messages: { diff --git a/src/rules/no-ignored-default-value.ts b/src/rules/no-ignored-default-value.ts index 81173a73..9e8a6a53 100644 --- a/src/rules/no-ignored-default-value.ts +++ b/src/rules/no-ignored-default-value.ts @@ -7,6 +7,7 @@ export const noIgnoredDefaultValueRule = ruleCreator({ meta: { docs: { description: 'Disallow using `firstValueFrom`, `lastValueFrom`, `first`, and `last` without specifying a default value.', + recommended: 'strict', requiresTypeChecking: true, }, messages: { diff --git a/src/rules/no-ignored-error.ts b/src/rules/no-ignored-error.ts index b3657d45..0a5a7cbf 100644 --- a/src/rules/no-ignored-error.ts +++ b/src/rules/no-ignored-error.ts @@ -8,6 +8,7 @@ export const noIgnoredErrorRule = ruleCreator({ docs: { description: 'Disallow calling `subscribe` without specifying an error handler.', + recommended: 'strict', requiresTypeChecking: true, }, messages: { diff --git a/src/rules/no-ignored-notifier.ts b/src/rules/no-ignored-notifier.ts index c94d177a..6bea60ba 100644 --- a/src/rules/no-ignored-notifier.ts +++ b/src/rules/no-ignored-notifier.ts @@ -12,7 +12,7 @@ export const noIgnoredNotifierRule = ruleCreator({ docs: { description: 'Disallow observables not composed from the `repeatWhen` or `retryWhen` notifier.', - recommended: true, + recommended: 'recommended', requiresTypeChecking: true, }, messages: { diff --git a/src/rules/no-ignored-replay-buffer.ts b/src/rules/no-ignored-replay-buffer.ts index c2f10219..4b5d4412 100644 --- a/src/rules/no-ignored-replay-buffer.ts +++ b/src/rules/no-ignored-replay-buffer.ts @@ -8,7 +8,7 @@ export const noIgnoredReplayBufferRule = ruleCreator({ docs: { description: 'Disallow using `ReplaySubject`, `publishReplay` or `shareReplay` without specifying the buffer size.', - recommended: true, + recommended: 'recommended', }, messages: { forbidden: 'Ignoring the buffer size is forbidden.', diff --git a/src/rules/no-ignored-takewhile-value.ts b/src/rules/no-ignored-takewhile-value.ts index 607ea30a..025381b0 100644 --- a/src/rules/no-ignored-takewhile-value.ts +++ b/src/rules/no-ignored-takewhile-value.ts @@ -12,7 +12,7 @@ export const noIgnoredTakewhileValueRule = ruleCreator({ meta: { docs: { description: 'Disallow ignoring the value within `takeWhile`.', - recommended: true, + recommended: 'recommended', }, messages: { forbidden: 'Ignoring the value within takeWhile is forbidden.', diff --git a/src/rules/no-implicit-any-catch.ts b/src/rules/no-implicit-any-catch.ts index 5c74081b..6039fd87 100644 --- a/src/rules/no-implicit-any-catch.ts +++ b/src/rules/no-implicit-any-catch.ts @@ -40,7 +40,12 @@ export const noImplicitAnyCatchRule = ruleCreator({ docs: { description: 'Disallow implicit `any` error parameters in `catchError` operators.', - recommended: true, + recommended: { + recommended: true, + strict: [{ + allowExplicitAny: false, + }], + }, requiresTypeChecking: true, }, fixable: 'code', diff --git a/src/rules/no-index.ts b/src/rules/no-index.ts index 5cde4a8c..aa33acef 100644 --- a/src/rules/no-index.ts +++ b/src/rules/no-index.ts @@ -6,7 +6,7 @@ export const noIndexRule = ruleCreator({ meta: { docs: { description: 'Disallow importing index modules.', - recommended: true, + recommended: 'recommended', }, messages: { forbidden: 'RxJS imports from index modules are forbidden.', diff --git a/src/rules/no-internal.ts b/src/rules/no-internal.ts index b6c73d3e..2789fdd9 100644 --- a/src/rules/no-internal.ts +++ b/src/rules/no-internal.ts @@ -9,7 +9,7 @@ export const noInternalRule = ruleCreator({ meta: { docs: { description: 'Disallow importing internal modules.', - recommended: true, + recommended: 'recommended', }, fixable: 'code', hasSuggestions: true, diff --git a/src/rules/no-nested-subscribe.ts b/src/rules/no-nested-subscribe.ts index d6ce255f..bd94d086 100644 --- a/src/rules/no-nested-subscribe.ts +++ b/src/rules/no-nested-subscribe.ts @@ -8,7 +8,7 @@ export const noNestedSubscribeRule = ruleCreator({ docs: { description: 'Disallow calling `subscribe` within a `subscribe` callback.', - recommended: true, + recommended: 'recommended', requiresTypeChecking: true, }, messages: { diff --git a/src/rules/no-redundant-notify.ts b/src/rules/no-redundant-notify.ts index d14a28f6..f515f9e7 100644 --- a/src/rules/no-redundant-notify.ts +++ b/src/rules/no-redundant-notify.ts @@ -18,7 +18,7 @@ export const noRedundantNotifyRule = ruleCreator({ docs: { description: 'Disallow sending redundant notifications from completed or errored observables.', - recommended: true, + recommended: 'recommended', requiresTypeChecking: true, }, messages: { diff --git a/src/rules/no-sharereplay.ts b/src/rules/no-sharereplay.ts index 75c1295f..bfbe29b7 100644 --- a/src/rules/no-sharereplay.ts +++ b/src/rules/no-sharereplay.ts @@ -10,7 +10,7 @@ export const noSharereplayRule = ruleCreator({ meta: { docs: { description: 'Disallow unsafe `shareReplay` usage.', - recommended: true, + recommended: 'recommended', }, messages: { forbidden: 'shareReplay is forbidden.', diff --git a/src/rules/no-subject-unsubscribe.ts b/src/rules/no-subject-unsubscribe.ts index 43f70cfb..40ac8e8e 100644 --- a/src/rules/no-subject-unsubscribe.ts +++ b/src/rules/no-subject-unsubscribe.ts @@ -8,7 +8,7 @@ export const noSubjectUnsubscribeRule = ruleCreator({ docs: { description: 'Disallow calling the `unsubscribe` method of subjects.', - recommended: true, + recommended: 'recommended', requiresTypeChecking: true, }, messages: { diff --git a/src/rules/no-topromise.ts b/src/rules/no-topromise.ts index c71acedf..d508e9d0 100644 --- a/src/rules/no-topromise.ts +++ b/src/rules/no-topromise.ts @@ -7,6 +7,7 @@ export const noTopromiseRule = ruleCreator({ meta: { docs: { description: 'Disallow use of the `toPromise` method.', + recommended: 'strict', requiresTypeChecking: true, }, hasSuggestions: true, diff --git a/src/rules/no-unbound-methods.ts b/src/rules/no-unbound-methods.ts index 706f91a4..ab7ee39b 100644 --- a/src/rules/no-unbound-methods.ts +++ b/src/rules/no-unbound-methods.ts @@ -10,7 +10,7 @@ export const noUnboundMethodsRule = ruleCreator({ meta: { docs: { description: 'Disallow passing unbound methods.', - recommended: true, + recommended: 'recommended', requiresTypeChecking: true, }, messages: { diff --git a/src/rules/no-unsafe-subject-next.ts b/src/rules/no-unsafe-subject-next.ts index f5fae2af..29906cef 100644 --- a/src/rules/no-unsafe-subject-next.ts +++ b/src/rules/no-unsafe-subject-next.ts @@ -12,7 +12,7 @@ export const noUnsafeSubjectNext = ruleCreator({ meta: { docs: { description: 'Disallow unsafe optional `next` calls.', - recommended: true, + recommended: 'recommended', requiresTypeChecking: true, }, messages: { diff --git a/src/rules/no-unsafe-takeuntil.ts b/src/rules/no-unsafe-takeuntil.ts index edda0b54..5ff9b984 100644 --- a/src/rules/no-unsafe-takeuntil.ts +++ b/src/rules/no-unsafe-takeuntil.ts @@ -42,7 +42,7 @@ export const noUnsafeTakeuntilRule = ruleCreator({ meta: { docs: { description: 'Disallow applying operators after `takeUntil`.', - recommended: true, + recommended: 'recommended', requiresTypeChecking: true, }, messages: { diff --git a/src/rules/prefer-observer.ts b/src/rules/prefer-observer.ts index 108d477b..9efb6fde 100644 --- a/src/rules/prefer-observer.ts +++ b/src/rules/prefer-observer.ts @@ -20,6 +20,7 @@ export const preferObserverRule = ruleCreator({ docs: { description: 'Disallow passing separate handlers to `subscribe` and `tap`.', + recommended: 'strict', requiresTypeChecking: true, }, fixable: 'code', diff --git a/src/rules/prefer-root-operators.ts b/src/rules/prefer-root-operators.ts index 1e7e793b..e62989d7 100644 --- a/src/rules/prefer-root-operators.ts +++ b/src/rules/prefer-root-operators.ts @@ -22,6 +22,7 @@ export const preferRootOperatorsRule = ruleCreator({ meta: { docs: { description: 'Disallow importing operators from `rxjs/operators`.', + recommended: 'strict', }, fixable: 'code', hasSuggestions: true, diff --git a/src/rules/throw-error.ts b/src/rules/throw-error.ts index 75c63b6d..185ca1af 100644 --- a/src/rules/throw-error.ts +++ b/src/rules/throw-error.ts @@ -15,6 +15,7 @@ export const throwErrorRule = ruleCreator({ docs: { description: 'Enforce passing only `Error` values to `throwError`.', + recommended: 'strict', requiresTypeChecking: true, }, messages: { diff --git a/src/utils.ts b/src/utils.ts index 34c73403..7035d045 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,4 @@ -import { ESLintUtils } from '@typescript-eslint/utils'; +import { ESLintUtils, TSESLint } from '@typescript-eslint/utils'; export function createRegExpForWords( config: string | string[], @@ -22,7 +22,7 @@ export function escapeRegExp(text: string): string { export interface RxjsXRuleDocs { description: string; - recommended?: boolean; + recommended?: TSESLint.RuleRecommendation | TSESLint.RuleRecommendationAcrossConfigs; requiresTypeChecking?: boolean; } From 3f9fc5b66608416e019029a6d46b61c032e12240 Mon Sep 17 00:00:00 2001 From: Jason Weinzierl Date: Fri, 22 Nov 2024 10:53:28 -0600 Subject: [PATCH 04/12] test: ensure recommended meta aligns with configs --- tests/package.test.ts | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/package.test.ts b/tests/package.test.ts index 11d39154..71825a81 100644 --- a/tests/package.test.ts +++ b/tests/package.test.ts @@ -45,4 +45,38 @@ describe('package', () => { } } }); + + it('has rules flagged according to their configs', () => { + if (!plugin.configs) { + expect.fail('No configs found.'); + } + + const namespace = 'rxjs-x'; + + for (const [ruleName, rule] of Object.entries(plugin.rules)) { + const fullRuleName = `${namespace}/${ruleName}`; + const ruleRec = rule.meta.docs?.recommended; + + if (!ruleRec) { + // Rule is not part of any config. + expect(plugin.configs.recommended.rules).not.toHaveProperty(fullRuleName); + expect(plugin.configs.strict.rules).not.toHaveProperty(fullRuleName); + } else if (typeof ruleRec === 'string') { + // Rule is part of a single config. + if (ruleRec === 'recommended') { + expect(plugin.configs.recommended.rules).toHaveProperty(fullRuleName); + } else if (ruleRec === 'strict') { + expect(plugin.configs.strict.rules).toHaveProperty(fullRuleName); + } else { + expect.fail(`Invalid recommended value for rule ${fullRuleName}: ${ruleRec}`); + } + } else { + // Rule is part of several configs. + if (ruleRec.recommended) { + expect(plugin.configs.recommended.rules).toHaveProperty(fullRuleName); + } + expect(plugin.configs.strict.rules).toHaveProperty(fullRuleName); + } + } + }); }); From 4275a0457a7bb2fce0c75a73bdf7939a4735169d Mon Sep 17 00:00:00 2001 From: Jason Weinzierl Date: Fri, 22 Nov 2024 10:56:44 -0600 Subject: [PATCH 05/12] refactor: sharereplay already defaults allowConfig true --- src/configs/recommended.ts | 2 +- src/configs/strict.ts | 2 +- tests/configs/recommended.test.ts | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/configs/recommended.ts b/src/configs/recommended.ts index 91007f6d..61ffca1e 100644 --- a/src/configs/recommended.ts +++ b/src/configs/recommended.ts @@ -17,7 +17,7 @@ export const createRecommendedConfig = ( 'rxjs-x/no-internal': 'error', 'rxjs-x/no-nested-subscribe': 'error', 'rxjs-x/no-redundant-notify': 'error', - 'rxjs-x/no-sharereplay': ['error', { allowConfig: true }], + 'rxjs-x/no-sharereplay': 'error', 'rxjs-x/no-subject-unsubscribe': 'error', 'rxjs-x/no-unbound-methods': 'error', 'rxjs-x/no-unsafe-subject-next': 'error', diff --git a/src/configs/strict.ts b/src/configs/strict.ts index 80e2f4ec..606f0787 100644 --- a/src/configs/strict.ts +++ b/src/configs/strict.ts @@ -20,7 +20,7 @@ export const createStrictConfig = ( 'rxjs-x/no-internal': 'error', 'rxjs-x/no-nested-subscribe': 'error', 'rxjs-x/no-redundant-notify': 'error', - 'rxjs-x/no-sharereplay': ['error', { allowConfig: true }], + 'rxjs-x/no-sharereplay': 'error', 'rxjs-x/no-subject-unsubscribe': 'error', 'rxjs-x/no-topromise': 'error', 'rxjs-x/no-unbound-methods': 'error', diff --git a/tests/configs/recommended.test.ts b/tests/configs/recommended.test.ts index 3ba4581c..f52dcc6f 100644 --- a/tests/configs/recommended.test.ts +++ b/tests/configs/recommended.test.ts @@ -8,8 +8,10 @@ describe('recommended', () => { expect(config.plugins).toEqual({ 'rxjs-x': mockPlugin }); }); - it('should default no-sharereplay to allowConfig: true', () => { + it('should use the defaults of each rule', () => { expect(config.rules).instanceOf(Object); - expect(config.rules['rxjs-x/no-sharereplay']).toEqual(['error', { allowConfig: true }]); + for (const ruleEntry of Object.values(config.rules)) { + expect(ruleEntry).toEqual('error'); + } }); }); From f1cf40ab8ee84e64b43da2cec40dbcfa2b2fad9a Mon Sep 17 00:00:00 2001 From: Jason Weinzierl Date: Fri, 22 Nov 2024 11:03:49 -0600 Subject: [PATCH 06/12] test(strict): ensure strict rule options match strict config --- tests/package.test.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/package.test.ts b/tests/package.test.ts index 71825a81..a26f97a6 100644 --- a/tests/package.test.ts +++ b/tests/package.test.ts @@ -52,6 +52,8 @@ describe('package', () => { } const namespace = 'rxjs-x'; + const recommendedRules = plugin.configs.recommended.rules; + const strictRules = plugin.configs.strict.rules; for (const [ruleName, rule] of Object.entries(plugin.rules)) { const fullRuleName = `${namespace}/${ruleName}`; @@ -59,23 +61,25 @@ describe('package', () => { if (!ruleRec) { // Rule is not part of any config. - expect(plugin.configs.recommended.rules).not.toHaveProperty(fullRuleName); - expect(plugin.configs.strict.rules).not.toHaveProperty(fullRuleName); + expect(recommendedRules).not.toHaveProperty(fullRuleName); + expect(strictRules).not.toHaveProperty(fullRuleName); } else if (typeof ruleRec === 'string') { // Rule is part of a single config. if (ruleRec === 'recommended') { - expect(plugin.configs.recommended.rules).toHaveProperty(fullRuleName); + expect(recommendedRules).toHaveProperty(fullRuleName); } else if (ruleRec === 'strict') { - expect(plugin.configs.strict.rules).toHaveProperty(fullRuleName); + expect(strictRules).toHaveProperty(fullRuleName); } else { expect.fail(`Invalid recommended value for rule ${fullRuleName}: ${ruleRec}`); } } else { // Rule is part of several configs. if (ruleRec.recommended) { - expect(plugin.configs.recommended.rules).toHaveProperty(fullRuleName); + expect(recommendedRules).toHaveProperty(fullRuleName); } - expect(plugin.configs.strict.rules).toHaveProperty(fullRuleName); + expect(strictRules).toHaveProperty(fullRuleName); + expect(strictRules[fullRuleName as keyof typeof strictRules]).toBeInstanceOf(Array); + expect(strictRules[fullRuleName as keyof typeof strictRules][1]).toEqual(ruleRec.strict[0]); } } }); From 58a2997b758bc8b8451f2701ed7aadc90b247ea0 Mon Sep 17 00:00:00 2001 From: Jason Weinzierl Date: Fri, 22 Nov 2024 14:34:19 -0600 Subject: [PATCH 07/12] feat(strict): add additional rules to strict config --- src/configs/strict.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/configs/strict.ts b/src/configs/strict.ts index 606f0787..459d70e1 100644 --- a/src/configs/strict.ts +++ b/src/configs/strict.ts @@ -9,10 +9,12 @@ export const createStrictConfig = ( rules: { 'rxjs-x/no-async-subscribe': 'error', 'rxjs-x/no-create': 'error', + 'rxjs-x/no-explicit-generics': 'error', 'rxjs-x/no-exposed-subjects': 'error', 'rxjs-x/no-ignored-default-value': 'error', 'rxjs-x/no-ignored-error': 'error', 'rxjs-x/no-ignored-notifier': 'error', + 'rxjs-x/no-ignored-observable': 'error', 'rxjs-x/no-ignored-replay-buffer': 'error', 'rxjs-x/no-ignored-takewhile-value': 'error', 'rxjs-x/no-implicit-any-catch': ['error', { allowExplicitAny: false }], @@ -21,6 +23,7 @@ export const createStrictConfig = ( 'rxjs-x/no-nested-subscribe': 'error', 'rxjs-x/no-redundant-notify': 'error', 'rxjs-x/no-sharereplay': 'error', + 'rxjs-x/no-subclass': 'error', 'rxjs-x/no-subject-unsubscribe': 'error', 'rxjs-x/no-topromise': 'error', 'rxjs-x/no-unbound-methods': 'error', From e08b28bb4ffc4f5b255e557397e2dc11f1f6e70a Mon Sep 17 00:00:00 2001 From: Jason Weinzierl Date: Fri, 22 Nov 2024 14:38:58 -0600 Subject: [PATCH 08/12] test: add missing recommended labels --- README.md | 6 +++--- docs/rules/no-explicit-generics.md | 2 ++ docs/rules/no-ignored-observable.md | 2 ++ docs/rules/no-subclass.md | 2 ++ src/rules/no-explicit-generics.ts | 1 + src/rules/no-ignored-observable.ts | 1 + src/rules/no-subclass.ts | 1 + 7 files changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f4f59b5d..5e1bd97e 100644 --- a/README.md +++ b/README.md @@ -85,13 +85,13 @@ The package includes the following rules. | [no-connectable](docs/rules/no-connectable.md) | Disallow operators that return connectable observables. | | | | πŸ’­ | | | [no-create](docs/rules/no-create.md) | Disallow the static `Observable.create` function. | βœ… πŸ”’ | | | πŸ’­ | | | [no-cyclic-action](docs/rules/no-cyclic-action.md) | Disallow cyclic actions in effects and epics. | | | | πŸ’­ | | -| [no-explicit-generics](docs/rules/no-explicit-generics.md) | Disallow unnecessary explicit generic type arguments. | | | | | | +| [no-explicit-generics](docs/rules/no-explicit-generics.md) | Disallow unnecessary explicit generic type arguments. | πŸ”’ | | | | | | [no-exposed-subjects](docs/rules/no-exposed-subjects.md) | Disallow public and protected subjects. | πŸ”’ | | | πŸ’­ | | | [no-finnish](docs/rules/no-finnish.md) | Disallow Finnish notation. | | | | πŸ’­ | | | [no-ignored-default-value](docs/rules/no-ignored-default-value.md) | Disallow using `firstValueFrom`, `lastValueFrom`, `first`, and `last` without specifying a default value. | πŸ”’ | | | πŸ’­ | | | [no-ignored-error](docs/rules/no-ignored-error.md) | Disallow calling `subscribe` without specifying an error handler. | πŸ”’ | | | πŸ’­ | | | [no-ignored-notifier](docs/rules/no-ignored-notifier.md) | Disallow observables not composed from the `repeatWhen` or `retryWhen` notifier. | βœ… πŸ”’ | | | πŸ’­ | | -| [no-ignored-observable](docs/rules/no-ignored-observable.md) | Disallow ignoring observables returned by functions. | | | | πŸ’­ | | +| [no-ignored-observable](docs/rules/no-ignored-observable.md) | Disallow ignoring observables returned by functions. | πŸ”’ | | | πŸ’­ | | | [no-ignored-replay-buffer](docs/rules/no-ignored-replay-buffer.md) | Disallow using `ReplaySubject`, `publishReplay` or `shareReplay` without specifying the buffer size. | βœ… πŸ”’ | | | | | | [no-ignored-subscribe](docs/rules/no-ignored-subscribe.md) | Disallow calling `subscribe` without specifying arguments. | | | | πŸ’­ | | | [no-ignored-subscription](docs/rules/no-ignored-subscription.md) | Disallow ignoring the subscription returned by `subscribe`. | | | | πŸ’­ | | @@ -102,7 +102,7 @@ The package includes the following rules. | [no-nested-subscribe](docs/rules/no-nested-subscribe.md) | Disallow calling `subscribe` within a `subscribe` callback. | βœ… πŸ”’ | | | πŸ’­ | | | [no-redundant-notify](docs/rules/no-redundant-notify.md) | Disallow sending redundant notifications from completed or errored observables. | βœ… πŸ”’ | | | πŸ’­ | | | [no-sharereplay](docs/rules/no-sharereplay.md) | Disallow unsafe `shareReplay` usage. | βœ… πŸ”’ | | | | | -| [no-subclass](docs/rules/no-subclass.md) | Disallow subclassing RxJS classes. | | | | πŸ’­ | | +| [no-subclass](docs/rules/no-subclass.md) | Disallow subclassing RxJS classes. | πŸ”’ | | | πŸ’­ | | | [no-subject-unsubscribe](docs/rules/no-subject-unsubscribe.md) | Disallow calling the `unsubscribe` method of subjects. | βœ… πŸ”’ | | | πŸ’­ | | | [no-subject-value](docs/rules/no-subject-value.md) | Disallow accessing the `value` property of a `BehaviorSubject` instance. | | | | πŸ’­ | | | [no-subscribe-handlers](docs/rules/no-subscribe-handlers.md) | Disallow passing handlers to `subscribe`. | | | | πŸ’­ | | diff --git a/docs/rules/no-explicit-generics.md b/docs/rules/no-explicit-generics.md index 029ff4c2..e249d050 100644 --- a/docs/rules/no-explicit-generics.md +++ b/docs/rules/no-explicit-generics.md @@ -1,5 +1,7 @@ # Disallow unnecessary explicit generic type arguments (`rxjs-x/no-explicit-generics`) +πŸ’Ό This rule is enabled in the πŸ”’ `strict` config. + This rule prevents the use of explicit type arguments when the type arguments can be inferred. diff --git a/docs/rules/no-ignored-observable.md b/docs/rules/no-ignored-observable.md index 000564ea..2b113752 100644 --- a/docs/rules/no-ignored-observable.md +++ b/docs/rules/no-ignored-observable.md @@ -1,5 +1,7 @@ # Disallow ignoring observables returned by functions (`rxjs-x/no-ignored-observable`) +πŸ’Ό This rule is enabled in the πŸ”’ `strict` config. + πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/docs/rules/no-subclass.md b/docs/rules/no-subclass.md index 80a1a664..8ad58c94 100644 --- a/docs/rules/no-subclass.md +++ b/docs/rules/no-subclass.md @@ -1,5 +1,7 @@ # Disallow subclassing RxJS classes (`rxjs-x/no-subclass`) +πŸ’Ό This rule is enabled in the πŸ”’ `strict` config. + πŸ’­ This rule requires [type information](https://typescript-eslint.io/linting/typed-linting). diff --git a/src/rules/no-explicit-generics.ts b/src/rules/no-explicit-generics.ts index 199867e5..c2612891 100644 --- a/src/rules/no-explicit-generics.ts +++ b/src/rules/no-explicit-generics.ts @@ -7,6 +7,7 @@ export const noExplicitGenericsRule = ruleCreator({ meta: { docs: { description: 'Disallow unnecessary explicit generic type arguments.', + recommended: 'strict', }, messages: { forbidden: 'Explicit generic type arguments are forbidden.', diff --git a/src/rules/no-ignored-observable.ts b/src/rules/no-ignored-observable.ts index b3be02ff..e1b9e46b 100644 --- a/src/rules/no-ignored-observable.ts +++ b/src/rules/no-ignored-observable.ts @@ -7,6 +7,7 @@ export const noIgnoredObservableRule = ruleCreator({ meta: { docs: { description: 'Disallow ignoring observables returned by functions.', + recommended: 'strict', requiresTypeChecking: true, }, messages: { diff --git a/src/rules/no-subclass.ts b/src/rules/no-subclass.ts index 193e1d4d..3bdae3db 100644 --- a/src/rules/no-subclass.ts +++ b/src/rules/no-subclass.ts @@ -7,6 +7,7 @@ export const noSubclassRule = ruleCreator({ meta: { docs: { description: 'Disallow subclassing RxJS classes.', + recommended: 'strict', requiresTypeChecking: true, }, messages: { From f67c464e1940a3d01eb6a3636d97c0b038a34de0 Mon Sep 17 00:00:00 2001 From: Jason Weinzierl Date: Fri, 22 Nov 2024 14:53:39 -0600 Subject: [PATCH 09/12] docs(prefer-observer): add link to rxjs observer docs --- docs/rules/prefer-observer.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/rules/prefer-observer.md b/docs/rules/prefer-observer.md index 6c231255..4b71e7a4 100644 --- a/docs/rules/prefer-observer.md +++ b/docs/rules/prefer-observer.md @@ -48,3 +48,7 @@ This rule accepts a single option which is an object with an `allowNext` propert ] } ``` + +## Further reading + +- [Subscribe Arguments](https://rxjs.dev/deprecations/subscribe-arguments) From 64f4337102d348fc33db7d0efcc2ad643f921f1a Mon Sep 17 00:00:00 2001 From: Jason Weinzierl Date: Fri, 22 Nov 2024 15:01:38 -0600 Subject: [PATCH 10/12] docs(throw-error): add strict defaults to rule meta --- src/rules/throw-error.ts | 4 +++- tests/package.test.ts | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/rules/throw-error.ts b/src/rules/throw-error.ts index 185ca1af..0baab379 100644 --- a/src/rules/throw-error.ts +++ b/src/rules/throw-error.ts @@ -15,7 +15,9 @@ export const throwErrorRule = ruleCreator({ docs: { description: 'Enforce passing only `Error` values to `throwError`.', - recommended: 'strict', + recommended: { + strict: [{ allowThrowingAny: false, allowThrowingUnknown: false }], + }, requiresTypeChecking: true, }, messages: { diff --git a/tests/package.test.ts b/tests/package.test.ts index a26f97a6..07624399 100644 --- a/tests/package.test.ts +++ b/tests/package.test.ts @@ -69,6 +69,7 @@ describe('package', () => { expect(recommendedRules).toHaveProperty(fullRuleName); } else if (ruleRec === 'strict') { expect(strictRules).toHaveProperty(fullRuleName); + expect(strictRules[fullRuleName as keyof typeof strictRules]).toBe('error'); } else { expect.fail(`Invalid recommended value for rule ${fullRuleName}: ${ruleRec}`); } From 3f32a309ac27a4d15259dcf2f779d929f77199db Mon Sep 17 00:00:00 2001 From: Jason Weinzierl Date: Fri, 22 Nov 2024 15:02:18 -0600 Subject: [PATCH 11/12] feat(strict): allow single next callback in strict subscribe --- src/configs/strict.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/configs/strict.ts b/src/configs/strict.ts index 459d70e1..281baa9e 100644 --- a/src/configs/strict.ts +++ b/src/configs/strict.ts @@ -29,7 +29,7 @@ export const createStrictConfig = ( 'rxjs-x/no-unbound-methods': 'error', 'rxjs-x/no-unsafe-subject-next': 'error', 'rxjs-x/no-unsafe-takeuntil': 'error', - 'rxjs-x/prefer-observer': ['error', { allowNext: false }], + 'rxjs-x/prefer-observer': 'error', 'rxjs-x/prefer-root-operators': 'error', 'rxjs-x/throw-error': ['error', { allowThrowingAny: false, allowThrowingUnknown: false }], }, From 9ae8db563992afc854685529b8fcdf992c69e1ec Mon Sep 17 00:00:00 2001 From: Jason Weinzierl Date: Fri, 22 Nov 2024 15:38:57 -0600 Subject: [PATCH 12/12] feat(strict): show boolean values in type definitions Adding `as const` will cause the generated type definitions to show `false` instead of `boolean`, which is helpful for developers exploring the config's contents via intellisense. --- src/configs/strict.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/configs/strict.ts b/src/configs/strict.ts index 281baa9e..9fcfef6b 100644 --- a/src/configs/strict.ts +++ b/src/configs/strict.ts @@ -17,7 +17,9 @@ export const createStrictConfig = ( 'rxjs-x/no-ignored-observable': 'error', 'rxjs-x/no-ignored-replay-buffer': 'error', 'rxjs-x/no-ignored-takewhile-value': 'error', - 'rxjs-x/no-implicit-any-catch': ['error', { allowExplicitAny: false }], + 'rxjs-x/no-implicit-any-catch': ['error', { + allowExplicitAny: false as const, + }], 'rxjs-x/no-index': 'error', 'rxjs-x/no-internal': 'error', 'rxjs-x/no-nested-subscribe': 'error', @@ -31,6 +33,9 @@ export const createStrictConfig = ( 'rxjs-x/no-unsafe-takeuntil': 'error', 'rxjs-x/prefer-observer': 'error', 'rxjs-x/prefer-root-operators': 'error', - 'rxjs-x/throw-error': ['error', { allowThrowingAny: false, allowThrowingUnknown: false }], + 'rxjs-x/throw-error': ['error', { + allowThrowingAny: false as const, + allowThrowingUnknown: false as const, + }], }, } satisfies TSESLint.FlatConfig.Config);