From 0d91e7d28e5eba79a6032165cdef5d4549d26462 Mon Sep 17 00:00:00 2001 From: Remco Haszing Date: Fri, 4 Jan 2019 21:49:02 +0100 Subject: [PATCH] Update: Add sort-imports ignoreDeclarationSort (fixes #11019) (#11040) * Update: Add sort-imports ignoreDeclarationSort (fixes #11019) This allows users to enforce sorting import members, without having to enforce sorting of import declarations. * Docs: fix typo in documentation for sort-imports --- docs/rules/sort-imports.md | 30 +++++++++++++ lib/rules/sort-imports.js | 80 ++++++++++++++++++--------------- tests/lib/rules/sort-imports.js | 23 ++++++++++ 3 files changed, 96 insertions(+), 37 deletions(-) diff --git a/docs/rules/sort-imports.md b/docs/rules/sort-imports.md index d375279384e..d885c9c1c4a 100644 --- a/docs/rules/sort-imports.md +++ b/docs/rules/sort-imports.md @@ -34,6 +34,7 @@ The `--fix` option on the command line automatically fixes some problems reporte This rule accepts an object with its properties as * `ignoreCase` (default: `false`) +* `ignoreDeclarationSort` (default: `false`) * `ignoreMemberSort` (default: `false`) * `memberSyntaxSortOrder` (default: `["none", "all", "multiple", "single"]`); all 4 items must be present in the array, but you can change the order: * `none` = import module without exported bindings. @@ -47,6 +48,7 @@ Default option settings are: { "sort-imports": ["error", { "ignoreCase": false, + "ignoreDeclarationSort": false, "ignoreMemberSort": false, "memberSyntaxSortOrder": ["none", "all", "multiple", "single"] }] @@ -136,6 +138,34 @@ import c from 'baz.js'; Default is `false`. +### `ignoreDeclarationSort` + +Ignores the sorting of import declaration statements. + +Examples of **incorrect** code for this rule with the default `{ "ignoreDeclarationSort": false }` option: + +```js +/*eslint sort-imports: ["error", { "ignoreDeclarationSort": false }]*/ +import 'foo.js' +import 'bar.js' +``` + +Examples of **correct** code for this rule with the `{ "ignoreDeclarationSort": true }` option: + +```js +/*eslint sort-imports: ["error", { "ignoreDeclarationSort": true }]*/ +import 'foo.js' +import 'bar.js' +``` + +```js +/*eslint sort-imports: ["error", { "ignoreDeclarationSort": true }]*/ +import 'bar.js' +import 'foo.js' +``` + +Default is `false`. + ### `ignoreMemberSort` Ignores the member sorting within a `multiple` member import declaration. diff --git a/lib/rules/sort-imports.js b/lib/rules/sort-imports.js index 76997cc73d8..1c0d134046d 100644 --- a/lib/rules/sort-imports.js +++ b/lib/rules/sort-imports.js @@ -36,6 +36,9 @@ module.exports = { minItems: 4, maxItems: 4 }, + ignoreDeclarationSort: { + type: "boolean" + }, ignoreMemberSort: { type: "boolean" } @@ -51,6 +54,7 @@ module.exports = { const configuration = context.options[0] || {}, ignoreCase = configuration.ignoreCase || false, + ignoreDeclarationSort = configuration.ignoreDeclarationSort || false, ignoreMemberSort = configuration.ignoreMemberSort || false, memberSyntaxSortOrder = configuration.memberSyntaxSortOrder || ["none", "all", "multiple", "single"], sourceCode = context.getSourceCode(); @@ -105,44 +109,48 @@ module.exports = { return { ImportDeclaration(node) { - if (previousDeclaration) { - const currentMemberSyntaxGroupIndex = getMemberParameterGroupIndex(node), - previousMemberSyntaxGroupIndex = getMemberParameterGroupIndex(previousDeclaration); - let currentLocalMemberName = getFirstLocalMemberName(node), - previousLocalMemberName = getFirstLocalMemberName(previousDeclaration); - - if (ignoreCase) { - previousLocalMemberName = previousLocalMemberName && previousLocalMemberName.toLowerCase(); - currentLocalMemberName = currentLocalMemberName && currentLocalMemberName.toLowerCase(); - } - - /* - * When the current declaration uses a different member syntax, - * then check if the ordering is correct. - * Otherwise, make a default string compare (like rule sort-vars to be consistent) of the first used local member name. - */ - if (currentMemberSyntaxGroupIndex !== previousMemberSyntaxGroupIndex) { - if (currentMemberSyntaxGroupIndex < previousMemberSyntaxGroupIndex) { - context.report({ - node, - message: "Expected '{{syntaxA}}' syntax before '{{syntaxB}}' syntax.", - data: { - syntaxA: memberSyntaxSortOrder[currentMemberSyntaxGroupIndex], - syntaxB: memberSyntaxSortOrder[previousMemberSyntaxGroupIndex] - } - }); + if (!ignoreDeclarationSort) { + if (previousDeclaration) { + const currentMemberSyntaxGroupIndex = getMemberParameterGroupIndex(node), + previousMemberSyntaxGroupIndex = getMemberParameterGroupIndex(previousDeclaration); + let currentLocalMemberName = getFirstLocalMemberName(node), + previousLocalMemberName = getFirstLocalMemberName(previousDeclaration); + + if (ignoreCase) { + previousLocalMemberName = previousLocalMemberName && previousLocalMemberName.toLowerCase(); + currentLocalMemberName = currentLocalMemberName && currentLocalMemberName.toLowerCase(); } - } else { - if (previousLocalMemberName && - currentLocalMemberName && - currentLocalMemberName < previousLocalMemberName - ) { - context.report({ - node, - message: "Imports should be sorted alphabetically." - }); + + /* + * When the current declaration uses a different member syntax, + * then check if the ordering is correct. + * Otherwise, make a default string compare (like rule sort-vars to be consistent) of the first used local member name. + */ + if (currentMemberSyntaxGroupIndex !== previousMemberSyntaxGroupIndex) { + if (currentMemberSyntaxGroupIndex < previousMemberSyntaxGroupIndex) { + context.report({ + node, + message: "Expected '{{syntaxA}}' syntax before '{{syntaxB}}' syntax.", + data: { + syntaxA: memberSyntaxSortOrder[currentMemberSyntaxGroupIndex], + syntaxB: memberSyntaxSortOrder[previousMemberSyntaxGroupIndex] + } + }); + } + } else { + if (previousLocalMemberName && + currentLocalMemberName && + currentLocalMemberName < previousLocalMemberName + ) { + context.report({ + node, + message: "Imports should be sorted alphabetically." + }); + } } } + + previousDeclaration = node; } if (!ignoreMemberSort) { @@ -191,8 +199,6 @@ module.exports = { }); } } - - previousDeclaration = node; } }; } diff --git a/tests/lib/rules/sort-imports.js b/tests/lib/rules/sort-imports.js index 4cee0a2c5bb..290505650ea 100644 --- a/tests/lib/rules/sort-imports.js +++ b/tests/lib/rules/sort-imports.js @@ -61,6 +61,14 @@ ruleTester.run("sort-imports", rule, { options: ignoreCaseArgs }, "import {a, b, c, d} from 'foo.js';", + { + code: + "import a from 'foo.js';\n" + + "import B from 'bar.js';", + options: [{ + ignoreDeclarationSort: true + }] + }, { code: "import {b, A, C, d} from 'foo.js';", options: [{ @@ -175,6 +183,21 @@ ruleTester.run("sort-imports", rule, { type: "ImportSpecifier" }] }, + { + code: + "import {b, a, d, c} from 'foo.js';\n" + + "import {e, f, g, h} from 'bar.js';", + output: + "import {a, b, c, d} from 'foo.js';\n" + + "import {e, f, g, h} from 'bar.js';", + options: [{ + ignoreDeclarationSort: true + }], + errors: [{ + message: "Member 'a' of the import declaration should be sorted alphabetically.", + type: "ImportSpecifier" + }] + }, { code: "import {a, B, c, D} from 'foo.js';", output: "import {B, D, a, c} from 'foo.js';",