diff --git a/src/constants.ts b/src/constants.ts index 7c2c3acf..a2e6e4ef 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -15,6 +15,9 @@ export const sortImportsIgnoredComment = 'sort-imports-ignore'; */ export const THIRD_PARTY_MODULES_SPECIAL_WORD = ''; +export const THIRD_PARTY_TYPES_SPECIAL_WORD = ''; +export const TYPES_SPECIAL_WORD = ''; + const PRETTIER_PLUGIN_SORT_IMPORTS_NEW_LINE = 'PRETTIER_PLUGIN_SORT_IMPORTS_NEW_LINE'; diff --git a/src/utils/__tests__/get-sorted-nodes.spec.ts b/src/utils/__tests__/get-sorted-nodes.spec.ts index d488c92a..6f7e71ea 100644 --- a/src/utils/__tests__/get-sorted-nodes.spec.ts +++ b/src/utils/__tests__/get-sorted-nodes.spec.ts @@ -20,6 +20,24 @@ import XY from 'XY'; import Xa from 'Xa'; `; +const typeCode = `// first comment +// second comment +import type sm from 'sm'; +import type xl from './xl'; +import l from './l'; +import z from 'z'; +import c, { cD } from 'c'; +import g from 'g'; +import { tC, tA, tB } from 't'; +import k, { kE, kB } from 'k'; +import * as a from 'a'; +import * as x from 'x'; +import BY from 'BY'; +import Ba from 'Ba'; +import XY from 'XY'; +import Xa from 'Xa'; +`; + test('it returns all sorted nodes', () => { const result = getImportNodes(code); const sorted = getSortedNodes(result, { @@ -329,3 +347,55 @@ test('it returns all sorted nodes with namespace specifiers at the top', () => { 'z', ]); }); + +test('it returns all sorted nodes with types', () => { + const result = getImportNodes(typeCode, { + plugins: ['typescript'], + }); + const sorted = getSortedNodes(result, { + importOrder: ["", "^[./]", "^[./]"], + importOrderCaseInsensitive: false, + importOrderSeparation: false, + importOrderGroupNamespaceSpecifiers: false, + importOrderSortSpecifiers: false, + }) as ImportDeclaration[]; + + expect(getSortedNodesNames(sorted)).toEqual([ + 'BY', + 'Ba', + 'XY', + 'Xa', + 'a', + 'c', + 'g', + 'k', + 't', + 'x', + 'z', + 'sm', + './l', + './xl', + ]); + expect( + sorted + .filter((node) => node.type === 'ImportDeclaration') + .map((importDeclaration) => + getSortedNodesModulesNames(importDeclaration.specifiers), + ), + ).toEqual([ + ['BY'], + ['Ba'], + ['XY'], + ['Xa'], + ['a'], + ['c', 'cD'], + ['g'], + ['k', 'kE', 'kB'], + ['tC', 'tA', 'tB'], + ['x'], + ['z'], + ['sm'], + ['l'], + ['xl'], + ]); +}); diff --git a/src/utils/get-import-nodes-matched-group.ts b/src/utils/get-import-nodes-matched-group.ts index 3f4a9d1e..2173d6f6 100644 --- a/src/utils/get-import-nodes-matched-group.ts +++ b/src/utils/get-import-nodes-matched-group.ts @@ -1,6 +1,10 @@ import { ImportDeclaration } from '@babel/types'; -import { THIRD_PARTY_MODULES_SPECIAL_WORD } from '../constants'; +import { + THIRD_PARTY_MODULES_SPECIAL_WORD, + THIRD_PARTY_TYPES_SPECIAL_WORD, + TYPES_SPECIAL_WORD, +} from '../constants'; /** * Get the regexp group to keep the import nodes. @@ -13,13 +17,26 @@ export const getImportNodesMatchedGroup = ( ) => { const groupWithRegExp = importOrder.map((group) => ({ group, - regExp: new RegExp(group), + regExp: group.startsWith(TYPES_SPECIAL_WORD) + ? new RegExp(group.replace(TYPES_SPECIAL_WORD, '')) + : new RegExp(group), })); for (const { group, regExp } of groupWithRegExp) { + if ( + (group.startsWith(TYPES_SPECIAL_WORD) && + node.importKind !== 'type') || + (!group.startsWith(TYPES_SPECIAL_WORD) && + node.importKind === 'type') + ) + continue; + const matched = node.source.value.match(regExp) !== null; if (matched) return group; } - return THIRD_PARTY_MODULES_SPECIAL_WORD; + return node.importKind === 'type' && + importOrder.find((group) => group === THIRD_PARTY_TYPES_SPECIAL_WORD) + ? THIRD_PARTY_TYPES_SPECIAL_WORD + : THIRD_PARTY_MODULES_SPECIAL_WORD; };