Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,35 @@ importOrderParserPlugins: []
The plugin extracts the imports which are defined in `importOrder`. These imports are considered as _local imports_.
The imports which are not part of the `importOrder` is considered as _third party imports_.

After, the plugin sorts the _local imports_ and _third party imports_ using [natural sort algorithm](https://en.wikipedia.org/wiki/Natural_sort_order).
First, the plugin checks for
[side effect imports](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#import_a_module_for_its_side_effects_only),
such as `import 'mock-fs'`. These imports often modify the global scope or apply some patches to the current
environment, which may affect other imports. To preserve potential side effects, these kind of side effect imports are
not sorted. They also behave as a barrier that other imports may not cross during the sort. So for example, let's say
you've got these imports:

```javascript
import E from 'e';
import F from 'f';
import D from 'd';
import 'c';
import B from 'b';
import A from 'a';
```

Then the first three imports are sorted and the last two imports are sorted, but all imports above `c` stay above `c`
and all imports below `c` stay below `c`, resulting in:

```javascript
import D from 'd';
import E from 'e';
import F from 'f';
import 'c';
import A from 'a';
import B from 'b';
```

Next, the plugin sorts the _local imports_ and _third party imports_ using [natural sort algorithm](https://en.wikipedia.org/wiki/Natural_sort_order).

In the end, the plugin returns final imports with _third party imports_ on top and _local imports_ at the end.

Expand Down
4 changes: 2 additions & 2 deletions docs/DEBUG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

### How to run example in the repository ?
```shell
yarn run example examples/example.ts --config .prettierrc
yarn run example examples/example.ts --config examples/.prettierrc
```

### How to debug the plugin using node `debugger` ?
You can set a `debugger` anywhere in the code and then use following command:
```shell
yarn run compile && node --inspect-brk ./node_modules/.bin/prettier --config .prettierrc --plugin lib/src/index.js examples/example.ts
yarn run compile && node --inspect-brk ./node_modules/.bin/prettier --config examples/.prettierrc --plugin lib/src/index.js examples/example.ts
```

### How to debug the unit test using `debugger` ?
Expand Down
2 changes: 1 addition & 1 deletion examples/example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import React, {
} from 'react';
import { logger } from '@core/logger';
import { reduce, debounce } from 'lodash';
import { Message } from '../Mesage';
import { Message } from '../Message';
import { createServer } from '@server/node';
import { Alert } from '@ui/Alert';
import { repeat, filter, add } from './utils';
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@
"devDependencies": {
"@types/chai": "4.2.15",
"@types/jest": "26.0.20",
"@types/node": "14.14.34",
"@types/lodash": "4.14.168",
"@types/node": "14.14.34",
"jest": "26.6.3",
"prettier": "2.3.1",
"ts-jest": "26.5.3",
Expand Down
3 changes: 3 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export const jsx: ParserPlugin = 'jsx';

export const newLineCharacters = '\n\n';

export const ChunkSideEffectNode = 'side-effect-node';
Comment thread
blutorange marked this conversation as resolved.
Outdated
export const ChunkSideOtherNode = 'other-node';
Comment thread
blutorange marked this conversation as resolved.
Outdated

/*
* Used to mark the position between RegExps,
* where the not matched imports should be placed
Expand Down
5 changes: 5 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ export interface PrettierOptions extends RequiredOptions {
importOrderSortSpecifiers: boolean;
}

export interface ImportChunk {
nodes: ImportDeclaration[];
type: string;
}

export type ImportGroups = Record<string, ImportDeclaration[]>;
export type ImportOrLine = ImportDeclaration | ExpressionStatement;

Expand Down
107 changes: 107 additions & 0 deletions src/utils/__tests__/adjust-comments-on-sorted-nodes.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { ImportDeclaration } from '@babel/types';

import { adjustCommentsOnSortedNodes } from '../adjust-comments-on-sorted-nodes';
import { getImportNodes } from '../get-import-nodes';

function leadingComments(node: ImportDeclaration): string[] {
return node.leadingComments?.map((c) => c.value) ?? [];
}

function trailingComments(node: ImportDeclaration): string[] {
return node.trailingComments?.map((c) => c.value) ?? [];
}

test('it preserves the single leading comment for each import declaration', () => {
const importNodes = getImportNodes(`
import {x} from "c";
// comment b
import {y} from "b";
// comment a
import {z} from "a";
`);
expect(importNodes).toHaveLength(3);
const finalNodes = [importNodes[2], importNodes[1], importNodes[0]];
adjustCommentsOnSortedNodes(importNodes, finalNodes);
expect(finalNodes).toHaveLength(3);
expect(leadingComments(finalNodes[0])).toEqual([' comment a']);
expect(trailingComments(finalNodes[0])).toEqual([]);
expect(leadingComments(finalNodes[1])).toEqual([' comment b']);
expect(trailingComments(finalNodes[1])).toEqual([]);
expect(leadingComments(finalNodes[2])).toEqual([]);
expect(trailingComments(finalNodes[2])).toEqual([]);
});

test('it preserves multiple leading comments for each import declaration', () => {
const importNodes = getImportNodes(`
import {x} from "c";
// comment b1
// comment b2
// comment b3
import {y} from "b";
// comment a1
// comment a2
// comment a3
import {z} from "a";
`);
expect(importNodes).toHaveLength(3);
const finalNodes = [importNodes[2], importNodes[1], importNodes[0]];
adjustCommentsOnSortedNodes(importNodes, finalNodes);
expect(finalNodes).toHaveLength(3);
expect(leadingComments(finalNodes[0])).toEqual([
' comment a1',
' comment a2',
' comment a3',
]);
expect(trailingComments(finalNodes[0])).toEqual([]);
expect(leadingComments(finalNodes[1])).toEqual([
' comment b1',
' comment b2',
' comment b3',
]);
expect(trailingComments(finalNodes[1])).toEqual([]);
expect(leadingComments(finalNodes[2])).toEqual([]);
expect(trailingComments(finalNodes[2])).toEqual([]);
});

test('it does not move comments at before all import declarations', () => {
const importNodes = getImportNodes(`
// comment c1
// comment c2
import {x} from "c";
import {y} from "b";
import {z} from "a";
`);
expect(importNodes).toHaveLength(3);
const finalNodes = [importNodes[2], importNodes[1], importNodes[0]];
adjustCommentsOnSortedNodes(importNodes, finalNodes);
expect(finalNodes).toHaveLength(3);
expect(leadingComments(finalNodes[0])).toEqual([
' comment c1',
' comment c2',
]);
expect(trailingComments(finalNodes[0])).toEqual([]);
expect(leadingComments(finalNodes[1])).toEqual([]);
expect(trailingComments(finalNodes[1])).toEqual([]);
expect(leadingComments(finalNodes[2])).toEqual([]);
expect(trailingComments(finalNodes[2])).toEqual([]);
});

test('it does not affect comments after all import declarations', () => {
const importNodes = getImportNodes(`
import {x} from "c";
import {y} from "b";
import {z} from "a";
// comment final 1
// comment final 2
`);
expect(importNodes).toHaveLength(3);
const finalNodes = [importNodes[2], importNodes[1], importNodes[0]];
adjustCommentsOnSortedNodes(importNodes, finalNodes);
expect(finalNodes).toHaveLength(3);
expect(leadingComments(finalNodes[0])).toEqual([]);
expect(trailingComments(finalNodes[0])).toEqual([]);
expect(leadingComments(finalNodes[1])).toEqual([]);
expect(trailingComments(finalNodes[1])).toEqual([]);
expect(leadingComments(finalNodes[2])).toEqual([]);
expect(trailingComments(finalNodes[2])).toEqual([]);
});
Loading