diff --git a/README.md b/README.md index 5e1bd97e..b2b8e189 100644 --- a/README.md +++ b/README.md @@ -107,16 +107,16 @@ The package includes the following rules. | [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-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`. | 🔒 | 🔧 | 💡 | | | +| [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`. | 🔒 | | | 💭 | | +| [throw-error](docs/rules/throw-error.md) | Enforce passing only `Error` values to `throwError`. | ✅ 🔒 | | | 💭 | | diff --git a/docs/rules/no-topromise.md b/docs/rules/no-topromise.md index 5359dce2..b62d3aa6 100644 --- a/docs/rules/no-topromise.md +++ b/docs/rules/no-topromise.md @@ -1,6 +1,6 @@ # Disallow use of the `toPromise` method (`rxjs-x/no-topromise`) -💼 This rule is enabled in the 🔒 `strict` config. +💼 This rule is enabled in the following configs: ✅ `recommended`, 🔒 `strict`. 💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). diff --git a/docs/rules/prefer-observer.md b/docs/rules/prefer-observer.md index 4b71e7a4..ffb454f1 100644 --- a/docs/rules/prefer-observer.md +++ b/docs/rules/prefer-observer.md @@ -1,6 +1,6 @@ # Disallow passing separate handlers to `subscribe` and `tap` (`rxjs-x/prefer-observer`) -💼 This rule is enabled in the 🔒 `strict` 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/prefer-root-operators.md b/docs/rules/prefer-root-operators.md index 8cff5fab..1e6c33cf 100644 --- a/docs/rules/prefer-root-operators.md +++ b/docs/rules/prefer-root-operators.md @@ -1,6 +1,6 @@ # Disallow importing operators from `rxjs/operators` (`rxjs-x/prefer-root-operators`) -💼 This rule is enabled in the 🔒 `strict` 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/throw-error.md b/docs/rules/throw-error.md index 7c3a98b2..8f4f91f8 100644 --- a/docs/rules/throw-error.md +++ b/docs/rules/throw-error.md @@ -1,6 +1,6 @@ # Enforce passing only `Error` values to `throwError` (`rxjs-x/throw-error`) -💼 This rule is enabled in the 🔒 `strict` 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/package.json b/package.json index 65f9c7b3..4418eee0 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "rxjs": ">=7.0.0", + "rxjs": ">=7.2.0", "typescript": ">=4.7.4" }, "peerDependenciesMeta": { diff --git a/src/configs/recommended.ts b/src/configs/recommended.ts index 61ffca1e..5f6e53fd 100644 --- a/src/configs/recommended.ts +++ b/src/configs/recommended.ts @@ -19,8 +19,12 @@ export const createRecommendedConfig = ( 'rxjs-x/no-redundant-notify': 'error', 'rxjs-x/no-sharereplay': 'error', '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', + 'rxjs-x/prefer-root-operators': 'error', + 'rxjs-x/throw-error': 'error', }, } satisfies TSESLint.FlatConfig.Config); diff --git a/src/rules/no-topromise.ts b/src/rules/no-topromise.ts index d508e9d0..ee9dde70 100644 --- a/src/rules/no-topromise.ts +++ b/src/rules/no-topromise.ts @@ -7,7 +7,7 @@ export const noTopromiseRule = ruleCreator({ meta: { docs: { description: 'Disallow use of the `toPromise` method.', - recommended: 'strict', + recommended: 'recommended', requiresTypeChecking: true, }, hasSuggestions: true, diff --git a/src/rules/prefer-observer.ts b/src/rules/prefer-observer.ts index 9efb6fde..0c29c5c4 100644 --- a/src/rules/prefer-observer.ts +++ b/src/rules/prefer-observer.ts @@ -20,7 +20,7 @@ export const preferObserverRule = ruleCreator({ docs: { description: 'Disallow passing separate handlers to `subscribe` and `tap`.', - recommended: 'strict', + recommended: 'recommended', requiresTypeChecking: true, }, fixable: 'code', diff --git a/src/rules/prefer-root-operators.ts b/src/rules/prefer-root-operators.ts index e62989d7..60c69ecf 100644 --- a/src/rules/prefer-root-operators.ts +++ b/src/rules/prefer-root-operators.ts @@ -22,7 +22,7 @@ export const preferRootOperatorsRule = ruleCreator({ meta: { docs: { description: 'Disallow importing operators from `rxjs/operators`.', - recommended: 'strict', + recommended: 'recommended', }, fixable: 'code', hasSuggestions: true, diff --git a/src/rules/throw-error.ts b/src/rules/throw-error.ts index 0baab379..e63e027c 100644 --- a/src/rules/throw-error.ts +++ b/src/rules/throw-error.ts @@ -16,6 +16,7 @@ export const throwErrorRule = ruleCreator({ description: 'Enforce passing only `Error` values to `throwError`.', recommended: { + recommended: true, strict: [{ allowThrowingAny: false, allowThrowingUnknown: false }], }, requiresTypeChecking: true, diff --git a/tests/package.test.ts b/tests/package.test.ts index 07624399..aa388512 100644 --- a/tests/package.test.ts +++ b/tests/package.test.ts @@ -46,42 +46,35 @@ describe('package', () => { } }); - it('has rules flagged according to their configs', () => { - if (!plugin.configs) { - expect.fail('No configs found.'); - } - + it.for(Object.keys(plugin.rules))('includes rule %s in configurations based on meta.docs.recommended', (ruleName, { expect }) => { + const rule = plugin.rules[ruleName as keyof typeof plugin.rules]; const namespace = 'rxjs-x'; - const recommendedRules = plugin.configs.recommended.rules; - const strictRules = plugin.configs.strict.rules; + const fullRuleName = `${namespace}/${ruleName}`; - for (const [ruleName, rule] of Object.entries(plugin.rules)) { - const fullRuleName = `${namespace}/${ruleName}`; - const ruleRec = rule.meta.docs?.recommended; + if (!rule.meta.docs?.recommended) { + // Rule is not included in any configuration. + expect(plugin.configs.recommended.rules).not.toHaveProperty(fullRuleName); + expect(plugin.configs.strict.rules).not.toHaveProperty(fullRuleName); + } else if (typeof rule.meta.docs.recommended === 'string') { + // Rule specifies only a configuration name. + expect(rule.meta.docs.recommended).toMatch(/^(recommended|strict)$/); + if (rule.meta.docs.recommended === 'recommended') { + expect(plugin.configs.recommended.rules).toHaveProperty(fullRuleName); + } else { + expect(plugin.configs.recommended.rules).not.toHaveProperty(fullRuleName); + } - if (!ruleRec) { - // Rule is not part of any config. - 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(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}`); - } + // Strict configuration always includes all recommended rules. + // Not allowed to specify non-default options since rule only specifies a configuration name. + expect(plugin.configs.strict.rules).toHaveProperty(fullRuleName, expect.any(String)); + } else { + // Rule specifies non-default options for strict. + if (rule.meta.docs.recommended.recommended) { + expect(plugin.configs.recommended.rules).toHaveProperty(fullRuleName); } else { - // Rule is part of several configs. - if (ruleRec.recommended) { - expect(recommendedRules).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]); + expect(plugin.configs.recommended.rules).not.toHaveProperty(fullRuleName); } + expect(plugin.configs.strict.rules).toHaveProperty(fullRuleName, [expect.any(String), rule.meta.docs.recommended.strict[0]]); } }); }); diff --git a/yarn.lock b/yarn.lock index fa82bb7e..9744f9fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2202,7 +2202,7 @@ __metadata: vitest: "npm:^2.1.5" peerDependencies: eslint: ^8.57.0 || ^9.0.0 - rxjs: ">=7.0.0" + rxjs: ">=7.2.0" typescript: ">=4.7.4" peerDependenciesMeta: rxjs: