diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index 0004dff1..3aadcd8a 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -90,3 +90,7 @@ via prettier config. plugins: [require('@trivago/prettier-plugin-sort-imports')], } ``` + +#### Q. How can I prevent the plugin from reordering specific import statements? + +Due to the complexity of maintaining the position of certain imports while reordering others, you can prevent the plugin from rearranging your file by adding the following comment at the top of your file: `// sort-imports-ignore`. diff --git a/src/constants.ts b/src/constants.ts index e04f402c..7c2c3acf 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -7,6 +7,8 @@ export const jsx: ParserPlugin = 'jsx'; export const newLineCharacters = '\n\n'; +export const sortImportsIgnoredComment = 'sort-imports-ignore'; + /* * Used to mark the position between RegExps, * where the not matched imports should be placed diff --git a/src/index.ts b/src/index.ts index f60f943d..5a6eafba 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ import { parsers as babelParsers } from 'prettier/parser-babel'; import { parsers as flowParsers } from 'prettier/parser-flow'; -import { parsers as typescriptParsers } from 'prettier/parser-typescript'; import { parsers as htmlParsers } from 'prettier/parser-html'; +import { parsers as typescriptParsers } from 'prettier/parser-typescript'; import { defaultPreprocessor } from './preprocessors/default-processor'; import { vuePreprocessor } from './preprocessors/vue-preprocessor'; diff --git a/src/preprocessors/preprocessor.ts b/src/preprocessors/preprocessor.ts index 04f96257..bf5da668 100644 --- a/src/preprocessors/preprocessor.ts +++ b/src/preprocessors/preprocessor.ts @@ -6,6 +6,7 @@ import { extractASTNodes } from '../utils/extract-ast-nodes'; import { getCodeFromAst } from '../utils/get-code-from-ast'; import { getExperimentalParserPlugins } from '../utils/get-experimental-parser-plugins'; import { getSortedNodes } from '../utils/get-sorted-nodes'; +import { isSortImportsIgnored } from '../utils/is-sort-imports-ignored'; export function preprocessor(code: string, options: PrettierOptions) { const { @@ -33,6 +34,7 @@ export function preprocessor(code: string, options: PrettierOptions) { // short-circuit if there are no import declaration if (importNodes.length === 0) return code; + if (isSortImportsIgnored(importNodes)) return code; const allImports = getSortedNodes(importNodes, { importOrder, diff --git a/src/utils/__tests__/is-sort-imports-ignored.spec.ts b/src/utils/__tests__/is-sort-imports-ignored.spec.ts new file mode 100644 index 00000000..d1429d9b --- /dev/null +++ b/src/utils/__tests__/is-sort-imports-ignored.spec.ts @@ -0,0 +1,23 @@ +import { getImportNodes } from '../get-import-nodes'; +import { isSortImportsIgnored } from '../is-sort-imports-ignored'; + +const codeIgnored = `// sort-imports-ignore +// second comment +import z from 'z'; +`; + +const codeNotIgnored = `// second comment +import z from 'z'; +`; + +test('it should return true if specific leading comment detected', () => { + const importNodes = getImportNodes(codeIgnored); + + expect(isSortImportsIgnored(importNodes)).toBeTruthy(); +}); + +test('it should return false if no specific leading comment detected', () => { + const importNodes = getImportNodes(codeNotIgnored); + + expect(isSortImportsIgnored(importNodes)).toBeFalsy(); +}); diff --git a/src/utils/get-sorted-nodes-group.ts b/src/utils/get-sorted-nodes-group.ts index 9c9ae6bd..89951336 100644 --- a/src/utils/get-sorted-nodes-group.ts +++ b/src/utils/get-sorted-nodes-group.ts @@ -1,4 +1,5 @@ import { Import, ImportDeclaration } from '@babel/types'; + import { naturalSort } from '../natural-sort'; import { PrettierOptions } from '../types'; diff --git a/src/utils/is-sort-imports-ignored.ts b/src/utils/is-sort-imports-ignored.ts new file mode 100644 index 00000000..0606e862 --- /dev/null +++ b/src/utils/is-sort-imports-ignored.ts @@ -0,0 +1,11 @@ +import { Statement } from '@babel/types'; + +import { sortImportsIgnoredComment } from '../constants'; +import { getAllCommentsFromNodes } from './get-all-comments-from-nodes'; + +export const isSortImportsIgnored = (nodes: Statement[]) => + getAllCommentsFromNodes(nodes).some( + (comment) => + comment.loc.start.line === 1 && + comment.value.includes(sortImportsIgnoredComment), + ); diff --git a/tests/ImportsNotSeparated/__snapshots__/ppsi.spec.js.snap b/tests/ImportsNotSeparated/__snapshots__/ppsi.spec.js.snap index a4282680..79565021 100644 --- a/tests/ImportsNotSeparated/__snapshots__/ppsi.spec.js.snap +++ b/tests/ImportsNotSeparated/__snapshots__/ppsi.spec.js.snap @@ -385,3 +385,30 @@ import "./commands"; // require('./commands') `; + +exports[`sort-imports-ignored.ts - typescript-verify: sort-imports-ignored.ts 1`] = ` +// sort-imports-ignore + +import './commands'; +import b from 'b'; +import a from 'a'; + +// Comment + +function add(a:number,b:number) { + return a + b; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// sort-imports-ignore + +import "./commands"; +import b from "b"; +import a from "a"; + +// Comment + +function add(a: number, b: number) { + return a + b; +} + +`; diff --git a/tests/ImportsNotSeparated/sort-imports-ignored.ts b/tests/ImportsNotSeparated/sort-imports-ignored.ts new file mode 100644 index 00000000..c53ddcf0 --- /dev/null +++ b/tests/ImportsNotSeparated/sort-imports-ignored.ts @@ -0,0 +1,11 @@ +// sort-imports-ignore + +import './commands'; +import b from 'b'; +import a from 'a'; + +// Comment + +function add(a:number,b:number) { + return a + b; +} diff --git a/tests/ImportsNotSeparatedRest/__snapshots__/ppsi.spec.js.snap b/tests/ImportsNotSeparatedRest/__snapshots__/ppsi.spec.js.snap index b30addd1..ecc8d513 100644 --- a/tests/ImportsNotSeparatedRest/__snapshots__/ppsi.spec.js.snap +++ b/tests/ImportsNotSeparatedRest/__snapshots__/ppsi.spec.js.snap @@ -328,3 +328,30 @@ import "./commands"; // require('./commands') `; + +exports[`sort-imports-ignored.ts - typescript-verify: sort-imports-ignored.ts 1`] = ` +// sort-imports-ignore + +import './commands'; +import b from 'b'; +import a from 'a'; + +// Comment + +function add(a:number,b:number) { + return a + b; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// sort-imports-ignore + +import "./commands"; +import b from "b"; +import a from "a"; + +// Comment + +function add(a: number, b: number) { + return a + b; +} + +`; diff --git a/tests/ImportsNotSeparatedRest/sort-imports-ignored.ts b/tests/ImportsNotSeparatedRest/sort-imports-ignored.ts new file mode 100644 index 00000000..c53ddcf0 --- /dev/null +++ b/tests/ImportsNotSeparatedRest/sort-imports-ignored.ts @@ -0,0 +1,11 @@ +// sort-imports-ignore + +import './commands'; +import b from 'b'; +import a from 'a'; + +// Comment + +function add(a:number,b:number) { + return a + b; +} diff --git a/tests/ImportsSeparated/__snapshots__/ppsi.spec.js.snap b/tests/ImportsSeparated/__snapshots__/ppsi.spec.js.snap index 0b31f66d..4dc55697 100644 --- a/tests/ImportsSeparated/__snapshots__/ppsi.spec.js.snap +++ b/tests/ImportsSeparated/__snapshots__/ppsi.spec.js.snap @@ -412,3 +412,30 @@ import "./commands"; // require('./commands') `; + +exports[`sort-imports-ignored.ts - typescript-verify: sort-imports-ignored.ts 1`] = ` +// sort-imports-ignore + +import './commands'; +import b from 'b'; +import a from 'a'; + +// Comment + +function add(a:number,b:number) { + return a + b; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// sort-imports-ignore + +import "./commands"; +import b from "b"; +import a from "a"; + +// Comment + +function add(a: number, b: number) { + return a + b; +} + +`; diff --git a/tests/ImportsSeparated/sort-imports-ignored.ts b/tests/ImportsSeparated/sort-imports-ignored.ts new file mode 100644 index 00000000..c53ddcf0 --- /dev/null +++ b/tests/ImportsSeparated/sort-imports-ignored.ts @@ -0,0 +1,11 @@ +// sort-imports-ignore + +import './commands'; +import b from 'b'; +import a from 'a'; + +// Comment + +function add(a:number,b:number) { + return a + b; +} diff --git a/tests/ImportsSeparatedRest/__snapshots__/ppsi.spec.js.snap b/tests/ImportsSeparatedRest/__snapshots__/ppsi.spec.js.snap index 57f43871..b9a6b680 100644 --- a/tests/ImportsSeparatedRest/__snapshots__/ppsi.spec.js.snap +++ b/tests/ImportsSeparatedRest/__snapshots__/ppsi.spec.js.snap @@ -347,3 +347,30 @@ import "./commands"; // require('./commands') `; + +exports[`sort-imports-ignored.ts - typescript-verify: sort-imports-ignored.ts 1`] = ` +// sort-imports-ignore + +import './commands'; +import b from 'b'; +import a from 'a'; + +// Comment + +function add(a:number,b:number) { + return a + b; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// sort-imports-ignore + +import "./commands"; +import b from "b"; +import a from "a"; + +// Comment + +function add(a: number, b: number) { + return a + b; +} + +`; diff --git a/tests/ImportsSeparatedRest/sort-imports-ignored.ts b/tests/ImportsSeparatedRest/sort-imports-ignored.ts new file mode 100644 index 00000000..c53ddcf0 --- /dev/null +++ b/tests/ImportsSeparatedRest/sort-imports-ignored.ts @@ -0,0 +1,11 @@ +// sort-imports-ignore + +import './commands'; +import b from 'b'; +import a from 'a'; + +// Comment + +function add(a:number,b:number) { + return a + b; +}