Skip to content

Commit

Permalink
fix(eslint-plugin): expose *-type-checked-only configs for extension (#…
Browse files Browse the repository at this point in the history
…8600)

* eslint-plugin: expose -type-checked-only from index

* typescript-eslint: expose -type-checked-only rules in index

* Rename filter to include-only, for consistency

* Fix lint error with conditional check
  • Loading branch information
fpapado committed Mar 5, 2024
1 parent e20edec commit 4c8b06d
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 14 deletions.
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

0 comments on commit 4c8b06d

Please sign in to comment.