diff --git a/docs/Architecture.md b/docs/Architecture.md index 4ec5bc349..7bd83e8c5 100644 --- a/docs/Architecture.md +++ b/docs/Architecture.md @@ -13,9 +13,10 @@ 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 +3. ESLint configurations are summarized 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 + - 3b. Any ESLint rules that are configured the same as an extended preset are trimmed +4. The summarized configuration is written to the output config file 5. Files to transform comments in have source text rewritten using the same rule conversion logic 6. A summary of the results is printed to the user's console diff --git a/src/cli/main.ts b/src/cli/main.ts index 0b0f4bbb2..9b3030afa 100644 --- a/src/cli/main.ts +++ b/src/cli/main.ts @@ -16,16 +16,16 @@ import { convertEditorConfig, ConvertEditorConfigDependencies, } from "../conversion/convertEditorConfig"; -import { addPrettierExtensions } from "../creation/simplification/prettier/addPrettierExtensions"; -import { removeExtendsDuplicatedRules } from "../creation/simplification/removeExtendsDuplicatedRules"; +import { addPrettierExtensions } from "../creation/summarization/prettier/addPrettierExtensions"; +import { removeExtendsDuplicatedRules } from "../creation/pruning/removeExtendsDuplicatedRules"; import { retrieveExtendsValues, RetrieveExtendsValuesDependencies, -} from "../creation/simplification/retrieveExtendsValues"; +} from "../creation/summarization/retrieveExtendsValues"; import { - simplifyPackageRules, - SimplifyPackageRulesDependencies, -} from "../creation/simplification/simplifyPackageRules"; + summarizePackageRules, + SummarizePackageRulesDependencies, +} from "../creation/summarization/summarizePackageRules"; import { writeConversionResults, WriteConversionResultsDependencies, @@ -138,7 +138,7 @@ const retrieveExtendsValuesDependencies: RetrieveExtendsValuesDependencies = { importer: boundImporter, }; -const simplifyPackageRulesDependencies: SimplifyPackageRulesDependencies = { +const summarizePackageRulesDependencies: SummarizePackageRulesDependencies = { addPrettierExtensions, removeExtendsDuplicatedRules, retrieveExtendsValues: bind(retrieveExtendsValues, retrieveExtendsValuesDependencies), @@ -175,7 +175,7 @@ const convertConfigDependencies: ConvertConfigDependencies = { logMissingPackages: bind(logMissingPackages, logMissingPackagesDependencies), reportCommentResults: bind(reportCommentResults, reportCommentResultsDependencies), reportConversionResults: bind(reportConversionResults, reportConversionResultsDependencies), - simplifyPackageRules: bind(simplifyPackageRules, simplifyPackageRulesDependencies), + summarizePackageRules: bind(summarizePackageRules, summarizePackageRulesDependencies), writeConversionResults: bind(writeConversionResults, writeConversionResultsDependencies), }; diff --git a/src/conversion/conversionResults.stubs.ts b/src/conversion/conversionResults.stubs.ts index fbcc05dd8..b669023c4 100644 --- a/src/conversion/conversionResults.stubs.ts +++ b/src/conversion/conversionResults.stubs.ts @@ -1,10 +1,12 @@ +import { SummarizedResultsConfiguration } from "../creation/summarization/types"; import { EditorSettingConversionResults } from "../editorSettings/convertEditorSettings"; -import { SimplifiedResultsConfiguration } from "../creation/simplification/simplifyPackageRules"; export const createEmptyConversionResults = ( - overrides: Partial = {}, -): SimplifiedResultsConfiguration => ({ + overrides: Partial = {}, +): SummarizedResultsConfiguration => ({ converted: new Map(), + extends: [], + extensionRules: new Map(), failed: [], missing: [], plugins: new Set(), diff --git a/src/conversion/convertConfig.test.ts b/src/conversion/convertConfig.test.ts index d674366a5..7e7945230 100644 --- a/src/conversion/convertConfig.test.ts +++ b/src/conversion/convertConfig.test.ts @@ -16,10 +16,11 @@ const createStubDependencies = ( }), reportCommentResults: jest.fn(), reportConversionResults: jest.fn(), - simplifyPackageRules: async (_configurations, data) => ({ + summarizePackageRules: async (_configurations, data) => ({ ...data, converted: new Map(), extends: [], + extensionRules: new Map(), failed: [], missing: [], plugins: new Set(), diff --git a/src/conversion/convertConfig.ts b/src/conversion/convertConfig.ts index 5b1bb2b74..472f55c5a 100644 --- a/src/conversion/convertConfig.ts +++ b/src/conversion/convertConfig.ts @@ -1,6 +1,6 @@ import { SansDependencies } from "../binding"; import { convertComments } from "../comments/convertComments"; -import { simplifyPackageRules } from "../creation/simplification/simplifyPackageRules"; +import { summarizePackageRules } from "../creation/summarization/summarizePackageRules"; import { writeConversionResults } from "../creation/writeConversionResults"; import { findOriginalConfigurations } from "../input/findOriginalConfigurations"; import { logMissingPackages } from "../reporting/packages/logMissingPackages"; @@ -16,7 +16,7 @@ export type ConvertConfigDependencies = { logMissingPackages: SansDependencies; reportCommentResults: SansDependencies; reportConversionResults: SansDependencies; - simplifyPackageRules: SansDependencies; + summarizePackageRules: SansDependencies; writeConversionResults: SansDependencies; }; @@ -39,18 +39,18 @@ export const convertConfig = async ( originalConfigurations.data.tslint.full.rules, ); - // 3. ESLint configurations are simplified based on extended ESLint and TSLint presets - const simplifiedConfiguration = await dependencies.simplifyPackageRules( + // 3. ESLint configurations are summarized based on extended ESLint and TSLint presets + const summarizedConfiguration = await dependencies.summarizePackageRules( originalConfigurations.data.eslint, originalConfigurations.data.tslint, ruleConversionResults, settings.prettier, ); - // 4. The simplified configuration is written to the output config file + // 4. The summarized configuration is written to the output config file const fileWriteError = await dependencies.writeConversionResults( settings.config, - simplifiedConfiguration, + summarizedConfiguration, originalConfigurations.data, ); if (fileWriteError !== undefined) { @@ -64,10 +64,10 @@ export const convertConfig = async ( const commentsResult = await dependencies.convertComments(settings.comments); // 6. A summary of the results is printed to the user's console - await dependencies.reportConversionResults(settings.config, simplifiedConfiguration); + await dependencies.reportConversionResults(settings.config, summarizedConfiguration); dependencies.reportCommentResults(commentsResult); await dependencies.logMissingPackages( - simplifiedConfiguration, + summarizedConfiguration, originalConfigurations.data.packages, ); diff --git a/src/creation/pruning/normalizeExtensions.test.ts b/src/creation/pruning/normalizeExtensions.test.ts new file mode 100644 index 000000000..93839ff8b --- /dev/null +++ b/src/creation/pruning/normalizeExtensions.test.ts @@ -0,0 +1,73 @@ +import { normalizeExtensions } from "./normalizeExtensions"; +import { ESLintConfigurationRuleValue } from "../../input/findESLintConfiguration"; + +const createStubExtension = (ruleName: string, ruleValue: ESLintConfigurationRuleValue) => { + return { + rules: { + [ruleName]: ruleValue, + }, + }; +}; + +describe("removeExtendsDuplicatedRules", () => { + it("ignores an empty extension", () => { + // Arrange + const extensions = [{}]; + + // Act + const results = normalizeExtensions(extensions); + + // Assert + expect(results).toEqual(new Map()); + }); + + it("overrides a rule's first value when a second extension contains it", () => { + // Arrange + const ruleName = "rule-a"; + const extensions = [ + createStubExtension(ruleName, "error"), + createStubExtension(ruleName, "warn"), + ]; + + // Act + const results = normalizeExtensions(extensions); + + // Assert + expect(results).toEqual( + new Map([ + [ + ruleName, + { + ruleArguments: [], + ruleName, + ruleSeverity: "warn", + }, + ], + ]), + ); + }); + + it("normalizes a configuration when an array", () => { + // Arrange + const ruleName = "rule-a"; + const ruleArgument = { value: true }; + const extensions = [createStubExtension(ruleName, ["error", ruleArgument])]; + + // Act + const results = normalizeExtensions(extensions); + + // Assert + expect(results).toEqual( + new Map([ + [ + ruleName, + { + ruleArguments: [ruleArgument], + ruleName, + ruleSeverity: "error", + }, + ], + ]), + ); + }); +}); diff --git a/src/creation/pruning/normalizeExtensions.ts b/src/creation/pruning/normalizeExtensions.ts new file mode 100644 index 000000000..f3a22b4f0 --- /dev/null +++ b/src/creation/pruning/normalizeExtensions.ts @@ -0,0 +1,41 @@ +import { + ESLintConfiguration, + ESLintConfigurationRuleValue, +} from "../../input/findESLintConfiguration"; +import { ESLintRuleOptionsWithArguments } from "../../rules/types"; +import { normalizeRawESLintRuleSeverity } from "./normalizeRawESLintRuleSeverity"; + +export const normalizeExtensions = (extensions: Partial[]) => { + const mergedRules = new Map(); + + for (const extension of extensions) { + if (extension.rules === undefined) { + continue; + } + + for (const ruleName in extension.rules) { + mergedRules.set(ruleName, formatRuleArguments(ruleName, extension.rules[ruleName])); + } + } + + return mergedRules; +}; + +const formatRuleArguments = ( + ruleName: string, + originalValue: ESLintConfigurationRuleValue, +): ESLintRuleOptionsWithArguments => { + if (originalValue instanceof Array) { + return { + ruleArguments: originalValue.slice(1), + ruleName, + ruleSeverity: normalizeRawESLintRuleSeverity(originalValue[0]), + }; + } + + return { + ruleArguments: [], + ruleName, + ruleSeverity: normalizeRawESLintRuleSeverity(originalValue), + }; +}; diff --git a/src/creation/pruning/normalizeRawESLintRuleSeverity.test.ts b/src/creation/pruning/normalizeRawESLintRuleSeverity.test.ts new file mode 100644 index 000000000..06c98798f --- /dev/null +++ b/src/creation/pruning/normalizeRawESLintRuleSeverity.test.ts @@ -0,0 +1,47 @@ +import { normalizeRawESLintRuleSeverity } from "./normalizeRawESLintRuleSeverity"; + +describe("normalizeRawESLintRuleSeverity", () => { + it("converts the severity to off when equal to 0", () => { + // Arrange + const rawSeverity = 0; + + // Act + const result = normalizeRawESLintRuleSeverity(rawSeverity); + + // Assert + expect(result).toEqual("off"); + }); + + it("converts the severity to warn when equal to 1", () => { + // Arrange + const rawSeverity = 1; + + // Act + const result = normalizeRawESLintRuleSeverity(rawSeverity); + + // Assert + expect(result).toEqual("warn"); + }); + + it("converts the severity to error when equal to 2", () => { + // Arrange + const rawSeverity = 2; + + // Act + const result = normalizeRawESLintRuleSeverity(rawSeverity); + + // Assert + expect(result).toEqual("error"); + }); + + it("returns the same severity when already a string", () => { + // Arrange + const rawSeverity = "error"; + + // Act + const result = normalizeRawESLintRuleSeverity(rawSeverity); + + // Assert + expect(result).toEqual(rawSeverity); + }); +}); diff --git a/src/creation/pruning/normalizeRawESLintRuleSeverity.ts b/src/creation/pruning/normalizeRawESLintRuleSeverity.ts new file mode 100644 index 000000000..a3063b5bd --- /dev/null +++ b/src/creation/pruning/normalizeRawESLintRuleSeverity.ts @@ -0,0 +1,19 @@ +import { ESLintRuleSeverity, RawESLintRuleSeverity } from "../../rules/types"; + +export const normalizeRawESLintRuleSeverity = ( + rawSeverity: RawESLintRuleSeverity, +): ESLintRuleSeverity => { + switch (rawSeverity) { + case 0: + return "off"; + + case 1: + return "warn"; + + case 2: + return "error"; + + default: + return rawSeverity; + } +}; diff --git a/src/creation/pruning/removeExtendsDuplicatedRules.test.ts b/src/creation/pruning/removeExtendsDuplicatedRules.test.ts new file mode 100644 index 000000000..37f2ae750 --- /dev/null +++ b/src/creation/pruning/removeExtendsDuplicatedRules.test.ts @@ -0,0 +1,300 @@ +import { ESLintRuleOptions, ESLintRuleOptionsWithArguments } from "../../rules/types"; +import { removeExtendsDuplicatedRules } from "./removeExtendsDuplicatedRules"; + +const prepareTestRule = ( + ruleOptions: Partial, + extensionConfiguration: Partial = {}, +) => { + const ruleName = "rule-a"; + const createSingleRuleMap = (overrides: Partial) => { + return new Map([ + [ + ruleName, + { + ruleArguments: [], + ruleName, + ruleSeverity: "off", + ...overrides, + }, + ], + ]); + }; + const allRules = createSingleRuleMap(ruleOptions); + const extensions = createSingleRuleMap(extensionConfiguration); + + return { ruleName, allRules, extensions }; +}; + +describe("removeExtendsDuplicatedRules", () => { + it("keeps a rule when it doesn't match an extended rule", () => { + // Arrange + const { allRules } = prepareTestRule({ + ruleName: "mismatched", + }); + + // Act + const { differentRules } = removeExtendsDuplicatedRules(allRules, new Map()); + + // Assert + expect(differentRules.size).toBe(1); + }); + + it("keeps a rule when its severity doesn't match its extended rule", () => { + // Arrange + const { allRules, extensions } = prepareTestRule( + { + ruleSeverity: "warn", + }, + { + ruleSeverity: "error", + }, + ); + + // Act + const { differentRules } = removeExtendsDuplicatedRules(allRules, extensions); + + // Assert + expect(differentRules.size).toBe(1); + }); + + it("keeps a rule when its arguments don't match its extended arguments", () => { + // Arrange + const { allRules, extensions } = prepareTestRule( + { + ruleSeverity: "warn", + }, + { + ruleSeverity: "error", + }, + ); + + // Act + const { differentRules } = removeExtendsDuplicatedRules(allRules, extensions); + + // Assert + expect(differentRules.size).toBe(1); + }); + + it("keeps a rule when its arguments don't match its extended arguments", () => { + // Arrange + const ruleArguments = [{ value: true }]; + const { allRules, extensions } = prepareTestRule( + { + ruleArguments, + ruleSeverity: "warn", + }, + { + ruleArguments, + ruleSeverity: "error", + }, + ); + + // Act + const { differentRules } = removeExtendsDuplicatedRules(allRules, extensions); + + // Assert + expect(differentRules.size).toBe(1); + }); + + it("keeps a rule when its arguments don't exist and the extended rule has arguments", () => { + // Arrange + const { allRules, extensions } = prepareTestRule( + { + ruleArguments: undefined, + ruleSeverity: "warn", + }, + { + ruleArguments: [{ value: true }], + ruleSeverity: "warn", + }, + ); + + // Act + const { differentRules } = removeExtendsDuplicatedRules(allRules, extensions); + + // Assert + expect(differentRules.size).toBe(1); + }); + + it("removes a rule when it matches its extended rule", () => { + // Arrange + const { allRules, extensions } = prepareTestRule( + { + ruleSeverity: "warn", + }, + { + ruleSeverity: "warn", + }, + ); + + // Act + const { differentRules } = removeExtendsDuplicatedRules(allRules, extensions); + + // Assert + expect(differentRules.size).toBe(0); + }); + + // it("keeps a rule when there are no rules in the extension", () => { + // // Arrange + // const { allRules } = prepareTestRule( + // { + // ruleName: "mismatched", + // }, + // 2, + // ); + + // // Act + // const { differentRules } = removeExtendsDuplicatedRules(allRules, [{}]); + + // // Assert + // expect(differentRules.size).toBe(1); + // }); + + // it("keeps a rule when it doesn't match any existing rule", () => { + // // Arrange + // const { allRules, extensions } = prepareTestRule( + // { + // ruleName: "mismatched", + // }, + // 2, + // ); + + // // Act + // const { differentRules } = removeExtendsDuplicatedRules(allRules, extensions); + + // // Assert + // expect(differentRules.size).toBe(1); + // }); + + // it("removes a rule when it matches an existing rule as numbers", () => { + // // Arrange + // const { allRules, extensions } = prepareTestRule( + // { + // ruleSeverity: "warn", + // }, + // 1, + // ); + + // // Act + // const { differentRules } = removeExtendsDuplicatedRules(allRules, extensions); + + // // Assert + // expect(differentRules.size).toBe(0); + // }); + + // it("removes a rule when it has no arguments and matches an extended rule with an empty arguments array", () => { + // // Arrange + // const { allRules, extensions } = prepareTestRule( + // { + // ruleArguments: undefined, + // ruleSeverity: "error", + // }, + // ["error"], + // ); + + // // Act + // const { differentRules } = removeExtendsDuplicatedRules(allRules, extensions); + + // // Assert + // expect(differentRules.size).toBe(0); + // }); + + // it("removes a rule when it has an empty arguments array and matches an extended rule with no arguments", () => { + // // Arrange + // const { allRules, extensions } = prepareTestRule( + // { + // ruleArguments: [], + // ruleSeverity: "error", + // }, + // ["error"], + // ); + + // // Act + // const { differentRules } = removeExtendsDuplicatedRules(allRules, extensions); + + // // Assert + // expect(differentRules.size).toBe(0); + // }); + + // it("keeps a rule when it conflicts with an existing rule as numbers", () => { + // // Arrange + // const { allRules, extensions } = prepareTestRule( + // { + // ruleSeverity: "warn", + // }, + // 2, + // ); + + // // Act + // const { differentRules } = removeExtendsDuplicatedRules(allRules, extensions); + + // // Assert + // expect(differentRules.size).toBe(1); + // }); + + // it("removes a rule when it matches an existing rule as strings", () => { + // // Arrange + // const { allRules, extensions } = prepareTestRule( + // { + // ruleSeverity: "warn", + // }, + // "warn", + // ); + + // // Act + // const { differentRules } = removeExtendsDuplicatedRules(allRules, extensions); + + // // Assert + // expect(differentRules.size).toBe(0); + // }); + + // it("keeps a rule when it conflicts with an existing rule as strings", () => { + // // Arrange + // const { allRules, extensions } = prepareTestRule( + // { + // ruleSeverity: "warn", + // }, + // "error", + // ); + + // // Act + // const { differentRules } = removeExtendsDuplicatedRules(allRules, extensions); + + // // Assert + // expect(differentRules.size).toBe(1); + // }); + + // it("removes a rule when it matches an existing rule as objects", () => { + // // Arrange + // const { allRules, extensions } = prepareTestRule( + // { + // ruleArguments: ["some-argument"], + // ruleSeverity: "warn", + // }, + // ["warn", "some-argument"], + // ); + + // // Act + // const { differentRules } = removeExtendsDuplicatedRules(allRules, extensions); + + // // Assert + // expect(differentRules.size).toBe(0); + // }); + + // it("keeps a rule when it conflicts with an existing rule as objects", () => { + // // Arrange + // const { allRules, extensions } = prepareTestRule( + // { + // ruleArguments: ["some-argument-one"], + // ruleSeverity: "warn", + // }, + // ["warn", "some-argument-modified"], + // ); + + // // Act + // const { differentRules } = removeExtendsDuplicatedRules(allRules, extensions); + + // // Assert + // expect(differentRules.size).toBe(1); + // }); +}); diff --git a/src/creation/pruning/removeExtendsDuplicatedRules.ts b/src/creation/pruning/removeExtendsDuplicatedRules.ts new file mode 100644 index 000000000..9e7618f74 --- /dev/null +++ b/src/creation/pruning/removeExtendsDuplicatedRules.ts @@ -0,0 +1,32 @@ +import { isDeepStrictEqual } from "util"; + +import { ESLintRuleOptions, ESLintRuleOptionsWithArguments } from "../../rules/types"; + +/** + * Finds only the ESLint rules configured differently than their (extended) configurations. + */ +export const removeExtendsDuplicatedRules = ( + userRules: Map, + extensionRules: Map, +) => { + const differentRules = new Map(); + + for (const [ruleName, value] of userRules) { + if (!ruleValuesAreTheSame(value, extensionRules.get(ruleName))) { + differentRules.set(ruleName, value); + } + } + + return { differentRules, extensionRules }; +}; + +const ruleValuesAreTheSame = ( + configurationValue: ESLintRuleOptions, + extensionValue: ESLintRuleOptionsWithArguments | undefined, +) => { + return ( + extensionValue !== undefined && + configurationValue.ruleSeverity === extensionValue.ruleSeverity && + isDeepStrictEqual(configurationValue.ruleArguments ?? [], extensionValue.ruleArguments) + ); +}; diff --git a/src/creation/simplification/removeExtendsDuplicatedRules.test.ts b/src/creation/simplification/removeExtendsDuplicatedRules.test.ts deleted file mode 100644 index 5c64be1d4..000000000 --- a/src/creation/simplification/removeExtendsDuplicatedRules.test.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { - ESLintConfiguration, - ESLintConfigurationRuleValue, -} from "../../input/findESLintConfiguration"; -import { ESLintRuleOptions } from "../../rules/types"; -import { removeExtendsDuplicatedRules } from "./removeExtendsDuplicatedRules"; - -const prepareTestRule = ( - ruleOptions: Partial, - extensionConfiguration: ESLintConfigurationRuleValue = 2, -) => { - const ruleName = "rule-a"; - const allRules = new Map([ - [ - ruleName, - { - ruleArguments: [], - ruleName, - ruleSeverity: "off", - ...ruleOptions, - }, - ], - ]); - const extensions: Partial[] = [ - { - rules: { - [ruleName]: extensionConfiguration, - }, - }, - ]; - - return { ruleName, allRules, extensions }; -}; - -describe("removeExtendsDuplicatedRules", () => { - it("keeps a rule when there are no rules in the extension", () => { - // Arrange - const { allRules } = prepareTestRule( - { - ruleName: "mismatched", - }, - 2, - ); - - // Act - const differentRules = removeExtendsDuplicatedRules(allRules, [{}]); - - // Assert - expect(differentRules.size).toBe(1); - }); - - it("keeps a rule when it doesn't match any existing rule", () => { - // Arrange - const { allRules, extensions } = prepareTestRule( - { - ruleName: "mismatched", - }, - 2, - ); - - // Act - const differentRules = removeExtendsDuplicatedRules(allRules, extensions); - - // Assert - expect(differentRules.size).toBe(1); - }); - - it("removes a rule when it matches an existing rule as numbers", () => { - // Arrange - const { allRules, extensions } = prepareTestRule( - { - ruleSeverity: "warn", - }, - 1, - ); - - // Act - const differentRules = removeExtendsDuplicatedRules(allRules, extensions); - - // Assert - expect(differentRules.size).toBe(0); - }); - - it("keeps a rule when it conflicts with an existing rule as numbers", () => { - // Arrange - const { allRules, extensions } = prepareTestRule( - { - ruleSeverity: "warn", - }, - 2, - ); - - // Act - const differentRules = removeExtendsDuplicatedRules(allRules, extensions); - - // Assert - expect(differentRules.size).toBe(1); - }); - - it("removes a rule when it matches an existing rule as strings", () => { - // Arrange - const { allRules, extensions } = prepareTestRule( - { - ruleSeverity: "warn", - }, - "warn", - ); - - // Act - const differentRules = removeExtendsDuplicatedRules(allRules, extensions); - - // Assert - expect(differentRules.size).toBe(0); - }); - - it("keeps a rule when it conflicts with an existing rule as strings", () => { - // Arrange - const { allRules, extensions } = prepareTestRule( - { - ruleSeverity: "warn", - }, - "error", - ); - - // Act - const differentRules = removeExtendsDuplicatedRules(allRules, extensions); - - // Assert - expect(differentRules.size).toBe(1); - }); - - it("removes a rule when it matches an existing rule as objects", () => { - // Arrange - const { allRules, extensions } = prepareTestRule( - { - ruleArguments: ["some-argument"], - ruleSeverity: "warn", - }, - ["warn", "some-argument"], - ); - - // Act - const differentRules = removeExtendsDuplicatedRules(allRules, extensions); - - // Assert - expect(differentRules.size).toBe(0); - }); - - it("keeps a rule when it conflicts with an existing rule as objects", () => { - // Arrange - const { allRules, extensions } = prepareTestRule( - { - ruleArguments: ["some-argument-one"], - ruleSeverity: "warn", - }, - ["warn", "some-argument-modified"], - ); - - // Act - const differentRules = removeExtendsDuplicatedRules(allRules, extensions); - - // Assert - expect(differentRules.size).toBe(1); - }); -}); diff --git a/src/creation/simplification/removeExtendsDuplicatedRules.ts b/src/creation/simplification/removeExtendsDuplicatedRules.ts deleted file mode 100644 index 2e1744699..000000000 --- a/src/creation/simplification/removeExtendsDuplicatedRules.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { isDeepStrictEqual } from "util"; - -import { - ESLintConfiguration, - ESLintConfigurationRuleValue, -} from "../../input/findESLintConfiguration"; -import { convertRawESLintRuleSeverity } from "../../rules/convertRuleSeverity"; -import { ESLintRuleOptions } from "../../rules/types"; - -export const removeExtendsDuplicatedRules = ( - allRules: Map, - extensions: Partial[], -): Map => { - const differentRules = new Map(); - const mergedExtensionRules = mergeExtensions(extensions); - - for (const [ruleName, value] of allRules) { - if (!ruleValuesAreTheSame(value, mergedExtensionRules.get(ruleName))) { - differentRules.set(ruleName, value); - } - } - - return differentRules; -}; - -const mergeExtensions = (extensions: Partial[]) => { - const mergedRules = new Map(); - - for (const extension of extensions) { - if (extension.rules === undefined) { - continue; - } - - for (const ruleName in extension.rules) { - mergedRules.set(ruleName, formatRuleArguments(ruleName, extension.rules[ruleName])); - } - } - - return mergedRules; -}; - -const formatRuleArguments = ( - ruleName: string, - originalValue: ESLintConfigurationRuleValue, -): ESLintRuleOptions => { - if (typeof originalValue === "number") { - return { - ruleArguments: [], - ruleName, - ruleSeverity: convertRawESLintRuleSeverity(originalValue), - }; - } - - if (typeof originalValue === "string") { - return { - ruleArguments: [], - ruleName, - ruleSeverity: originalValue, - }; - } - - return { - ruleArguments: originalValue.slice(1), - ruleName, - ruleSeverity: convertRawESLintRuleSeverity(originalValue[0]), - }; -}; - -const ruleValuesAreTheSame = ( - configurationValue: ESLintRuleOptions, - extensionValue: ESLintRuleOptions | undefined, -) => { - return ( - extensionValue !== undefined && - configurationValue.ruleSeverity === extensionValue.ruleSeverity && - isDeepStrictEqual( - { - ruleArguments: [], - ...configurationValue.ruleArguments, - }, - { - ruleArguments: [], - ...extensionValue.ruleArguments, - }, - ) - ); -}; diff --git a/src/creation/simplification/collectTSLintRulesets.test.ts b/src/creation/summarization/collectTSLintRulesets.test.ts similarity index 100% rename from src/creation/simplification/collectTSLintRulesets.test.ts rename to src/creation/summarization/collectTSLintRulesets.test.ts diff --git a/src/creation/simplification/collectTSLintRulesets.ts b/src/creation/summarization/collectTSLintRulesets.ts similarity index 100% rename from src/creation/simplification/collectTSLintRulesets.ts rename to src/creation/summarization/collectTSLintRulesets.ts diff --git a/src/creation/summarization/normalizeESLintRules.test.ts b/src/creation/summarization/normalizeESLintRules.test.ts new file mode 100644 index 000000000..ac793e4f0 --- /dev/null +++ b/src/creation/summarization/normalizeESLintRules.test.ts @@ -0,0 +1,65 @@ +import { ESLintConfigurationRules } from "../../input/findESLintConfiguration"; +import { normalizeESLintRules } from "./normalizeESLintRules"; + +const ruleName = "rule-a"; + +describe("normalizeESLintRules", () => { + it("returns an empty map when there are no user rules", () => { + // Arrange + const userRules = undefined; + + // Act + const result = normalizeESLintRules(userRules); + + // Assert + expect(result).toEqual(new Map()); + }); + + it("converts a rule when given as an array", () => { + // Arrange + const userRules: ESLintConfigurationRules = { + [ruleName]: ["error", {}], + }; + + // Act + const result = normalizeESLintRules(userRules); + + // Assert + expect(result).toEqual( + new Map([ + [ + ruleName, + { + ruleArguments: {}, + ruleName: "rule-a", + ruleSeverity: "error", + }, + ], + ]), + ); + }); + + it("converts a rule when given as a severity level", () => { + // Arrange + const userRules: ESLintConfigurationRules = { + [ruleName]: "error", + }; + + // Act + const result = normalizeESLintRules(userRules); + + // Assert + expect(result).toEqual( + new Map([ + [ + ruleName, + { + ruleArguments: {}, + ruleName: "rule-a", + ruleSeverity: "error", + }, + ], + ]), + ); + }); +}); diff --git a/src/creation/summarization/normalizeESLintRules.ts b/src/creation/summarization/normalizeESLintRules.ts new file mode 100644 index 000000000..7af8660c6 --- /dev/null +++ b/src/creation/summarization/normalizeESLintRules.ts @@ -0,0 +1,20 @@ +import { ESLintConfigurationRules } from "../../input/findESLintConfiguration"; +import { ESLintRuleOptions } from "../../rules/types"; +import { normalizeRawESLintRuleSeverity } from "../pruning/normalizeRawESLintRuleSeverity"; + +/** + * Normalizes raw ESLint rule configurations into our standardized output format. + */ +export const normalizeESLintRules = (userRules: ESLintConfigurationRules | undefined) => { + const output: Map = new Map(); + + for (const [ruleName, configuration] of Object.entries(userRules ?? {})) { + const [rawRuleSeverity, ruleArguments] = + configuration instanceof Array ? configuration : [configuration, {}]; + const ruleSeverity = normalizeRawESLintRuleSeverity(rawRuleSeverity); + + output.set(ruleName, { ruleArguments, ruleName, ruleSeverity }); + } + + return output; +}; diff --git a/src/creation/simplification/prettier/addPrettierExtensions.test.ts b/src/creation/summarization/prettier/addPrettierExtensions.test.ts similarity index 100% rename from src/creation/simplification/prettier/addPrettierExtensions.test.ts rename to src/creation/summarization/prettier/addPrettierExtensions.test.ts diff --git a/src/creation/simplification/prettier/addPrettierExtensions.ts b/src/creation/summarization/prettier/addPrettierExtensions.ts similarity index 100% rename from src/creation/simplification/prettier/addPrettierExtensions.ts rename to src/creation/summarization/prettier/addPrettierExtensions.ts diff --git a/src/creation/simplification/resolveExtensionNames.test.ts b/src/creation/summarization/resolveExtensionNames.test.ts similarity index 100% rename from src/creation/simplification/resolveExtensionNames.test.ts rename to src/creation/summarization/resolveExtensionNames.test.ts diff --git a/src/creation/simplification/resolveExtensionNames.ts b/src/creation/summarization/resolveExtensionNames.ts similarity index 100% rename from src/creation/simplification/resolveExtensionNames.ts rename to src/creation/summarization/resolveExtensionNames.ts diff --git a/src/creation/simplification/retrieveExtendsValues.test.ts b/src/creation/summarization/retrieveExtendsValues.test.ts similarity index 100% rename from src/creation/simplification/retrieveExtendsValues.test.ts rename to src/creation/summarization/retrieveExtendsValues.test.ts diff --git a/src/creation/simplification/retrieveExtendsValues.ts b/src/creation/summarization/retrieveExtendsValues.ts similarity index 100% rename from src/creation/simplification/retrieveExtendsValues.ts rename to src/creation/summarization/retrieveExtendsValues.ts diff --git a/src/creation/simplification/simplifyPackageRules.test.ts b/src/creation/summarization/summarizePackageRules.test.ts similarity index 70% rename from src/creation/simplification/simplifyPackageRules.test.ts rename to src/creation/summarization/summarizePackageRules.test.ts index 5bde76411..e86e8370e 100644 --- a/src/creation/simplification/simplifyPackageRules.test.ts +++ b/src/creation/summarization/summarizePackageRules.test.ts @@ -1,11 +1,14 @@ import { ConfigurationError } from "../../errors/configurationError"; -import { ESLintRuleOptions } from "../../rules/types"; +import { ESLintRuleOptionsWithArguments } from "../../rules/types"; import { createEmptyConversionResults } from "../../conversion/conversionResults.stubs"; -import { simplifyPackageRules, SimplifyPackageRulesDependencies } from "./simplifyPackageRules"; +import { summarizePackageRules, SummarizePackageRulesDependencies } from "./summarizePackageRules"; -const createStubDependencies = (overrides: Partial = {}) => ({ +const createStubDependencies = (overrides: Partial = {}) => ({ addPrettierExtensions: jest.fn(), - removeExtendsDuplicatedRules: jest.fn(), + removeExtendsDuplicatedRules: () => ({ + differentRules: new Map(), + extensionRules: new Map(), + }), retrieveExtendsValues: async () => ({ configurationErrors: [], importedExtensions: [], @@ -26,7 +29,7 @@ const createStubTSLintConfiguration = () => ({ raw: {}, }); -describe("simplifyPackageRules", () => { +describe("summarizePackageRules", () => { it("returns equivalent conversion results when there is no loaded ESLint configuration and no TSLint extensions", async () => { // Arrange const dependencies = createStubDependencies(); @@ -35,7 +38,7 @@ describe("simplifyPackageRules", () => { const ruleConversionResults = createEmptyConversionResults(); // Act - const simplifiedResults = await simplifyPackageRules( + const summarizedResults = await summarizePackageRules( dependencies, eslint, tslint, @@ -43,7 +46,7 @@ describe("simplifyPackageRules", () => { ); // Assert - expect(simplifiedResults).toEqual(ruleConversionResults); + expect(summarizedResults).toEqual(ruleConversionResults); }); it("adds Prettier extensions when addPrettierExtensions returns true", async () => { @@ -56,7 +59,7 @@ describe("simplifyPackageRules", () => { const ruleConversionResults = createEmptyConversionResults(); // Act - const simplifiedResults = await simplifyPackageRules( + const summarizedResults = await summarizePackageRules( dependencies, eslint, tslint, @@ -65,9 +68,9 @@ describe("simplifyPackageRules", () => { ); // Assert - expect(simplifiedResults).toEqual({ + expect(summarizedResults).toEqual({ ...ruleConversionResults, - converted: undefined, + converted: new Map(), extends: ["prettier", "prettier/@typescript-eslint"], }); }); @@ -80,7 +83,7 @@ describe("simplifyPackageRules", () => { const ruleConversionResults = createEmptyConversionResults(); // Act - const simplifiedResults = await simplifyPackageRules( + const summarizedResults = await summarizePackageRules( dependencies, eslint, tslint, @@ -88,13 +91,13 @@ describe("simplifyPackageRules", () => { ); // Assert - expect(simplifiedResults).toEqual(ruleConversionResults); + expect(summarizedResults).toEqual(ruleConversionResults); }); it("includes deduplicated rules and extension failures when the ESLint configuration extends", async () => { // Arrange const configurationErrors = [new ConfigurationError(new Error("oh no"), "darn")]; - const deduplicatedRules = new Map([ + const differentRules = new Map([ [ "rule-name", { @@ -104,8 +107,9 @@ describe("simplifyPackageRules", () => { }, ], ]); + const extensionRules = new Map(differentRules); const dependencies = createStubDependencies({ - removeExtendsDuplicatedRules: () => deduplicatedRules, + removeExtendsDuplicatedRules: () => ({ differentRules, extensionRules }), retrieveExtendsValues: async () => ({ configurationErrors, importedExtensions: [], @@ -117,7 +121,7 @@ describe("simplifyPackageRules", () => { const ruleConversionResults = createEmptyConversionResults(); // Act - const simplifiedResults = await simplifyPackageRules( + const summarizedResults = await summarizePackageRules( dependencies, eslint, tslint, @@ -125,9 +129,19 @@ describe("simplifyPackageRules", () => { ); // Assert - expect(simplifiedResults).toEqual({ + expect(summarizedResults).toEqual({ ...ruleConversionResults, - converted: deduplicatedRules, + extensionRules: new Map([ + [ + "rule-name", + { + ruleArguments: [], + ruleName: "rule-name", + ruleSeverity: "warn", + }, + ], + ]), + converted: differentRules, extends: [...eslintExtends], failed: configurationErrors, }); diff --git a/src/creation/simplification/simplifyPackageRules.ts b/src/creation/summarization/summarizePackageRules.ts similarity index 65% rename from src/creation/simplification/simplifyPackageRules.ts rename to src/creation/summarization/summarizePackageRules.ts index b7df6f39e..fd94473cc 100644 --- a/src/creation/simplification/simplifyPackageRules.ts +++ b/src/creation/summarization/summarizePackageRules.ts @@ -4,32 +4,31 @@ import { OriginalConfigurations } from "../../input/findOriginalConfigurations"; import { TSLintConfiguration } from "../../input/findTSLintConfiguration"; import { RuleConversionResults } from "../../rules/convertRules"; import { uniqueFromSources } from "../../utils"; +import { removeExtendsDuplicatedRules } from "../pruning/removeExtendsDuplicatedRules"; +import { normalizeExtensions } from "../pruning/normalizeExtensions"; import { collectTSLintRulesets } from "./collectTSLintRulesets"; import { addPrettierExtensions } from "./prettier/addPrettierExtensions"; -import { removeExtendsDuplicatedRules } from "./removeExtendsDuplicatedRules"; import { retrieveExtendsValues } from "./retrieveExtendsValues"; +import { SummarizedResultsConfiguration } from "./types"; +import { normalizeESLintRules } from "./normalizeESLintRules"; -export type SimplifyPackageRulesDependencies = { +export type SummarizePackageRulesDependencies = { addPrettierExtensions: typeof addPrettierExtensions; removeExtendsDuplicatedRules: typeof removeExtendsDuplicatedRules; retrieveExtendsValues: SansDependencies; }; -export type SimplifiedResultsConfiguration = RuleConversionResults & { - extends?: string[]; -}; - /** * Given an initial set of rule conversion results and original configurations, * determines which ESLint rulesets to extend from and removes redundant rule values. */ -export const simplifyPackageRules = async ( - dependencies: SimplifyPackageRulesDependencies, +export const summarizePackageRules = async ( + dependencies: SummarizePackageRulesDependencies, eslint: Pick, "full"> | undefined, tslint: OriginalConfigurations>, ruleConversionResults: RuleConversionResults, prettierRequested?: boolean, -): Promise => { +): Promise => { const extendedESLintRulesets = eslint?.full.extends ?? []; const extendedTSLintRulesets = collectTSLintRulesets(tslint); const allExtensions = uniqueFromSources(extendedESLintRulesets, extendedTSLintRulesets); @@ -40,22 +39,31 @@ export const simplifyPackageRules = async ( } if (allExtensions.length === 0) { - return ruleConversionResults; + return { + ...ruleConversionResults, + extends: [], + extensionRules: new Map(), + }; } + // 3b. Any ESLint rules that are configured the same as an extended preset are trimmed const { configurationErrors, importedExtensions } = await dependencies.retrieveExtendsValues( uniqueFromSources(extendedESLintRulesets, extendedTSLintRulesets), ); - - const converted = dependencies.removeExtendsDuplicatedRules( - ruleConversionResults.converted, - importedExtensions, + const extensionRules = normalizeExtensions(importedExtensions); + const deduplicated = dependencies.removeExtendsDuplicatedRules( + new Map([ + ...Array.from(normalizeESLintRules(eslint?.full.rules)), + ...Array.from(ruleConversionResults.converted), + ]), + extensionRules, ); return { ...ruleConversionResults, - converted, + converted: deduplicated.differentRules, extends: uniqueFromSources(allExtensions), + extensionRules: deduplicated.extensionRules, failed: [...ruleConversionResults.failed, ...configurationErrors], }; }; diff --git a/src/creation/summarization/types.ts b/src/creation/summarization/types.ts new file mode 100644 index 000000000..250ae65af --- /dev/null +++ b/src/creation/summarization/types.ts @@ -0,0 +1,7 @@ +import { RuleConversionResults } from "../../rules/convertRules"; +import { ESLintRuleOptions } from "../../rules/types"; + +export type SummarizedResultsConfiguration = RuleConversionResults & { + extends: string[]; + extensionRules: Map; +}; diff --git a/src/creation/writeConversionResults.test.ts b/src/creation/writeConversionResults.test.ts index 95c66ff7f..d78c66e78 100644 --- a/src/creation/writeConversionResults.test.ts +++ b/src/creation/writeConversionResults.test.ts @@ -1,11 +1,11 @@ import { createEmptyConversionResults } from "../conversion/conversionResults.stubs"; import { AllOriginalConfigurations } from "../input/findOriginalConfigurations"; import { formatJsonOutput } from "./formatting/formatters/formatJsonOutput"; -import { SimplifiedResultsConfiguration } from "./simplification/simplifyPackageRules"; +import { SummarizedResultsConfiguration } from "./summarization/types"; import { writeConversionResults } from "./writeConversionResults"; const createStubOriginalConfigurations = ( - overrides: Partial = {}, + overrides: Partial = {}, ) => ({ tslint: { full: { diff --git a/src/creation/writeConversionResults.ts b/src/creation/writeConversionResults.ts index cc379215b..d1c1c23a8 100644 --- a/src/creation/writeConversionResults.ts +++ b/src/creation/writeConversionResults.ts @@ -3,7 +3,7 @@ import { AllOriginalConfigurations } from "../input/findOriginalConfigurations"; import { createEnv } from "./eslint/createEnv"; import { formatConvertedRules } from "./formatConvertedRules"; import { formatOutput } from "./formatting/formatOutput"; -import { SimplifiedResultsConfiguration } from "./simplification/simplifyPackageRules"; +import { SummarizedResultsConfiguration } from "./summarization/types"; export type WriteConversionResultsDependencies = { fileSystem: Pick; @@ -12,13 +12,13 @@ export type WriteConversionResultsDependencies = { export const writeConversionResults = async ( dependencies: WriteConversionResultsDependencies, outputPath: string, - ruleConversionResults: SimplifiedResultsConfiguration, + summarizedResults: SummarizedResultsConfiguration, originalConfigurations: AllOriginalConfigurations, ) => { const plugins = ["@typescript-eslint"]; const { eslint, tslint } = originalConfigurations; - if (ruleConversionResults.missing.length !== 0) { + if (summarizedResults.missing.length !== 0) { plugins.push("@typescript-eslint/tslint"); } @@ -26,7 +26,7 @@ export const writeConversionResults = async ( ...eslint?.full, env: createEnv(originalConfigurations), ...(eslint && { globals: eslint.raw.globals }), - ...(ruleConversionResults.extends && { extends: ruleConversionResults.extends }), + ...(summarizedResults.extends?.length !== 0 && { extends: summarizedResults.extends }), parser: "@typescript-eslint/parser", parserOptions: { project: "tsconfig.json", @@ -34,8 +34,8 @@ export const writeConversionResults = async ( }, plugins, rules: { - ...eslint?.full.rules, - ...formatConvertedRules(ruleConversionResults, tslint.full), + // ...trimESLintRules(eslint?.full.rules, summarizedResults.extensionRules), + ...formatConvertedRules(summarizedResults, tslint.full), }, }; diff --git a/src/input/findESLintConfiguration.ts b/src/input/findESLintConfiguration.ts index f066520cf..0442b07a8 100644 --- a/src/input/findESLintConfiguration.ts +++ b/src/input/findESLintConfiguration.ts @@ -1,6 +1,6 @@ import { Exec } from "../adapters/exec"; import { SansDependencies } from "../binding"; -import { ESLintRuleSeverity } from "../rules/types"; +import { RawESLintRuleSeverity } from "../rules/types"; import { TSLintToESLintSettings } from "../types"; import { uniqueFromSources } from "../utils"; import { findRawConfiguration } from "./findRawConfiguration"; @@ -20,11 +20,9 @@ export type ESLintConfigurationRules = { }; export type ESLintConfigurationRuleValue = - | 0 - | 1 - | 2 - | ESLintRuleSeverity - | [ESLintRuleSeverity, any]; + | RawESLintRuleSeverity + | [RawESLintRuleSeverity] + | [RawESLintRuleSeverity, any]; const defaultESLintConfiguration = { env: {}, diff --git a/src/reporting/packages/logMissingPackages.test.ts b/src/reporting/packages/logMissingPackages.test.ts index 7396d2570..670c28cd8 100644 --- a/src/reporting/packages/logMissingPackages.test.ts +++ b/src/reporting/packages/logMissingPackages.test.ts @@ -50,24 +50,6 @@ describe("logMissingPackages", () => { ); }); - it("does not include eslint-config-prettier when there are no extensions", async () => { - // Arrange - const { choosePackageManager, logger } = createStubDependencies(); - const ruleConversionResults = createEmptyConversionResults({ - extends: undefined, - }); - - // Act - await logMissingPackages({ choosePackageManager, logger }, ruleConversionResults); - - // Assert - expectEqualWrites( - logger.stdout.write, - `⚡ 3 new packages are required for this ESLint configuration. ⚡`, - ` npm install @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --save-dev`, - ); - }); - it("does not include eslint-config-prettier when extensions don't include eslint-config-prettier", async () => { // Arrange const { choosePackageManager, logger } = createStubDependencies(); diff --git a/src/reporting/packages/logMissingPackages.ts b/src/reporting/packages/logMissingPackages.ts index 8a662e6a1..38b93e0ae 100644 --- a/src/reporting/packages/logMissingPackages.ts +++ b/src/reporting/packages/logMissingPackages.ts @@ -3,7 +3,7 @@ import { EOL } from "os"; import { Logger } from "../../adapters/logger"; import { SansDependencies } from "../../binding"; -import { SimplifiedResultsConfiguration } from "../../creation/simplification/simplifyPackageRules"; +import { SummarizedResultsConfiguration } from "../../creation/summarization/types"; import { PackagesConfiguration } from "../../input/findPackagesConfiguration"; import { isTruthy } from "../../utils"; import { installationMessages } from "../packages/packageManagers"; @@ -16,7 +16,7 @@ export type LogMissingPackagesDependencies = { export const logMissingPackages = async ( dependencies: LogMissingPackagesDependencies, - ruleConversionResults: Pick, + ruleConversionResults: Pick, packageConfiguration?: PackagesConfiguration, ) => { const packageManager = await dependencies.choosePackageManager(); @@ -29,7 +29,7 @@ export const logMissingPackages = async ( const requiredPackageNames = [ "@typescript-eslint/eslint-plugin", "@typescript-eslint/parser", - ruleConversionResults.extends?.join("").includes("prettier") && "eslint-config-prettier", + ruleConversionResults.extends.join("").includes("prettier") && "eslint-config-prettier", ruleConversionResults.missing.length !== 0 && "@typescript-eslint/eslint-plugin-tslint", "eslint", ...Array.from(ruleConversionResults.plugins), diff --git a/src/reporting/reportConversionResults.test.ts b/src/reporting/reportConversionResults.test.ts index 75c6da81f..92ccf77a9 100644 --- a/src/reporting/reportConversionResults.test.ts +++ b/src/reporting/reportConversionResults.test.ts @@ -225,26 +225,7 @@ describe("reportConversionResults", () => { ); }); - it("logs a Prettier recommendation when there are no extensions", async () => { - // Arrange - const logger = createStubLogger(); - const conversionResults = createEmptyConversionResults({ - extends: undefined, - }); - - // Act - await reportConversionResults({ logger }, ".eslintrc.js", conversionResults); - - // Assert - expectEqualWrites( - logger.stdout.write, - `☠ Prettier plugins are missing from your configuration. ☠`, - ` We highly recommend running tslint-to-eslint-config --prettier to disable formatting ESLint rules.`, - ` See https://github.com/typescript-eslint/tslint-to-eslint-config/blob/master/docs/FAQs.md#should-i-use-prettier.`, - ); - }); - - it("logs a Prettier recommendation when extends don't include eslint-config-prettier", async () => { + it("logs a Prettier recommendation when extends doesn't include eslint-config-prettier", async () => { // Arrange const logger = createStubLogger(); const conversionResults = createEmptyConversionResults({ diff --git a/src/reporting/reportConversionResults.ts b/src/reporting/reportConversionResults.ts index d3949eb77..29926dc19 100644 --- a/src/reporting/reportConversionResults.ts +++ b/src/reporting/reportConversionResults.ts @@ -2,7 +2,7 @@ import chalk from "chalk"; import { EOL } from "os"; import { Logger } from "../adapters/logger"; -import { SimplifiedResultsConfiguration } from "../creation/simplification/simplifyPackageRules"; +import { SummarizedResultsConfiguration } from "../creation/summarization/types"; import { ESLintRuleOptions, TSLintRuleOptions } from "../rules/types"; import { logFailedConversions, @@ -17,7 +17,7 @@ export type ReportConversionResultsDependencies = { export const reportConversionResults = async ( dependencies: ReportConversionResultsDependencies, outputPath: string, - ruleConversionResults: SimplifiedResultsConfiguration, + ruleConversionResults: SummarizedResultsConfiguration, ) => { if (ruleConversionResults.converted.size !== 0) { logSuccessfulConversions("rule", ruleConversionResults.converted, dependencies.logger); @@ -42,7 +42,7 @@ export const reportConversionResults = async ( ); } - if (!ruleConversionResults.extends?.join("").includes("prettier")) { + if (!ruleConversionResults.extends.join("").includes("prettier")) { logPrettierExtension(dependencies.logger); } }; diff --git a/src/rules/convertRuleSeverity.test.ts b/src/rules/convertRuleSeverity.test.ts deleted file mode 100644 index 2297e7bc8..000000000 --- a/src/rules/convertRuleSeverity.test.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { convertTSLintRuleSeverity, convertRawESLintRuleSeverity } from "./convertRuleSeverity"; - -describe("convertRuleSeverity", () => { - it("returns error when the severity is error", () => { - // Arrange - const tslintSeverity = "error"; - - // Act - const eslintSeverity = convertTSLintRuleSeverity(tslintSeverity); - - // Assert - expect(eslintSeverity).toEqual("error"); - }); - - it("returns off when the severity is off", () => { - // Arrange - const tslintSeverity = "off"; - - // Act - const eslintSeverity = convertTSLintRuleSeverity(tslintSeverity); - - // Assert - expect(eslintSeverity).toEqual("off"); - }); - - it("returns warn when the severity is warning", () => { - // Arrange - const tslintSeverity = "warning"; - - // Act - const eslintSeverity = convertTSLintRuleSeverity(tslintSeverity); - - // Assert - expect(eslintSeverity).toEqual("warn"); - }); -}); - -describe("convertRawESLintRuleSeverity", () => { - it("returns off when the severity is 0", () => { - // Arrange - const rawSeverity = 0; - - // Act - const converted = convertRawESLintRuleSeverity(rawSeverity); - - // Assert - expect(converted).toEqual("off"); - }); - - it("returns warn when the severity is 1", () => { - // Arrange - const rawSeverity = 1; - - // Act - const converted = convertRawESLintRuleSeverity(rawSeverity); - - // Assert - expect(converted).toEqual("warn"); - }); - - it("returns error when the severity is 2", () => { - // Arrange - const rawSeverity = 2; - - // Act - const converted = convertRawESLintRuleSeverity(rawSeverity); - - // Assert - expect(converted).toEqual("error"); - }); - - it("returns the original severity when it's a string", () => { - // Arrange - const rawSeverity = "warn"; - - // Act - const converted = convertRawESLintRuleSeverity(rawSeverity); - - // Assert - expect(converted).toEqual("warn"); - }); -}); diff --git a/src/rules/convertRuleSeverity.ts b/src/rules/convertRuleSeverity.ts deleted file mode 100644 index 861a1eab4..000000000 --- a/src/rules/convertRuleSeverity.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ESLintRuleSeverity, TSLintRuleSeverity } from "./types"; - -/** - * Converts a TSLint rule severity string to the ESLint equivalent. - */ -export const convertTSLintRuleSeverity = ( - tslintSeverity: TSLintRuleSeverity, -): ESLintRuleSeverity => { - return tslintSeverity === "warning" ? "warn" : tslintSeverity; -}; - -export const convertRawESLintRuleSeverity = ( - rawSeverity: 0 | 1 | 2 | ESLintRuleSeverity, -): ESLintRuleSeverity => { - switch (rawSeverity) { - case 0: - return "off"; - - case 1: - return "warn"; - - case 2: - return "error"; - - default: - return rawSeverity; - } -}; diff --git a/src/rules/convertRules.ts b/src/rules/convertRules.ts index 0440bfcf6..e4a77816c 100644 --- a/src/rules/convertRules.ts +++ b/src/rules/convertRules.ts @@ -3,8 +3,8 @@ import { ErrorSummary } from "../errors/errorSummary"; import { TSLintConfigurationRules } from "../input/findTSLintConfiguration"; import { RuleConverter } from "./converter"; import { convertRule } from "./convertRule"; -import { convertTSLintRuleSeverity } from "./convertRuleSeverity"; -import { formatRawTslintRule } from "./formatRawTslintRule"; +import { convertTSLintRuleSeverity } from "./formats/convertTSLintRuleSeverity"; +import { formatRawTslintRule } from "./formats/formatRawTslintRule"; import { RuleMerger } from "./merger"; import { TSLintRuleOptions, ESLintRuleOptions } from "./types"; diff --git a/src/rules/formatRawTslintRule.test.ts b/src/rules/formatRawTslintRule.test.ts index 2dd8f06d5..cc85a81ad 100644 --- a/src/rules/formatRawTslintRule.test.ts +++ b/src/rules/formatRawTslintRule.test.ts @@ -1,4 +1,4 @@ -import { formatRawTslintRule } from "./formatRawTslintRule"; +import { formatRawTslintRule } from "./formats/formatRawTslintRule"; describe("formatRawTslintRule", () => { it("supplies default values when none are provided", () => { diff --git a/src/rules/formats/convertTSLintRuleSeverity.test.ts b/src/rules/formats/convertTSLintRuleSeverity.test.ts new file mode 100644 index 000000000..5f0bca3e8 --- /dev/null +++ b/src/rules/formats/convertTSLintRuleSeverity.test.ts @@ -0,0 +1,36 @@ +import { convertTSLintRuleSeverity } from "./convertTSLintRuleSeverity"; + +describe("convertRuleSeverity", () => { + it("returns error when the severity is error", () => { + // Arrange + const tslintSeverity = "error"; + + // Act + const eslintSeverity = convertTSLintRuleSeverity(tslintSeverity); + + // Assert + expect(eslintSeverity).toEqual("error"); + }); + + it("returns off when the severity is off", () => { + // Arrange + const tslintSeverity = "off"; + + // Act + const eslintSeverity = convertTSLintRuleSeverity(tslintSeverity); + + // Assert + expect(eslintSeverity).toEqual("off"); + }); + + it("returns warn when the severity is warning", () => { + // Arrange + const tslintSeverity = "warning"; + + // Act + const eslintSeverity = convertTSLintRuleSeverity(tslintSeverity); + + // Assert + expect(eslintSeverity).toEqual("warn"); + }); +}); diff --git a/src/rules/formats/convertTSLintRuleSeverity.ts b/src/rules/formats/convertTSLintRuleSeverity.ts new file mode 100644 index 000000000..f13856402 --- /dev/null +++ b/src/rules/formats/convertTSLintRuleSeverity.ts @@ -0,0 +1,10 @@ +import { ESLintRuleSeverity, TSLintRuleSeverity } from "../types"; + +/** + * Converts a TSLint rule severity string to the ESLint equivalent. + */ +export const convertTSLintRuleSeverity = ( + tslintSeverity: TSLintRuleSeverity, +): ESLintRuleSeverity => { + return tslintSeverity === "warning" ? "warn" : tslintSeverity; +}; diff --git a/src/rules/formatRawTslintRule.ts b/src/rules/formats/formatRawTslintRule.ts similarity index 81% rename from src/rules/formatRawTslintRule.ts rename to src/rules/formats/formatRawTslintRule.ts index a79211707..c4c7f0f92 100644 --- a/src/rules/formatRawTslintRule.ts +++ b/src/rules/formats/formatRawTslintRule.ts @@ -1,4 +1,4 @@ -import { TSLintRuleOptions } from "./types"; +import { TSLintRuleOptions } from "../types"; export const formatRawTslintRule = ( ruleName: string, diff --git a/src/rules/types.ts b/src/rules/types.ts index 791d59472..e0016d435 100644 --- a/src/rules/types.ts +++ b/src/rules/types.ts @@ -8,9 +8,15 @@ export type TSLintRuleOptions = { export type ESLintRuleSeverity = "warn" | "error" | "off"; +export type RawESLintRuleSeverity = ESLintRuleSeverity | 0 | 1 | 2; + export type ESLintRuleOptions = { notices?: any[]; ruleArguments?: any[]; ruleName: string; ruleSeverity: ESLintRuleSeverity; }; + +export type ESLintRuleOptionsWithArguments = ESLintRuleOptions & { + ruleArguments: any[]; +};