Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Update: Add sort-imports ignoreDeclarationSort (fixes #11019) #11040

Merged
merged 2 commits into from Jan 4, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 30 additions & 0 deletions docs/rules/sort-imports.md
Expand Up @@ -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.
Expand All @@ -47,6 +48,7 @@ Default option settings are:
{
"sort-imports": ["error", {
"ignoreCase": false,
"ignoreDeclarationSort": false,
"ignoreMemberSort": false,
"memberSyntaxSortOrder": ["none", "all", "multiple", "single"]
}]
Expand Down Expand Up @@ -136,6 +138,34 @@ import c from 'baz.js';

Default is `false`.

### `ignoreDeclarationSort`

Ignores the sorting of import declaration statements.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a note that the default is false here. (I see the note below, but I think it's important enough to be included in the intro/summary of the section.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to keep it at the end for consistency with the other sections.

Please let me know if this really needs to be changed.


Examples of **incorrect** code for this rule with the default `{ "ignoreMemberSort": false }` option:
remcohaszing marked this conversation as resolved.
Show resolved Hide resolved

```js
/*eslint sort-imports: ["error", { "ignoreDeclarationSort": false }]*/
import 'foo.js'
import 'bar.js'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out. I fixed it in #11242.

```

Examples of **correct** code for this rule with the `{ "ignoreMemberSort": true }` option:
remcohaszing marked this conversation as resolved.
Show resolved Hide resolved

```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.
Expand Down
80 changes: 43 additions & 37 deletions lib/rules/sort-imports.js
Expand Up @@ -34,6 +34,9 @@ module.exports = {
minItems: 4,
maxItems: 4
},
ignoreDeclarationSort: {
type: "boolean"
},
ignoreMemberSort: {
type: "boolean"
}
Expand All @@ -49,6 +52,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();
Expand Down Expand Up @@ -103,44 +107,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) {
Expand Down Expand Up @@ -189,8 +197,6 @@ module.exports = {
});
}
}

previousDeclaration = node;
}
};
}
Expand Down
23 changes: 23 additions & 0 deletions tests/lib/rules/sort-imports.js
Expand Up @@ -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: [{
Expand Down Expand Up @@ -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';",
Expand Down