Skip to content

Commit 9e04342

Browse files
authored
Merge pull request #83 from YuriSS/feat/allow-change-group-order
feat: allow changing the groups order
2 parents 815f518 + 6569138 commit 9e04342

File tree

10 files changed

+107
-11
lines changed

10 files changed

+107
-11
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,13 @@ import-conductor -p @customA @customB
135135
import-conductor --separator '' ==> no separator
136136
```
137137

138+
- `groupOrder` - The group order to follow: (defaults to `[thirdParty, userLibrary, differentModule, sameModule]`)
139+
140+
```shell script
141+
import-conductor --groupOrder 'userLibrary' 'differentModule' 'sameModule' 'thirdParty'
142+
import-conductor -g 'userLibrary' 'differentModule' 'sameModule' 'thirdParty'
143+
```
144+
138145
- `staged` - Run against staged files: (defaults to `false`)
139146

140147
```shell script

__tests__/optimize-imports-mocks.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export type TestCase = { input: string; expected: string; noOfRuns?: number };
1+
export type TestCase = { input: string; expected: string; noOfRuns?: number; groupOrder?: string[] };
22

33
export const readmeExample: TestCase = {
44
input: `import fs from 'fs';
@@ -111,3 +111,43 @@ import { MatDialogRef } from '@angular/material/dialog';
111111
import { Observable } from 'rxjs';
112112
import { AboutDialogBloc, AboutState } from './about-dialog.bloc';`,
113113
};
114+
115+
export const noImportStatement: TestCase = {
116+
input: `const x = 2;`,
117+
expected: `const x = 2;`,
118+
};
119+
120+
export const importsOnDifferentGroupOrder: TestCase = {
121+
groupOrder: ['userLibrary', 'sameModule', 'differentModule', 'thirdParty'],
122+
input: `import { Component } from '@angular/core';
123+
import fs from 'fs';
124+
import { LoggerService } from '@myorg/logger';
125+
import { Order } from '../order/order.model';
126+
import { CustomService } from './customer.service';`,
127+
expected: `import { LoggerService } from '@myorg/logger';
128+
import { CustomService } from './customer.service';
129+
import { Order } from '../order/order.model';
130+
import { Component } from '@angular/core';
131+
import fs from 'fs';`,
132+
};
133+
134+
export const importsWithGroupOrderIncorrect: TestCase = {
135+
groupOrder: ['userLibrary', 'differentModule', 'thirdParty'],
136+
input: `import fs from 'fs';
137+
import { CustomerService } from './customer.service';
138+
import { Order } from '../order/order.model';
139+
import { Component, OnInit } from '@angular/core';
140+
import { LoggerService } from '@myorg/logger';
141+
import { Observable } from 'rxjs';
142+
import { spawn } from 'child_process';`,
143+
expected: `import { Component, OnInit } from '@angular/core';
144+
import { spawn } from 'child_process';
145+
import fs from 'fs';
146+
import { Observable } from 'rxjs';
147+
148+
import { LoggerService } from '@myorg/logger';
149+
150+
import { Order } from '../order/order.model';
151+
152+
import { CustomerService } from './customer.service';`,
153+
};

__tests__/optimize-imports.spec.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,18 @@ import { actions, organizeImports, organizeImportsForFile } from '@ic/conductor/
22
import * as config from '@ic/config';
33
import fs from 'fs';
44
import { Config } from '@ic/types';
5-
import { readmeExample, comments, TestCase, codeBetweenImports, emptyNewLineSeparator } from './optimize-imports-mocks';
5+
import {
6+
readmeExample,
7+
comments,
8+
TestCase,
9+
codeBetweenImports,
10+
emptyNewLineSeparator,
11+
noImportStatement,
12+
importsOnDifferentGroupOrder,
13+
importsWithGroupOrderIncorrect,
14+
} from './optimize-imports-mocks';
615
import { defaultConfig } from '@ic/defaultConfig';
16+
import { getGroupOrder } from '@ic/conductor/get-group-order';
717

818
jest.mock('fs');
919
jest.mock('simple-git');
@@ -72,4 +82,22 @@ describe('optimizeImports', () => {
7282
expect(fs.writeFileSync).not.toHaveBeenCalled();
7383
}
7484
});
85+
86+
it('should do nothing if the file has no import', async () => {
87+
(fs.readFileSync as any).mockReturnValue(Buffer.from(noImportStatement.input));
88+
const file = 'test.ts';
89+
const result = await organizeImportsForFile(file);
90+
expect(result).toBe(actions.none);
91+
expect(fs.writeFileSync).not.toHaveBeenCalled();
92+
});
93+
94+
it('should change group order', async () => {
95+
spy.and.returnValue({ ...basicConfig, groupOrder: importsOnDifferentGroupOrder.groupOrder, separator: '' });
96+
await assertConductor(importsOnDifferentGroupOrder);
97+
});
98+
99+
it('should use default order because incorrect group order input', async () => {
100+
spy.and.returnValue({ ...basicConfig, groupOrder: getGroupOrder({ groupOrder: importsWithGroupOrderIncorrect.groupOrder }) });
101+
await assertConductor(importsWithGroupOrderIncorrect);
102+
});
75103
});

src/cliOptions.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ export const optionDefinitions = [
2525
multiple: true,
2626
description: 'The prefix of custom user libraries',
2727
},
28+
{
29+
name: 'groupOrder',
30+
alias: 'g',
31+
type: String,
32+
multiple: true,
33+
description: 'The group order it should follow',
34+
},
2835
{
2936
name: 'staged',
3037
type: Boolean,

src/conductor/format-import-statements.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,11 @@ import { ImportCategories } from '../types';
33

44
type CategoryEntry = [string, Map<string, string>];
55

6-
const categoriesOrder = ['thirdParty', 'userLibrary', 'differentModule', 'sameModule'];
7-
86
export function formatImportStatements(importCategories: ImportCategories, lineEnding: string) {
97
const { separator } = getConfig();
108
const [first, ...otherCategories] = Object.entries(importCategories)
119
.filter(hasImports)
12-
.sort(byCategoriesOrder)
10+
.sort(byCategoriesOrder(getConfig().groupOrder))
1311
.map((imports) => toImportBlock(imports, lineEnding));
1412

1513
let result = first || '';
@@ -21,8 +19,8 @@ export function formatImportStatements(importCategories: ImportCategories, lineE
2119
return result;
2220
}
2321

24-
function byCategoriesOrder([a]: CategoryEntry, [b]: CategoryEntry): number {
25-
return categoriesOrder.indexOf(a) - categoriesOrder.indexOf(b);
22+
function byCategoriesOrder(categoriesOrder: string[]) {
23+
return ([a]: CategoryEntry, [b]: CategoryEntry): number => categoriesOrder.indexOf(a) - categoriesOrder.indexOf(b);
2624
}
2725

2826
function hasImports([, imports]: CategoryEntry) {

src/conductor/get-group-order.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { defaultConfig } from '../defaultConfig';
2+
import { Config } from '../types';
3+
4+
export function getGroupOrder(config: Partial<Config>) {
5+
const groups = new Set(config?.groupOrder || []);
6+
const uniqueGroups = Array.from(groups);
7+
return isValidGroupArgument(uniqueGroups) ? uniqueGroups : defaultConfig.groupOrder;
8+
}
9+
10+
function isValidGroupArgument(groups: string[]): boolean {
11+
return groups.length === defaultConfig.groupOrder.length && groups.every((group) => defaultConfig.groupOrder.includes(group));
12+
}

src/conductor/organize-imports.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export async function organizeImportsForFile(filePath: string): Promise<string>
4545
const { staged, autoAdd, dryRun } = getConfig();
4646
const fileWithOrganizedImports = await organizeImports(fileContent);
4747
const fileHasChanged = fileWithOrganizedImports !== fileContent;
48-
const isValidAction = [actions.none, actions.skipped].every(action => action !== fileWithOrganizedImports);
48+
const isValidAction = [actions.none, actions.skipped].every((action) => action !== fileWithOrganizedImports);
4949

5050
if (fileHasChanged && isValidAction) {
5151
!dryRun && writeFileSync(filePath, fileWithOrganizedImports);
@@ -55,11 +55,11 @@ export async function organizeImportsForFile(filePath: string): Promise<string>
5555
msg += ', added to git';
5656
}
5757
log('green', msg, filePath);
58-
} else {
59-
log('gray', 'no change needed', filePath);
58+
return actions.reordered;
6059
}
6160

62-
return fileHasChanged ? actions.reordered : actions.none;
61+
log('gray', 'no change needed', filePath);
62+
return actions.none;
6363
}
6464

6565
export async function organizeImports(fileContent: string): Promise<string> {

src/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { sync } from 'glob';
22

3+
import { getGroupOrder } from './conductor/get-group-order';
34
import { getThirdParty } from './conductor/get-third-party';
45
import { defaultConfig } from './defaultConfig';
56
import { CliConfig, Config } from './types';
@@ -17,6 +18,7 @@ export function resolveConfig(cliConfig: Partial<CliConfig>): Config {
1718
...defaultConfig,
1819
...normalized,
1920
thirdPartyDependencies: getThirdParty(),
21+
groupOrder: getGroupOrder(normalized),
2022
};
2123
if (merged.ignore.length > 0) {
2224
merged.ignore = merged.ignore.map((pattern) => (pattern.includes('*') ? sync(pattern) : pattern)).flat();

src/defaultConfig.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ export const defaultConfig: Config = {
1010
staged: false,
1111
dryRun: false,
1212
ignore: [],
13+
groupOrder: ['thirdParty', 'userLibrary', 'differentModule', 'sameModule'],
1314
};

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export interface Config {
1313
ignore: string[];
1414
userLibPrefixes: string[];
1515
thirdPartyDependencies?: Set<string>;
16+
groupOrder: string[];
1617
}
1718

1819
export type CliConfig = Omit<Config, 'autoAdd'> & { noAutoAdd: boolean };

0 commit comments

Comments
 (0)