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

[New] order: add option pathGroupsExcludedImportTypes to allow ordering of external import types #1570

Merged
merged 1 commit into from Jan 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -16,6 +16,9 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
- [`no-extraneous-dependencies`]: ensure `node.source` is truthy ([#1589], thanks [@ljharb])
- [`extensions`]: Ignore query strings when checking for extensions ([#1572], thanks [@pcorpet])

### Added
- [`order`]: add option pathGroupsExcludedImportTypes to allow ordering of external import types ([#1565], thanks [@Mairu])

## [2.19.1] - 2019-12-08
### Fixed
- [`no-extraneous-dependencies`]: ensure `node.source` exists
Expand Down Expand Up @@ -789,6 +792,7 @@ for info on changes for earlier releases.
[#211]: https://github.com/benmosher/eslint-plugin-import/pull/211
[#164]: https://github.com/benmosher/eslint-plugin-import/pull/164
[#157]: https://github.com/benmosher/eslint-plugin-import/pull/157
[#1565]: https://github.com/benmosher/eslint-plugin-import/issues/1565
[#1366]: https://github.com/benmosher/eslint-plugin-import/issues/1366
[#1334]: https://github.com/benmosher/eslint-plugin-import/issues/1334
[#1323]: https://github.com/benmosher/eslint-plugin-import/issues/1323
Expand Down
24 changes: 23 additions & 1 deletion docs/rules/order.md
Expand Up @@ -96,7 +96,7 @@ You can set the options like this:

### `pathGroups: [array of objects]`:

To be able so group by paths mostly needed with aliases pathGroups can be defined.
To be able to group by paths mostly needed with aliases pathGroups can be defined.

Properties of the objects

Expand All @@ -120,6 +120,28 @@ Properties of the objects
}
```

### `pathGroupsExcludedImportTypes: [array]`:

This defines import types that are not handled by configured pathGroups.
This is mostly needed when you want to handle path groups that look like external imports.

Example:
```json
{
"import/order": ["error", {
"pathGroups": [
{
"pattern": "@app/**",
"group": "external",
"position": "after"
}
],
"pathGroupsExcludedImportTypes": ["builtin"]
}]
}
```
The default value is `["builtin", "external"]`.

### `newlines-between: [ignore|always|always-and-inside-groups|never]`:

Enforces or forbids new lines between import groups:
Expand Down
34 changes: 27 additions & 7 deletions src/rules/order.js
Expand Up @@ -269,7 +269,7 @@ function importsSorterDesc(importA, importB) {

function mutateRanksToAlphabetize(imported, alphabetizeOptions) {
const groupedByRanks = imported.reduce(function(acc, importedItem) {
if (!Array.isArray(acc[importedItem.rank])) {
if (!Array.isArray(acc[importedItem.rank])) {
acc[importedItem.rank] = []
}
acc[importedItem.rank].push(importedItem.name)
Expand Down Expand Up @@ -312,10 +312,10 @@ function computePathRank(ranks, pathGroups, path, maxPosition) {
}
}

function computeRank(context, ranks, name, type) {
function computeRank(context, ranks, name, type, excludedImportTypes) {
const impType = importType(name, context)
let rank
if (impType !== 'builtin' && impType !== 'external') {
if (!excludedImportTypes.has(impType)) {
rank = computePathRank(ranks.groups, ranks.pathGroups, name, ranks.maxPosition)
}
if (!rank) {
Expand All @@ -328,8 +328,8 @@ function computeRank(context, ranks, name, type) {
return rank
}

function registerNode(context, node, name, type, ranks, imported) {
const rank = computeRank(context, ranks, name, type)
function registerNode(context, node, name, type, ranks, imported, excludedImportTypes) {
const rank = computeRank(context, ranks, name, type, excludedImportTypes)
if (rank !== -1) {
imported.push({name, rank, node})
}
Expand Down Expand Up @@ -508,6 +508,9 @@ module.exports = {
groups: {
type: 'array',
},
pathGroupsExcludedImportTypes: {
type: 'array',
},
pathGroups: {
type: 'array',
items: {
Expand Down Expand Up @@ -562,6 +565,7 @@ module.exports = {
create: function importOrderRule (context) {
const options = context.options[0] || {}
const newlinesBetweenImports = options['newlines-between'] || 'ignore'
const pathGroupsExcludedImportTypes = new Set(options['pathGroupsExcludedImportTypes'] || ['builtin', 'external'])
const alphabetize = getAlphabetizeConfig(options)
let ranks

Expand Down Expand Up @@ -594,15 +598,31 @@ module.exports = {
ImportDeclaration: function handleImports(node) {
if (node.specifiers.length) { // Ignoring unassigned imports
const name = node.source.value
registerNode(context, node, name, 'import', ranks, imported)
registerNode(
context,
node,
name,
'import',
ranks,
imported,
pathGroupsExcludedImportTypes
)
}
},
CallExpression: function handleRequires(node) {
if (level !== 0 || !isStaticRequire(node) || !isInVariableDeclarator(node.parent)) {
return
}
const name = node.arguments[0].value
registerNode(context, node, name, 'require', ranks, imported)
registerNode(
context,
node,
name,
'require',
ranks,
imported,
pathGroupsExcludedImportTypes
)
},
'Program:exit': function reportAndReset() {
if (newlinesBetweenImports !== 'ignore') {
Expand Down
22 changes: 22 additions & 0 deletions tests/src/rules/order.js
Expand Up @@ -276,6 +276,28 @@ ruleTester.run('order', rule, {
],
}],
}),
// Using pathGroups to customize ordering for imports that are recognized as 'external'
// by setting pathGroupsExcludedImportTypes without 'external'
test({
code: `
import fs from 'fs';

import { Input } from '@app/components/Input';

import { Button } from '@app2/components/Button';

import _ from 'lodash';

import { add } from './helper';`,
options: [{
'newlines-between': 'always',
pathGroupsExcludedImportTypes: ['builtin'],
pathGroups: [
{ pattern: '@app/**', group: 'external', position: 'before' },
{ pattern: '@app2/**', group: 'external', position: 'before' },
],
}],
}),

// Option: newlines-between: 'always'
test({
Expand Down