Skip to content

Commit

Permalink
feat(eslint-plugin): add meta.docs.recommended setting for strict con…
Browse files Browse the repository at this point in the history
…fig options (#8364)

* feat(eslint-plugin): add meta.docs.recommended setting for strict config options

* Also updated generate:configs script

* fix: use recommended, not strict, in recommended configs

* fix: no-floating-promises disables ignoreVoid in strict

* fix: no-floating-promises disables ignoreVoid in strict

* fix introduced build and lint issues

* Fix configs.test.ts tests

* Fix test conflict post-merge
  • Loading branch information
JoshuaKGoldberg committed Mar 17, 2024
1 parent 994812b commit ce79c55
Show file tree
Hide file tree
Showing 21 changed files with 319 additions and 76 deletions.
25 changes: 22 additions & 3 deletions packages/eslint-plugin/src/configs/strict-type-checked-only.ts
Expand Up @@ -15,7 +15,7 @@ export = {
'@typescript-eslint/no-base-to-string': 'error',
'@typescript-eslint/no-confusing-void-expression': 'error',
'@typescript-eslint/no-duplicate-type-constituents': 'error',
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: false }],
'@typescript-eslint/no-for-in-array': 'error',
'no-implied-eval': 'off',
'@typescript-eslint/no-implied-eval': 'error',
Expand Down Expand Up @@ -43,8 +43,27 @@ export = {
'@typescript-eslint/prefer-return-this-type': 'error',
'require-await': 'off',
'@typescript-eslint/require-await': 'error',
'@typescript-eslint/restrict-plus-operands': 'error',
'@typescript-eslint/restrict-template-expressions': 'error',
'@typescript-eslint/restrict-plus-operands': [
'error',
{
allowAny: false,
allowBoolean: false,
allowNullish: false,
allowNumberAndString: false,
allowRegExp: false,
},
],
'@typescript-eslint/restrict-template-expressions': [
'error',
{
allowAny: false,
allowBoolean: false,
allowNullish: false,
allowNumber: false,
allowRegExp: false,
allowNever: false,
},
],
'@typescript-eslint/unbound-method': 'error',
},
} satisfies ClassicConfig.Config;
30 changes: 26 additions & 4 deletions packages/eslint-plugin/src/configs/strict-type-checked.ts
Expand Up @@ -11,7 +11,10 @@ export = {
extends: ['./configs/base', './configs/eslint-recommended'],
rules: {
'@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/ban-ts-comment': 'error',
'@typescript-eslint/ban-ts-comment': [
'error',
{ minimumDescriptionLength: 10 },
],
'@typescript-eslint/ban-types': 'error',
'no-array-constructor': 'off',
'@typescript-eslint/no-array-constructor': 'error',
Expand All @@ -24,7 +27,7 @@ export = {
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-extra-non-null-assertion': 'error',
'@typescript-eslint/no-extraneous-class': 'error',
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: false }],
'@typescript-eslint/no-for-in-array': 'error',
'no-implied-eval': 'off',
'@typescript-eslint/no-implied-eval': 'error',
Expand Down Expand Up @@ -71,8 +74,27 @@ export = {
'@typescript-eslint/prefer-ts-expect-error': 'error',
'require-await': 'off',
'@typescript-eslint/require-await': 'error',
'@typescript-eslint/restrict-plus-operands': 'error',
'@typescript-eslint/restrict-template-expressions': 'error',
'@typescript-eslint/restrict-plus-operands': [
'error',
{
allowAny: false,
allowBoolean: false,
allowNullish: false,
allowNumberAndString: false,
allowRegExp: false,
},
],
'@typescript-eslint/restrict-template-expressions': [
'error',
{
allowAny: false,
allowBoolean: false,
allowNullish: false,
allowNumber: false,
allowRegExp: false,
allowNever: false,
},
],
'@typescript-eslint/triple-slash-reference': 'error',
'@typescript-eslint/unbound-method': 'error',
'@typescript-eslint/unified-signatures': 'error',
Expand Down
5 changes: 4 additions & 1 deletion packages/eslint-plugin/src/configs/strict.ts
Expand Up @@ -10,7 +10,10 @@ import type { ClassicConfig } from '@typescript-eslint/utils/ts-eslint';
export = {
extends: ['./configs/base', './configs/eslint-recommended'],
rules: {
'@typescript-eslint/ban-ts-comment': 'error',
'@typescript-eslint/ban-ts-comment': [
'error',
{ minimumDescriptionLength: 10 },
],
'@typescript-eslint/ban-types': 'error',
'no-array-constructor': 'off',
'@typescript-eslint/no-array-constructor': 'error',
Expand Down
5 changes: 4 additions & 1 deletion packages/eslint-plugin/src/rules/ban-ts-comment.ts
Expand Up @@ -32,7 +32,10 @@ export default createRule<[Options], MessageIds>({
docs: {
description:
'Disallow `@ts-<directive>` comments or require descriptions after directives',
recommended: 'recommended',
recommended: {
recommended: true,
strict: [{ minimumDescriptionLength: 10 }],
},
},
messages: {
tsDirectiveComment:
Expand Down
5 changes: 4 additions & 1 deletion packages/eslint-plugin/src/rules/no-floating-promises.ts
Expand Up @@ -50,7 +50,10 @@ export default createRule<Options, MessageId>({
docs: {
description:
'Require Promise-like statements to be handled appropriately',
recommended: 'recommended',
recommended: {
recommended: true,
strict: [{ ignoreVoid: false }],
},
requiresTypeChecking: true,
},
hasSuggestions: true,
Expand Down
13 changes: 12 additions & 1 deletion packages/eslint-plugin/src/rules/restrict-plus-operands.ts
Expand Up @@ -31,7 +31,18 @@ export default createRule<Options, MessageIds>({
docs: {
description:
'Require both operands of addition to be the same type and be `bigint`, `number`, or `string`',
recommended: 'recommended',
recommended: {
recommended: true,
strict: [
{
allowAny: false,
allowBoolean: false,
allowNullish: false,
allowNumberAndString: false,
allowRegExp: false,
},
],
},
requiresTypeChecking: true,
},
messages: {
Expand Down
Expand Up @@ -62,7 +62,19 @@ export default createRule<Options, MessageId>({
docs: {
description:
'Enforce template literal expressions to be of `string` type',
recommended: 'recommended',
recommended: {
recommended: true,
strict: [
{
allowAny: false,
allowBoolean: false,
allowNullish: false,
allowNumber: false,
allowRegExp: false,
allowNever: false,
},
],
},
requiresTypeChecking: true,
},
messages: {
Expand Down
49 changes: 38 additions & 11 deletions packages/eslint-plugin/tests/configs.test.ts
Expand Up @@ -23,7 +23,9 @@ function entriesToObject<T = unknown>(value: [string, T][]): Record<string, T> {
}, {});
}

function filterRules(values: Record<string, string>): [string, string][] {
function filterRules(
values: Record<string, string | unknown[]>,
): [string, string | unknown[]][] {
return Object.entries(values).filter(([name]) =>
name.startsWith(RULE_NAME_PREFIX),
);
Expand All @@ -39,7 +41,7 @@ function filterAndMapRuleConfigs({
excludeDeprecated,
typeChecked,
recommendations,
}: FilterAndMapRuleConfigsSettings = {}): [string, string][] {
}: FilterAndMapRuleConfigsSettings = {}): [string, unknown][] {
let result = Object.entries(rules);

if (excludeDeprecated) {
Expand All @@ -55,16 +57,41 @@ function filterAndMapRuleConfigs({
}

if (recommendations) {
result = result.filter(([, rule]) =>
recommendations.includes(rule.meta.docs?.recommended),
);
result = result.filter(([, rule]) => {
switch (typeof rule.meta.docs?.recommended) {
case 'undefined':
return false;
case 'object':
return Object.keys(rule.meta.docs.recommended).some(recommended =>
recommendations.includes(recommended as RuleRecommendation),
);
case 'string':
return recommendations.includes(rule.meta.docs.recommended);
}
});
}

return result.map(([name]) => [`${RULE_NAME_PREFIX}${name}`, 'error']);
const highestRecommendation = recommendations?.filter(Boolean).at(-1);

return result.map(([name, rule]) => {
const customRecommendation =
highestRecommendation &&
typeof rule.meta.docs?.recommended === 'object' &&
rule.meta.docs.recommended[
highestRecommendation as 'recommended' | 'strict'
];

return [
`${RULE_NAME_PREFIX}${name}`,
customRecommendation && typeof customRecommendation !== 'boolean'
? ['error', customRecommendation[0]]
: 'error',
];
});
}

function itHasBaseRulesOverriden(
unfilteredConfigRules: Record<string, string>,
unfilteredConfigRules: Record<string, string | unknown[]>,
): void {
it('has the base rules overriden by the appropriate extension rules', () => {
const ruleNames = new Set(Object.keys(unfilteredConfigRules));
Expand Down Expand Up @@ -166,7 +193,7 @@ describe('recommended-type-checked-only.ts', () => {
});

describe('strict.ts', () => {
const unfilteredConfigRules: Record<string, string> =
const unfilteredConfigRules: Record<string, string | unknown[]> =
plugin.configs.strict.rules;

it('contains all strict rules, excluding type checked ones', () => {
Expand All @@ -185,7 +212,7 @@ describe('strict.ts', () => {
});

describe('strict-type-checked.ts', () => {
const unfilteredConfigRules: Record<string, string> =
const unfilteredConfigRules: Record<string, string | unknown[]> =
plugin.configs['strict-type-checked'].rules;

it('contains all strict rules', () => {
Expand All @@ -202,7 +229,7 @@ describe('strict-type-checked.ts', () => {
});

describe('strict-type-checked-only.ts', () => {
const unfilteredConfigRules: Record<string, string> =
const unfilteredConfigRules: Record<string, string | unknown[]> =
plugin.configs['strict-type-checked-only'].rules;

it('contains only type-checked strict rules', () => {
Expand All @@ -221,7 +248,7 @@ describe('strict-type-checked-only.ts', () => {
});

describe('stylistic.ts', () => {
const unfilteredConfigRules: Record<string, string> =
const unfilteredConfigRules: Record<string, string | unknown[]> =
plugin.configs.stylistic.rules;

it('contains all stylistic rules, excluding deprecated or type checked ones', () => {
Expand Down

0 comments on commit ce79c55

Please sign in to comment.