Skip to content

Commit e99a5b9

Browse files
author
Josh Goldberg
authored
Respect ESLint extensions in deduplicating rules and config writing (#78)
* Respect ESLint extensions in deduplicating rules and config writing The original ESLint configuration is now included in the `writeConversionResults` written file with a single `...`. Additionally skipped outputting rules that match an existing ESLint plugin. If an extended ESLint plugin defines a rule with the same values as the resultant config, the config will skip printing it. This necessitated expanding "failures" to allow a new `ConfigurationError` type of error for unfound ESLint configurations. Renames "packages" in the configuration reading/converting logic areas to "plugins", as that's what ESLint calls them. * Used formatJsonOutput in merged test
1 parent c6454fb commit e99a5b9

31 files changed

+886
-70
lines changed

.eslintrc.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,19 @@ module.exports = {
1717
"@typescript-eslint/no-use-before-define": 0,
1818
"@typescript-eslint/prefer-interface": 0,
1919
"default-case": 0,
20+
"guard-for-in": 0,
2021
"import/no-extraneous-dependencies": [
2122
"error",
2223
{ devDependencies: ["**/*.stubs.ts", "**/*.test.*"] },
2324
],
2425
"import/first": 0,
25-
"import/newline-after-import": 0,
2626
"import/no-unresolved": 0,
2727
"import/prefer-default-export": 0,
2828
"no-console": 0,
2929
"no-continue": 0,
3030
"no-empty-function": 0,
3131
"no-restricted-syntax": 0,
32+
"no-param-reassign": 0,
3233
"no-shadow": 0,
3334
"no-undef": 0,
3435
"no-useless-constructor": 0,

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ npx tslint-to-eslint-config --eslint ./path/to/eslintrc.js
6666
_Default: `--config`'s value_
6767

6868
Path to an ESLint configuration file to read settings from.
69-
This isn't yet used for anything, but will eventually inform settings for the generated ESLint configuration file.
69+
The generated ESLint configuration file will include any settings `import`ed from this file.
7070

7171
#### `package`
7272

src/adapters/importer.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export type Importer = (moduleName: string) => unknown | Error;
2+
3+
export const nativeImporter = async (moduleName: string) => {
4+
try {
5+
return await import(moduleName);
6+
} catch (error) {
7+
return error;
8+
}
9+
};

src/cli/main.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
import { EOL } from "os";
22

3-
import { bind } from "../binding";
4-
import { runCli, RunCliDependencies } from "./runCli";
3+
import { nativeImporter } from "../adapters/importer";
54
import { processLogger } from "../adapters/processLogger";
65
import { childProcessExec } from "../adapters/childProcessExec";
76
import { fsFileSystem } from "../adapters/fsFileSystem";
7+
import { bind } from "../binding";
88
import { ConvertConfigDependencies, convertConfig } from "../conversion/convertConfig";
9+
import { removeExtendsDuplicatedRules } from "../creation/simplification/removeExtendsDuplicatedRules";
10+
import {
11+
RetrieveExtendsValuesDependencies,
12+
retrieveExtendsValues,
13+
} from "../creation/simplification/retrieveExtendsValues";
14+
import {
15+
simplifyPackageRules,
16+
SimplifyPackageRulesDependencies,
17+
} from "../creation/simplification/simplifyPackageRules";
918
import {
1019
writeConversionResults,
1120
WriteConversionResultsDependencies,
@@ -14,6 +23,7 @@ import {
1423
findOriginalConfigurations,
1524
FindOriginalConfigurationsDependencies,
1625
} from "../input/findOriginalConfigurations";
26+
import { findPackagesConfiguration } from "../input/findPackagesConfiguration";
1727
import { findESLintConfiguration } from "../input/findESLintConfiguration";
1828
import { findTSLintConfiguration } from "../input/findTSLintConfiguration";
1929
import { findTypeScriptConfiguration } from "../input/findTypeScriptConfiguration";
@@ -24,7 +34,7 @@ import {
2434
import { converters } from "../rules/converters";
2535
import { convertRules } from "../rules/convertRules";
2636
import { mergers } from "../rules/mergers";
27-
import { findPackagesConfiguration } from "../input/findPackagesConfiguration";
37+
import { runCli, RunCliDependencies } from "./runCli";
2838

2939
const convertRulesDependencies = {
3040
converters,
@@ -46,6 +56,15 @@ const reportConversionResultsDependencies: ReportConversionResultsDependencies =
4656
logger: processLogger,
4757
};
4858

59+
const retrieveExtendsValuesDependencies: RetrieveExtendsValuesDependencies = {
60+
importer: nativeImporter,
61+
};
62+
63+
const simplifyPackageRulesDependencies: SimplifyPackageRulesDependencies = {
64+
removeExtendsDuplicatedRules,
65+
retrieveExtendsValues: bind(retrieveExtendsValues, retrieveExtendsValuesDependencies),
66+
};
67+
4968
const writeConversionResultsDependencies: WriteConversionResultsDependencies = {
5069
fileSystem: fsFileSystem,
5170
};
@@ -57,6 +76,7 @@ const convertConfigDependencies: ConvertConfigDependencies = {
5776
findOriginalConfigurationsDependencies,
5877
),
5978
reportConversionResults: bind(reportConversionResults, reportConversionResultsDependencies),
79+
simplifyPackageRules: bind(simplifyPackageRules, simplifyPackageRulesDependencies),
6080
writeConversionResults: bind(writeConversionResults, writeConversionResultsDependencies),
6181
};
6282

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { RuleConversionResults } from "../rules/convertRules";
22

33
export const createEmptyConversionResults = (
4-
overrides: Partial<RuleConversionResults>,
4+
overrides: Partial<RuleConversionResults> = {},
55
): RuleConversionResults => ({
66
converted: new Map(),
77
failed: [],
88
missing: [],
9-
packages: new Set(),
9+
plugins: new Set(),
1010
...overrides,
1111
});

src/conversion/convertConfig.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import { OriginalConfigurations } from "../input/findOriginalConfigurations";
44

55
const createStubDependencies = (
66
overrides: Pick<ConvertConfigDependencies, "findOriginalConfigurations">,
7-
) => ({
7+
): ConvertConfigDependencies => ({
88
convertRules: jest.fn(),
99
reportConversionResults: jest.fn(),
10+
simplifyPackageRules: async (_configurations, data) => data,
1011
writeConversionResults: jest.fn().mockReturnValue(Promise.resolve()),
1112
...overrides,
1213
});

src/conversion/convertConfig.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { SansDependencies } from "../binding";
2+
import { simplifyPackageRules } from "../creation/simplification/simplifyPackageRules";
23
import { writeConversionResults } from "../creation/writeConversionResults";
34
import { findOriginalConfigurations } from "../input/findOriginalConfigurations";
45
import { reportConversionResults } from "../reporting/reportConversionResults";
@@ -9,6 +10,7 @@ export type ConvertConfigDependencies = {
910
convertRules: SansDependencies<typeof convertRules>;
1011
findOriginalConfigurations: SansDependencies<typeof findOriginalConfigurations>;
1112
reportConversionResults: SansDependencies<typeof reportConversionResults>;
13+
simplifyPackageRules: SansDependencies<typeof simplifyPackageRules>;
1214
writeConversionResults: SansDependencies<typeof writeConversionResults>;
1315
};
1416

@@ -24,13 +26,20 @@ export const convertConfig = async (
2426
const ruleConversionResults = dependencies.convertRules(
2527
originalConfigurations.data.tslint.rules,
2628
);
29+
const mergedConfiguration = {
30+
...ruleConversionResults,
31+
...(await dependencies.simplifyPackageRules(
32+
originalConfigurations.data.eslint,
33+
ruleConversionResults,
34+
)),
35+
};
2736

2837
await dependencies.writeConversionResults(
2938
settings.config,
30-
ruleConversionResults,
39+
mergedConfiguration,
3140
originalConfigurations.data,
3241
);
33-
dependencies.reportConversionResults(ruleConversionResults);
42+
dependencies.reportConversionResults(mergedConfiguration);
3443

3544
return {
3645
status: ResultStatus.Succeeded,
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import {
2+
ESLintConfiguration,
3+
ESLintConfigurationRuleValue,
4+
} from "../../input/findESLintConfiguration";
5+
import { ESLintRuleOptions } from "../../rules/types";
6+
import { removeExtendsDuplicatedRules } from "./removeExtendsDuplicatedRules";
7+
8+
const prepareTestRule = (
9+
ruleOptions: Partial<ESLintRuleOptions>,
10+
extensionConfiguration: ESLintConfigurationRuleValue = 2,
11+
) => {
12+
const ruleName = "rule-a";
13+
const allRules = new Map<string, ESLintRuleOptions>([
14+
[
15+
ruleName,
16+
{
17+
ruleArguments: [],
18+
ruleName,
19+
ruleSeverity: "off",
20+
...ruleOptions,
21+
},
22+
],
23+
]);
24+
const extensions: Partial<ESLintConfiguration>[] = [
25+
{
26+
rules: {
27+
[ruleName]: extensionConfiguration,
28+
},
29+
},
30+
];
31+
32+
return { ruleName, allRules, extensions };
33+
};
34+
35+
describe("removeExtendsDuplicatedRules", () => {
36+
it("keeps a rule when there are no rules in the extension", () => {
37+
// Arrange
38+
const { allRules } = prepareTestRule(
39+
{
40+
ruleName: "mismatched",
41+
},
42+
2,
43+
);
44+
45+
// Act
46+
const differentRules = removeExtendsDuplicatedRules(allRules, [{}]);
47+
48+
// Assert
49+
expect(differentRules.size).toBe(1);
50+
});
51+
52+
it("keeps a rule when it doesn't match any existing rule", () => {
53+
// Arrange
54+
const { allRules, extensions } = prepareTestRule(
55+
{
56+
ruleName: "mismatched",
57+
},
58+
2,
59+
);
60+
61+
// Act
62+
const differentRules = removeExtendsDuplicatedRules(allRules, extensions);
63+
64+
// Assert
65+
expect(differentRules.size).toBe(1);
66+
});
67+
68+
it("removes a rule when it matches an existing rule as numbers", () => {
69+
// Arrange
70+
const { allRules, extensions } = prepareTestRule(
71+
{
72+
ruleSeverity: "warn",
73+
},
74+
1,
75+
);
76+
77+
// Act
78+
const differentRules = removeExtendsDuplicatedRules(allRules, extensions);
79+
80+
// Assert
81+
expect(differentRules.size).toBe(0);
82+
});
83+
84+
it("keeps a rule when it conflicts with an existing rule as numbers", () => {
85+
// Arrange
86+
const { allRules, extensions } = prepareTestRule(
87+
{
88+
ruleSeverity: "warn",
89+
},
90+
2,
91+
);
92+
93+
// Act
94+
const differentRules = removeExtendsDuplicatedRules(allRules, extensions);
95+
96+
// Assert
97+
expect(differentRules.size).toBe(1);
98+
});
99+
100+
it("removes a rule when it matches an existing rule as strings", () => {
101+
// Arrange
102+
const { allRules, extensions } = prepareTestRule(
103+
{
104+
ruleSeverity: "warn",
105+
},
106+
"warn",
107+
);
108+
109+
// Act
110+
const differentRules = removeExtendsDuplicatedRules(allRules, extensions);
111+
112+
// Assert
113+
expect(differentRules.size).toBe(0);
114+
});
115+
116+
it("keeps a rule when it conflicts with an existing rule as strings", () => {
117+
// Arrange
118+
const { allRules, extensions } = prepareTestRule(
119+
{
120+
ruleSeverity: "warn",
121+
},
122+
"error",
123+
);
124+
125+
// Act
126+
const differentRules = removeExtendsDuplicatedRules(allRules, extensions);
127+
128+
// Assert
129+
expect(differentRules.size).toBe(1);
130+
});
131+
132+
it("removes a rule when it matches an existing rule as objects", () => {
133+
// Arrange
134+
const { allRules, extensions } = prepareTestRule(
135+
{
136+
ruleArguments: ["some-argument"],
137+
ruleSeverity: "warn",
138+
},
139+
["warn", "some-argument"],
140+
);
141+
142+
// Act
143+
const differentRules = removeExtendsDuplicatedRules(allRules, extensions);
144+
145+
// Assert
146+
expect(differentRules.size).toBe(0);
147+
});
148+
149+
it("keeps a rule when it conflicts with an existing rule as objects", () => {
150+
// Arrange
151+
const { allRules, extensions } = prepareTestRule(
152+
{
153+
ruleArguments: ["some-argument-one"],
154+
ruleSeverity: "warn",
155+
},
156+
["warn", "some-argument-modified"],
157+
);
158+
159+
// Act
160+
const differentRules = removeExtendsDuplicatedRules(allRules, extensions);
161+
162+
// Assert
163+
expect(differentRules.size).toBe(1);
164+
});
165+
});

0 commit comments

Comments
 (0)