Skip to content

Commit

Permalink
feature: order respects side effects
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladislav Arsenev committed Nov 27, 2024
1 parent e427746 commit 71c91b1
Show file tree
Hide file tree
Showing 20 changed files with 823 additions and 105 deletions.
1 change: 0 additions & 1 deletion examples/example.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import otherthing from '@core/otherthing';
import twoLevelRelativePath from '../../twoLevelRelativePath';
import component from '@ui/hello';


const HelloWorld = ({ name }) => {
return <div>Hello, {name}</div>;
};
Expand Down
3 changes: 3 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export const newLineCharacters = '\n\n';

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

export const chunkSideEffectNode = 'side-effect-node';
export const chunkSideOtherNode = 'other-node';

/*
* Used to mark the position between RegExps,
* where the not matched imports should be placed
Expand Down
9 changes: 8 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { parsers as babelParsers } from 'prettier/plugins/babel';
import { parsers as flowParsers } from 'prettier/plugins/flow';
import { parsers as htmlParsers } from 'prettier/plugins/html';
import { parsers as typescriptParsers } from 'prettier/plugins/typescript';

import { defaultPreprocessor } from './preprocessors/default-processor';
import { vuePreprocessor } from './preprocessors/vue-preprocessor';
import { sveltePreprocessor } from './preprocessors/svelte-preprocessor';
import { vuePreprocessor } from './preprocessors/vue-preprocessor';

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

Expand Down Expand Up @@ -50,6 +51,12 @@ const options = {
default: false,
description: 'Should specifiers be sorted?',
},
importOrderPreventSortingSideEffectNodes: {
type: 'boolean',
category: 'Global',
default: false,
description: 'Should side effect nodes be prevented from being sorted?',
},
};

module.exports = {
Expand Down
2 changes: 2 additions & 0 deletions src/preprocessors/preprocessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export function preprocessor(code: string, options: PrettierOptions) {
importOrderSeparation,
importOrderGroupNamespaceSpecifiers,
importOrderSortSpecifiers,
importOrderPreventSortingSideEffectNodes,
} = options;

const parserOptions: ParserOptions = {
Expand All @@ -42,6 +43,7 @@ export function preprocessor(code: string, options: PrettierOptions) {
importOrderSeparation,
importOrderGroupNamespaceSpecifiers,
importOrderSortSpecifiers,
importOrderPreventSortingSideEffectNodes,
});

return getCodeFromAst(allImports, directives, code, interpreter);
Expand Down
6 changes: 6 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,11 @@ export type GetSortedNodes = (
| 'importOrderSeparation'
| 'importOrderGroupNamespaceSpecifiers'
| 'importOrderSortSpecifiers'
| 'importOrderPreventSortingSideEffectNodes'
>,
) => ImportOrLine[];

export interface ImportChunk {
nodes: ImportDeclaration[];
type: string;
}
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([]);
});
1 change: 1 addition & 0 deletions src/utils/__tests__/get-all-comments-from-nodes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const getSortedImportNodes = (code: string, options?: ParserOptions) => {
importOrderSeparation: false,
importOrderGroupNamespaceSpecifiers: false,
importOrderSortSpecifiers: false,
importOrderPreventSortingSideEffectNodes: false,
});
};

Expand Down
1 change: 1 addition & 0 deletions src/utils/__tests__/get-code-from-ast.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import a from 'a';
importOrderSeparation: false,
importOrderGroupNamespaceSpecifiers: false,
importOrderSortSpecifiers: false,
importOrderPreventSortingSideEffectNodes: false,
});
const formatted = getCodeFromAst(sortedNodes, [], code, null);
expect(await format(formatted, { parser: 'babel' })).toEqual(
Expand Down
Loading

0 comments on commit 71c91b1

Please sign in to comment.