diff --git a/src/converters/lintConfigs/rules/ruleConverters/ordered-imports.ts b/src/converters/lintConfigs/rules/ruleConverters/ordered-imports.ts index 39c56272..ba47e37e 100644 --- a/src/converters/lintConfigs/rules/ruleConverters/ordered-imports.ts +++ b/src/converters/lintConfigs/rules/ruleConverters/ordered-imports.ts @@ -1,21 +1,124 @@ import { RuleConverter } from "../ruleConverter"; -const unsupportedTSLintOptions = [ - "import-sources-order", - "module-source-path", - "named-imports-order", -]; - export const convertOrderedImports: RuleConverter = (tslintRule) => { - const notices = unsupportedTSLintOptions - .filter((option) => tslintRule.ruleArguments.includes(option)) - .map((option) => `Option "${option}" is not supported by ESLint.`); + const argument = { ...tslintRule.ruleArguments[0] }; + const notices: string[] = []; + + const patternOptions = { + nocomment: true, + dot: true, + }; + + const importOrderRule = { + alphabetize: { + caseInsensitive: true, + order: "asc", + }, + "newlines-between": "ignore", + groups: [ + ["builtin", "external", "internal", "unknown", "object", "type"], + "parent", + ["sibling", "index"], + ], + distinctGroup: false, + pathGroupsExcludedImportTypes: [], + pathGroups: [ + { + pattern: "./", + patternOptions, + group: "sibling", + position: "before", + }, + + { + pattern: ".", + patternOptions, + group: "sibling", + position: "before", + }, + { + pattern: "..", + patternOptions, + group: "parent", + position: "before", + }, + { + pattern: "../", + patternOptions, + group: "parent", + position: "before", + }, + ], + }; + + switch (argument["import-sources-order"]) { + case "case-insensitive": + case "case-insensitive-legacy": + importOrderRule.alphabetize.caseInsensitive = true; + importOrderRule.alphabetize.order = "asc"; + break; + case "lowercase-first": + importOrderRule.alphabetize.caseInsensitive = false; + importOrderRule.alphabetize.order = "asc"; + importOrderRule.pathGroups = importOrderRule.pathGroups.concat([ + { + pattern: "[a-z]*", + patternOptions, + group: "external", + position: "before", + }, + { + pattern: "../[a-z]*", + patternOptions, + group: "parent", + position: "before", + }, + { + pattern: "./[a-z]*", + patternOptions, + group: "sibling", + position: "before", + }, + ]); + break; + case "lowercase-last": + importOrderRule.alphabetize.caseInsensitive = false; + importOrderRule.alphabetize.order = "asc"; + break; + case "any": + importOrderRule.alphabetize.caseInsensitive = false; + importOrderRule.alphabetize.order = "ignore"; + break; + } + + if (argument["grouped-imports"] === true) { + importOrderRule["newlines-between"] = "always"; + } + + if ("groups" in argument) { + notices.push( + "Option 'groups' is too bespoke to be converted to ESLint plugin 'eslint-plugin-import'", + ); + } + + if ("named-imports-order" in argument) { + notices.push( + "Option 'named-imports-order' is not supported by ESLint plugin 'eslint-plugin-import'", + ); + } + + if (argument["module-source-path"] === "basename") { + notices.push( + "Option 'module-source-path' with a value of 'basename' is not supported by ESLint plugin 'eslint-plugin-import'. The behavior will fallback to 'full'", + ); + } return { plugins: ["eslint-plugin-import"], rules: [ { ...(notices.length !== 0 && { notices }), + ruleArguments: [importOrderRule], ruleName: "import/order", }, ], diff --git a/src/converters/lintConfigs/rules/ruleConverters/tests/ordered-imports.test.ts b/src/converters/lintConfigs/rules/ruleConverters/tests/ordered-imports.test.ts index 67868244..88e5c815 100644 --- a/src/converters/lintConfigs/rules/ruleConverters/tests/ordered-imports.test.ts +++ b/src/converters/lintConfigs/rules/ruleConverters/tests/ordered-imports.test.ts @@ -12,47 +12,1080 @@ describe("convertOrderedImports", () => { plugins: ["eslint-plugin-import"], rules: [ { + ruleArguments: [ + { + "newlines-between": "ignore", + alphabetize: { + caseInsensitive: true, + order: "asc", + }, + groups: [ + ["builtin", "external", "internal", "unknown", "object", "type"], + "parent", + ["sibling", "index"], + ], + pathGroupsExcludedImportTypes: [], + distinctGroup: false, + pathGroups: [ + { + pattern: "./", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + + { + pattern: ".", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: "..", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "../", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + ], + }, + ], + ruleName: "import/order", + }, + ], + }); + }); + + test("conversion with option import-sources-order as case-insensitive", () => { + const result = convertOrderedImports({ + ruleArguments: [ + { + "import-sources-order": "case-insensitive", + }, + ], + }); + + expect(result).toEqual({ + plugins: ["eslint-plugin-import"], + rules: [ + { + ruleArguments: [ + { + "newlines-between": "ignore", + alphabetize: { + caseInsensitive: true, + order: "asc", + }, + groups: [ + ["builtin", "external", "internal", "unknown", "object", "type"], + "parent", + ["sibling", "index"], + ], + pathGroupsExcludedImportTypes: [], + distinctGroup: false, + pathGroups: [ + { + pattern: "./", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + + { + pattern: ".", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: "..", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "../", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + ], + }, + ], + ruleName: "import/order", + }, + ], + }); + }); + + test("conversion with option import-sources-order as case-insensitive-legacy", () => { + const result = convertOrderedImports({ + ruleArguments: [ + { + "import-sources-order": "case-insensitive-legacy", + }, + ], + }); + + expect(result).toEqual({ + plugins: ["eslint-plugin-import"], + rules: [ + { + ruleArguments: [ + { + "newlines-between": "ignore", + alphabetize: { + caseInsensitive: true, + order: "asc", + }, + groups: [ + ["builtin", "external", "internal", "unknown", "object", "type"], + "parent", + ["sibling", "index"], + ], + pathGroupsExcludedImportTypes: [], + distinctGroup: false, + pathGroups: [ + { + pattern: "./", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + + { + pattern: ".", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: "..", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "../", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + ], + }, + ], + ruleName: "import/order", + }, + ], + }); + }); + + test("conversion with option import-sources-order as lowercase-first", () => { + const result = convertOrderedImports({ + ruleArguments: [{ "import-sources-order": "lowercase-first" }], + }); + + expect(result).toEqual({ + plugins: ["eslint-plugin-import"], + rules: [ + { + ruleArguments: [ + { + "newlines-between": "ignore", + alphabetize: { + caseInsensitive: false, + order: "asc", + }, + groups: [ + ["builtin", "external", "internal", "unknown", "object", "type"], + "parent", + ["sibling", "index"], + ], + pathGroupsExcludedImportTypes: [], + distinctGroup: false, + pathGroups: [ + { + pattern: "./", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: ".", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: "..", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "../", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "[a-z]*", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "external", + position: "before", + }, + { + pattern: "../[a-z]*", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "./[a-z]*", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + ], + }, + ], + ruleName: "import/order", + }, + ], + }); + }); + + test("conversion with option import-sources-order as lowercase-last", () => { + const result = convertOrderedImports({ + ruleArguments: [{ "import-sources-order": "lowercase-last" }], + }); + + expect(result).toEqual({ + plugins: ["eslint-plugin-import"], + rules: [ + { + ruleArguments: [ + { + "newlines-between": "ignore", + alphabetize: { + caseInsensitive: false, + order: "asc", + }, + groups: [ + ["builtin", "external", "internal", "unknown", "object", "type"], + "parent", + ["sibling", "index"], + ], + pathGroupsExcludedImportTypes: [], + distinctGroup: false, + pathGroups: [ + { + pattern: "./", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: ".", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: "..", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "../", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + ], + }, + ], + ruleName: "import/order", + }, + ], + }); + }); + + test("conversion with option import-sources-order as any", () => { + const result = convertOrderedImports({ + ruleArguments: [{ "import-sources-order": "any" }], + }); + + expect(result).toEqual({ + plugins: ["eslint-plugin-import"], + rules: [ + { + ruleArguments: [ + { + "newlines-between": "ignore", + alphabetize: { + caseInsensitive: false, + order: "ignore", + }, + groups: [ + ["builtin", "external", "internal", "unknown", "object", "type"], + "parent", + ["sibling", "index"], + ], + pathGroupsExcludedImportTypes: [], + distinctGroup: false, + pathGroups: [ + { + pattern: "./", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: ".", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: "..", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "../", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + ], + }, + ], + ruleName: "import/order", + }, + ], + }); + }); + + test("conversion with option import-sources-order as case-insensitive (with grouped-imports)", () => { + const result = convertOrderedImports({ + ruleArguments: [ + { + "import-sources-order": "case-insensitive", + "grouped-imports": true, + }, + ], + }); + + expect(result).toEqual({ + plugins: ["eslint-plugin-import"], + rules: [ + { + ruleArguments: [ + { + "newlines-between": "always", + alphabetize: { + caseInsensitive: true, + order: "asc", + }, + groups: [ + ["builtin", "external", "internal", "unknown", "object", "type"], + "parent", + ["sibling", "index"], + ], + pathGroupsExcludedImportTypes: [], + distinctGroup: false, + pathGroups: [ + { + pattern: "./", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + + { + pattern: ".", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: "..", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "../", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + ], + }, + ], + ruleName: "import/order", + }, + ], + }); + }); + + test("conversion with option import-sources-order as case-insensitive-legacy (with grouped-imports)", () => { + const result = convertOrderedImports({ + ruleArguments: [ + { + "import-sources-order": "case-insensitive-legacy", + "grouped-imports": true, + }, + ], + }); + + expect(result).toEqual({ + plugins: ["eslint-plugin-import"], + rules: [ + { + ruleArguments: [ + { + "newlines-between": "always", + alphabetize: { + caseInsensitive: true, + order: "asc", + }, + groups: [ + ["builtin", "external", "internal", "unknown", "object", "type"], + "parent", + ["sibling", "index"], + ], + pathGroupsExcludedImportTypes: [], + distinctGroup: false, + pathGroups: [ + { + pattern: "./", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + + { + pattern: ".", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: "..", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "../", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + ], + }, + ], + ruleName: "import/order", + }, + ], + }); + }); + + test("conversion with option import-sources-order as lowercase-first (with grouped-imports)", () => { + const result = convertOrderedImports({ + ruleArguments: [ + { + "import-sources-order": "lowercase-first", + "grouped-imports": true, + }, + ], + }); + + expect(result).toEqual({ + plugins: ["eslint-plugin-import"], + rules: [ + { + ruleArguments: [ + { + "newlines-between": "always", + alphabetize: { + caseInsensitive: false, + order: "asc", + }, + groups: [ + ["builtin", "external", "internal", "unknown", "object", "type"], + "parent", + ["sibling", "index"], + ], + pathGroupsExcludedImportTypes: [], + distinctGroup: false, + pathGroups: [ + { + pattern: "./", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: ".", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: "..", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "../", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "[a-z]*", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "external", + position: "before", + }, + { + pattern: "../[a-z]*", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "./[a-z]*", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + ], + }, + ], + ruleName: "import/order", + }, + ], + }); + }); + + test("conversion with option import-sources-order as lowercase-last (with grouped-imports)", () => { + const result = convertOrderedImports({ + ruleArguments: [ + { + "import-sources-order": "lowercase-last", + "grouped-imports": true, + }, + ], + }); + + expect(result).toEqual({ + plugins: ["eslint-plugin-import"], + rules: [ + { + ruleArguments: [ + { + "newlines-between": "always", + alphabetize: { + caseInsensitive: false, + order: "asc", + }, + groups: [ + ["builtin", "external", "internal", "unknown", "object", "type"], + "parent", + ["sibling", "index"], + ], + pathGroupsExcludedImportTypes: [], + distinctGroup: false, + pathGroups: [ + { + pattern: "./", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: ".", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: "..", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "../", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + ], + }, + ], ruleName: "import/order", }, ], }); }); - test("conversion with allow-declarations argument", () => { + test("conversion with option import-sources-order as any (with grouped-imports)", () => { const result = convertOrderedImports({ - ruleArguments: ["import-sources-order"], + ruleArguments: [ + { + "import-sources-order": "any", + "grouped-imports": true, + }, + ], + }); + + expect(result).toEqual({ + plugins: ["eslint-plugin-import"], + rules: [ + { + ruleArguments: [ + { + "newlines-between": "always", + alphabetize: { + caseInsensitive: false, + order: "ignore", + }, + groups: [ + ["builtin", "external", "internal", "unknown", "object", "type"], + "parent", + ["sibling", "index"], + ], + pathGroupsExcludedImportTypes: [], + distinctGroup: false, + pathGroups: [ + { + pattern: "./", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: ".", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: "..", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "../", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + ], + }, + ], + ruleName: "import/order", + }, + ], + }); + }); + + test("conversion with grouped-imports as true", () => { + const result = convertOrderedImports({ + ruleArguments: [ + { + "grouped-imports": true, + }, + ], + }); + + expect(result).toEqual({ + plugins: ["eslint-plugin-import"], + rules: [ + { + ruleArguments: [ + { + "newlines-between": "always", + alphabetize: { + caseInsensitive: true, + order: "asc", + }, + groups: [ + ["builtin", "external", "internal", "unknown", "object", "type"], + "parent", + ["sibling", "index"], + ], + pathGroupsExcludedImportTypes: [], + distinctGroup: false, + pathGroups: [ + { + pattern: "./", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: ".", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: "..", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "../", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + ], + }, + ], + ruleName: "import/order", + }, + ], + }); + }); + + test("fails with option groups", () => { + const result = convertOrderedImports({ + ruleArguments: [ + { + groups: [], + }, + ], }); expect(result).toEqual({ plugins: ["eslint-plugin-import"], rules: [ { - notices: ['Option "import-sources-order" is not supported by ESLint.'], + notices: [ + "Option 'groups' is too bespoke to be converted to ESLint plugin 'eslint-plugin-import'", + ], + ruleArguments: [ + { + "newlines-between": "ignore", + alphabetize: { + caseInsensitive: true, + order: "asc", + }, + groups: [ + ["builtin", "external", "internal", "unknown", "object", "type"], + "parent", + ["sibling", "index"], + ], + pathGroupsExcludedImportTypes: [], + distinctGroup: false, + pathGroups: [ + { + pattern: "./", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: ".", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: "..", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "../", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + ], + }, + ], ruleName: "import/order", }, ], }); }); - test("conversion with allow-declarations argument", () => { + test("fails with option named-imports-order", () => { const result = convertOrderedImports({ - ruleArguments: ["named-imports-order"], + ruleArguments: [ + { + "named-imports-order": "any", + }, + ], }); expect(result).toEqual({ plugins: ["eslint-plugin-import"], rules: [ { - notices: ['Option "named-imports-order" is not supported by ESLint.'], + notices: [ + "Option 'named-imports-order' is not supported by ESLint plugin 'eslint-plugin-import'", + ], + ruleArguments: [ + { + "newlines-between": "ignore", + alphabetize: { + caseInsensitive: true, + order: "asc", + }, + groups: [ + ["builtin", "external", "internal", "unknown", "object", "type"], + "parent", + ["sibling", "index"], + ], + pathGroupsExcludedImportTypes: [], + distinctGroup: false, + pathGroups: [ + { + pattern: "./", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: ".", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: "..", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "../", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + ], + }, + ], ruleName: "import/order", }, ], }); }); - test("conversion with unsupported arguments", () => { + test("fails with option module-source-path as 'basename'", () => { const result = convertOrderedImports({ - ruleArguments: ["import-sources-order", "named-imports-order", "module-source-path"], + ruleArguments: [ + { + "module-source-path": "basename", + }, + ], }); expect(result).toEqual({ @@ -60,9 +1093,61 @@ describe("convertOrderedImports", () => { rules: [ { notices: [ - 'Option "import-sources-order" is not supported by ESLint.', - 'Option "module-source-path" is not supported by ESLint.', - 'Option "named-imports-order" is not supported by ESLint.', + "Option 'module-source-path' with a value of 'basename' is not supported by ESLint plugin 'eslint-plugin-import'. The behavior will fallback to 'full'", + ], + ruleArguments: [ + { + "newlines-between": "ignore", + alphabetize: { + caseInsensitive: true, + order: "asc", + }, + groups: [ + ["builtin", "external", "internal", "unknown", "object", "type"], + "parent", + ["sibling", "index"], + ], + pathGroupsExcludedImportTypes: [], + distinctGroup: false, + pathGroups: [ + { + pattern: "./", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: ".", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "sibling", + position: "before", + }, + { + pattern: "..", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + { + pattern: "../", + patternOptions: { + nocomment: true, + dot: true, + }, + group: "parent", + position: "before", + }, + ], + }, ], ruleName: "import/order", },