Skip to content

Commit 71c91b1

Browse files
author
Vladislav Arsenev
committed
feature: order respects side effects
1 parent e427746 commit 71c91b1

20 files changed

+823
-105
lines changed

examples/example.jsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import otherthing from '@core/otherthing';
88
import twoLevelRelativePath from '../../twoLevelRelativePath';
99
import component from '@ui/hello';
1010

11-
1211
const HelloWorld = ({ name }) => {
1312
return <div>Hello, {name}</div>;
1413
};

src/constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ export const newLineCharacters = '\n\n';
99

1010
export const sortImportsIgnoredComment = 'sort-imports-ignore';
1111

12+
export const chunkSideEffectNode = 'side-effect-node';
13+
export const chunkSideOtherNode = 'other-node';
14+
1215
/*
1316
* Used to mark the position between RegExps,
1417
* where the not matched imports should be placed

src/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import { parsers as babelParsers } from 'prettier/plugins/babel';
22
import { parsers as flowParsers } from 'prettier/plugins/flow';
33
import { parsers as htmlParsers } from 'prettier/plugins/html';
44
import { parsers as typescriptParsers } from 'prettier/plugins/typescript';
5+
56
import { defaultPreprocessor } from './preprocessors/default-processor';
6-
import { vuePreprocessor } from './preprocessors/vue-preprocessor';
77
import { sveltePreprocessor } from './preprocessors/svelte-preprocessor';
8+
import { vuePreprocessor } from './preprocessors/vue-preprocessor';
89

910
const { parsers: svelteParsers } = require('prettier-plugin-svelte');
1011

@@ -50,6 +51,12 @@ const options = {
5051
default: false,
5152
description: 'Should specifiers be sorted?',
5253
},
54+
importOrderPreventSortingSideEffectNodes: {
55+
type: 'boolean',
56+
category: 'Global',
57+
default: false,
58+
description: 'Should side effect nodes be prevented from being sorted?',
59+
},
5360
};
5461

5562
module.exports = {

src/preprocessors/preprocessor.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export function preprocessor(code: string, options: PrettierOptions) {
1616
importOrderSeparation,
1717
importOrderGroupNamespaceSpecifiers,
1818
importOrderSortSpecifiers,
19+
importOrderPreventSortingSideEffectNodes,
1920
} = options;
2021

2122
const parserOptions: ParserOptions = {
@@ -42,6 +43,7 @@ export function preprocessor(code: string, options: PrettierOptions) {
4243
importOrderSeparation,
4344
importOrderGroupNamespaceSpecifiers,
4445
importOrderSortSpecifiers,
46+
importOrderPreventSortingSideEffectNodes,
4547
});
4648

4749
return getCodeFromAst(allImports, directives, code, interpreter);

src/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,11 @@ export type GetSortedNodes = (
1919
| 'importOrderSeparation'
2020
| 'importOrderGroupNamespaceSpecifiers'
2121
| 'importOrderSortSpecifiers'
22+
| 'importOrderPreventSortingSideEffectNodes'
2223
>,
2324
) => ImportOrLine[];
25+
26+
export interface ImportChunk {
27+
nodes: ImportDeclaration[];
28+
type: string;
29+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { ImportDeclaration } from '@babel/types';
2+
3+
import { adjustCommentsOnSortedNodes } from '../adjust-comments-on-sorted-nodes';
4+
import { getImportNodes } from '../get-import-nodes';
5+
6+
function leadingComments(node: ImportDeclaration): string[] {
7+
return node.leadingComments?.map((c) => c.value) ?? [];
8+
}
9+
10+
function trailingComments(node: ImportDeclaration): string[] {
11+
return node.trailingComments?.map((c) => c.value) ?? [];
12+
}
13+
14+
test('it preserves the single leading comment for each import declaration', () => {
15+
const importNodes = getImportNodes(`
16+
import {x} from "c";
17+
// comment b
18+
import {y} from "b";
19+
// comment a
20+
import {z} from "a";
21+
`);
22+
expect(importNodes).toHaveLength(3);
23+
const finalNodes = [importNodes[2], importNodes[1], importNodes[0]];
24+
adjustCommentsOnSortedNodes(importNodes, finalNodes);
25+
expect(finalNodes).toHaveLength(3);
26+
expect(leadingComments(finalNodes[0])).toEqual([' comment a']);
27+
expect(trailingComments(finalNodes[0])).toEqual([]);
28+
expect(leadingComments(finalNodes[1])).toEqual([' comment b']);
29+
expect(trailingComments(finalNodes[1])).toEqual([]);
30+
expect(leadingComments(finalNodes[2])).toEqual([]);
31+
expect(trailingComments(finalNodes[2])).toEqual([]);
32+
});
33+
34+
test('it preserves multiple leading comments for each import declaration', () => {
35+
const importNodes = getImportNodes(`
36+
import {x} from "c";
37+
// comment b1
38+
// comment b2
39+
// comment b3
40+
import {y} from "b";
41+
// comment a1
42+
// comment a2
43+
// comment a3
44+
import {z} from "a";
45+
`);
46+
expect(importNodes).toHaveLength(3);
47+
const finalNodes = [importNodes[2], importNodes[1], importNodes[0]];
48+
adjustCommentsOnSortedNodes(importNodes, finalNodes);
49+
expect(finalNodes).toHaveLength(3);
50+
expect(leadingComments(finalNodes[0])).toEqual([
51+
' comment a1',
52+
' comment a2',
53+
' comment a3',
54+
]);
55+
expect(trailingComments(finalNodes[0])).toEqual([]);
56+
expect(leadingComments(finalNodes[1])).toEqual([
57+
' comment b1',
58+
' comment b2',
59+
' comment b3',
60+
]);
61+
expect(trailingComments(finalNodes[1])).toEqual([]);
62+
expect(leadingComments(finalNodes[2])).toEqual([]);
63+
expect(trailingComments(finalNodes[2])).toEqual([]);
64+
});
65+
66+
test('it does not move comments at before all import declarations', () => {
67+
const importNodes = getImportNodes(`
68+
// comment c1
69+
// comment c2
70+
import {x} from "c";
71+
import {y} from "b";
72+
import {z} from "a";
73+
`);
74+
expect(importNodes).toHaveLength(3);
75+
const finalNodes = [importNodes[2], importNodes[1], importNodes[0]];
76+
adjustCommentsOnSortedNodes(importNodes, finalNodes);
77+
expect(finalNodes).toHaveLength(3);
78+
expect(leadingComments(finalNodes[0])).toEqual([
79+
' comment c1',
80+
' comment c2',
81+
]);
82+
expect(trailingComments(finalNodes[0])).toEqual([]);
83+
expect(leadingComments(finalNodes[1])).toEqual([]);
84+
expect(trailingComments(finalNodes[1])).toEqual([]);
85+
expect(leadingComments(finalNodes[2])).toEqual([]);
86+
expect(trailingComments(finalNodes[2])).toEqual([]);
87+
});
88+
89+
test('it does not affect comments after all import declarations', () => {
90+
const importNodes = getImportNodes(`
91+
import {x} from "c";
92+
import {y} from "b";
93+
import {z} from "a";
94+
// comment final 1
95+
// comment final 2
96+
`);
97+
expect(importNodes).toHaveLength(3);
98+
const finalNodes = [importNodes[2], importNodes[1], importNodes[0]];
99+
adjustCommentsOnSortedNodes(importNodes, finalNodes);
100+
expect(finalNodes).toHaveLength(3);
101+
expect(leadingComments(finalNodes[0])).toEqual([]);
102+
expect(trailingComments(finalNodes[0])).toEqual([]);
103+
expect(leadingComments(finalNodes[1])).toEqual([]);
104+
expect(trailingComments(finalNodes[1])).toEqual([]);
105+
expect(leadingComments(finalNodes[2])).toEqual([]);
106+
expect(trailingComments(finalNodes[2])).toEqual([]);
107+
});

src/utils/__tests__/get-all-comments-from-nodes.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const getSortedImportNodes = (code: string, options?: ParserOptions) => {
1414
importOrderSeparation: false,
1515
importOrderGroupNamespaceSpecifiers: false,
1616
importOrderSortSpecifiers: false,
17+
importOrderPreventSortingSideEffectNodes: false,
1718
});
1819
};
1920

src/utils/__tests__/get-code-from-ast.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import a from 'a';
2525
importOrderSeparation: false,
2626
importOrderGroupNamespaceSpecifiers: false,
2727
importOrderSortSpecifiers: false,
28+
importOrderPreventSortingSideEffectNodes: false,
2829
});
2930
const formatted = getCodeFromAst(sortedNodes, [], code, null);
3031
expect(await format(formatted, { parser: 'babel' })).toEqual(

0 commit comments

Comments
 (0)