-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Closes #35 Adapted from trivago/prettier-plugin-sort-imports#153, by @Xenfo. This adds a new special string, `<TYPES>` that can be added to the `importOrder` array. When used, it will cause type imports to be sorted as specified by its location in the array. Notes: - If it is used, it will disable `importOrderCombineTypeAndValueImports`, throwing a warning if both are used. This is because: - We will split apart type and value import declarations if `<TYPES>` is used, so that types can be sorted appropriately. - Thinking towards the next breaking change when we remove options, I think the default will be to enable `importOrderCombineTypeAndValueImports`, and this change will give users a good way to opt-out of that behavior if they want, by specifying the location for `<TYPES>`.
- Loading branch information
Showing
13 changed files
with
325 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
126 changes: 126 additions & 0 deletions
126
src/utils/__tests__/explode-type-and-value-specifiers.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import { explodeTypeAndValueSpecifiers } from '../explode-type-and-value-specifiers'; | ||
import { getCodeFromAst } from '../get-code-from-ast'; | ||
import { getImportNodes } from '../get-import-nodes'; | ||
|
||
test('it should return a default value import unchanged', () => { | ||
const code = `import Default from './source';`; | ||
const importNodes = getImportNodes(code); | ||
const explodedNodes = explodeTypeAndValueSpecifiers(importNodes); | ||
const formatted = getCodeFromAst({ | ||
nodesToOutput: explodedNodes, | ||
originalCode: code, | ||
directives: [], | ||
}); | ||
expect(formatted).toEqual(`import Default from './source';`); | ||
}); | ||
|
||
test('it should return a default value and namespace import unchanged', () => { | ||
const code = `import Default, * as Namespace from './source';`; | ||
const importNodes = getImportNodes(code); | ||
const explodedNodes = explodeTypeAndValueSpecifiers(importNodes); | ||
const formatted = getCodeFromAst({ | ||
nodesToOutput: explodedNodes, | ||
originalCode: code, | ||
directives: [], | ||
}); | ||
expect(formatted).toEqual( | ||
`import Default, * as Namespace from './source';`, | ||
); | ||
}); | ||
|
||
test('it should return default and namespaced value imports unchanged', () => { | ||
const code = `import Default, { named } from './source';`; | ||
const importNodes = getImportNodes(code); | ||
const explodedNodes = explodeTypeAndValueSpecifiers(importNodes); | ||
const formatted = getCodeFromAst({ | ||
nodesToOutput: explodedNodes, | ||
originalCode: code, | ||
directives: [], | ||
}); | ||
expect(formatted).toEqual(`import Default, { named } from './source';`); | ||
}); | ||
|
||
test('it should return default type imports unchanged', () => { | ||
const code = `import type DefaultType from './source';`; | ||
const importNodes = getImportNodes(code, { plugins: ['typescript'] }); | ||
const explodedNodes = explodeTypeAndValueSpecifiers(importNodes); | ||
const formatted = getCodeFromAst({ | ||
nodesToOutput: explodedNodes, | ||
originalCode: code, | ||
directives: [], | ||
}); | ||
expect(formatted).toEqual(`import type DefaultType from './source';`); | ||
}); | ||
|
||
test('it should return namespace type imports unchanged', () => { | ||
const code = `import type * as NamespaceType from './source';`; | ||
const importNodes = getImportNodes(code, { plugins: ['typescript'] }); | ||
const explodedNodes = explodeTypeAndValueSpecifiers(importNodes); | ||
const formatted = getCodeFromAst({ | ||
nodesToOutput: explodedNodes, | ||
originalCode: code, | ||
directives: [], | ||
}); | ||
expect(formatted).toEqual( | ||
`import type * as NamespaceType from './source';`, | ||
); | ||
}); | ||
|
||
test('it should return named type imports unchanged', () => { | ||
const code = `import type { NamedType1, NamedType2 } from './source';`; | ||
const importNodes = getImportNodes(code, { plugins: ['typescript'] }); | ||
const explodedNodes = explodeTypeAndValueSpecifiers(importNodes); | ||
const formatted = getCodeFromAst({ | ||
nodesToOutput: explodedNodes, | ||
originalCode: code, | ||
directives: [], | ||
}); | ||
expect(formatted).toEqual( | ||
`import type { NamedType1, NamedType2 } from './source';`, | ||
); | ||
}); | ||
|
||
test('it should separate named type and value imports', () => { | ||
const code = `import { named, type NamedType } from './source';`; | ||
const importNodes = getImportNodes(code, { plugins: ['typescript'] }); | ||
const explodedNodes = explodeTypeAndValueSpecifiers(importNodes); | ||
const formatted = getCodeFromAst({ | ||
nodesToOutput: explodedNodes, | ||
originalCode: code, | ||
directives: [], | ||
}); | ||
expect(formatted).toEqual( | ||
`import { named } from './source'; | ||
import type { NamedType } from './source';`, | ||
); | ||
}); | ||
|
||
test('it should separate named type and default value imports', () => { | ||
const code = `import Default, { type NamedType } from './source';`; | ||
const importNodes = getImportNodes(code, { plugins: ['typescript'] }); | ||
const explodedNodes = explodeTypeAndValueSpecifiers(importNodes); | ||
const formatted = getCodeFromAst({ | ||
nodesToOutput: explodedNodes, | ||
originalCode: code, | ||
directives: [], | ||
}); | ||
expect(formatted).toEqual( | ||
`import Default from './source'; | ||
import type { NamedType } from './source';`, | ||
); | ||
}); | ||
|
||
test('it should separate named type and default and named value imports', () => { | ||
const code = `import Default, { named, type NamedType } from './source';`; | ||
const importNodes = getImportNodes(code, { plugins: ['typescript'] }); | ||
const explodedNodes = explodeTypeAndValueSpecifiers(importNodes); | ||
const formatted = getCodeFromAst({ | ||
nodesToOutput: explodedNodes, | ||
originalCode: code, | ||
directives: [], | ||
}); | ||
expect(formatted).toEqual( | ||
`import Default, { named } from './source'; | ||
import type { NamedType } from './source';`, | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { importDeclaration, type ImportSpecifier } from '@babel/types'; | ||
|
||
import { ExplodeTypeAndValueSpecifiers } from '../types'; | ||
|
||
/** | ||
* Breaks apart import declarations containing mixed type and value imports into separate declarations. | ||
* | ||
* e.g. | ||
* | ||
* ```diff | ||
* - import foo, { bar, type Baz } from './source'; | ||
* + import foo, { bar } from './source'; | ||
* + import type { Baz } from './source'; | ||
* ``` | ||
*/ | ||
export const explodeTypeAndValueSpecifiers: ExplodeTypeAndValueSpecifiers = ( | ||
nodes, | ||
) => { | ||
const explodedNodes = []; | ||
|
||
for (const node of nodes) { | ||
// We don't need to explode type imports, they won't mix type and value | ||
if (node.importKind === 'type') { | ||
explodedNodes.push(node); | ||
continue; | ||
} | ||
|
||
// Nothing to do if there's only one specifier | ||
if (node.specifiers.length <= 1) { | ||
explodedNodes.push(node); | ||
continue; | ||
} | ||
|
||
// @ts-expect-error TS is not refining correctly, but we're checking the type | ||
const typeImports: ImportSpecifier[] = node.specifiers.filter( | ||
(i) => i.type === 'ImportSpecifier' && i.importKind === 'type', | ||
); | ||
|
||
// If we have a mix of type and value imports, we need to 'splode them into two import declarations | ||
if (typeImports.length) { | ||
const valueImports = node.specifiers.filter( | ||
(i) => | ||
!(i.type === 'ImportSpecifier' && i.importKind === 'type'), | ||
); | ||
const newValueNode = importDeclaration(valueImports, node.source); | ||
explodedNodes.push(newValueNode); | ||
|
||
// Change the importKind of the specifiers, to avoid `import type {type Foo} from 'foo'` | ||
typeImports.forEach( | ||
(specifier) => (specifier.importKind = 'value'), | ||
); | ||
const newTypeNode = importDeclaration(typeImports, node.source); | ||
newTypeNode.importKind = 'type'; | ||
explodedNodes.push(newTypeNode); | ||
continue; | ||
} | ||
|
||
// Just a boring old values-only node | ||
explodedNodes.push(node); | ||
} | ||
return explodedNodes; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`imports-with-mixed-declarations.ts - typescript-verify: imports-with-mixed-declarations.ts 1`] = ` | ||
import a, {type LocalType} from './local-file'; | ||
import value, {tp} from 'third-party'; | ||
import {specifier, type ThirdPartyType} from 'third-party'; | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
import type { ThirdPartyType } from "third-party"; | ||
import value, { tp, specifier } from "third-party"; | ||
import type { LocalType } from "./local-file"; | ||
import a from "./local-file"; | ||
`; | ||
|
||
exports[`imports-with-third-party-types.ts - typescript-verify: imports-with-third-party-types.ts 1`] = ` | ||
import a from './local-file'; | ||
import type LocalType from './local-file'; | ||
import value from 'third-party'; | ||
import {specifier} from 'third-party'; | ||
import type ThirdPartyType from 'third-party'; | ||
import type {LocalSpecifierType} from './local-file'; | ||
import type {SpecifierType} from 'third-party'; | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
import type ThirdPartyType from "third-party"; | ||
import type { SpecifierType } from "third-party"; | ||
import value, { specifier } from "third-party"; | ||
import type LocalType from "./local-file"; | ||
import type { LocalSpecifierType } from "./local-file"; | ||
import a from "./local-file"; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import a, {type LocalType} from './local-file'; | ||
import value, {tp} from 'third-party'; | ||
import {specifier, type ThirdPartyType} from 'third-party'; |
Oops, something went wrong.