Skip to content

Commit a39ae6c

Browse files
author
Josh Goldberg
authored
Used package install command for list of required ESLint-related packages (#405)
* Used package install command for list of required ESLint-related packages * Cleanups and test fixings
1 parent bdcc6bc commit a39ae6c

24 files changed

+246
-102
lines changed

.eslintrc.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ module.exports = {
1818
},
1919
plugins: ["@typescript-eslint"],
2020
rules: {
21+
"@typescript-eslint/require-array-sort-compare": "off",
2122
"@typescript-eslint/consistent-type-definitions": ["error", "type"],
2223
"@typescript-eslint/explicit-function-return-type": "off",
2324
"@typescript-eslint/explicit-module-boundary-types": "off",
@@ -36,6 +37,7 @@ module.exports = {
3637
"@typescript-eslint/no-unsafe-member-access": "off",
3738
"@typescript-eslint/no-unsafe-return": "off",
3839
"@typescript-eslint/no-untyped-public-signature": "off",
40+
"@typescript-eslint/no-unused-vars": "off",
3941
"@typescript-eslint/no-use-before-define": "off",
4042
"@typescript-eslint/prefer-readonly-parameter-types": "off",
4143
"@typescript-eslint/prefer-reduce-type-parameter": "off",

src/cli/main.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,11 @@ import { findTSLintConfiguration } from "../input/findTSLintConfiguration";
4343
import { findTypeScriptConfiguration } from "../input/findTypeScriptConfiguration";
4444
import { importer, ImporterDependencies } from "../input/importer";
4545
import { mergeLintConfigurations } from "../input/mergeLintConfigurations";
46-
import { ReportConversionResultsDependencies } from "../reporting/dependencies";
47-
import { reportConversionResults } from "../reporting/reportConversionResults";
46+
import { choosePackageManager } from "../reporting/packages/choosePackageManager";
47+
import {
48+
reportConversionResults,
49+
ReportConversionResultsDependencies,
50+
} from "../reporting/reportConversionResults";
4851
import { reportEditorSettingConversionResults } from "../reporting/reportEditorSettingConversionResults";
4952
import { convertRules, ConvertRulesDependencies } from "../rules/convertRules";
5053
import { mergers } from "../rules/mergers";
@@ -86,7 +89,12 @@ const findOriginalConfigurationsDependencies: FindOriginalConfigurationsDependen
8689
mergeLintConfigurations,
8790
};
8891

92+
const choosePackageManagerDependencies = {
93+
fileSystem: fsFileSystem,
94+
};
95+
8996
const reportConversionResultsDependencies: ReportConversionResultsDependencies = {
97+
choosePackageManager: bind(choosePackageManager, choosePackageManagerDependencies),
9098
logger: processLogger,
9199
};
92100

src/conversion/convertConfig.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export const convertConfig = async (
5757
}
5858

5959
// 5. A summary of the results is printed to the user's console
60-
dependencies.reportConversionResults(simplifiedConfiguration);
60+
await dependencies.reportConversionResults(simplifiedConfiguration);
6161

6262
return {
6363
status: ResultStatus.Succeeded,

src/reporting/dependencies.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { choosePackageManager } from "./choosePackageManager";
2+
import { PackageManager } from "./packageManagers";
3+
4+
describe("choosePackageManager", () => {
5+
it("uses a non-npm package manager when that package manager's lock file exists", async () => {
6+
// Arrange
7+
const fileSystem = {
8+
fileExists: async (fileName: string) => fileName === "./yarn.lock",
9+
};
10+
11+
// Act
12+
const result = await choosePackageManager({ fileSystem });
13+
14+
// Assert
15+
expect(result).toEqual(PackageManager.Yarn);
16+
});
17+
18+
it("uses npm when no lock file exists", async () => {
19+
// Arrange
20+
const fileSystem = {
21+
fileExists: async () => false,
22+
};
23+
24+
// Act
25+
const result = await choosePackageManager({ fileSystem });
26+
27+
// Assert
28+
expect(result).toEqual(PackageManager.npm);
29+
});
30+
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { FileSystem } from "../../adapters/fileSystem";
2+
import { preferredLockfiles, PackageManager } from "./packageManagers";
3+
4+
export type ChoosePackageManagerDependencies = {
5+
fileSystem: Pick<FileSystem, "fileExists">;
6+
};
7+
8+
export const choosePackageManager = async (dependencies: ChoosePackageManagerDependencies) => {
9+
for (const [packageManager, lockFile] of preferredLockfiles) {
10+
if (await dependencies.fileSystem.fileExists(lockFile)) {
11+
return packageManager;
12+
}
13+
}
14+
15+
return PackageManager.npm;
16+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export enum PackageManager {
2+
npm,
3+
pnpm,
4+
Yarn,
5+
}
6+
7+
export const preferredLockfiles = new Map([
8+
[PackageManager.npm, "./package-lock.json"],
9+
[PackageManager.pnpm, "./pnpm-lock.yaml"],
10+
[PackageManager.Yarn, "./yarn.lock"],
11+
]);
12+
13+
export const installationMessages = {
14+
[PackageManager.npm]: (packages: string) => `npm install ${packages} --save-dev`,
15+
[PackageManager.pnpm]: (packages: string) => `pnpm add ${packages} --save-dev`,
16+
[PackageManager.Yarn]: (packages: string) => `yarn add ${packages} --dev`,
17+
};

src/reporting/reportConversionResults.test.ts

Lines changed: 52 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,18 @@ import { EOL } from "os";
33
import { createStubLogger, expectEqualWrites } from "../adapters/logger.stubs";
44
import { createEmptyConversionResults } from "../conversion/conversionResults.stubs";
55
import { ESLintRuleOptions } from "../rules/types";
6+
import { PackageManager } from "./packages/packageManagers";
67
import { reportConversionResults } from "./reportConversionResults";
78

9+
const createStubDependencies = (packageManager = PackageManager.Yarn) => {
10+
const choosePackageManager = jest.fn().mockResolvedValueOnce(packageManager);
11+
const logger = createStubLogger();
12+
13+
return { choosePackageManager, logger };
14+
};
15+
816
describe("reportConversionResults", () => {
9-
it("logs a successful conversion without notices when there is one converted rule without notices", () => {
17+
it("logs a successful conversion without notices when there is one converted rule without notices", async () => {
1018
// Arrange
1119
const conversionResults = createEmptyConversionResults({
1220
converted: new Map<string, ESLintRuleOptions>([
@@ -21,19 +29,22 @@ describe("reportConversionResults", () => {
2129
]),
2230
});
2331

24-
const logger = createStubLogger();
32+
const { choosePackageManager, logger } = createStubDependencies();
2533

2634
// Act
27-
reportConversionResults({ logger }, conversionResults);
35+
await reportConversionResults({ choosePackageManager, logger }, conversionResults);
2836

2937
// Assert
3038
expectEqualWrites(
3139
logger.stdout.write,
32-
`✨ 1 rule replaced with its ESLint equivalent. ✨${EOL}`,
40+
`✨ 1 rule replaced with its ESLint equivalent. ✨`,
41+
``,
42+
`⚡ 3 packages are required for running with ESLint. ⚡`,
43+
` yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --dev`,
3344
);
3445
});
3546

36-
it("logs a successful conversion with notices when there is one converted rule with notices", () => {
47+
it("logs a successful conversion with notices when there is one converted rule with notices", async () => {
3748
// Arrange
3849
const conversionResults = createEmptyConversionResults({
3950
converted: new Map<string, ESLintRuleOptions>([
@@ -49,10 +60,10 @@ describe("reportConversionResults", () => {
4960
]),
5061
});
5162

52-
const logger = createStubLogger();
63+
const { choosePackageManager, logger } = createStubDependencies();
5364

5465
// Act
55-
reportConversionResults({ logger }, conversionResults);
66+
await reportConversionResults({ choosePackageManager, logger }, conversionResults);
5667

5768
// Assert
5869
expectEqualWrites(
@@ -62,10 +73,13 @@ describe("reportConversionResults", () => {
6273
` * tslint-rule-one:`,
6374
` - 1`,
6475
` - 2`,
76+
``,
77+
`⚡ 3 packages are required for running with ESLint. ⚡`,
78+
` yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --dev`,
6579
);
6680
});
6781

68-
it("logs successful conversions when there are multiple converted rules", () => {
82+
it("logs successful conversions when there are multiple converted rules", async () => {
6983
// Arrange
7084
const conversionResults = createEmptyConversionResults({
7185
converted: new Map<string, ESLintRuleOptions>([
@@ -90,35 +104,39 @@ describe("reportConversionResults", () => {
90104
]),
91105
});
92106

93-
const logger = createStubLogger();
107+
const { choosePackageManager, logger } = createStubDependencies();
94108

95109
// Act
96-
reportConversionResults({ logger }, conversionResults);
110+
await reportConversionResults({ choosePackageManager, logger }, conversionResults);
97111

98112
// Assert
99113
expectEqualWrites(
100114
logger.stdout.write,
101-
`✨ 2 rules replaced with their ESLint equivalents. ✨${EOL}`,
115+
`✨ 2 rules replaced with their ESLint equivalents. ✨`,
116+
``,
102117
`❗ 2 ESLint rules behave differently from their TSLint counterparts ❗`,
103118
` * tslint-rule-one:`,
104119
` - 1`,
105120
` - 2`,
106121
` * tslint-rule-two:`,
107122
` - 3`,
108123
` - 4`,
124+
``,
125+
`⚡ 3 packages are required for running with ESLint. ⚡`,
126+
` yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --dev`,
109127
);
110128
});
111129

112-
it("logs a failed conversion when there is one failed conversion", () => {
130+
it("logs a failed conversion when there is one failed conversion", async () => {
113131
// Arrange
114132
const conversionResults = createEmptyConversionResults({
115133
failed: [{ getSummary: () => "It broke." }],
116134
});
117135

118-
const logger = createStubLogger();
136+
const { choosePackageManager, logger } = createStubDependencies();
119137

120138
// Act
121-
reportConversionResults({ logger }, conversionResults);
139+
await reportConversionResults({ choosePackageManager, logger }, conversionResults);
122140

123141
// Assert
124142
expectEqualWrites(
@@ -128,16 +146,16 @@ describe("reportConversionResults", () => {
128146
);
129147
});
130148

131-
it("logs failed conversions when there are multiple failed conversions", () => {
149+
it("logs failed conversions when there are multiple failed conversions", async () => {
132150
// Arrange
133151
const conversionResults = createEmptyConversionResults({
134152
failed: [{ getSummary: () => "It broke." }, { getSummary: () => "It really broke." }],
135153
});
136154

137-
const logger = createStubLogger();
155+
const { choosePackageManager, logger } = createStubDependencies();
138156

139157
// Act
140-
reportConversionResults({ logger }, conversionResults);
158+
await reportConversionResults({ choosePackageManager, logger }, conversionResults);
141159

142160
// Assert
143161
expectEqualWrites(
@@ -147,7 +165,7 @@ describe("reportConversionResults", () => {
147165
);
148166
});
149167

150-
it("logs a missing rule when there is a missing rule", () => {
168+
it("logs a missing rule when there is a missing rule", async () => {
151169
// Arrange
152170
const conversionResults = createEmptyConversionResults({
153171
missing: [
@@ -159,24 +177,27 @@ describe("reportConversionResults", () => {
159177
],
160178
});
161179

162-
const logger = createStubLogger();
180+
const { choosePackageManager, logger } = createStubDependencies();
163181

164182
// Act
165-
reportConversionResults({ logger }, conversionResults);
183+
await reportConversionResults({ choosePackageManager, logger }, conversionResults);
166184

167185
// Assert
168186
expectEqualWrites(
169187
logger.stdout.write,
170188
"❓ 1 rule does not yet have an ESLint equivalent ❓",
171189
` See generated log file; defaulting to eslint-plugin-tslint for it.`,
190+
"",
191+
"⚡ 3 packages are required for running with ESLint. ⚡",
192+
" yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --dev",
172193
);
173194
expectEqualWrites(
174195
logger.info.write,
175196
'tslint-to-eslint-config does not know the ESLint equivalent for TSLint\'s "tslint-rule-one"',
176197
);
177198
});
178199

179-
it("logs missing rules when there are missing rules", () => {
200+
it("logs missing rules when there are missing rules", async () => {
180201
// Arrange
181202
const conversionResults = createEmptyConversionResults({
182203
missing: [
@@ -193,16 +214,19 @@ describe("reportConversionResults", () => {
193214
],
194215
});
195216

196-
const logger = createStubLogger();
217+
const { choosePackageManager, logger } = createStubDependencies();
197218

198219
// Act
199-
reportConversionResults({ logger }, conversionResults);
220+
await reportConversionResults({ choosePackageManager, logger }, conversionResults);
200221

201222
// Assert
202223
expectEqualWrites(
203224
logger.stdout.write,
204225
"❓ 2 rules do not yet have ESLint equivalents ❓",
205226
` See generated log file; defaulting to eslint-plugin-tslint for these rules.`,
227+
"",
228+
"⚡ 3 packages are required for running with ESLint. ⚡",
229+
" yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --dev",
206230
);
207231
expectEqualWrites(
208232
logger.info.write,
@@ -211,42 +235,22 @@ describe("reportConversionResults", () => {
211235
);
212236
});
213237

214-
it("logs a missing plugin when there is a missing plugin", () => {
215-
// Arrange
216-
const conversionResults = createEmptyConversionResults({
217-
plugins: new Set(["plugin-one"]),
218-
});
219-
220-
const logger = createStubLogger();
221-
222-
// Act
223-
reportConversionResults({ logger }, conversionResults);
224-
225-
// Assert
226-
expectEqualWrites(
227-
logger.stdout.write,
228-
"⚡ 1 package is required for new ESLint rules. ⚡",
229-
" plugin-one",
230-
);
231-
});
232-
233-
it("logs missing plugins when there are missing plugins", () => {
238+
it("logs missing plugins when there are missing plugins", async () => {
234239
// Arrange
235240
const conversionResults = createEmptyConversionResults({
236241
plugins: new Set(["plugin-one", "plugin-two"]),
237242
});
238243

239-
const logger = createStubLogger();
244+
const { choosePackageManager, logger } = createStubDependencies();
240245

241246
// Act
242-
reportConversionResults({ logger }, conversionResults);
247+
await reportConversionResults({ choosePackageManager, logger }, conversionResults);
243248

244249
// Assert
245250
expectEqualWrites(
246251
logger.stdout.write,
247-
"⚡ 2 packages are required for new ESLint rules. ⚡",
248-
" plugin-one",
249-
" plugin-two",
252+
"⚡ 5 packages are required for running with ESLint. ⚡",
253+
" yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint plugin-one plugin-two --dev",
250254
);
251255
});
252256
});

0 commit comments

Comments
 (0)