Skip to content

Commit

Permalink
[New] order: support type imports
Browse files Browse the repository at this point in the history
Fixes #645.
  • Loading branch information
Geraint White authored and ljharb committed Apr 1, 2021
1 parent ab0181d commit 1c10e79
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 29 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -12,6 +12,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
- add [`no-relative-packages`] ([#1860], [#966], thanks [@tapayne88] [@panrafal])
- add [`no-import-module-exports`] rule: report import declarations with CommonJS exports ([#804], thanks [@kentcdodds] and [@ttmarek])
- [`no-unused-modules`]: Support destructuring assignment for `export`. ([#1997], thanks [@s-h-a-d-o-w])
- [`order`]: support type imports ([#2021], thanks [@grit96])

### Fixed
- [`export`]/TypeScript: properly detect export specifiers as children of a TS module block ([#1889], thanks [@andreubotella])
Expand Down Expand Up @@ -761,6 +762,7 @@ for info on changes for earlier releases.

[`memo-parser`]: ./memo-parser/README.md

[#2021]: https://github.com/benmosher/eslint-plugin-import/pull/2021
[#1997]: https://github.com/benmosher/eslint-plugin-import/pull/1997
[#1993]: https://github.com/benmosher/eslint-plugin-import/pull/1993
[#1983]: https://github.com/benmosher/eslint-plugin-import/pull/1983
Expand Down Expand Up @@ -1347,3 +1349,4 @@ for info on changes for earlier releases.
[@devongovett]: https://github.com/devongovett
[@dwardu]: https://github.com/dwardu
[@s-h-a-d-o-w]: https://github.com/s-h-a-d-o-w
[@grit96]: https://github.com/grit96
6 changes: 4 additions & 2 deletions docs/rules/order.md
Expand Up @@ -24,6 +24,8 @@ import baz from './bar/baz';
import main from './';
// 7. "object"-imports (only available in TypeScript)
import log = console.log;
// 8. "type" imports (only available in Flow and TypeScript)
import type { Foo } from 'foo';
```

Unassigned imports are ignored, as the order they are imported in may be important.
Expand Down Expand Up @@ -80,7 +82,7 @@ This rule supports the following options:
### `groups: [array]`:

How groups are defined, and the order to respect. `groups` must be an array of `string` or [`string`]. The only allowed `string`s are:
`"builtin"`, `"external"`, `"internal"`, `"unknown"`, `"parent"`, `"sibling"`, `"index"`, `"object"`.
`"builtin"`, `"external"`, `"internal"`, `"unknown"`, `"parent"`, `"sibling"`, `"index"`, `"object"`, `"type"`.
The enforced order is the same as the order of each element in a group. Omitted types are implicitly grouped together as the last element. Example:
```js
[
Expand All @@ -96,7 +98,7 @@ The default value is `["builtin", "external", "parent", "sibling", "index"]`.
You can set the options like this:

```js
"import/order": ["error", {"groups": ["index", "sibling", "parent", "internal", "external", "builtin", "object"]}]
"import/order": ["error", {"groups": ["index", "sibling", "parent", "internal", "external", "builtin", "object", "type"]}]
```

### `pathGroups: [array of objects]`:
Expand Down
8 changes: 5 additions & 3 deletions src/rules/order.js
Expand Up @@ -265,7 +265,7 @@ function mutateRanksToAlphabetize(imported, alphabetizeOptions) {
if (!Array.isArray(acc[importedItem.rank])) {
acc[importedItem.rank] = [];
}
acc[importedItem.rank].push(importedItem.value);
acc[importedItem.rank].push(`${importedItem.value}-${importedItem.node.importKind}`);
return acc;
}, {});

Expand All @@ -290,7 +290,7 @@ function mutateRanksToAlphabetize(imported, alphabetizeOptions) {

// mutate the original group-rank with alphabetized-rank
imported.forEach(function(importedItem) {
importedItem.rank = alphabetizedRanks[importedItem.value];
importedItem.rank = alphabetizedRanks[`${importedItem.value}-${importedItem.node.importKind}`];
});
}

Expand All @@ -310,6 +310,8 @@ function computeRank(context, ranks, importEntry, excludedImportTypes) {
let rank;
if (importEntry.type === 'import:object') {
impType = 'object';
} else if (importEntry.node.importKind === 'type') {
impType = 'type';
} else {
impType = importType(importEntry.value, context);
}
Expand Down Expand Up @@ -350,7 +352,7 @@ function isModuleLevelRequire(node) {
);
}

const types = ['builtin', 'external', 'internal', 'unknown', 'parent', 'sibling', 'index', 'object'];
const types = ['builtin', 'external', 'internal', 'unknown', 'parent', 'sibling', 'index', 'object', 'type'];

// Creates an object with type-rank pairs.
// Example: { index: 0, sibling: 1, parent: 1, external: 1, builtin: 2, internal: 2 }
Expand Down
54 changes: 30 additions & 24 deletions tests/src/rules/order.js
Expand Up @@ -2186,12 +2186,13 @@ context('TypeScript', function () {
{
code: `
import c from 'Bar';
import type { C } from 'Bar';
import b from 'bar';
import a from 'foo';
import type { A } from 'foo';
import index from './';
import type { C } from 'Bar';
import type { A } from 'foo';
`,
parser,
options: [
Expand All @@ -2208,12 +2209,13 @@ context('TypeScript', function () {
{
code: `
import a from 'foo';
import type { A } from 'foo';
import b from 'bar';
import c from 'Bar';
import type { C } from 'Bar';
import index from './';
import type { A } from 'foo';
import type { C } from 'Bar';
`,
parser,
options: [
Expand All @@ -2233,20 +2235,22 @@ context('TypeScript', function () {
code: `
import b from 'bar';
import c from 'Bar';
import type { C } from 'Bar';
import a from 'foo';
import type { A } from 'foo';
import index from './';
import type { A } from 'foo';
import type { C } from 'Bar';
`,
output: `
import c from 'Bar';
import type { C } from 'Bar';
import b from 'bar';
import a from 'foo';
import type { A } from 'foo';
import index from './';
import type { C } from 'Bar';
import type { A } from 'foo';
`,
parser,
options: [
Expand All @@ -2255,12 +2259,12 @@ context('TypeScript', function () {
alphabetize: { order: 'asc' },
},
],
errors: [
{
message: semver.satisfies(eslintPkg.version, '< 3')
? '`bar` import should occur after import of `Bar`'
: /(`bar` import should occur after import of `Bar`)|(`Bar` import should occur before import of `bar`)/,
},
errors: semver.satisfies(eslintPkg.version, '< 3') ? [
{ message: '`Bar` import should occur before import of `bar`' },
{ message: '`Bar` import should occur before import of `foo`' },
] : [
{ message: /(`Bar` import should occur before import of `bar`)|(`bar` import should occur after import of `Bar`)/ },
{ message: /(`Bar` import should occur before import of `foo`)|(`foo` import should occur after import of `Bar`)/ },
],
},
parserConfig,
Expand All @@ -2270,21 +2274,23 @@ context('TypeScript', function () {
{
code: `
import a from 'foo';
import type { A } from 'foo';
import c from 'Bar';
import type { C } from 'Bar';
import b from 'bar';
import index from './';
import type { C } from 'Bar';
import type { A } from 'foo';
`,
output: `
import a from 'foo';
import type { A } from 'foo';
import b from 'bar';
import c from 'Bar';
import type { C } from 'Bar';
import index from './';
import type { A } from 'foo';
import type { C } from 'Bar';
`,
parser,
options: [
Expand All @@ -2293,12 +2299,12 @@ context('TypeScript', function () {
alphabetize: { order: 'desc' },
},
],
errors: [
{
message: semver.satisfies(eslintPkg.version, '< 3')
? '`bar` import should occur before import of `Bar`'
: /(`bar` import should occur before import of `Bar`)|(`Bar` import should occur after import of `bar`)/,
},
errors: semver.satisfies(eslintPkg.version, '< 3') ? [
{ message: '`bar` import should occur before import of `Bar`' },
{ message: '`foo` import should occur before import of `Bar`' },
] : [
{ message: /(`bar` import should occur before import of `Bar`)|(`Bar` import should occur after import of `bar`)/ },
{ message: /(`foo` import should occur before import of `Bar`)|(`Bar` import should occur after import of `foo`)/ },
],
},
parserConfig,
Expand Down

0 comments on commit 1c10e79

Please sign in to comment.