Skip to content

Commit c6c3e88

Browse files
author
Josh Goldberg
authored
Account for TSLint and @typescript-eslint rulesets (#276)
* WIP * Fixed tsc failures and existing or new unit tests * Brought coverage back up to 100%
1 parent 428b2f9 commit c6c3e88

18 files changed

+250
-48
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
[![Join the chat at https://gitter.im/tslint-to-eslint-config/community](https://img.shields.io/badge/chat-gitter-informational.svg)](https://gitter.im/tslint-to-eslint-config/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
99
[![Code Style: Prettier](https://img.shields.io/badge/speed-blazingly_fast-blueviolet.svg)](https://prettier.io)
1010

11-
Converts your TSLint configuration to the closest possible ESLint equivalent.
11+
Converts your TSLint configuration to the closest reasonable ESLint equivalent.
1212

1313
👉 Did you know [TSLint is being deprecated this year](https://github.com/palantir/tslint/issues/4534)?
1414
Hooray!

docs/Architecture.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ 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 presets
16+
3. ESLint configurations are simplified based on extended ESLint and TSLint presets
1717
4. The simplified configuration is written to the output config file
1818
5. A summary of the results is printed to the user's console
1919

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"bugs": {
66
"url": "https://github.com/typescript-eslint/tslint-to-eslint-config/issues"
77
},
8-
"description": "Converts your TSLint configuration to the closest possible ESLint equivalent.",
8+
"description": "Converts your TSLint configuration to the closest reasonable ESLint equivalent.",
99
"dependencies": {
1010
"chalk": "3.0.0",
1111
"commander": "4.0.1",

src/conversion/convertConfig.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ const createStubDependencies = (
1414
status: ResultStatus.Succeeded,
1515
}),
1616
reportConversionResults: jest.fn(),
17-
simplifyPackageRules: async (_configurations, data) => data,
17+
simplifyPackageRules: async (_configurations, data) => ({
18+
...data,
19+
converted: new Map(),
20+
failed: [],
21+
}),
1822
writeConversionResults: jest.fn().mockReturnValue(Promise.resolve()),
1923
...overrides,
2024
});

src/conversion/convertConfig.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,12 @@ export const convertConfig = async (
3333
originalConfigurations.data.tslint.full.rules,
3434
);
3535

36-
// 3. ESLint configurations are simplified based on extended ESLint presets
36+
// 3. ESLint configurations are simplified based on extended ESLint and TSLint presets
3737
const simplifiedConfiguration = {
3838
...ruleConversionResults,
3939
...(await dependencies.simplifyPackageRules(
4040
originalConfigurations.data.eslint,
41+
originalConfigurations.data.tslint,
4142
ruleConversionResults,
4243
)),
4344
};
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { collectTSLintRulesets } from "./collectTSLintRulesets";
2+
3+
describe("collectTSLintRulesets", () => {
4+
it("includes mapped ESLint extensions for a full TSLint extension when it exists", () => {
5+
const tslint = {
6+
full: {
7+
extends: ["tslint:recommended"],
8+
},
9+
raw: {},
10+
};
11+
12+
const extensions = collectTSLintRulesets(tslint);
13+
14+
expect(extensions).toEqual([
15+
"plugin:@typescript-eslint/recommended",
16+
"plugin:@typescript-eslint/recommended-requiring-type-checking",
17+
]);
18+
});
19+
20+
it("includes mapped ESLint extensions for a raw TSLint extension when it exists", () => {
21+
const tslint = {
22+
full: {},
23+
raw: {
24+
extends: ["tslint:recommended"],
25+
},
26+
};
27+
28+
const extensions = collectTSLintRulesets(tslint);
29+
30+
expect(extensions).toEqual([
31+
"plugin:@typescript-eslint/recommended",
32+
"plugin:@typescript-eslint/recommended-requiring-type-checking",
33+
]);
34+
});
35+
36+
it("ignores a TSLint extension when it has no mapped ESLint extensions", () => {
37+
const tslint = {
38+
full: {
39+
extends: ["does not exist"],
40+
},
41+
raw: {
42+
extends: ["also does not exist"],
43+
},
44+
};
45+
46+
const extensions = collectTSLintRulesets(tslint);
47+
48+
expect(extensions).toEqual([]);
49+
});
50+
});
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { OriginalConfigurations } from "../../input/findOriginalConfigurations";
2+
import { TSLintConfiguration } from "../../input/findTSLintConfiguration";
3+
import { uniqueFromSources } from "../../utils";
4+
5+
const nativeExtensions = new Map([
6+
["tslint:all", ["plugin:@typescript-eslint/all"]],
7+
[
8+
"tslint:recommended",
9+
[
10+
"plugin:@typescript-eslint/recommended",
11+
"plugin:@typescript-eslint/recommended-requiring-type-checking",
12+
],
13+
],
14+
]);
15+
16+
export const collectTSLintRulesets = (
17+
tslint: OriginalConfigurations<Pick<TSLintConfiguration, "extends">>,
18+
) => {
19+
const allExtensions = uniqueFromSources(tslint.full.extends, tslint.raw.extends);
20+
21+
const extensions = new Set<string>();
22+
23+
for (const extension of allExtensions) {
24+
const mappedExtensions = nativeExtensions.get(extension);
25+
26+
if (mappedExtensions !== undefined) {
27+
for (const mappedExtension of mappedExtensions) {
28+
extensions.add(mappedExtension);
29+
}
30+
}
31+
}
32+
33+
return Array.from(extensions);
34+
};

src/creation/simplification/resolveExtensionNames.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ describe("resolveExtensionNames", () => {
5555
// Assert
5656
expect(extensionNames).toEqual(["eslint-plugin-value"]);
5757
});
58+
5859
it("doesn't prepend eslint-plugin- when a plugin starts with eslint:", () => {
5960
// Arrange
6061
const rawExtensionName = "eslint:recommended";
@@ -65,4 +66,15 @@ describe("resolveExtensionNames", () => {
6566
// Assert
6667
expect(extensionNames).toEqual(["eslint:recommended"]);
6768
});
69+
70+
it("doesn't prepend eslint-plugin- when a plugin starts with plugin:", () => {
71+
// Arrange
72+
const rawExtensionName = "eslint:recommended";
73+
74+
// Act
75+
const extensionNames = resolveExtensionNames(rawExtensionName);
76+
77+
// Assert
78+
expect(extensionNames).toEqual(["eslint:recommended"]);
79+
});
6880
});

src/creation/simplification/resolveExtensionNames.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ export const resolveExtensionNames = (rawExtensionNames: string | string[]) => {
66
return rawExtensionNames.map(rawExtensionName =>
77
rawExtensionName.startsWith(".") ||
88
rawExtensionName.startsWith("eslint-plugin-") ||
9-
rawExtensionName.startsWith("eslint:")
9+
rawExtensionName.startsWith("eslint:") ||
10+
rawExtensionName.startsWith("plugin:")
1011
? rawExtensionName
1112
: `eslint-plugin-${rawExtensionName}`,
1213
);

src/creation/simplification/retrieveExtendsValues.test.ts

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

33
describe("retrieveExtendsValues", () => {
4-
it("retrieves eslint-all when an extension is named eslint:all", async () => {
4+
it("retrieves an equivalent ESLint configuration when a retrieved extensions is an ESLint builtin", async () => {
55
// Arrange
66
const eslintAll = { rules: {} };
77
const importer = async (extensionName: string) =>
@@ -16,22 +16,22 @@ describe("retrieveExtendsValues", () => {
1616
expect(importedExtensions).toEqual([eslintAll]);
1717
});
1818

19-
it("retrieves eslint-recommended when an extension is named eslint:recommended", async () => {
19+
it("retrieves an equivalent typescript-eslint configuration when a retrieved extensions is a typescript-eslint builtin", async () => {
2020
// Arrange
21-
const eslintRecommended = { rules: {} };
21+
const eslintAll = { rules: {} };
2222
const importer = async (extensionName: string) =>
23-
extensionName === "eslint/conf/eslint-recommended"
24-
? eslintRecommended
23+
extensionName === "node_modules/@typescript-eslint/eslint-plugin/dist/configs/all.json"
24+
? eslintAll
2525
: new Error(`Unknown extension name: '${extensionName}`);
2626

2727
// Act
2828
const { importedExtensions } = await retrieveExtendsValues(
2929
{ importer },
30-
"eslint:recommended",
30+
"plugin:@typescript-eslint/all",
3131
);
3232

3333
// Assert
34-
expect(importedExtensions).toEqual([eslintRecommended]);
34+
expect(importedExtensions).toEqual([eslintAll]);
3535
});
3636

3737
it("reports a failure when an extension fails to import", async () => {

0 commit comments

Comments
 (0)