From 96b18814a6518a27a01ef024c112d69e2d093fb1 Mon Sep 17 00:00:00 2001 From: Dimitar Date: Sun, 23 Feb 2020 13:42:19 +0200 Subject: [PATCH] Update: Allows for grouped sort-imports (fixes #12951) --- docs/rules/sort-imports.md | 53 +++++++++++++++++++++++++++++++++ lib/rules/sort-imports.js | 20 +++++++++++-- tests/lib/rules/sort-imports.js | 21 ++++++++++++- 3 files changed, 91 insertions(+), 3 deletions(-) diff --git a/docs/rules/sort-imports.md b/docs/rules/sort-imports.md index f6fd04f0683d..2597cd5c92b4 100644 --- a/docs/rules/sort-imports.md +++ b/docs/rules/sort-imports.md @@ -36,6 +36,7 @@ This rule accepts an object with its properties as * `ignoreCase` (default: `false`) * `ignoreDeclarationSort` (default: `false`) * `ignoreMemberSort` (default: `false`) +* `ignoreBlankLines` (default: `true`) * `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. * `all` = import all members provided by exported bindings. @@ -50,6 +51,7 @@ Default option settings are: "ignoreCase": false, "ignoreDeclarationSort": false, "ignoreMemberSort": false, + "ignoreBlankLines": true, "memberSyntaxSortOrder": ["none", "all", "multiple", "single"] }] } @@ -84,6 +86,13 @@ import c from 'qux.js'; /*eslint sort-imports: "error"*/ import {a, b, c} from 'foo.js' + +/*eslint sort-imports: "error"*/ +import a from 'bar.js'; + +import b from 'foo.js'; + +import c from 'baz.js'; ``` Examples of **incorrect** code for this rule when using default options: @@ -93,6 +102,11 @@ Examples of **incorrect** code for this rule when using default options: import b from 'foo.js'; import a from 'bar.js'; +/*eslint sort-imports: "error"*/ +import b from 'foo.js'; + +import a from 'bar.js'; + /*eslint sort-imports: "error"*/ import a from 'foo.js'; import A from 'bar.js'; @@ -186,6 +200,45 @@ import {b, a, c} from 'foo.js' Default is `false`. +### `ignoreBlankLines` + +When `true` the rule ignores the blank lines between the imports. + +Examples of **incorrect** code for this rule with the default `{ "ignoreBlankLines": true }` option: + +```js +/*eslint sort-imports: ["error", { "ignoreBlankLines": true }]*/ +import b from 'foo.js' + +import a from 'bar.js' + + +/*eslint sort-imports: ["error", { "ignoreBlankLines": true }]*/ +import b from 'foo.js'; +import c from 'baz.js'; + +import a from 'bar.js'; +import x from 'qux.js'; +``` + +Examples of **correct** code for this rule with the `{ "ignoreBlankLines": false }` option: + +```js +/*eslint sort-imports: ["error", { "ignoreDeclarationSort": true }]*/ +import b from 'bar.js' + +import a from 'foo.js' + +/*eslint sort-imports: ["error", { "ignoreBlankLines": false }]*/ +import b from 'foo.js'; +import c from 'baz.js'; + +import a from 'bar.js'; +import x from 'qux.js'; +``` + +Default is `true`. + ### `memberSyntaxSortOrder` There are four different styles and the default member syntax sort order is: diff --git a/lib/rules/sort-imports.js b/lib/rules/sort-imports.js index 65ad9a18a931..df05ba7d2377 100644 --- a/lib/rules/sort-imports.js +++ b/lib/rules/sort-imports.js @@ -44,6 +44,10 @@ module.exports = { ignoreMemberSort: { type: "boolean", default: false + }, + ignoreBlankLines: { + type: "boolean", + default: true } }, additionalProperties: false @@ -65,6 +69,7 @@ module.exports = { ignoreCase = configuration.ignoreCase || false, ignoreDeclarationSort = configuration.ignoreDeclarationSort || false, ignoreMemberSort = configuration.ignoreMemberSort || false, + ignoreBlankLines = configuration.ignoreBlankLines !== false, memberSyntaxSortOrder = configuration.memberSyntaxSortOrder || ["none", "all", "multiple", "single"], sourceCode = context.getSourceCode(); let previousDeclaration = null; @@ -112,7 +117,16 @@ module.exports = { return node.specifiers[0].local.name; } return null; + } + /** + * Gets the number of lines between the given declarations. + * @param {ASTNode} node1 the ImportDeclaration node. + * @param {ASTNode} node2 the ImportDeclaration node. + * @returns {number} number of lines. + */ + function getLinesBetweenMembers(node1, node2) { + return node1.loc.start.line - node2.loc.end.line - 1; } return { @@ -120,7 +134,8 @@ module.exports = { if (!ignoreDeclarationSort) { if (previousDeclaration) { const currentMemberSyntaxGroupIndex = getMemberParameterGroupIndex(node), - previousMemberSyntaxGroupIndex = getMemberParameterGroupIndex(previousDeclaration); + previousMemberSyntaxGroupIndex = getMemberParameterGroupIndex(previousDeclaration), + linesBetweenMembers = getLinesBetweenMembers(node, previousDeclaration); let currentLocalMemberName = getFirstLocalMemberName(node), previousLocalMemberName = getFirstLocalMemberName(previousDeclaration); @@ -148,7 +163,8 @@ module.exports = { } else { if (previousLocalMemberName && currentLocalMemberName && - currentLocalMemberName < previousLocalMemberName + currentLocalMemberName < previousLocalMemberName && + (ignoreBlankLines || linesBetweenMembers < 1) ) { context.report({ node, diff --git a/tests/lib/rules/sort-imports.js b/tests/lib/rules/sort-imports.js index 51f3ee3a8045..613bc03f8775 100644 --- a/tests/lib/rules/sort-imports.js +++ b/tests/lib/rules/sort-imports.js @@ -101,7 +101,17 @@ ruleTester.run("sort-imports", rule, { }, // https://github.com/eslint/eslint/issues/5305 - "import React, {Component} from 'react';" + "import React, {Component} from 'react';", + + // https://github.com/eslint/eslint/issues/12951 + { + code: + "import b from 'foo.js';\n\n" + + "import a from 'bar.js';", + options: [{ + ignoreBlankLines: false + }] + } ], invalid: [ { @@ -287,6 +297,15 @@ ruleTester.run("sort-imports", rule, { data: { memberName: "qux" }, type: "ImportSpecifier" }] + }, + + // https://github.com/eslint/eslint/issues/12951 + { + code: + "import b from 'foo.js';\n\n" + + "import a from 'bar.js';", + output: null, + errors: [expectedError] } ] });