Skip to content

Commit 50c4338

Browse files
committed
fix type import ordering
1 parent eece72c commit 50c4338

File tree

2 files changed

+91
-14
lines changed

2 files changed

+91
-14
lines changed

src/utils/__tests__/get-import-nodes-matched-group.spec.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,69 @@ test('should return correct matched groups', () => {
4343
]);
4444
});
4545

46+
test('should return type imports as part of a matching group if no type-specific group is present', () => {
47+
const code = `
48+
import type { ExternalType } from 'external-type-module';
49+
import type { InternalType } from './internal-type-module';
50+
import { externalFn } from 'external-fn-module';
51+
import { internalFn } from './internal-fn-module';
52+
`
53+
const importNodes = getImportNodes(code,{
54+
plugins: ['typescript'],
55+
});
56+
const importOrder = [
57+
'^[^.].*',
58+
'^[.].*',
59+
];
60+
61+
let matchedGroups: string[] = [];
62+
for (const importNode of importNodes) {
63+
const matchedGroup = getImportNodesMatchedGroup(
64+
importNode,
65+
importOrder,
66+
);
67+
matchedGroups.push(matchedGroup);
68+
}
69+
expect(matchedGroups).toEqual([
70+
'^[^.].*',
71+
'^[.].*',
72+
'^[^.].*',
73+
'^[.].*',
74+
]);
75+
});
76+
77+
test('should return type imports as part of a type-specific group even if a matching non-type specific group precedes it', () => {
78+
const code = `
79+
import type { ExternalType } from 'external-type-module';
80+
import type { InternalType } from './internal-type-module';
81+
import { externalFn } from 'external-fn-module';
82+
import { internalFn } from './internal-fn-module';
83+
`
84+
const importNodes = getImportNodes(code, {
85+
plugins: ['typescript'],
86+
});
87+
const importOrder = [
88+
'^[^.].*',
89+
'^[.].*',
90+
'<TS_TYPES>^[.].*',
91+
];
92+
93+
let matchedGroups: string[] = [];
94+
for (const importNode of importNodes) {
95+
const matchedGroup = getImportNodesMatchedGroup(
96+
importNode,
97+
importOrder,
98+
);
99+
matchedGroups.push(matchedGroup);
100+
}
101+
expect(matchedGroups).toEqual([
102+
'^[^.].*',
103+
'<TS_TYPES>^[.].*',
104+
'^[^.].*',
105+
'^[.].*',
106+
]);
107+
});
108+
46109
test('should return THIRD_PARTY_MODULES as matched group with empty order list', () => {
47110
const importNodes = getImportNodes(code);
48111
const importOrder: string[] = [];

src/utils/get-import-nodes-matched-group.ts

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,35 @@ export const getImportNodesMatchedGroup = (
2222
: new RegExp(group),
2323
}));
2424

25-
for (const { group, regExp } of groupWithRegExp) {
25+
// finding the group for non-type imports is easy: it's the first group that matches.
26+
// however, for type imports, we need to make sure that we don't match a non-type group
27+
// that's earlier in the list than a type-specific group that would otherwise match.
28+
// so we need to get all matching groups, look for the first matching _type-specific_ group,
29+
// and if it exists, return it. otherwise, return the first matching group if there is one.
30+
const matchingGroups = groupWithRegExp.filter(({ group, regExp }) => {
2631
if (
27-
(group.startsWith(TYPES_SPECIAL_WORD) &&
28-
node.importKind !== 'type') ||
29-
(!group.startsWith(TYPES_SPECIAL_WORD) &&
30-
node.importKind === 'type')
31-
)
32-
continue;
32+
group.startsWith(TYPES_SPECIAL_WORD) &&
33+
node.importKind !== 'type'
34+
) {
35+
return false;
36+
} else {
37+
return node.source.value.match(regExp) !== null;
38+
}
39+
});
3340

34-
const matched = node.source.value.match(regExp) !== null;
35-
if (matched) return group;
41+
if (matchingGroups.length === 0) {
42+
return node.importKind === 'type' &&
43+
importOrder.find(
44+
(group) => group === THIRD_PARTY_TYPES_SPECIAL_WORD,
45+
)
46+
? THIRD_PARTY_TYPES_SPECIAL_WORD
47+
: THIRD_PARTY_MODULES_SPECIAL_WORD;
48+
} else if (node.importKind !== 'type') {
49+
return matchingGroups[0].group;
50+
} else {
51+
for (const { group } of matchingGroups) {
52+
if (group.startsWith(TYPES_SPECIAL_WORD)) return group;
53+
}
54+
return matchingGroups[0].group;
3655
}
37-
38-
return node.importKind === 'type' &&
39-
importOrder.find((group) => group === THIRD_PARTY_TYPES_SPECIAL_WORD)
40-
? THIRD_PARTY_TYPES_SPECIAL_WORD
41-
: THIRD_PARTY_MODULES_SPECIAL_WORD;
4256
};

0 commit comments

Comments
 (0)