Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(eslint-plugin): expose *-type-checked-only configs for extension #8600

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/eslint-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import disableTypeChecked from './configs/disable-type-checked';
import eslintRecommended from './configs/eslint-recommended';
import recommended from './configs/recommended';
import recommendedTypeChecked from './configs/recommended-type-checked';
import recommendedTypeCheckedOnly from './configs/recommended-type-checked-only';
import strict from './configs/strict';
import strictTypeChecked from './configs/strict-type-checked';
import strictTypeCheckedOnly from './configs/strict-type-checked-only';
import stylistic from './configs/stylistic';
import stylisticTypeChecked from './configs/stylistic-type-checked';
import stylisticTypeCheckedOnly from './configs/stylistic-type-checked-only';
import rules from './rules';

// note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder
Expand All @@ -28,10 +31,13 @@ export = {
/** @deprecated - please use "recommended-type-checked" instead. */
'recommended-requiring-type-checking': recommendedTypeChecked,
'recommended-type-checked': recommendedTypeChecked,
'recommended-type-checked-only': recommendedTypeCheckedOnly,
strict,
'strict-type-checked': strictTypeChecked,
'strict-type-checked-only': strictTypeCheckedOnly,
stylistic,
'stylistic-type-checked': stylisticTypeChecked,
'stylistic-type-checked-only': stylisticTypeCheckedOnly,
},
meta: {
name,
Expand Down
73 changes: 66 additions & 7 deletions packages/eslint-plugin/tests/configs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ function filterRules(values: Record<string, string>): [string, string][] {

interface FilterAndMapRuleConfigsSettings {
excludeDeprecated?: boolean;
excludeTypeChecked?: boolean;
typeChecked?: 'exclude' | 'include-only';
recommendations?: (RuleRecommendation | undefined)[];
}

function filterAndMapRuleConfigs({
excludeDeprecated,
excludeTypeChecked,
typeChecked,
recommendations,
}: FilterAndMapRuleConfigsSettings = {}): [string, string][] {
let result = Object.entries(rules);
Expand All @@ -46,8 +46,12 @@ function filterAndMapRuleConfigs({
result = result.filter(([, rule]) => !rule.meta.deprecated);
}

if (excludeTypeChecked) {
result = result.filter(([, rule]) => !rule.meta.docs?.requiresTypeChecking);
if (typeChecked) {
result = result.filter(([, rule]) =>
typeChecked === 'exclude'
? !rule.meta.docs?.requiresTypeChecking
: rule.meta.docs?.requiresTypeChecking,
);
}

if (recommendations) {
Expand Down Expand Up @@ -116,7 +120,7 @@ describe('recommended.ts', () => {
const configRules = filterRules(unfilteredConfigRules);
// note: include deprecated rules so that the config doesn't change between major bumps
const ruleConfigs = filterAndMapRuleConfigs({
excludeTypeChecked: true,
typeChecked: 'exclude',
recommendations: ['recommended'],
});

Expand All @@ -143,6 +147,24 @@ describe('recommended-type-checked.ts', () => {
itHasBaseRulesOverriden(unfilteredConfigRules);
});

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

it('contains only type-checked recommended rules', () => {
const configRules = filterRules(unfilteredConfigRules);
// note: include deprecated rules so that the config doesn't change between major bumps
const ruleConfigs = filterAndMapRuleConfigs({
typeChecked: 'include-only',
recommendations: ['recommended'],
}).filter(([ruleName]) => ruleName);

expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules));
});

itHasBaseRulesOverriden(unfilteredConfigRules);
});

describe('strict.ts', () => {
const unfilteredConfigRules: Record<string, string> =
plugin.configs.strict.rules;
Expand All @@ -152,7 +174,7 @@ describe('strict.ts', () => {
// note: exclude deprecated rules, this config is allowed to change between minor versions
const ruleConfigs = filterAndMapRuleConfigs({
excludeDeprecated: true,
excludeTypeChecked: true,
typeChecked: 'exclude',
recommendations: ['recommended', 'strict'],
});

Expand All @@ -179,6 +201,25 @@ describe('strict-type-checked.ts', () => {
itHasBaseRulesOverriden(unfilteredConfigRules);
});

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

it('contains only type-checked strict rules', () => {
const configRules = filterRules(unfilteredConfigRules);
// note: exclude deprecated rules, this config is allowed to change between minor versions
const ruleConfigs = filterAndMapRuleConfigs({
excludeDeprecated: true,
typeChecked: 'include-only',
recommendations: ['recommended', 'strict'],
}).filter(([ruleName]) => ruleName);

expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules));
});

itHasBaseRulesOverriden(unfilteredConfigRules);
});

describe('stylistic.ts', () => {
const unfilteredConfigRules: Record<string, string> =
plugin.configs.stylistic.rules;
Expand All @@ -187,7 +228,7 @@ describe('stylistic.ts', () => {
const configRules = filterRules(unfilteredConfigRules);
// note: include deprecated rules so that the config doesn't change between major bumps
const ruleConfigs = filterAndMapRuleConfigs({
excludeTypeChecked: true,
typeChecked: 'exclude',
recommendations: ['stylistic'],
});

Expand All @@ -212,3 +253,21 @@ describe('stylistic-type-checked.ts', () => {

itHasBaseRulesOverriden(unfilteredConfigRules);
});

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

it('contains only type-checked stylistic rules', () => {
const configRules = filterRules(unfilteredConfigRules);
// note: include deprecated rules so that the config doesn't change between major bumps
const ruleConfigs = filterAndMapRuleConfigs({
typeChecked: 'include-only',
recommendations: ['stylistic'],
}).filter(([ruleName]) => ruleName);

expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules));
});

itHasBaseRulesOverriden(unfilteredConfigRules);
});
6 changes: 6 additions & 0 deletions packages/typescript-eslint/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ import disableTypeCheckedConfig from './configs/disable-type-checked';
import eslintRecommendedConfig from './configs/eslint-recommended';
import recommendedConfig from './configs/recommended';
import recommendedTypeCheckedConfig from './configs/recommended-type-checked';
import recommendedTypeCheckedOnlyConfig from './configs/recommended-type-checked-only';
import strictConfig from './configs/strict';
import strictTypeCheckedConfig from './configs/strict-type-checked';
import strictTypeCheckedOnlyConfig from './configs/strict-type-checked-only';
import stylisticConfig from './configs/stylistic';
import stylisticTypeCheckedConfig from './configs/stylistic-type-checked';
import stylisticTypeCheckedOnlyConfig from './configs/stylistic-type-checked-only';

const parser: TSESLint.FlatConfig.Parser = {
meta: parserBase.meta,
Expand All @@ -32,10 +35,13 @@ const configs = {
eslintRecommended: eslintRecommendedConfig(plugin, parser),
recommended: recommendedConfig(plugin, parser),
recommendedTypeChecked: recommendedTypeCheckedConfig(plugin, parser),
recommendedTypeCheckedOnly: recommendedTypeCheckedOnlyConfig(plugin, parser),
strict: strictConfig(plugin, parser),
strictTypeChecked: strictTypeCheckedConfig(plugin, parser),
strictTypeCheckedOnly: strictTypeCheckedOnlyConfig(plugin, parser),
stylistic: stylisticConfig(plugin, parser),
stylisticTypeChecked: stylisticTypeCheckedConfig(plugin, parser),
stylisticTypeCheckedOnly: stylisticTypeCheckedOnlyConfig(plugin, parser),
};

export type Config = TSESLint.FlatConfig.ConfigFile;
Expand Down
72 changes: 65 additions & 7 deletions packages/typescript-eslint/tests/configs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ function filterRules(

interface FilterAndMapRuleConfigsSettings {
excludeDeprecated?: boolean;
excludeTypeChecked?: boolean;
typeChecked?: 'exclude' | 'include-only';
recommendations?: (RuleRecommendation | undefined)[];
}

function filterAndMapRuleConfigs({
excludeDeprecated,
excludeTypeChecked,
typeChecked,
recommendations,
}: FilterAndMapRuleConfigsSettings = {}): [string, string][] {
let result = Object.entries(rules);
Expand All @@ -52,8 +52,12 @@ function filterAndMapRuleConfigs({
result = result.filter(([, rule]) => !rule.meta.deprecated);
}

if (excludeTypeChecked) {
result = result.filter(([, rule]) => !rule.meta.docs?.requiresTypeChecking);
if (typeChecked) {
result = result.filter(([, rule]) =>
typeChecked === 'exclude'
? !rule.meta.docs?.requiresTypeChecking
: rule.meta.docs?.requiresTypeChecking,
);
}

if (recommendations) {
Expand Down Expand Up @@ -120,7 +124,7 @@ describe('recommended.ts', () => {
const configRules = filterRules(unfilteredConfigRules);
// note: include deprecated rules so that the config doesn't change between major bumps
const ruleConfigs = filterAndMapRuleConfigs({
excludeTypeChecked: true,
typeChecked: 'exclude',
recommendations: ['recommended'],
});

Expand All @@ -146,6 +150,24 @@ describe('recommended-type-checked.ts', () => {
itHasBaseRulesOverriden(unfilteredConfigRules);
});

describe('recommended-type-checked-only.ts', () => {
const unfilteredConfigRules =
plugin.configs.recommendedTypeCheckedOnly[2]?.rules;

it('contains only type-checked recommended rules', () => {
const configRules = filterRules(unfilteredConfigRules);
// note: include deprecated rules so that the config doesn't change between major bumps
const ruleConfigs = filterAndMapRuleConfigs({
typeChecked: 'include-only',
recommendations: ['recommended'],
}).filter(([ruleName]) => ruleName);

expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules));
});

itHasBaseRulesOverriden(unfilteredConfigRules);
});

describe('strict.ts', () => {
const unfilteredConfigRules = plugin.configs.strict[2]?.rules;

Expand All @@ -154,7 +176,7 @@ describe('strict.ts', () => {
// note: exclude deprecated rules, this config is allowed to change between minor versions
const ruleConfigs = filterAndMapRuleConfigs({
excludeDeprecated: true,
excludeTypeChecked: true,
typeChecked: 'exclude',
recommendations: ['recommended', 'strict'],
});

Expand All @@ -180,14 +202,32 @@ describe('strict-type-checked.ts', () => {
itHasBaseRulesOverriden(unfilteredConfigRules);
});

describe('strict-type-checked-only.ts', () => {
const unfilteredConfigRules = plugin.configs.strictTypeCheckedOnly[2]?.rules;

it('contains only type-checked strict rules', () => {
const configRules = filterRules(unfilteredConfigRules);
// note: exclude deprecated rules, this config is allowed to change between minor versions
const ruleConfigs = filterAndMapRuleConfigs({
excludeDeprecated: true,
typeChecked: 'include-only',
recommendations: ['recommended', 'strict'],
}).filter(([ruleName]) => ruleName);

expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules));
});

itHasBaseRulesOverriden(unfilteredConfigRules);
});

describe('stylistic.ts', () => {
const unfilteredConfigRules = plugin.configs.stylistic[2]?.rules;

it('contains all stylistic rules, excluding deprecated or type checked ones', () => {
const configRules = filterRules(unfilteredConfigRules);
// note: include deprecated rules so that the config doesn't change between major bumps
const ruleConfigs = filterAndMapRuleConfigs({
excludeTypeChecked: true,
typeChecked: 'exclude',
recommendations: ['stylistic'],
});

Expand All @@ -212,6 +252,24 @@ describe('stylistic-type-checked.ts', () => {
itHasBaseRulesOverriden(unfilteredConfigRules);
});

describe('stylistic-type-checked-only.ts', () => {
const unfilteredConfigRules =
plugin.configs.stylisticTypeCheckedOnly[2]?.rules;

it('contains only type-checked stylistic rules', () => {
const configRules = filterRules(unfilteredConfigRules);
// note: include deprecated rules so that the config doesn't change between major bumps
const ruleConfigs = filterAndMapRuleConfigs({
typeChecked: 'include-only',
recommendations: ['stylistic'],
}).filter(([ruleName]) => ruleName);

expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules));
});

itHasBaseRulesOverriden(unfilteredConfigRules);
});

describe('config helper', () => {
it('works without extends', () => {
expect(
Expand Down