Skip to content

Commit bb4dcc6

Browse files
author
Josh Goldberg
authored
Removed already-installed packages from install command (#424)
* WIP: excluded package names from install suggestion * Fixed up using extends * Removed commented out imports
1 parent ecf6ee7 commit bb4dcc6

14 files changed

+298
-245
lines changed

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ module.exports = {
3838
"@typescript-eslint/no-unsafe-return": "off",
3939
"@typescript-eslint/no-untyped-public-signature": "off",
4040
"@typescript-eslint/no-unused-vars": "off",
41+
"@typescript-eslint/no-unused-vars-experimental": "off",
4142
"@typescript-eslint/no-use-before-define": "off",
4243
"@typescript-eslint/prefer-readonly-parameter-types": "off",
4344
"@typescript-eslint/prefer-reduce-type-parameter": "off",

src/cli/main.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,14 @@ import { findTSLintConfiguration } from "../input/findTSLintConfiguration";
4444
import { findTypeScriptConfiguration } from "../input/findTypeScriptConfiguration";
4545
import { importer, ImporterDependencies } from "../input/importer";
4646
import { mergeLintConfigurations } from "../input/mergeLintConfigurations";
47-
import { choosePackageManager } from "../reporting/packages/choosePackageManager";
47+
import {
48+
ChoosePackageManagerDependencies,
49+
choosePackageManager,
50+
} from "../reporting/packages/choosePackageManager";
51+
import {
52+
logMissingPackages,
53+
LogMissingPackagesDependencies,
54+
} from "../reporting/packages/logMissingPackages";
4855
import {
4956
reportConversionResults,
5057
ReportConversionResultsDependencies,
@@ -90,15 +97,19 @@ const findOriginalConfigurationsDependencies: FindOriginalConfigurationsDependen
9097
mergeLintConfigurations,
9198
};
9299

93-
const choosePackageManagerDependencies = {
100+
const choosePackageManagerDependencies: ChoosePackageManagerDependencies = {
94101
fileSystem: fsFileSystem,
95102
};
96103

97-
const reportConversionResultsDependencies: ReportConversionResultsDependencies = {
104+
const logMissingPackagesDependencies: LogMissingPackagesDependencies = {
98105
choosePackageManager: bind(choosePackageManager, choosePackageManagerDependencies),
99106
logger: processLogger,
100107
};
101108

109+
const reportConversionResultsDependencies: ReportConversionResultsDependencies = {
110+
logger: processLogger,
111+
};
112+
102113
const retrieveExtendsValuesDependencies: RetrieveExtendsValuesDependencies = {
103114
importer: boundImporter,
104115
};
@@ -132,6 +143,7 @@ const convertConfigDependencies: ConvertConfigDependencies = {
132143
findOriginalConfigurations,
133144
findOriginalConfigurationsDependencies,
134145
),
146+
logMissingPackages: bind(logMissingPackages, logMissingPackagesDependencies),
135147
reportConversionResults: bind(reportConversionResults, reportConversionResultsDependencies),
136148
simplifyPackageRules: bind(simplifyPackageRules, simplifyPackageRulesDependencies),
137149
writeConversionResults: bind(writeConversionResults, writeConversionResultsDependencies),

src/conversion/convertConfig.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const createStubDependencies = (
2222
missing: [],
2323
plugins: new Set(),
2424
}),
25+
logMissingPackages: jest.fn().mockReturnValue(Promise.resolve()),
2526
writeConversionResults: jest.fn().mockReturnValue(Promise.resolve()),
2627
...overrides,
2728
});

src/conversion/convertConfig.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ import { SansDependencies } from "../binding";
22
import { simplifyPackageRules } from "../creation/simplification/simplifyPackageRules";
33
import { writeConversionResults } from "../creation/writeConversionResults";
44
import { findOriginalConfigurations } from "../input/findOriginalConfigurations";
5+
import { logMissingPackages } from "../reporting/packages/logMissingPackages";
56
import { reportConversionResults } from "../reporting/reportConversionResults";
67
import { convertRules } from "../rules/convertRules";
78
import { ResultStatus, ResultWithStatus, TSLintToESLintSettings } from "../types";
89

910
export type ConvertConfigDependencies = {
1011
convertRules: SansDependencies<typeof convertRules>;
1112
findOriginalConfigurations: SansDependencies<typeof findOriginalConfigurations>;
13+
logMissingPackages: SansDependencies<typeof logMissingPackages>;
1214
reportConversionResults: SansDependencies<typeof reportConversionResults>;
1315
simplifyPackageRules: SansDependencies<typeof simplifyPackageRules>;
1416
writeConversionResults: SansDependencies<typeof writeConversionResults>;
@@ -56,6 +58,10 @@ export const convertConfig = async (
5658

5759
// 5. A summary of the results is printed to the user's console
5860
await dependencies.reportConversionResults(settings.config, simplifiedConfiguration);
61+
await dependencies.logMissingPackages(
62+
simplifiedConfiguration,
63+
originalConfigurations.data.packages,
64+
);
5965

6066
return {
6167
status: ResultStatus.Succeeded,

src/creation/simplification/simplifyPackageRules.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ describe("simplifyPackageRules", () => {
6868
expect(simplifiedResults).toEqual({
6969
...ruleConversionResults,
7070
converted: undefined,
71-
extends: ["eslint-config-prettier", "eslint-config-prettier/@typescript-eslint"],
71+
extends: [
72+
"plugin:eslint-config-prettier",
73+
"plugin:eslint-config-prettier/@typescript-eslint",
74+
],
7275
});
7376
});
7477

src/creation/simplification/simplifyPackageRules.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ export const simplifyPackageRules = async (
3636

3737
// 3a. If no output rules conflict with `eslint-config-prettier`, it's added in
3838
if (await dependencies.addPrettierExtensions(ruleConversionResults, prettierRequested)) {
39-
allExtensions.push("eslint-config-prettier", "eslint-config-prettier/@typescript-eslint");
39+
allExtensions.push(
40+
"plugin:eslint-config-prettier",
41+
"plugin:eslint-config-prettier/@typescript-eslint",
42+
);
4043
}
4144

4245
if (allExtensions.length === 0) {

src/input/findPackagesConfiguration.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,8 @@ import {
44
} from "./findReportedConfiguration";
55

66
export type PackagesConfiguration = {
7-
dependencies: {
8-
[i: string]: string;
9-
};
10-
devDependencies: {
11-
[i: string]: string;
12-
};
13-
};
14-
15-
const defaultPackagesConfiguration = {
16-
dependencies: {},
17-
devDependencies: {},
7+
dependencies: Record<string, string>;
8+
devDependencies: Record<string, string>;
189
};
1910

2011
export const findPackagesConfiguration = async (
@@ -32,11 +23,9 @@ export const findPackagesConfiguration = async (
3223
: {
3324
dependencies: {
3425
...rawConfiguration.dependencies,
35-
...defaultPackagesConfiguration.dependencies,
3626
},
3727
devDependencies: {
3828
...rawConfiguration.devDependencies,
39-
...defaultPackagesConfiguration.devDependencies,
4029
},
4130
};
4231
};
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
import { createStubLogger, expectEqualWrites } from "../../adapters/logger.stubs";
2+
import { createEmptyConversionResults } from "../../conversion/conversionResults.stubs";
3+
import { logMissingPackages } from "./logMissingPackages";
4+
import { PackageManager } from "./packageManagers";
5+
6+
const createStubDependencies = (packageManager = PackageManager.npm) => ({
7+
choosePackageManager: async () => packageManager,
8+
logger: createStubLogger(),
9+
});
10+
11+
describe("logMissingPackages", () => {
12+
it("reports a singular message when one package is missing", async () => {
13+
// Arrange
14+
const { choosePackageManager, logger } = createStubDependencies(PackageManager.npm);
15+
const ruleConversionResults = createEmptyConversionResults();
16+
17+
// Act
18+
await logMissingPackages({ choosePackageManager, logger }, ruleConversionResults, {
19+
dependencies: {
20+
"@typescript-eslint/eslint-plugin": "*",
21+
"@typescript-eslint/parser": "*",
22+
},
23+
devDependencies: {},
24+
});
25+
26+
// Assert
27+
expectEqualWrites(
28+
logger.stdout.write,
29+
`⚡ 1 new package is required for this ESLint configuration. ⚡`,
30+
` npm install eslint --save-dev`,
31+
);
32+
});
33+
34+
it("does not include eslint-config-prettier when there are no extensions", async () => {
35+
// Arrange
36+
const { choosePackageManager, logger } = createStubDependencies();
37+
const ruleConversionResults = createEmptyConversionResults({
38+
extends: undefined,
39+
});
40+
41+
// Act
42+
await logMissingPackages({ choosePackageManager, logger }, ruleConversionResults);
43+
44+
// Assert
45+
expectEqualWrites(
46+
logger.stdout.write,
47+
`⚡ 3 new packages are required for this ESLint configuration. ⚡`,
48+
` npm install @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --save-dev`,
49+
);
50+
});
51+
52+
it("does not include eslint-config-prettier when extensions don't include eslint-config-prettier", async () => {
53+
// Arrange
54+
const { choosePackageManager, logger } = createStubDependencies();
55+
const ruleConversionResults = createEmptyConversionResults({
56+
extends: [],
57+
});
58+
59+
// Act
60+
await logMissingPackages({ choosePackageManager, logger }, ruleConversionResults);
61+
62+
// Assert
63+
expectEqualWrites(
64+
logger.stdout.write,
65+
`⚡ 3 new packages are required for this ESLint configuration. ⚡`,
66+
` npm install @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --save-dev`,
67+
);
68+
});
69+
70+
it("includes eslint-config-prettier when extensions include eslint-config-prettier", async () => {
71+
// Arrange
72+
const { choosePackageManager, logger } = createStubDependencies();
73+
const ruleConversionResults = createEmptyConversionResults({
74+
extends: ["plugin:eslint-config-prettier"],
75+
});
76+
77+
// Act
78+
await logMissingPackages({ choosePackageManager, logger }, ruleConversionResults);
79+
80+
// Assert
81+
expectEqualWrites(
82+
logger.stdout.write,
83+
`⚡ 4 new packages are required for this ESLint configuration. ⚡`,
84+
` npm install @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint eslint-config-prettier --save-dev`,
85+
);
86+
});
87+
88+
it("includes @typescript-eslint/eslint-plugin-tslint when there are missing conversions", async () => {
89+
// Arrange
90+
const { choosePackageManager, logger } = createStubDependencies();
91+
const ruleConversionResults = createEmptyConversionResults({
92+
missing: [
93+
{
94+
ruleArguments: [],
95+
ruleName: "missing-rule",
96+
ruleSeverity: "error",
97+
},
98+
],
99+
});
100+
101+
// Act
102+
await logMissingPackages({ choosePackageManager, logger }, ruleConversionResults);
103+
104+
// Assert
105+
expectEqualWrites(
106+
logger.stdout.write,
107+
`⚡ 4 new packages are required for this ESLint configuration. ⚡`,
108+
` npm install @typescript-eslint/eslint-plugin @typescript-eslint/eslint-plugin-tslint @typescript-eslint/parser eslint --save-dev`,
109+
);
110+
});
111+
112+
it("reports an npm command when the package manager is npm", async () => {
113+
// Arrange
114+
const { choosePackageManager, logger } = createStubDependencies(PackageManager.npm);
115+
const ruleConversionResults = createEmptyConversionResults();
116+
117+
// Act
118+
await logMissingPackages({ choosePackageManager, logger }, ruleConversionResults);
119+
120+
// Assert
121+
expectEqualWrites(
122+
logger.stdout.write,
123+
`⚡ 3 new packages are required for this ESLint configuration. ⚡`,
124+
` npm install @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --save-dev`,
125+
);
126+
});
127+
128+
it("reports a pnpm command when the package manager is pnpm", async () => {
129+
// Arrange
130+
const { choosePackageManager, logger } = createStubDependencies(PackageManager.pnpm);
131+
const ruleConversionResults = createEmptyConversionResults();
132+
133+
// Act
134+
await logMissingPackages({ choosePackageManager, logger }, ruleConversionResults);
135+
136+
// Assert
137+
expectEqualWrites(
138+
logger.stdout.write,
139+
`⚡ 3 new packages are required for this ESLint configuration. ⚡`,
140+
` pnpm add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --save-dev`,
141+
);
142+
});
143+
144+
it("reports a Yarn command when the package manager is Yarn", async () => {
145+
// Arrange
146+
const { choosePackageManager, logger } = createStubDependencies(PackageManager.Yarn);
147+
const ruleConversionResults = createEmptyConversionResults();
148+
149+
// Act
150+
await logMissingPackages({ choosePackageManager, logger }, ruleConversionResults);
151+
152+
// Assert
153+
expectEqualWrites(
154+
logger.stdout.write,
155+
`⚡ 3 new packages are required for this ESLint configuration. ⚡`,
156+
` yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --dev`,
157+
);
158+
});
159+
160+
it("reports a Yarn command when the package manager is Yarn", async () => {
161+
// Arrange
162+
const { choosePackageManager, logger } = createStubDependencies(PackageManager.Yarn);
163+
const ruleConversionResults = createEmptyConversionResults();
164+
165+
// Act
166+
await logMissingPackages({ choosePackageManager, logger }, ruleConversionResults);
167+
168+
// Assert
169+
expectEqualWrites(
170+
logger.stdout.write,
171+
`⚡ 3 new packages are required for this ESLint configuration. ⚡`,
172+
` yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --dev`,
173+
);
174+
});
175+
});
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import chalk from "chalk";
2+
import { EOL } from "os";
3+
4+
import { Logger } from "../../adapters/logger";
5+
import { SansDependencies } from "../../binding";
6+
import { SimplifiedResultsConfiguration } from "../../creation/simplification/simplifyPackageRules";
7+
import { PackagesConfiguration } from "../../input/findPackagesConfiguration";
8+
import { isTruthy } from "../../utils";
9+
import { installationMessages } from "../packages/packageManagers";
10+
import { choosePackageManager } from "./choosePackageManager";
11+
12+
export type LogMissingPackagesDependencies = {
13+
choosePackageManager: SansDependencies<typeof choosePackageManager>;
14+
logger: Logger;
15+
};
16+
17+
export const logMissingPackages = async (
18+
dependencies: LogMissingPackagesDependencies,
19+
ruleConversionResults: Pick<SimplifiedResultsConfiguration, "extends" | "missing" | "plugins">,
20+
packageConfiguration?: PackagesConfiguration,
21+
) => {
22+
const packageManager = await dependencies.choosePackageManager();
23+
24+
const existingPackageNames = new Set([
25+
...Object.keys(packageConfiguration?.dependencies ?? {}),
26+
...Object.keys(packageConfiguration?.devDependencies ?? {}),
27+
]);
28+
29+
const requiredPackageNames = [
30+
"@typescript-eslint/eslint-plugin",
31+
"@typescript-eslint/parser",
32+
ruleConversionResults.extends?.join("").includes("eslint-config-prettier") &&
33+
"eslint-config-prettier",
34+
ruleConversionResults.missing.length !== 0 && "@typescript-eslint/eslint-plugin-tslint",
35+
"eslint",
36+
...Array.from(ruleConversionResults.plugins),
37+
].filter(isTruthy);
38+
39+
const missingPackageNames = requiredPackageNames
40+
.filter((packageName) => !existingPackageNames.has(packageName))
41+
.sort();
42+
43+
dependencies.logger.stdout.write(chalk.cyanBright(`${EOL}${missingPackageNames.length}`));
44+
dependencies.logger.stdout.write(
45+
chalk.cyan(
46+
` new package${
47+
missingPackageNames.length === 1 ? " is" : "s are"
48+
} required for this ESLint configuration.`,
49+
),
50+
);
51+
dependencies.logger.stdout.write(chalk.cyanBright(" ⚡"));
52+
dependencies.logger.stdout.write(`${EOL} `);
53+
dependencies.logger.stdout.write(
54+
chalk.cyan(installationMessages[packageManager](missingPackageNames.join(" "))),
55+
);
56+
dependencies.logger.stdout.write(EOL);
57+
};

0 commit comments

Comments
 (0)