diff --git a/README.md b/README.md index 29974a5..6189a53 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Since then more critical features & fixes have been added, and the options have - Do not re-order across side-effect imports - Combine imports from the same source -- Combine type and value imports ([`importOrderCombineTypeAndValueImports`](#importordercombinetypeandvalueimports)) +- Combine type and value imports - Type import grouping with `` keyword - Sorts node.js builtin modules to top - Custom import order separation @@ -31,7 +31,7 @@ Since then more critical features & fixes have been added, and the options have - [How does import sort work?](#how-does-import-sort-work) - [Options](#options) - [`importOrder`](#importorder) - - [`importOrderCombineTypeAndValueImports`](#importordercombinetypeandvalueimports) + - [`importOrderTypeScriptVersion`](#importordertypescriptversion) - [`importOrderParserPlugins`](#importorderparserplugins) - [Prevent imports from being sorted](#prevent-imports-from-being-sorted) - [FAQ / Troubleshooting](#faq--troubleshooting) @@ -129,12 +129,10 @@ module.exports = { semi: true, importOrder: ['^@core/(.*)$', '', '^@server/(.*)$', '', '^@ui/(.*)$', '', '^[./]'], importOrderParserPlugins: ['typescript', 'jsx', 'decorators-legacy'], - importOrderCombineTypeAndValueImports: true, + importOrderTypeScriptVersion: '5.0.0', }; ``` -_Note: all flags are off by default, so explore your options [below](#options)_ - ### How does import sort work? The plugin extracts the imports which are defined in `importOrder`. These imports are considered as _local imports_. @@ -217,27 +215,13 @@ _Note:_ If you want to separate some groups from others, you can add an empty st ], ``` -#### `importOrderCombineTypeAndValueImports` - -**type**: `boolean` - -**default value:** `false` +#### `importOrderTypeScriptVersion` -A boolean value to control merging `import type` expressions into `import {…}`. +**type**: `string` -```diff -- import type { C1 } from 'c'; -- import { C2 } from 'c'; -+ import { type C1, C2 } from "c"; +**default value:** `1.0.0` -- import { D1 } from 'd'; -- import type { D2 } from 'd'; -+ import { D1, type D2 } from "d"; - -- import type { A1 } from 'a'; -- import type { A2 } from 'a'; -+ import type { A1, A2 } from "a"; -``` +When using TypeScript, some import syntax can only be used in newer versions of TypeScript. If you would like to enable modern features like mixed type and value imports, set this option to the semver version string of the TypeScript in use in your project. #### `importOrderParserPlugins` diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md index c8d2aa4..c8f15cf 100644 --- a/docs/MIGRATION.md +++ b/docs/MIGRATION.md @@ -9,6 +9,9 @@ - The `importOrderCaseInsensitive` option has been removed, and imports will always be sorted case-insensitive. - The `importOrderGroupNamespaceSpecifiers` option has been removed. - The `importOrderSortSpecifiers` option has been removed, and specifiers are now always sorted (previous `true` setting) +- The `importOrderMergeDuplicateImports` option has been removed, and imports are always combined (previous `true` setting) +- The `importOrderCombineTypeAndValueImports` option has been removed. See [below](#importOrderCombineTypeAndValueImports-removed) for details +- Added `importOrderTypeScriptVersion` option. #### `importOrderSeparation` removed @@ -38,6 +41,15 @@ Or, if you would like to keep all imports together, but add a newline before sid ] ``` +#### `importOrderCombineTypeAndValueImports` removed + +Combining type and value imports is supported in Flow and TypeScript 4.5.0 and above. To simplify the configuration of the plugin, the explicit setting has been removed. Instead, we will always enable combining these imports when using Flow and have introduced a new option, `importOrderTypeScriptVersion` to control whether or not merging can happen when using TypeScript. + +#### `importOrderTypeScriptVersion` added + +Some import statement syntax can only be used in certain versions of TypeScript. In order to enable these features, such as merging type and value imports, you can specify the version of TypeScript that you're using in your project using this option, which should be a valid semver string. + + ### Migrating from v2.x.x to v3.x.x #### TL;DR diff --git a/package.json b/package.json index fc412a6..6353429 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,8 @@ "@babel/traverse": "^7.17.3", "@babel/types": "^7.17.0", "lodash.clone": "^4.5.0", - "lodash.isequal": "^4.5.0" + "lodash.isequal": "^4.5.0", + "semver": "^7.5.0" }, "devDependencies": { "@types/babel__generator": "^7.6.4", @@ -67,6 +68,7 @@ "@types/lodash.isequal": "4.5.6", "@types/node": "^18.15.13", "@types/prettier": "^2.7.2", + "@types/semver": "^7.3.13", "@vue/compiler-sfc": "3.2.47", "prettier": "2.8.7", "typescript": "5.0.4", diff --git a/prettier.config.js b/prettier.config.js index 3528228..49fb777 100644 --- a/prettier.config.js +++ b/prettier.config.js @@ -7,4 +7,5 @@ module.exports = { semi: true, plugins: [require('./lib/src/index.js')], importOrder: ['', '', '', '^[./]'], + importOrderTypeScriptVersion: '5.0.0', }; diff --git a/src/constants.ts b/src/constants.ts index c33f692..7753550 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,6 +1,6 @@ import { builtinModules } from 'module'; -import { ParserPlugin } from '@babel/parser'; +import type { ParserPlugin } from '@babel/parser'; import { expressionStatement, stringLiteral } from '@babel/types'; export const flow: ParserPlugin = 'flow'; diff --git a/src/index.ts b/src/index.ts index 77dfcd6..e600aa8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -37,12 +37,12 @@ export const options: Record< default: [{ value: ['typescript', 'jsx'] }], description: 'Provide a list of plugins for special syntax', }, - importOrderCombineTypeAndValueImports: { - type: 'boolean', + importOrderTypeScriptVersion: { + type: 'string', category: 'Global', - default: false, + default: '1.0.0', description: - 'Should import-type expressions be merged into import-value expressions?', + 'Version of TypeScript in use in the project. Determines some output syntax when using TypeScript.', }, }; diff --git a/src/preprocessors/preprocessor.ts b/src/preprocessors/preprocessor.ts index 47c4e3d..edc226c 100644 --- a/src/preprocessors/preprocessor.ts +++ b/src/preprocessors/preprocessor.ts @@ -1,6 +1,7 @@ import { parse as babelParser, ParserOptions } from '@babel/parser'; import traverse, { NodePath } from '@babel/traverse'; import { ImportDeclaration, isTSModuleDeclaration } from '@babel/types'; +import semver from 'semver'; import { TYPES_SPECIAL_WORD } from '../constants'; import { PrettierOptions } from '../types'; @@ -10,25 +11,37 @@ import { getSortedNodes } from '../utils/get-sorted-nodes'; export function preprocessor(code: string, options: PrettierOptions): string { const { importOrderParserPlugins, importOrder } = options; + let { importOrderTypeScriptVersion } = options; + const isTSSemverValid = semver.valid(importOrderTypeScriptVersion); - let { importOrderCombineTypeAndValueImports } = options; - - if ( - importOrderCombineTypeAndValueImports && - importOrder.some((group) => group.includes(TYPES_SPECIAL_WORD)) - ) { + if (!isTSSemverValid) { console.warn( - `[@ianvs/prettier-plugin-sort-imports]: The option importOrderCombineTypeAndValueImports will have no effect since ${TYPES_SPECIAL_WORD} is used in importOrder.`, + `[@ianvs/prettier-plugin-sort-imports]: The option importOrderTypeScriptVersion is not a valid semver version and will be ignored.`, ); - importOrderCombineTypeAndValueImports = false; + importOrderTypeScriptVersion = '1.0.0'; } + // Do not combine type and value imports if `` is specified explicitly + let importOrderCombineTypeAndValueImports = importOrder.some((group) => + group.includes(TYPES_SPECIAL_WORD), + ) + ? false + : true; + const allOriginalImportNodes: ImportDeclaration[] = []; const parserOptions: ParserOptions = { sourceType: 'module', plugins: getExperimentalParserPlugins(importOrderParserPlugins), }; + // Disable importOrderCombineTypeAndValueImports if typescript is not set to a version that supports it + if ( + parserOptions.plugins?.includes('typescript') && + semver.lt(importOrderTypeScriptVersion, '4.5.0') + ) { + importOrderCombineTypeAndValueImports = false; + } + const ast = babelParser(code, parserOptions); const directives = ast.program.directives; diff --git a/src/types.ts b/src/types.ts index 39e4e2a..6175b84 100644 --- a/src/types.ts +++ b/src/types.ts @@ -32,10 +32,9 @@ export type ImportOrLine = ImportDeclaration | ExpressionStatement; export type GetSortedNodes = ( nodes: ImportDeclaration[], - options: Pick< - PrettierOptions, - 'importOrder' | 'importOrderCombineTypeAndValueImports' - >, + options: Pick & { + importOrderCombineTypeAndValueImports: boolean; + }, ) => ImportOrLine[]; export type GetChunkTypeOfNode = (node: ImportDeclaration) => ChunkType; diff --git a/src/utils/__tests__/get-all-comments-from-nodes.spec.ts b/src/utils/__tests__/get-all-comments-from-nodes.spec.ts index cf34eb8..0a4dfc6 100644 --- a/src/utils/__tests__/get-all-comments-from-nodes.spec.ts +++ b/src/utils/__tests__/get-all-comments-from-nodes.spec.ts @@ -1,5 +1,9 @@ -import { ParserOptions } from '@babel/parser'; -import { CommentBlock, CommentLine, ImportDeclaration } from '@babel/types'; +import type { ParserOptions } from '@babel/parser'; +import type { + CommentBlock, + CommentLine, + ImportDeclaration, +} from '@babel/types'; import { expect, test } from 'vitest'; import { getAllCommentsFromNodes } from '../get-all-comments-from-nodes'; @@ -11,7 +15,7 @@ const getSortedImportNodes = (code: string, options?: ParserOptions) => { return getSortedNodes(importNodes, { importOrder: [], - importOrderCombineTypeAndValueImports: false, + importOrderCombineTypeAndValueImports: true, }); }; diff --git a/src/utils/__tests__/get-code-from-ast.spec.ts b/src/utils/__tests__/get-code-from-ast.spec.ts index 723c29a..b973dbe 100644 --- a/src/utils/__tests__/get-code-from-ast.spec.ts +++ b/src/utils/__tests__/get-code-from-ast.spec.ts @@ -18,7 +18,7 @@ import a from 'a'; const importNodes = getImportNodes(code); const sortedNodes = getSortedNodes(importNodes, { importOrder: [], - importOrderCombineTypeAndValueImports: false, + importOrderCombineTypeAndValueImports: true, }); const formatted = getCodeFromAst({ nodesToOutput: sortedNodes, @@ -54,7 +54,7 @@ import type {See} from 'c'; const importNodes = getImportNodes(code, { plugins: ['typescript'] }); const sortedNodes = getSortedNodes(importNodes, { importOrder: [], - importOrderCombineTypeAndValueImports: false, + importOrderCombineTypeAndValueImports: true, }); const formatted = getCodeFromAst({ nodesToOutput: sortedNodes, @@ -66,8 +66,7 @@ import type {See} from 'c'; `// first comment // second comment import a, { b, type Bee } from "a"; -import c from "c"; -import type { C, See } from "c"; +import c, { type C, type See } from "c"; import g from "g"; import k from "k"; import t from "t"; diff --git a/src/utils/__tests__/get-sorted-nodes-by-import-order.spec.ts b/src/utils/__tests__/get-sorted-nodes-by-import-order.spec.ts index 67cb157..cb54e21 100644 --- a/src/utils/__tests__/get-sorted-nodes-by-import-order.spec.ts +++ b/src/utils/__tests__/get-sorted-nodes-by-import-order.spec.ts @@ -1,4 +1,4 @@ -import { ImportDeclaration } from '@babel/types'; +import type { ImportDeclaration } from '@babel/types'; import { expect, test } from 'vitest'; import { getImportNodes } from '../get-import-nodes'; @@ -29,7 +29,7 @@ test('it returns all sorted nodes', () => { const result = getImportNodes(code); const sorted = getSortedNodesByImportOrder(result, { importOrder: ['^[./]'], - importOrderCombineTypeAndValueImports: false, + importOrderCombineTypeAndValueImports: true, }) as ImportDeclaration[]; expect(getSortedNodesNamesAndNewlines(sorted)).toEqual([ @@ -78,7 +78,7 @@ test('it returns all sorted nodes with sort order', () => { const result = getImportNodes(code); const sorted = getSortedNodesByImportOrder(result, { importOrder: ['^a$', '^t$', '^k$', '^B', '^[./]'], - importOrderCombineTypeAndValueImports: false, + importOrderCombineTypeAndValueImports: true, }) as ImportDeclaration[]; expect(getSortedNodesNamesAndNewlines(sorted)).toEqual([ 'node:fs/promises', @@ -134,7 +134,7 @@ import {type B, A} from 'z'; }); const sorted = getSortedNodesByImportOrder(result, { importOrder: ['^[./]'], - importOrderCombineTypeAndValueImports: false, + importOrderCombineTypeAndValueImports: true, }) as ImportDeclaration[]; expect(getSortedNodesNamesAndNewlines(sorted)).toEqual(['k', 't', 'z']); expect( @@ -154,7 +154,7 @@ test('it returns all sorted nodes with builtin specifiers at the top', () => { const result = getImportNodes(code); const sorted = getSortedNodesByImportOrder(result, { importOrder: ['^[./]'], - importOrderCombineTypeAndValueImports: false, + importOrderCombineTypeAndValueImports: true, }) as ImportDeclaration[]; expect(getSortedNodesNamesAndNewlines(sorted)).toEqual([ @@ -180,7 +180,7 @@ test('it returns all sorted nodes with custom third party modules and builtins a const result = getImportNodes(code); const sorted = getSortedNodesByImportOrder(result, { importOrder: ['^a$', '', '^t$', '^k$', '^[./]'], - importOrderCombineTypeAndValueImports: false, + importOrderCombineTypeAndValueImports: true, }) as ImportDeclaration[]; expect(getSortedNodesNamesAndNewlines(sorted)).toEqual([ 'node:fs/promises', @@ -212,7 +212,7 @@ test('it returns all sorted nodes with custom separation', () => { '^k$', '^[./]', ], - importOrderCombineTypeAndValueImports: false, + importOrderCombineTypeAndValueImports: true, }) as ImportDeclaration[]; expect(getSortedNodesNamesAndNewlines(sorted)).toEqual([ 'node:fs/promises', @@ -247,7 +247,7 @@ test('it does not add multiple custom import separators', () => { '^k$', '^[./]', ], - importOrderCombineTypeAndValueImports: false, + importOrderCombineTypeAndValueImports: true, }) as ImportDeclaration[]; expect(getSortedNodesNamesAndNewlines(sorted)).toEqual([ 'node:fs/promises', diff --git a/src/utils/__tests__/get-sorted-nodes.spec.ts b/src/utils/__tests__/get-sorted-nodes.spec.ts index 63660d1..8ad7598 100644 --- a/src/utils/__tests__/get-sorted-nodes.spec.ts +++ b/src/utils/__tests__/get-sorted-nodes.spec.ts @@ -1,4 +1,4 @@ -import { ImportDeclaration } from '@babel/types'; +import type { ImportDeclaration } from '@babel/types'; import { expect, test } from 'vitest'; import { getImportNodes } from '../get-import-nodes'; @@ -30,7 +30,7 @@ test('it returns all sorted nodes, preserving the order side effect nodes', () = const result = getImportNodes(code); const sorted = getSortedNodes(result, { importOrder: [], - importOrderCombineTypeAndValueImports: false, + importOrderCombineTypeAndValueImports: true, }) as ImportDeclaration[]; expect(getSortedNodesNamesAndNewlines(sorted)).toEqual([ 'se3', diff --git a/src/utils/__tests__/merge-nodes-with-matching-flavors.spec.ts b/src/utils/__tests__/merge-nodes-with-matching-flavors.spec.ts index 54c9e64..71e95f0 100644 --- a/src/utils/__tests__/merge-nodes-with-matching-flavors.spec.ts +++ b/src/utils/__tests__/merge-nodes-with-matching-flavors.spec.ts @@ -7,7 +7,7 @@ import { getSortedNodes } from '../get-sorted-nodes'; const defaultOptions = { importOrder: [''], // Separate side-effect and ignored chunks, for easier test readability - importOrderCombineTypeAndValueImports: false, + importOrderCombineTypeAndValueImports: true, }; test('should merge duplicate imports within a given chunk', () => { @@ -43,10 +43,10 @@ test('should merge duplicate imports within a given chunk', () => { plugins: ['typescript'], }); - const nodesToOutput = getSortedNodes(allOriginalImportNodes, { - ...defaultOptions, - importOrderCombineTypeAndValueImports: false, - }); + const nodesToOutput = getSortedNodes( + allOriginalImportNodes, + defaultOptions, + ); const formatted = getCodeFromAst({ nodesToOutput, allOriginalImportNodes, @@ -61,8 +61,7 @@ import { Junk } from "junk-group-1"; import "./side-effects1"; // C, E and D will be separated from A, B because side-effects in-between -import type { C, E } from "a"; -import { D } from "a"; +import { D, type C, type E } from "a"; // prettier-ignore import type { NoMerge1 } from "a"; @@ -102,10 +101,10 @@ test('should merge type imports into regular imports', () => { plugins: ['typescript'], }); - const nodesToOutput = getSortedNodes(allOriginalImportNodes, { - ...defaultOptions, - importOrderCombineTypeAndValueImports: true, - }); + const nodesToOutput = getSortedNodes( + allOriginalImportNodes, + defaultOptions, + ); const formatted = getCodeFromAst({ nodesToOutput, allOriginalImportNodes, @@ -134,10 +133,10 @@ import defaultValue from './source'; plugins: ['typescript'], }); - const nodesToOutput = getSortedNodes(allOriginalImportNodes, { - ...defaultOptions, - importOrderCombineTypeAndValueImports: true, - }); + const nodesToOutput = getSortedNodes( + allOriginalImportNodes, + defaultOptions, + ); const formatted = getCodeFromAst({ nodesToOutput, allOriginalImportNodes, @@ -159,10 +158,10 @@ import * as Namespace from './source'; plugins: ['typescript'], }); - const nodesToOutput = getSortedNodes(allOriginalImportNodes, { - ...defaultOptions, - importOrderCombineTypeAndValueImports: true, - }); + const nodesToOutput = getSortedNodes( + allOriginalImportNodes, + defaultOptions, + ); const formatted = getCodeFromAst({ nodesToOutput, allOriginalImportNodes, @@ -185,10 +184,10 @@ import {value as alias} from './source'; plugins: ['typescript'], }); - const nodesToOutput = getSortedNodes(allOriginalImportNodes, { - ...defaultOptions, - importOrderCombineTypeAndValueImports: true, - }); + const nodesToOutput = getSortedNodes( + allOriginalImportNodes, + defaultOptions, + ); const formatted = getCodeFromAst({ nodesToOutput, allOriginalImportNodes, @@ -210,10 +209,10 @@ import {value, SecondValue} from './source'; plugins: ['typescript'], }); - const nodesToOutput = getSortedNodes(allOriginalImportNodes, { - ...defaultOptions, - importOrderCombineTypeAndValueImports: true, - }); + const nodesToOutput = getSortedNodes( + allOriginalImportNodes, + defaultOptions, + ); const formatted = getCodeFromAst({ nodesToOutput, allOriginalImportNodes, @@ -237,10 +236,10 @@ import {otherValue} from './other'; plugins: ['typescript'], }); - const nodesToOutput = getSortedNodes(allOriginalImportNodes, { - ...defaultOptions, - importOrderCombineTypeAndValueImports: true, - }); + const nodesToOutput = getSortedNodes( + allOriginalImportNodes, + defaultOptions, + ); const formatted = getCodeFromAst({ nodesToOutput, allOriginalImportNodes, @@ -265,10 +264,10 @@ import {SecondValue} from './source'; plugins: ['typescript'], }); - const nodesToOutput = getSortedNodes(allOriginalImportNodes, { - ...defaultOptions, - importOrderCombineTypeAndValueImports: true, - }); + const nodesToOutput = getSortedNodes( + allOriginalImportNodes, + defaultOptions, + ); const formatted = getCodeFromAst({ nodesToOutput, allOriginalImportNodes, @@ -292,10 +291,10 @@ import {value} from './source'; plugins: ['typescript'], }); - const nodesToOutput = getSortedNodes(allOriginalImportNodes, { - ...defaultOptions, - importOrderCombineTypeAndValueImports: true, - }); + const nodesToOutput = getSortedNodes( + allOriginalImportNodes, + defaultOptions, + ); const formatted = getCodeFromAst({ nodesToOutput, allOriginalImportNodes, @@ -319,10 +318,10 @@ test('should not combine default type imports', () => { plugins: ['typescript'], }); - const nodesToOutput = getSortedNodes(allOriginalImportNodes, { - ...defaultOptions, - importOrderCombineTypeAndValueImports: true, - }); + const nodesToOutput = getSortedNodes( + allOriginalImportNodes, + defaultOptions, + ); const formatted = getCodeFromAst({ nodesToOutput, allOriginalImportNodes, diff --git a/src/utils/__tests__/remove-nodes-from-original-code.spec.ts b/src/utils/__tests__/remove-nodes-from-original-code.spec.ts index e8d0115..8c4e452 100644 --- a/src/utils/__tests__/remove-nodes-from-original-code.spec.ts +++ b/src/utils/__tests__/remove-nodes-from-original-code.spec.ts @@ -24,7 +24,7 @@ test('it should remove nodes from the original code', () => { const importNodes = getImportNodes(code); const sortedNodes = getSortedNodes(importNodes, { importOrder: [], - importOrderCombineTypeAndValueImports: false, + importOrderCombineTypeAndValueImports: true, }); const allCommentsFromImports = getAllCommentsFromNodes(sortedNodes); diff --git a/src/utils/adjust-comments-on-sorted-nodes.ts b/src/utils/adjust-comments-on-sorted-nodes.ts index 3bfc3c9..20aadf2 100644 --- a/src/utils/adjust-comments-on-sorted-nodes.ts +++ b/src/utils/adjust-comments-on-sorted-nodes.ts @@ -1,4 +1,8 @@ -import { addComments, ImportDeclaration, removeComments } from '@babel/types'; +import { + addComments, + removeComments, + type ImportDeclaration, +} from '@babel/types'; import clone from 'lodash.clone'; import isEqual from 'lodash.isequal'; diff --git a/src/utils/get-all-comments-from-nodes.ts b/src/utils/get-all-comments-from-nodes.ts index 9202012..b84644c 100644 --- a/src/utils/get-all-comments-from-nodes.ts +++ b/src/utils/get-all-comments-from-nodes.ts @@ -1,4 +1,9 @@ -import { CommentBlock, CommentLine, Directive, Statement } from '@babel/types'; +import type { + CommentBlock, + CommentLine, + Directive, + Statement, +} from '@babel/types'; export const getAllCommentsFromNodes = (nodes: (Directive | Statement)[]) => nodes.reduce((acc, node) => { diff --git a/src/utils/get-chunk-type-of-node.ts b/src/utils/get-chunk-type-of-node.ts index 4bc264d..8bf4914 100644 --- a/src/utils/get-chunk-type-of-node.ts +++ b/src/utils/get-chunk-type-of-node.ts @@ -1,5 +1,5 @@ import { chunkTypeOther, chunkTypeUnsortable } from '../constants'; -import { GetChunkTypeOfNode } from '../types'; +import type { GetChunkTypeOfNode } from '../types'; import { hasIgnoreNextNode } from './has-ignore-next-node'; /** diff --git a/src/utils/get-code-from-ast.ts b/src/utils/get-code-from-ast.ts index 69cb9ab..6e5a097 100644 --- a/src/utils/get-code-from-ast.ts +++ b/src/utils/get-code-from-ast.ts @@ -1,5 +1,10 @@ import generate from '@babel/generator'; -import { Directive, file, InterpreterDirective, Statement } from '@babel/types'; +import { + file, + type Directive, + type InterpreterDirective, + type Statement, +} from '@babel/types'; import { newLineCharacters } from '../constants'; import { getAllCommentsFromNodes } from './get-all-comments-from-nodes'; diff --git a/src/utils/get-experimental-parser-plugins.ts b/src/utils/get-experimental-parser-plugins.ts index 954c370..516476f 100644 --- a/src/utils/get-experimental-parser-plugins.ts +++ b/src/utils/get-experimental-parser-plugins.ts @@ -1,4 +1,4 @@ -import { ParserPlugin, ParserPluginWithOptions } from '@babel/parser'; +import type { ParserPlugin, ParserPluginWithOptions } from '@babel/parser'; /** * Returns a list of babel parser plugin names diff --git a/src/utils/get-import-nodes-matched-group.ts b/src/utils/get-import-nodes-matched-group.ts index 8dd8eea..3d9a718 100644 --- a/src/utils/get-import-nodes-matched-group.ts +++ b/src/utils/get-import-nodes-matched-group.ts @@ -1,4 +1,4 @@ -import { ImportDeclaration } from '@babel/types'; +import type { ImportDeclaration } from '@babel/types'; import { THIRD_PARTY_MODULES_SPECIAL_WORD, diff --git a/src/utils/get-import-nodes.ts b/src/utils/get-import-nodes.ts index 8fca771..4bcc0f6 100644 --- a/src/utils/get-import-nodes.ts +++ b/src/utils/get-import-nodes.ts @@ -1,5 +1,5 @@ -import { parse as babelParser, ParserOptions } from '@babel/parser'; -import traverse, { NodePath } from '@babel/traverse'; +import { parse as babelParser, type ParserOptions } from '@babel/parser'; +import traverse, { type NodePath } from '@babel/traverse'; import { ImportDeclaration, isTSModuleDeclaration } from '@babel/types'; export const getImportNodes = ( diff --git a/src/utils/get-sorted-import-specifiers.ts b/src/utils/get-sorted-import-specifiers.ts index d8dc3ec..7df83c5 100644 --- a/src/utils/get-sorted-import-specifiers.ts +++ b/src/utils/get-sorted-import-specifiers.ts @@ -1,4 +1,4 @@ -import { ImportDeclaration } from '@babel/types'; +import { type ImportDeclaration } from '@babel/types'; import { naturalSort } from '../natural-sort'; diff --git a/src/utils/get-sorted-nodes-by-import-order.ts b/src/utils/get-sorted-nodes-by-import-order.ts index ea33432..0d18187 100644 --- a/src/utils/get-sorted-nodes-by-import-order.ts +++ b/src/utils/get-sorted-nodes-by-import-order.ts @@ -5,7 +5,7 @@ import { newLineNode, THIRD_PARTY_MODULES_SPECIAL_WORD, } from '../constants'; -import { GetSortedNodes, ImportGroups, ImportOrLine } from '../types'; +import type { GetSortedNodes, ImportGroups, ImportOrLine } from '../types'; import { getImportNodesMatchedGroup } from './get-import-nodes-matched-group'; import { getSortedImportSpecifiers } from './get-sorted-import-specifiers'; import { getSortedNodesGroup } from './get-sorted-nodes-group'; diff --git a/src/utils/get-sorted-nodes-group.ts b/src/utils/get-sorted-nodes-group.ts index d54e6ef..da58f36 100644 --- a/src/utils/get-sorted-nodes-group.ts +++ b/src/utils/get-sorted-nodes-group.ts @@ -1,4 +1,4 @@ -import { ImportDeclaration } from '@babel/types'; +import type { ImportDeclaration } from '@babel/types'; import { naturalSort } from '../natural-sort'; diff --git a/src/utils/get-sorted-nodes-modules-names.ts b/src/utils/get-sorted-nodes-modules-names.ts index 2aaf98f..3000a3d 100644 --- a/src/utils/get-sorted-nodes-modules-names.ts +++ b/src/utils/get-sorted-nodes-modules-names.ts @@ -1,4 +1,4 @@ -import { +import type { ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, diff --git a/src/utils/get-sorted-nodes-names-and-newlines.ts b/src/utils/get-sorted-nodes-names-and-newlines.ts index c5d1713..6ae3495 100644 --- a/src/utils/get-sorted-nodes-names-and-newlines.ts +++ b/src/utils/get-sorted-nodes-names-and-newlines.ts @@ -1,4 +1,4 @@ -import { ExpressionStatement, ImportDeclaration } from '@babel/types'; +import type { ExpressionStatement, ImportDeclaration } from '@babel/types'; /** * Test helper, to verify sort order and newline placement diff --git a/src/utils/get-sorted-nodes.ts b/src/utils/get-sorted-nodes.ts index 8ce82cd..d899152 100644 --- a/src/utils/get-sorted-nodes.ts +++ b/src/utils/get-sorted-nodes.ts @@ -3,7 +3,7 @@ import { newLineNode, TYPES_SPECIAL_WORD, } from '../constants'; -import { GetSortedNodes, ImportChunk, ImportOrLine } from '../types'; +import type { GetSortedNodes, ImportChunk, ImportOrLine } from '../types'; import { adjustCommentsOnSortedNodes } from './adjust-comments-on-sorted-nodes'; import { explodeTypeAndValueSpecifiers } from './explode-type-and-value-specifiers'; import { getChunkTypeOfNode } from './get-chunk-type-of-node'; diff --git a/src/utils/remove-nodes-from-original-code.ts b/src/utils/remove-nodes-from-original-code.ts index c31c480..8c933da 100644 --- a/src/utils/remove-nodes-from-original-code.ts +++ b/src/utils/remove-nodes-from-original-code.ts @@ -1,4 +1,4 @@ -import { +import type { CommentBlock, CommentLine, Directive, diff --git a/tests/Flow/ppsi.spec.ts b/tests/Flow/ppsi.spec.ts index a58e87d..2f0c024 100644 --- a/tests/Flow/ppsi.spec.ts +++ b/tests/Flow/ppsi.spec.ts @@ -3,5 +3,4 @@ import {run_spec} from '../../test-setup/run_spec'; run_spec(__dirname, ['flow'], { importOrder: ['^@core/(.*)$', '^@server/(.*)', '^@ui/(.*)$', '^[./]'], importOrderParserPlugins: ['flow'], - importOrderCombineTypeAndValueImports: true, }); diff --git a/tests/Typescript/__snapshots__/ppsi.spec.ts.snap b/tests/Typescript/__snapshots__/ppsi.spec.ts.snap index 71572bc..ea34743 100644 --- a/tests/Typescript/__snapshots__/ppsi.spec.ts.snap +++ b/tests/Typescript/__snapshots__/ppsi.spec.ts.snap @@ -168,8 +168,19 @@ export class AppComponent extends BaseComponent { exports[`imports-with-type-and-value-imports.js - typescript-verify > imports-with-type-and-value-imports.js 1`] = ` import type {Foo} from './foo'; import {fooValue} from './foo'; + +import def from './bar'; +import type {Bar} from './bar'; + +import * as namespace from './baz' +import type {Baz} from './bar'; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -import { fooValue, type Foo } from "./foo"; +import def from "./bar"; +import type { Bar, Baz } from "./bar"; +import * as namespace from "./baz"; +import type { Foo } from "./foo"; +import { fooValue } from "./foo"; `; diff --git a/tests/Typescript/imports-with-type-and-value-imports.js b/tests/Typescript/imports-with-type-and-value-imports.js index 07b2c6f..d54440f 100644 --- a/tests/Typescript/imports-with-type-and-value-imports.js +++ b/tests/Typescript/imports-with-type-and-value-imports.js @@ -1,2 +1,9 @@ import type {Foo} from './foo'; import {fooValue} from './foo'; + +import def from './bar'; +import type {Bar} from './bar'; + +import * as namespace from './baz' +import type {Baz} from './bar'; + diff --git a/tests/Typescript/ppsi.spec.ts b/tests/Typescript/ppsi.spec.ts index 51ad14c..1f3121c 100644 --- a/tests/Typescript/ppsi.spec.ts +++ b/tests/Typescript/ppsi.spec.ts @@ -3,5 +3,4 @@ import {run_spec} from '../../test-setup/run_spec'; run_spec(__dirname, ["typescript"], { importOrder: ['^@core/(.*)$', '^@server/(.*)', '^@ui/(.*)$', '^[./]'], importOrderParserPlugins : ['typescript', 'decorators-legacy', 'classProperties'], - importOrderCombineTypeAndValueImports: true, }); diff --git a/tests/TypescriptModern/__snapshots__/ppsi.spec.ts.snap b/tests/TypescriptModern/__snapshots__/ppsi.spec.ts.snap new file mode 100644 index 0000000..b413472 --- /dev/null +++ b/tests/TypescriptModern/__snapshots__/ppsi.spec.ts.snap @@ -0,0 +1,18 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`imports-with-type-and-value-imports.js - typescript-verify > imports-with-type-and-value-imports.js 1`] = ` +import type {Foo} from './foo'; +import {fooValue} from './foo'; + +import def from './bar'; +import type {Bar} from './bar'; + +import * as namespace from './baz' +import type {Baz} from './bar'; + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import def, { type Bar, type Baz } from "./bar"; +import * as namespace from "./baz"; +import { fooValue, type Foo } from "./foo"; + +`; diff --git a/tests/TypescriptModern/imports-with-type-and-value-imports.js b/tests/TypescriptModern/imports-with-type-and-value-imports.js new file mode 100644 index 0000000..d54440f --- /dev/null +++ b/tests/TypescriptModern/imports-with-type-and-value-imports.js @@ -0,0 +1,9 @@ +import type {Foo} from './foo'; +import {fooValue} from './foo'; + +import def from './bar'; +import type {Bar} from './bar'; + +import * as namespace from './baz' +import type {Baz} from './bar'; + diff --git a/tests/TypescriptModern/ppsi.spec.ts b/tests/TypescriptModern/ppsi.spec.ts new file mode 100644 index 0000000..e4fbd43 --- /dev/null +++ b/tests/TypescriptModern/ppsi.spec.ts @@ -0,0 +1,7 @@ +import {run_spec} from '../../test-setup/run_spec'; + +run_spec(__dirname, ["typescript"], { + importOrder: ['^@core/(.*)$', '^@server/(.*)', '^@ui/(.*)$', '^[./]'], + importOrderParserPlugins : ['typescript', 'decorators-legacy', 'classProperties'], + importOrderTypeScriptVersion: '4.5.0', +}); diff --git a/types/index.d.ts b/types/index.d.ts index c6064c2..56735b5 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -39,25 +39,9 @@ export interface PluginConfig { importOrder?: string[]; /** - * A boolean value to control merging `import type` expressions into `import {…}`. * - * ```diff - * - import type { C1 } from 'c'; - * - import { C2 } from 'c'; - * + import { type C1, C2 } from "c"; - * - * - import { D1 } from 'd'; - * - import type { D2 } from 'd'; - * + import { D1, type D2 } from "d"; - * - * - import type { A1 } from 'a'; - * - import type { A2 } from 'a'; - * + import type { A1, A2 } from "a"; - * ``` - * - * @default false */ - importOrderCombineTypeAndValueImports?: boolean; + importOrderTypeScriptVersion?: string; /** * A collection of plugins for babel parser. The plugin passes this list to babel parser, so it can understand the syntaxes diff --git a/yarn.lock b/yarn.lock index ff64750..466eddf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -390,6 +390,11 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.2.tgz#6c2324641cc4ba050a8c710b2b251b377581fbf0" integrity sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg== +"@types/semver@^7.3.13": + version "7.3.13" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" + integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== + "@vitest/expect@0.30.1": version "0.30.1" resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-0.30.1.tgz#3c92a3fc23a198315ce8cd16689dc2d5aeac40b8" @@ -721,9 +726,6 @@ has-flag@^3.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - resolved "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz" - integrity sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k= - js-string-escape@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" @@ -926,7 +928,7 @@ semver@^6.3.0: resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.2: +semver@^7.3.2, semver@^7.5.0: version "7.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.0.tgz#ed8c5dc8efb6c629c88b23d41dc9bf40c1d96cd0" integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==