Skip to content

Added recommended --prettier flag to include eslint-config-prettier #412

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 26, 2020
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
*.tsbuildinfo
*.d.ts
!src/typings/**/*.d.ts
*.log
*.map
coverage/
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Each of these flags is optional:
- **[`editor`](#editor)**: Path to an editor configuration file to convert linter settings within.
- **[`eslint`](#eslint)**: Path to an ESLint configuration file to read settings from.
- **[`package`](#package)**: Path to a package.json file to read dependencies from.
- **[`prettier`](#prettier)**: Add `eslint-config-prettier` to the plugins list.
- **[`tslint`](#tslint)**: Path to a TSLint configuration file to read settings from.
- **[`typescript`](#typescript)**: Path to a TypeScript configuration file to read TypeScript compiler options from.

Expand Down Expand Up @@ -97,6 +98,22 @@ _Default: `package.json`_
Path to a `package.json` file to read dependencies from.
This will help inform the generated ESLint configuration file's [env](https://eslint.org/docs/user-guide/configuring#specifying-parser-options) settings.

#### `prettier`

```shell
npx tslint-to-eslint-config --prettier
```

_Default: `false`_

Add [`eslint-config-prettier`](https://github.com/prettier/eslint-config-prettier) to the list of ESLint plugins.
We [highly recommend](./docs/FAQs.md#should-i-use-prettier) you use [Prettier](http://prettier.io) for code formatting.

When `--prettier` isn't enabled:

- If the output configuration already doesn't enable any formatting rules, it'll extend from `eslint-config-prettier`.
- Otherwise, a CLI message will suggest running with `--prettier`.

#### `tslint`

```shell
Expand Down
1 change: 1 addition & 0 deletions docs/Architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Within `src/conversion/convertConfig.ts`, the following steps occur:
1. Existing configurations are read from disk
2. TSLint rules are converted into their ESLint configurations
3. ESLint configurations are simplified based on extended ESLint and TSLint presets
- 3a. If no output rules conflict with `eslint-config-prettier`, it's added in
4. The simplified configuration is written to the output config file
5. A summary of the results is printed to the user's console

Expand Down
4 changes: 1 addition & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"dependencies": {
"chalk": "4.0.0",
"commander": "5.1.0",
"eslint-config-prettier": "^6.11.0",
"strip-json-comments": "3.1.0",
"tslint": "6.1.1",
"typescript": "3.8.3"
Expand All @@ -28,7 +29,6 @@
"@typescript-eslint/parser": "2.29.0",
"babel-jest": "25.4.0",
"eslint": "6.8.0",
"eslint-config-prettier": "6.11.0",
"husky": "4.2.5",
"jest": "25.4.0",
"lint-staged": "10.1.7",
Expand Down
2 changes: 2 additions & 0 deletions src/cli/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
convertEditorConfig,
ConvertEditorConfigDependencies,
} from "../conversion/convertEditorConfig";
import { addPrettierExtensions } from "../creation/simplification/prettier/addPrettierExtensions";
import { removeExtendsDuplicatedRules } from "../creation/simplification/removeExtendsDuplicatedRules";
import {
retrieveExtendsValues,
Expand Down Expand Up @@ -103,6 +104,7 @@ const retrieveExtendsValuesDependencies: RetrieveExtendsValuesDependencies = {
};

const simplifyPackageRulesDependencies: SimplifyPackageRulesDependencies = {
addPrettierExtensions,
removeExtendsDuplicatedRules,
retrieveExtendsValues: bind(retrieveExtendsValues, retrieveExtendsValuesDependencies),
};
Expand Down
3 changes: 2 additions & 1 deletion src/cli/runCli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ export const runCli = async (
const command = new Command()
.usage("[options] <file ...> --language [language]")
.option("--config [config]", "eslint configuration file to output to")
.option("--editor [editor]", "editor configuration file to convert")
.option("--eslint [eslint]", "eslint configuration file to convert using")
.option("--package [package]", "package configuration file to convert using")
.option("--prettier [prettier]", "add eslint-config-prettier to the plugins list")
.option("--tslint [tslint]", "tslint configuration file to convert using")
.option("--typescript [typescript]", "typescript configuration file to convert using")
.option("--editor [editor]", "editor configuration file to convert")
.option("-V --version", "output the package version");

const parsedArgv = {
Expand Down
6 changes: 3 additions & 3 deletions src/conversion/conversionResults.stubs.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { EditorSettingConversionResults } from "../editorSettings/convertEditorSettings";
import { RuleConversionResults } from "../rules/convertRules";
import { SimplifiedResultsConfiguration } from "../creation/simplification/simplifyPackageRules";

export const createEmptyConversionResults = (
overrides: Partial<RuleConversionResults> = {},
): RuleConversionResults => ({
overrides: Partial<SimplifiedResultsConfiguration> = {},
): SimplifiedResultsConfiguration => ({
converted: new Map(),
failed: [],
missing: [],
Expand Down
3 changes: 3 additions & 0 deletions src/conversion/convertConfig.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ const createStubDependencies = (
simplifyPackageRules: async (_configurations, data) => ({
...data,
converted: new Map(),
extends: [],
failed: [],
missing: [],
plugins: new Set(),
}),
writeConversionResults: jest.fn().mockReturnValue(Promise.resolve()),
...overrides,
Expand Down
14 changes: 6 additions & 8 deletions src/conversion/convertConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,12 @@ export const convertConfig = async (
);

// 3. ESLint configurations are simplified based on extended ESLint and TSLint presets
const simplifiedConfiguration = {
...ruleConversionResults,
...(await dependencies.simplifyPackageRules(
originalConfigurations.data.eslint,
originalConfigurations.data.tslint,
ruleConversionResults,
)),
};
const simplifiedConfiguration = await dependencies.simplifyPackageRules(
originalConfigurations.data.eslint,
originalConfigurations.data.tslint,
ruleConversionResults,
settings.prettier,
);

// 4. The simplified configuration is written to the output config file
const fileWriteError = await dependencies.writeConversionResults(
Expand Down
59 changes: 59 additions & 0 deletions src/creation/simplification/prettier/addPrettierExtensions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { createEmptyConversionResults } from "../../../conversion/conversionResults.stubs";
import { addPrettierExtensions } from "./addPrettierExtensions";

const createStubRuleConversions = (ruleName: string, ruleSeverity: "error" | "off") =>
new Map([[ruleName, { ruleName, ruleSeverity }]]);

describe("addPrettierExtensions", () => {
it("returns false when a matching converted rule is enabled", async () => {
// Arrange
const ruleConversionResults = createEmptyConversionResults({
converted: createStubRuleConversions("max-len", "error"),
});

// Act
const result = await addPrettierExtensions(ruleConversionResults);

// Assert
expect(result).toEqual(false);
});

it("returns true when a matching converted rule is disabled", async () => {
// Arrange
const ruleConversionResults = createEmptyConversionResults({
converted: createStubRuleConversions("max-len", "off"),
});

// Act
const result = await addPrettierExtensions(ruleConversionResults);

// Assert
expect(result).toEqual(true);
});

it("returns true when there are no matching converted rules", async () => {
// Arrange
const ruleConversionResults = createEmptyConversionResults({
converted: createStubRuleConversions("unknown", "error"),
});

// Act
const result = await addPrettierExtensions(ruleConversionResults);

// Assert
expect(result).toEqual(true);
});

it("returns true when prettier is requested", async () => {
// Arrange
const ruleConversionResults = createEmptyConversionResults({
converted: createStubRuleConversions("max-len", "off"),
});

// Act
const result = await addPrettierExtensions(ruleConversionResults, true);

// Assert
expect(result).toEqual(true);
});
});
21 changes: 21 additions & 0 deletions src/creation/simplification/prettier/addPrettierExtensions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import prettierRuleSettings from "eslint-config-prettier";

import { RuleConversionResults } from "../../../rules/convertRules";

export const addPrettierExtensions = async (
ruleConversionResults: Pick<RuleConversionResults, "converted">,
prettierRequested?: boolean,
) => {
if (prettierRequested) {
return true;
}

for (const rule in prettierRuleSettings.rules) {
const convertedRule = ruleConversionResults.converted.get(rule);
if (convertedRule !== undefined && convertedRule.ruleSeverity !== "off") {
return false;
}
}

return true;
};
47 changes: 38 additions & 9 deletions src/creation/simplification/simplifyPackageRules.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { ConfigurationError } from "../../errors/configurationError";
import { ESLintRuleOptions } from "../../rules/types";
import { createEmptyConversionResults } from "../../conversion/conversionResults.stubs";
import { simplifyPackageRules } from "./simplifyPackageRules";
import { simplifyPackageRules, SimplifyPackageRulesDependencies } from "./simplifyPackageRules";

const createStubDependencies = () => ({
const createStubDependencies = (overrides: Partial<SimplifyPackageRulesDependencies> = {}) => ({
addPrettierExtensions: jest.fn(),
removeExtendsDuplicatedRules: jest.fn(),
retrieveExtendsValues: async () => ({
configurationErrors: [],
importedExtensions: [],
}),
...overrides,
});

const createStubESLintConfiguration = (fullExtends: string[]) => ({
Expand All @@ -25,7 +27,7 @@ const createStubTSLintConfiguration = () => ({
});

describe("simplifyPackageRules", () => {
it("returns the conversion results directly when there is no loaded ESLint configuration and no TSLint extensions", async () => {
it("returns equivalent conversion results when there is no loaded ESLint configuration and no TSLint extensions", async () => {
// Arrange
const dependencies = createStubDependencies();
const eslint = undefined;
Expand All @@ -41,10 +43,36 @@ describe("simplifyPackageRules", () => {
);

// Assert
expect(simplifiedResults).toBe(ruleConversionResults);
expect(simplifiedResults).toEqual(ruleConversionResults);
});

it("returns the conversion results directly when there is an empty ESLint configuration and no TSLint extensions", async () => {
it("adds Prettier extensions when addPrettierExtensions returns true", async () => {
// Arrange
const dependencies = createStubDependencies({
addPrettierExtensions: async () => true,
});
const eslint = undefined;
const tslint = createStubTSLintConfiguration();
const ruleConversionResults = createEmptyConversionResults();

// Act
const simplifiedResults = await simplifyPackageRules(
dependencies,
eslint,
tslint,
ruleConversionResults,
true,
);

// Assert
expect(simplifiedResults).toEqual({
...ruleConversionResults,
converted: undefined,
extends: ["eslint-config-prettier", "eslint-config-prettier/@typescript-eslint"],
});
});

it("returns equivalent conversion results when there is an empty ESLint configuration and no TSLint extensions", async () => {
// Arrange
const dependencies = createStubDependencies();
const eslint = createStubESLintConfiguration([]);
Expand All @@ -60,7 +88,7 @@ describe("simplifyPackageRules", () => {
);

// Assert
expect(simplifiedResults).toBe(ruleConversionResults);
expect(simplifiedResults).toEqual(ruleConversionResults);
});

it("includes deduplicated rules and extension failures when the ESLint configuration extends", async () => {
Expand All @@ -76,13 +104,13 @@ describe("simplifyPackageRules", () => {
},
],
]);
const dependencies = {
const dependencies = createStubDependencies({
removeExtendsDuplicatedRules: () => deduplicatedRules,
retrieveExtendsValues: async () => ({
configurationErrors,
importedExtensions: [],
}),
};
});
const eslintExtends = ["extension-name"];
const eslint = createStubESLintConfiguration(eslintExtends);
const tslint = createStubTSLintConfiguration();
Expand All @@ -98,8 +126,9 @@ describe("simplifyPackageRules", () => {

// Assert
expect(simplifiedResults).toEqual({
...ruleConversionResults,
converted: deduplicatedRules,
extends: eslintExtends,
extends: [...eslintExtends],
failed: configurationErrors,
});
});
Expand Down
19 changes: 13 additions & 6 deletions src/creation/simplification/simplifyPackageRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,17 @@ import { TSLintConfiguration } from "../../input/findTSLintConfiguration";
import { RuleConversionResults } from "../../rules/convertRules";
import { uniqueFromSources } from "../../utils";
import { collectTSLintRulesets } from "./collectTSLintRulesets";
import { addPrettierExtensions } from "./prettier/addPrettierExtensions";
import { removeExtendsDuplicatedRules } from "./removeExtendsDuplicatedRules";
import { retrieveExtendsValues } from "./retrieveExtendsValues";

export type SimplifyPackageRulesDependencies = {
addPrettierExtensions: typeof addPrettierExtensions;
removeExtendsDuplicatedRules: typeof removeExtendsDuplicatedRules;
retrieveExtendsValues: SansDependencies<typeof retrieveExtendsValues>;
};

export type SimplifiedRuleConversionResults = Pick<
RuleConversionResults,
"converted" | "failed"
> & {
export type SimplifiedResultsConfiguration = RuleConversionResults & {
extends?: string[];
};

Expand All @@ -28,11 +27,18 @@ export const simplifyPackageRules = async (
dependencies: SimplifyPackageRulesDependencies,
eslint: Pick<OriginalConfigurations<ESLintConfiguration>, "full"> | undefined,
tslint: OriginalConfigurations<Pick<TSLintConfiguration, "extends">>,
ruleConversionResults: SimplifiedRuleConversionResults,
): Promise<SimplifiedRuleConversionResults> => {
ruleConversionResults: RuleConversionResults,
prettierRequested?: boolean,
): Promise<SimplifiedResultsConfiguration> => {
const extendedESLintRulesets = eslint?.full.extends ?? [];
const extendedTSLintRulesets = collectTSLintRulesets(tslint);
const allExtensions = uniqueFromSources(extendedESLintRulesets, extendedTSLintRulesets);

// 3a. If no output rules conflict with `eslint-config-prettier`, it's added in
if (await dependencies.addPrettierExtensions(ruleConversionResults, prettierRequested)) {
allExtensions.push("eslint-config-prettier", "eslint-config-prettier/@typescript-eslint");
}

if (allExtensions.length === 0) {
return ruleConversionResults;
}
Expand All @@ -47,6 +53,7 @@ export const simplifyPackageRules = async (
);

return {
...ruleConversionResults,
converted,
extends: allExtensions,
failed: [...ruleConversionResults.failed, ...configurationErrors],
Expand Down
Loading