From e5f6ae94fbab6f449ac2ca1a2af026c7035402d4 Mon Sep 17 00:00:00 2001 From: Samuel Corsi-House Date: Sat, 14 May 2022 10:04:38 -0400 Subject: [PATCH 1/4] feat: type imports --- src/constants.ts | 2 ++ src/utils/get-import-nodes-matched-group.ts | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/constants.ts b/src/constants.ts index e04f402c..034016f3 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -13,6 +13,8 @@ export const newLineCharacters = '\n\n'; */ export const THIRD_PARTY_MODULES_SPECIAL_WORD = ''; +export const THIRD_PARTY_TYPES_SPECIAL_WORD = ''; + const PRETTIER_PLUGIN_SORT_IMPORTS_NEW_LINE = 'PRETTIER_PLUGIN_SORT_IMPORTS_NEW_LINE'; diff --git a/src/utils/get-import-nodes-matched-group.ts b/src/utils/get-import-nodes-matched-group.ts index 3f4a9d1e..c3333939 100644 --- a/src/utils/get-import-nodes-matched-group.ts +++ b/src/utils/get-import-nodes-matched-group.ts @@ -1,6 +1,9 @@ import { ImportDeclaration } from '@babel/types'; -import { THIRD_PARTY_MODULES_SPECIAL_WORD } from '../constants'; +import { + THIRD_PARTY_MODULES_SPECIAL_WORD, + THIRD_PARTY_TYPES_SPECIAL_WORD, +} from '../constants'; /** * Get the regexp group to keep the import nodes. @@ -17,6 +20,9 @@ export const getImportNodesMatchedGroup = ( })); for (const { group, regExp } of groupWithRegExp) { + if (node.importKind === 'type' && group === THIRD_PARTY_TYPES_SPECIAL_WORD) + return THIRD_PARTY_TYPES_SPECIAL_WORD; + const matched = node.source.value.match(regExp) !== null; if (matched) return group; } From d1a1837efa5154a6852fa31778ad77e70a83b2c8 Mon Sep 17 00:00:00 2001 From: Samuel Corsi-House Date: Sat, 14 May 2022 10:46:04 -0400 Subject: [PATCH 2/4] feat: local type sorting --- src/constants.ts | 1 + src/utils/get-import-nodes-matched-group.ts | 46 ++++++++++++++++----- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 034016f3..a1ee5eeb 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -14,6 +14,7 @@ export const newLineCharacters = '\n\n'; export const THIRD_PARTY_MODULES_SPECIAL_WORD = ''; export const THIRD_PARTY_TYPES_SPECIAL_WORD = ''; +export const TYPE_SPECIAL_WORD = ''; const PRETTIER_PLUGIN_SORT_IMPORTS_NEW_LINE = 'PRETTIER_PLUGIN_SORT_IMPORTS_NEW_LINE'; diff --git a/src/utils/get-import-nodes-matched-group.ts b/src/utils/get-import-nodes-matched-group.ts index c3333939..d1b6a89f 100644 --- a/src/utils/get-import-nodes-matched-group.ts +++ b/src/utils/get-import-nodes-matched-group.ts @@ -3,6 +3,7 @@ import { ImportDeclaration } from '@babel/types'; import { THIRD_PARTY_MODULES_SPECIAL_WORD, THIRD_PARTY_TYPES_SPECIAL_WORD, + TYPE_SPECIAL_WORD, } from '../constants'; /** @@ -14,18 +15,43 @@ export const getImportNodesMatchedGroup = ( node: ImportDeclaration, importOrder: string[], ) => { - const groupWithRegExp = importOrder.map((group) => ({ - group, - regExp: new RegExp(group), - })); + const groupWithRegExp = importOrder + .sort((a, b) => { + if ( + a.startsWith(TYPE_SPECIAL_WORD) && + !b.startsWith(TYPE_SPECIAL_WORD) + ) { + return -1; + } + if ( + !a.startsWith(TYPE_SPECIAL_WORD) && + b.startsWith(TYPE_SPECIAL_WORD) + ) { + return 1; + } + return 0; + }) + .map((group) => ({ + group, + regExp: group.startsWith(TYPE_SPECIAL_WORD) + ? new RegExp(group.replace(TYPE_SPECIAL_WORD, '')) + : new RegExp(group), + })); for (const { group, regExp } of groupWithRegExp) { - if (node.importKind === 'type' && group === THIRD_PARTY_TYPES_SPECIAL_WORD) - return THIRD_PARTY_TYPES_SPECIAL_WORD; - - const matched = node.source.value.match(regExp) !== null; - if (matched) return group; + if (group.startsWith(TYPE_SPECIAL_WORD)) { + if (node.importKind === 'type') { + const matched = node.source.value.match(regExp) !== null; + if (matched) return group; + } + } else { + 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; }; From 2c6d4ac69ce093e002ec1ad8b0ea5666a921faf5 Mon Sep 17 00:00:00 2001 From: Samuel Corsi-House Date: Sat, 14 May 2022 10:55:04 -0400 Subject: [PATCH 3/4] chore: add tests --- src/utils/__tests__/get-sorted-nodes.spec.ts | 70 ++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/utils/__tests__/get-sorted-nodes.spec.ts b/src/utils/__tests__/get-sorted-nodes.spec.ts index d488c92a..42d8063a 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'], + ]); +}); From 0461ba836a94e841ce0d65135cd9f37b9c71d83c Mon Sep 17 00:00:00 2001 From: Samuel Corsi-House Date: Thu, 15 Dec 2022 18:09:44 -0500 Subject: [PATCH 4/4] recommendations --- src/constants.ts | 4 +- src/utils/__tests__/get-sorted-nodes.spec.ts | 2 +- src/utils/get-import-nodes-matched-group.ts | 49 +++++++------------- 3 files changed, 20 insertions(+), 35 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index a1ee5eeb..6c6fc7fd 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -13,8 +13,8 @@ export const newLineCharacters = '\n\n'; */ export const THIRD_PARTY_MODULES_SPECIAL_WORD = ''; -export const THIRD_PARTY_TYPES_SPECIAL_WORD = ''; -export const TYPE_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 42d8063a..6f7e71ea 100644 --- a/src/utils/__tests__/get-sorted-nodes.spec.ts +++ b/src/utils/__tests__/get-sorted-nodes.spec.ts @@ -353,7 +353,7 @@ test('it returns all sorted nodes with types', () => { plugins: ['typescript'], }); const sorted = getSortedNodes(result, { - importOrder: ["", "^[./]", "^[./]"], + importOrder: ["", "^[./]", "^[./]"], importOrderCaseInsensitive: false, importOrderSeparation: false, importOrderGroupNamespaceSpecifiers: false, diff --git a/src/utils/get-import-nodes-matched-group.ts b/src/utils/get-import-nodes-matched-group.ts index d1b6a89f..2173d6f6 100644 --- a/src/utils/get-import-nodes-matched-group.ts +++ b/src/utils/get-import-nodes-matched-group.ts @@ -3,7 +3,7 @@ import { ImportDeclaration } from '@babel/types'; import { THIRD_PARTY_MODULES_SPECIAL_WORD, THIRD_PARTY_TYPES_SPECIAL_WORD, - TYPE_SPECIAL_WORD, + TYPES_SPECIAL_WORD, } from '../constants'; /** @@ -15,39 +15,24 @@ export const getImportNodesMatchedGroup = ( node: ImportDeclaration, importOrder: string[], ) => { - const groupWithRegExp = importOrder - .sort((a, b) => { - if ( - a.startsWith(TYPE_SPECIAL_WORD) && - !b.startsWith(TYPE_SPECIAL_WORD) - ) { - return -1; - } - if ( - !a.startsWith(TYPE_SPECIAL_WORD) && - b.startsWith(TYPE_SPECIAL_WORD) - ) { - return 1; - } - return 0; - }) - .map((group) => ({ - group, - regExp: group.startsWith(TYPE_SPECIAL_WORD) - ? new RegExp(group.replace(TYPE_SPECIAL_WORD, '')) - : new RegExp(group), - })); + const groupWithRegExp = importOrder.map((group) => ({ + 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(TYPE_SPECIAL_WORD)) { - if (node.importKind === 'type') { - const matched = node.source.value.match(regExp) !== null; - if (matched) return group; - } - } else { - const matched = node.source.value.match(regExp) !== null; - if (matched) return group; - } + 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 node.importKind === 'type' &&