This repository has been archived by the owner on Sep 30, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat!: add sort-import-destructures rule
Closes: #124
- Loading branch information
Showing
7 changed files
with
265 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
plugins/eslint-plugin-liferay/docs/rules/sort-import-destructures.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Sort destructured names in `import` statements (sort-import-destructures) | ||
|
||
This rule enforces (and autofixes) that destructured names in `import` statements are sorted. | ||
|
||
## Rule Details | ||
|
||
Examples of **incorrect** code for this rule: | ||
|
||
```js | ||
import {xyz, abc} from 'other'; | ||
|
||
import main, {second as alias, first as nickname} from 'something'; | ||
``` | ||
|
||
Examples of **correct** code for this rule: | ||
|
||
```js | ||
import {abc, xyz} from 'other'; | ||
|
||
import main, {first as nickname, second as alias} from 'something'; | ||
``` | ||
|
||
Note how the sorting is based on the name of the imported export (eg. `first`, `second`) and not the local name (eg. `nickname`, `alias`). | ||
|
||
## Further Reading | ||
|
||
- https://github.com/liferay/eslint-config-liferay/issues/124 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
101 changes: 101 additions & 0 deletions
101
plugins/eslint-plugin-liferay/lib/rules/sort-import-destructures.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/** | ||
* © 2017 Liferay, Inc. <https://liferay.com> | ||
* | ||
* SPDX-License-Identifier: MIT | ||
*/ | ||
|
||
const DESCRIPTION = 'destructured names in imports must be sorted'; | ||
|
||
module.exports = { | ||
create(context) { | ||
return { | ||
ImportDeclaration(node) { | ||
const specifiers = node.specifiers.filter(specifier => { | ||
// Just `ImportSpecifier` (ignore `ImportDefaultSpecifier`). | ||
return specifier.type === 'ImportSpecifier'; | ||
}); | ||
|
||
if (specifiers.length > 1) { | ||
const source = context.getSourceCode(); | ||
|
||
if ( | ||
source.commentsExistBetween( | ||
source.getTokenBefore(specifiers[0]), | ||
node.source | ||
) | ||
) { | ||
// Don't touch if any of the specifiers have | ||
// comments. | ||
return; | ||
} | ||
|
||
let fix; | ||
|
||
// Given: | ||
// | ||
// import {a as b, c} from 'd'; | ||
// | ||
// We'll have two specifiers: | ||
// | ||
// - `imported.name === 'a'`, `local.name === 'b'). | ||
// - `imported.name === 'c'`. | ||
// | ||
// We sort by `imported` always, ignoring `local`. | ||
const sorted = specifiers.slice().sort((a, b) => { | ||
const order = | ||
a.imported.name > b.imported.name ? 1 : -1; | ||
|
||
if (order === 1) { | ||
fix = true; | ||
} | ||
|
||
return order; | ||
}); | ||
|
||
if (fix) { | ||
const text = | ||
' '.repeat(node.start) + source.getText(node); | ||
|
||
const start = specifiers[0].start; | ||
const end = specifiers[specifiers.length - 1].end; | ||
|
||
let fixed = ''; | ||
|
||
for (let i = 0; i < specifiers.length; i++) { | ||
fixed += source.getText(sorted[i]); | ||
|
||
if (i < specifiers.length - 1) { | ||
// Grab all text between specifier and next. | ||
const between = text.slice( | ||
specifiers[i].end, | ||
specifiers[i + 1].start | ||
); | ||
|
||
fixed += between; | ||
} | ||
} | ||
|
||
context.report({ | ||
fix: fixer => | ||
fixer.replaceTextRange([start, end], fixed), | ||
message: DESCRIPTION, | ||
node, | ||
}); | ||
} | ||
} | ||
}, | ||
}; | ||
}, | ||
|
||
meta: { | ||
docs: { | ||
category: 'Best Practices', | ||
description: DESCRIPTION, | ||
recommended: false, | ||
url: 'https://github.com/liferay/eslint-config-liferay/issues/124', | ||
}, | ||
fixable: 'code', | ||
schema: [], | ||
type: 'problem', | ||
}, | ||
}; |
133 changes: 133 additions & 0 deletions
133
plugins/eslint-plugin-liferay/tests/lib/rules/sort-import-destructures.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
/** | ||
* © 2017 Liferay, Inc. <https://liferay.com> | ||
* | ||
* SPDX-License-Identifier: MIT | ||
*/ | ||
|
||
const {RuleTester} = require('eslint'); | ||
|
||
const rule = require('../../../lib/rules/sort-import-destructures'); | ||
|
||
const parserOptions = { | ||
parserOptions: { | ||
ecmaVersion: 6, | ||
sourceType: 'module', | ||
}, | ||
}; | ||
|
||
const ruleTester = new RuleTester(parserOptions); | ||
|
||
ruleTester.run('sort-import-destructures', rule, { | ||
invalid: [ | ||
{ | ||
code: `import {z, g} from 'a';`, | ||
errors: [ | ||
{ | ||
message: 'destructured names in imports must be sorted', | ||
}, | ||
], | ||
output: `import {g, z} from 'a';`, | ||
}, | ||
{ | ||
code: `import {b as bar, a as foo} from 'b';`, | ||
errors: [ | ||
{ | ||
message: 'destructured names in imports must be sorted', | ||
}, | ||
], | ||
output: `import {a as foo, b as bar} from 'b';`, | ||
}, | ||
{ | ||
code: `import thing, {k, h, j} from 'c';`, | ||
errors: [ | ||
{ | ||
message: 'destructured names in imports must be sorted', | ||
}, | ||
], | ||
output: `import thing, {h, j, k} from 'c';`, | ||
}, | ||
{ | ||
// Same as previous, but with line breaks. | ||
code: ` | ||
import thing, { | ||
k, | ||
h, | ||
j | ||
} from 'c'; | ||
`, | ||
errors: [ | ||
{ | ||
message: 'destructured names in imports must be sorted', | ||
}, | ||
], | ||
output: ` | ||
import thing, { | ||
h, | ||
j, | ||
k | ||
} from 'c'; | ||
`, | ||
}, | ||
{ | ||
// Note that trailing commas are preserved. | ||
code: ` | ||
import { | ||
z, | ||
y, | ||
x, | ||
} from 'file'; | ||
`, | ||
errors: [ | ||
{ | ||
message: 'destructured names in imports must be sorted', | ||
}, | ||
], | ||
output: ` | ||
import { | ||
x, | ||
y, | ||
z, | ||
} from 'file'; | ||
`, | ||
}, | ||
], | ||
|
||
valid: [ | ||
{ | ||
code: `import thing from 'thing';`, | ||
}, | ||
{ | ||
code: `import {gizmo} from 'gizmo';`, | ||
}, | ||
{ | ||
code: `import {g, z} from 'a';`, | ||
}, | ||
{ | ||
code: `import {a as foo, b as bar} from 'b';`, | ||
}, | ||
{ | ||
code: `import thing, {h, j, k} from 'c';`, | ||
}, | ||
{ | ||
// We don't touch the sort order if there are comments anywhere. | ||
code: ` | ||
import { | ||
// Comment. | ||
zoo, | ||
school | ||
} from 'places'; | ||
import { | ||
zzz, // Comment. | ||
xxx | ||
} from 'letters'; | ||
import { | ||
three, | ||
two, | ||
one // Comment. | ||
} from 'numbers'; | ||
`, | ||
}, | ||
], | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters