Skip to content

Commit f5ee098

Browse files
author
Josh Goldberg
authored
Don't output ESLint rules that match extended configurations (#448)
* WIP: logic for deduplicating ESLint rules' extensions * Whoa, it actually works * Moved trimming into the existing summarization section * Reverted some unnecessary changes * Fixed up edge cases * Split extension merging and rule normalization * Fixed compile complaint
1 parent 23b66c7 commit f5ee098

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+759
-478
lines changed

docs/Architecture.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ Within `src/conversion/convertConfig.ts`, the following steps occur:
1313

1414
1. Existing configurations are read from disk
1515
2. TSLint rules are converted into their ESLint configurations
16-
3. ESLint configurations are simplified based on extended ESLint and TSLint presets
16+
3. ESLint configurations are summarized based on extended ESLint and TSLint presets
1717
- 3a. If no output rules conflict with `eslint-config-prettier`, it's added in
18-
4. The simplified configuration is written to the output config file
18+
- 3b. Any ESLint rules that are configured the same as an extended preset are trimmed
19+
4. The summarized configuration is written to the output config file
1920
5. Files to transform comments in have source text rewritten using the same rule conversion logic
2021
6. A summary of the results is printed to the user's console
2122

src/cli/main.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,16 @@ import {
1616
convertEditorConfig,
1717
ConvertEditorConfigDependencies,
1818
} from "../conversion/convertEditorConfig";
19-
import { addPrettierExtensions } from "../creation/simplification/prettier/addPrettierExtensions";
20-
import { removeExtendsDuplicatedRules } from "../creation/simplification/removeExtendsDuplicatedRules";
19+
import { addPrettierExtensions } from "../creation/summarization/prettier/addPrettierExtensions";
20+
import { removeExtendsDuplicatedRules } from "../creation/pruning/removeExtendsDuplicatedRules";
2121
import {
2222
retrieveExtendsValues,
2323
RetrieveExtendsValuesDependencies,
24-
} from "../creation/simplification/retrieveExtendsValues";
24+
} from "../creation/summarization/retrieveExtendsValues";
2525
import {
26-
simplifyPackageRules,
27-
SimplifyPackageRulesDependencies,
28-
} from "../creation/simplification/simplifyPackageRules";
26+
summarizePackageRules,
27+
SummarizePackageRulesDependencies,
28+
} from "../creation/summarization/summarizePackageRules";
2929
import {
3030
writeConversionResults,
3131
WriteConversionResultsDependencies,
@@ -138,7 +138,7 @@ const retrieveExtendsValuesDependencies: RetrieveExtendsValuesDependencies = {
138138
importer: boundImporter,
139139
};
140140

141-
const simplifyPackageRulesDependencies: SimplifyPackageRulesDependencies = {
141+
const summarizePackageRulesDependencies: SummarizePackageRulesDependencies = {
142142
addPrettierExtensions,
143143
removeExtendsDuplicatedRules,
144144
retrieveExtendsValues: bind(retrieveExtendsValues, retrieveExtendsValuesDependencies),
@@ -175,7 +175,7 @@ const convertConfigDependencies: ConvertConfigDependencies = {
175175
logMissingPackages: bind(logMissingPackages, logMissingPackagesDependencies),
176176
reportCommentResults: bind(reportCommentResults, reportCommentResultsDependencies),
177177
reportConversionResults: bind(reportConversionResults, reportConversionResultsDependencies),
178-
simplifyPackageRules: bind(simplifyPackageRules, simplifyPackageRulesDependencies),
178+
summarizePackageRules: bind(summarizePackageRules, summarizePackageRulesDependencies),
179179
writeConversionResults: bind(writeConversionResults, writeConversionResultsDependencies),
180180
};
181181

src/conversion/conversionResults.stubs.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import { SummarizedResultsConfiguration } from "../creation/summarization/types";
12
import { EditorSettingConversionResults } from "../editorSettings/convertEditorSettings";
2-
import { SimplifiedResultsConfiguration } from "../creation/simplification/simplifyPackageRules";
33

44
export const createEmptyConversionResults = (
5-
overrides: Partial<SimplifiedResultsConfiguration> = {},
6-
): SimplifiedResultsConfiguration => ({
5+
overrides: Partial<SummarizedResultsConfiguration> = {},
6+
): SummarizedResultsConfiguration => ({
77
converted: new Map(),
8+
extends: [],
9+
extensionRules: new Map(),
810
failed: [],
911
missing: [],
1012
plugins: new Set(),

src/conversion/convertConfig.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ const createStubDependencies = (
1616
}),
1717
reportCommentResults: jest.fn(),
1818
reportConversionResults: jest.fn(),
19-
simplifyPackageRules: async (_configurations, data) => ({
19+
summarizePackageRules: async (_configurations, data) => ({
2020
...data,
2121
converted: new Map(),
2222
extends: [],
23+
extensionRules: new Map(),
2324
failed: [],
2425
missing: [],
2526
plugins: new Set(),

src/conversion/convertConfig.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { SansDependencies } from "../binding";
22
import { convertComments } from "../comments/convertComments";
3-
import { simplifyPackageRules } from "../creation/simplification/simplifyPackageRules";
3+
import { summarizePackageRules } from "../creation/summarization/summarizePackageRules";
44
import { writeConversionResults } from "../creation/writeConversionResults";
55
import { findOriginalConfigurations } from "../input/findOriginalConfigurations";
66
import { logMissingPackages } from "../reporting/packages/logMissingPackages";
@@ -16,7 +16,7 @@ export type ConvertConfigDependencies = {
1616
logMissingPackages: SansDependencies<typeof logMissingPackages>;
1717
reportCommentResults: SansDependencies<typeof reportCommentResults>;
1818
reportConversionResults: SansDependencies<typeof reportConversionResults>;
19-
simplifyPackageRules: SansDependencies<typeof simplifyPackageRules>;
19+
summarizePackageRules: SansDependencies<typeof summarizePackageRules>;
2020
writeConversionResults: SansDependencies<typeof writeConversionResults>;
2121
};
2222

@@ -39,18 +39,18 @@ export const convertConfig = async (
3939
originalConfigurations.data.tslint.full.rules,
4040
);
4141

42-
// 3. ESLint configurations are simplified based on extended ESLint and TSLint presets
43-
const simplifiedConfiguration = await dependencies.simplifyPackageRules(
42+
// 3. ESLint configurations are summarized based on extended ESLint and TSLint presets
43+
const summarizedConfiguration = await dependencies.summarizePackageRules(
4444
originalConfigurations.data.eslint,
4545
originalConfigurations.data.tslint,
4646
ruleConversionResults,
4747
settings.prettier,
4848
);
4949

50-
// 4. The simplified configuration is written to the output config file
50+
// 4. The summarized configuration is written to the output config file
5151
const fileWriteError = await dependencies.writeConversionResults(
5252
settings.config,
53-
simplifiedConfiguration,
53+
summarizedConfiguration,
5454
originalConfigurations.data,
5555
);
5656
if (fileWriteError !== undefined) {
@@ -64,10 +64,10 @@ export const convertConfig = async (
6464
const commentsResult = await dependencies.convertComments(settings.comments);
6565

6666
// 6. A summary of the results is printed to the user's console
67-
await dependencies.reportConversionResults(settings.config, simplifiedConfiguration);
67+
await dependencies.reportConversionResults(settings.config, summarizedConfiguration);
6868
dependencies.reportCommentResults(commentsResult);
6969
await dependencies.logMissingPackages(
70-
simplifiedConfiguration,
70+
summarizedConfiguration,
7171
originalConfigurations.data.packages,
7272
);
7373

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { normalizeExtensions } from "./normalizeExtensions";
2+
import { ESLintConfigurationRuleValue } from "../../input/findESLintConfiguration";
3+
4+
const createStubExtension = (ruleName: string, ruleValue: ESLintConfigurationRuleValue) => {
5+
return {
6+
rules: {
7+
[ruleName]: ruleValue,
8+
},
9+
};
10+
};
11+
12+
describe("removeExtendsDuplicatedRules", () => {
13+
it("ignores an empty extension", () => {
14+
// Arrange
15+
const extensions = [{}];
16+
17+
// Act
18+
const results = normalizeExtensions(extensions);
19+
20+
// Assert
21+
expect(results).toEqual(new Map());
22+
});
23+
24+
it("overrides a rule's first value when a second extension contains it", () => {
25+
// Arrange
26+
const ruleName = "rule-a";
27+
const extensions = [
28+
createStubExtension(ruleName, "error"),
29+
createStubExtension(ruleName, "warn"),
30+
];
31+
32+
// Act
33+
const results = normalizeExtensions(extensions);
34+
35+
// Assert
36+
expect(results).toEqual(
37+
new Map([
38+
[
39+
ruleName,
40+
{
41+
ruleArguments: [],
42+
ruleName,
43+
ruleSeverity: "warn",
44+
},
45+
],
46+
]),
47+
);
48+
});
49+
50+
it("normalizes a configuration when an array", () => {
51+
// Arrange
52+
const ruleName = "rule-a";
53+
const ruleArgument = { value: true };
54+
const extensions = [createStubExtension(ruleName, ["error", ruleArgument])];
55+
56+
// Act
57+
const results = normalizeExtensions(extensions);
58+
59+
// Assert
60+
expect(results).toEqual(
61+
new Map([
62+
[
63+
ruleName,
64+
{
65+
ruleArguments: [ruleArgument],
66+
ruleName,
67+
ruleSeverity: "error",
68+
},
69+
],
70+
]),
71+
);
72+
});
73+
});
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import {
2+
ESLintConfiguration,
3+
ESLintConfigurationRuleValue,
4+
} from "../../input/findESLintConfiguration";
5+
import { ESLintRuleOptionsWithArguments } from "../../rules/types";
6+
import { normalizeRawESLintRuleSeverity } from "./normalizeRawESLintRuleSeverity";
7+
8+
export const normalizeExtensions = (extensions: Partial<ESLintConfiguration>[]) => {
9+
const mergedRules = new Map<string, ESLintRuleOptionsWithArguments>();
10+
11+
for (const extension of extensions) {
12+
if (extension.rules === undefined) {
13+
continue;
14+
}
15+
16+
for (const ruleName in extension.rules) {
17+
mergedRules.set(ruleName, formatRuleArguments(ruleName, extension.rules[ruleName]));
18+
}
19+
}
20+
21+
return mergedRules;
22+
};
23+
24+
const formatRuleArguments = (
25+
ruleName: string,
26+
originalValue: ESLintConfigurationRuleValue,
27+
): ESLintRuleOptionsWithArguments => {
28+
if (originalValue instanceof Array) {
29+
return {
30+
ruleArguments: originalValue.slice(1),
31+
ruleName,
32+
ruleSeverity: normalizeRawESLintRuleSeverity(originalValue[0]),
33+
};
34+
}
35+
36+
return {
37+
ruleArguments: [],
38+
ruleName,
39+
ruleSeverity: normalizeRawESLintRuleSeverity(originalValue),
40+
};
41+
};
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { normalizeRawESLintRuleSeverity } from "./normalizeRawESLintRuleSeverity";
2+
3+
describe("normalizeRawESLintRuleSeverity", () => {
4+
it("converts the severity to off when equal to 0", () => {
5+
// Arrange
6+
const rawSeverity = 0;
7+
8+
// Act
9+
const result = normalizeRawESLintRuleSeverity(rawSeverity);
10+
11+
// Assert
12+
expect(result).toEqual("off");
13+
});
14+
15+
it("converts the severity to warn when equal to 1", () => {
16+
// Arrange
17+
const rawSeverity = 1;
18+
19+
// Act
20+
const result = normalizeRawESLintRuleSeverity(rawSeverity);
21+
22+
// Assert
23+
expect(result).toEqual("warn");
24+
});
25+
26+
it("converts the severity to error when equal to 2", () => {
27+
// Arrange
28+
const rawSeverity = 2;
29+
30+
// Act
31+
const result = normalizeRawESLintRuleSeverity(rawSeverity);
32+
33+
// Assert
34+
expect(result).toEqual("error");
35+
});
36+
37+
it("returns the same severity when already a string", () => {
38+
// Arrange
39+
const rawSeverity = "error";
40+
41+
// Act
42+
const result = normalizeRawESLintRuleSeverity(rawSeverity);
43+
44+
// Assert
45+
expect(result).toEqual(rawSeverity);
46+
});
47+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { ESLintRuleSeverity, RawESLintRuleSeverity } from "../../rules/types";
2+
3+
export const normalizeRawESLintRuleSeverity = (
4+
rawSeverity: RawESLintRuleSeverity,
5+
): ESLintRuleSeverity => {
6+
switch (rawSeverity) {
7+
case 0:
8+
return "off";
9+
10+
case 1:
11+
return "warn";
12+
13+
case 2:
14+
return "error";
15+
16+
default:
17+
return rawSeverity;
18+
}
19+
};

0 commit comments

Comments
 (0)