From b39770d98c3ba9af8f9df8c8d6357b17ab9af786 Mon Sep 17 00:00:00 2001 From: Geraint White Date: Mon, 17 May 2021 22:48:43 +0100 Subject: [PATCH] [Fix] `order`: restore default behavior unless `type` is in groups Fixes #2070. Fixes #2084. --- CHANGELOG.md | 2 + src/rules/order.js | 10 +- tests/src/rules/order.js | 207 ++++++++++++++++++++++++++++++++------- 3 files changed, 182 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03526c700..e5f432932 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel - [`no-restricted-paths`]: fix false positive matches ([#2090], thanks [@malykhinvi]) - [`no-cycle`]: ignore imports where imported file only imports types of importing file ([#2083], thanks [@cherryblossom000]) - [`no-cycle`]: fix false negative when file imports a type after importing a value in Flow ([#2083], thanks [@cherryblossom000]) +- [`order`]: restore default behavior unless `type` is in groups ([#2087], thanks [@grit96]) ### Changed - [Docs] Add `no-relative-packages` to list of to the list of rules ([#2075], thanks [@arvigeus]) @@ -792,6 +793,7 @@ for info on changes for earlier releases. [`memo-parser`]: ./memo-parser/README.md [#2090]: https://github.com/benmosher/eslint-plugin-import/pull/2090 +[#2087]: https://github.com/benmosher/eslint-plugin-import/pull/2087 [#2083]: https://github.com/benmosher/eslint-plugin-import/pull/2083 [#2075]: https://github.com/benmosher/eslint-plugin-import/pull/2075 [#2071]: https://github.com/benmosher/eslint-plugin-import/pull/2071 diff --git a/src/rules/order.js b/src/rules/order.js index 515c089f7..ce34604c6 100644 --- a/src/rules/order.js +++ b/src/rules/order.js @@ -313,7 +313,7 @@ function computeRank(context, ranks, importEntry, excludedImportTypes) { let rank; if (importEntry.type === 'import:object') { impType = 'object'; - } else if (importEntry.node.importKind === 'type') { + } else if (importEntry.node.importKind === 'type' && ranks.omittedTypes.indexOf('type') === -1) { impType = 'type'; } else { impType = importType(importEntry.value, context); @@ -382,10 +382,12 @@ function convertGroupsToRanks(groups) { return rankObject[type] === undefined; }); - return omittedTypes.reduce(function(res, type) { + const ranks = omittedTypes.reduce(function(res, type) { res[type] = groups.length; return res; }, rankObject); + + return { groups: ranks, omittedTypes }; } function convertPathGroupsForRanks(pathGroups) { @@ -590,8 +592,10 @@ module.exports = { try { const { pathGroups, maxPosition } = convertPathGroupsForRanks(options.pathGroups || []); + const { groups, omittedTypes } = convertGroupsToRanks(options.groups || defaultGroups); ranks = { - groups: convertGroupsToRanks(options.groups || defaultGroups), + groups, + omittedTypes, pathGroups, maxPosition, }; diff --git a/tests/src/rules/order.js b/tests/src/rules/order.js index f621c811d..75d59ef31 100644 --- a/tests/src/rules/order.js +++ b/tests/src/rules/order.js @@ -2243,6 +2243,50 @@ context('TypeScript', function () { // #1667: typescript type import support // Option alphabetize: {order: 'asc'} + test( + { + 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 './'; + `, + parser, + options: [ + { + groups: ['external', 'index'], + alphabetize: { order: 'asc' }, + }, + ], + }, + parserConfig, + ), + // Option alphabetize: {order: 'desc'} + test( + { + 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 './'; + `, + parser, + options: [ + { + groups: ['external', 'index'], + alphabetize: { order: 'desc' }, + }, + ], + }, + parserConfig, + ), + // Option alphabetize: {order: 'asc'} with type group test( { code: ` @@ -2258,14 +2302,14 @@ context('TypeScript', function () { parser, options: [ { - groups: ['external', 'index'], + groups: ['external', 'index', 'type'], alphabetize: { order: 'asc' }, }, ], }, parserConfig, ), - // Option alphabetize: {order: 'desc'} + // Option alphabetize: {order: 'desc'} with type group test( { code: ` @@ -2281,7 +2325,7 @@ context('TypeScript', function () { parser, options: [ { - groups: ['external', 'index'], + groups: ['external', 'index', 'type'], alphabetize: { order: 'desc' }, }, ], @@ -2303,35 +2347,130 @@ context('TypeScript', function () { }, parserConfig, ), + test( + { + code: ` + import { serialize, parse, mapFieldErrors } from '@vtaits/form-schema'; + import type { GetFieldSchema } from '@vtaits/form-schema'; + import { useMemo, useCallback } from 'react'; + import type { ReactElement, ReactNode } from 'react'; + import { Form } from 'react-final-form'; + import type { FormProps as FinalFormProps } from 'react-final-form'; + `, + parser, + options: [ + { + alphabetize: { order: 'asc' }, + }, + ], + }, + parserConfig, + ), ], invalid: [ // Option alphabetize: {order: 'asc'} test( { code: ` - import b from 'bar'; - import c from 'Bar'; - import a from 'foo'; - - import index from './'; + import b from 'bar'; + import c from 'Bar'; + import type { C } from 'Bar'; + import a from 'foo'; + import type { A } from 'foo'; - import type { A } from 'foo'; - import type { C } from 'Bar'; - `, + import index from './'; + `, output: ` - import c from 'Bar'; - import b from 'bar'; - import a from 'foo'; + 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 index from './'; + `, + parser, + options: [ + { + groups: ['external', 'index'], + 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`)/, + }, + ], + }, + parserConfig, + ), + // Option alphabetize: {order: 'desc'} + test( + { + code: ` + import a from 'foo'; + import type { A } from 'foo'; + import c from 'Bar'; + import type { C } from 'Bar'; + import b from 'bar'; - import type { C } from 'Bar'; - import type { A } from 'foo'; - `, + import index from './'; + `, + 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 './'; + `, parser, options: [ { groups: ['external', 'index'], + 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`)/, + }, + ], + }, + parserConfig, + ), + // Option alphabetize: {order: 'asc'} with type group + test( + { + code: ` + import b from 'bar'; + import c from 'Bar'; + import a from 'foo'; + + import index from './'; + + import type { A } from 'foo'; + import type { C } from 'Bar'; + `, + output: ` + import c from 'Bar'; + import b from 'bar'; + import a from 'foo'; + + import index from './'; + + import type { C } from 'Bar'; + import type { A } from 'foo'; + `, + parser, + options: [ + { + groups: ['external', 'index', 'type'], alphabetize: { order: 'asc' }, }, ], @@ -2345,33 +2484,33 @@ context('TypeScript', function () { }, parserConfig, ), - // Option alphabetize: {order: 'desc'} + // Option alphabetize: {order: 'desc'} with type group test( { code: ` - import a from 'foo'; - import c from 'Bar'; - import b from 'bar'; + import a from 'foo'; + import c from 'Bar'; + import b from 'bar'; - import index from './'; + import index from './'; - import type { C } from 'Bar'; - import type { A } from 'foo'; - `, + import type { C } from 'Bar'; + import type { A } from 'foo'; + `, output: ` - import a from 'foo'; - import b from 'bar'; - import c from 'Bar'; + import a from 'foo'; + import b from 'bar'; + import c from 'Bar'; - import index from './'; + import index from './'; - import type { A } from 'foo'; - import type { C } from 'Bar'; - `, + import type { A } from 'foo'; + import type { C } from 'Bar'; + `, parser, options: [ { - groups: ['external', 'index'], + groups: ['external', 'index', 'type'], alphabetize: { order: 'desc' }, }, ],