110 lines
3.2 KiB
TypeScript
110 lines
3.2 KiB
TypeScript
import {
|
|
IComparatorFunction,
|
|
ISorterFunction,
|
|
IStyleAPI,
|
|
IStyleItem,
|
|
} from "import-sort-style";
|
|
import { IImport } from "import-sort-parser";
|
|
|
|
export default function (styleApi: IStyleAPI): IStyleItem[] {
|
|
const {
|
|
and,
|
|
always,
|
|
dotSegmentCount,
|
|
isAbsoluteModule,
|
|
isNodeModule,
|
|
isRelativeModule,
|
|
name,
|
|
startsWithAlphanumeric,
|
|
unicode,
|
|
} = styleApi;
|
|
|
|
// comparator function which place non-alphanumeric first
|
|
const natural: IComparatorFunction = (a: string, b: string) => {
|
|
if (a === b) {
|
|
return 0;
|
|
}
|
|
const sa = startsWithAlphanumeric(a),
|
|
sb = startsWithAlphanumeric(b);
|
|
if (sa === sb) {
|
|
return unicode(a, b);
|
|
} else {
|
|
return sa ? 1 : -1;
|
|
}
|
|
};
|
|
// sort: use member primarily, if member is not avaliable, use module name
|
|
const memberOrModule: (c: IComparatorFunction) => ISorterFunction = (
|
|
comparator: IComparatorFunction
|
|
) => {
|
|
return (a: IImport, b: IImport): number => {
|
|
const aHasDefaultMember = Boolean(a.defaultMember),
|
|
aHasNamespaceMember = Boolean(a.namespaceMember),
|
|
aHasNamedMember = Boolean(a.namedMembers[0]?.name),
|
|
aHasOnlyDefaultMember =
|
|
aHasDefaultMember && !aHasNamespaceMember && !aHasNamedMember,
|
|
aHasOnlyNamespaceMember =
|
|
aHasNamespaceMember && !aHasDefaultMember && !aHasNamedMember;
|
|
const bHasDefaultMember = Boolean(b.defaultMember),
|
|
bHasNamespaceMember = Boolean(b.namespaceMember),
|
|
bHasNamedMember = Boolean(b.namedMembers[0]?.name),
|
|
bHasOnlyDefaultMember =
|
|
bHasDefaultMember && !bHasNamespaceMember && !bHasNamedMember,
|
|
bHasOnlyNamespaceMember =
|
|
bHasNamespaceMember && !bHasDefaultMember && !bHasNamedMember;
|
|
if (aHasOnlyNamespaceMember !== bHasOnlyNamespaceMember) {
|
|
return aHasOnlyNamespaceMember ? -1 : 1;
|
|
} else if (aHasOnlyDefaultMember !== bHasOnlyDefaultMember) {
|
|
return aHasOnlyDefaultMember ? -1 : 1;
|
|
} else if (aHasNamespaceMember !== bHasNamespaceMember) {
|
|
return aHasNamespaceMember ? -1 : 1;
|
|
} else if (aHasDefaultMember !== bHasDefaultMember) {
|
|
return aHasDefaultMember ? -1 : 1;
|
|
} else if (aHasNamedMember !== bHasNamedMember) {
|
|
return aHasNamedMember ? -1 : 1;
|
|
}
|
|
const first =
|
|
a.defaultMember ||
|
|
a.namespaceMember ||
|
|
a.namedMembers[0]?.name ||
|
|
a.moduleName;
|
|
const second =
|
|
b.defaultMember ||
|
|
b.namespaceMember ||
|
|
b.namedMembers[0]?.name ||
|
|
b.moduleName;
|
|
return comparator(first, second);
|
|
};
|
|
};
|
|
|
|
return [
|
|
// built-in module, has member
|
|
{
|
|
match: isNodeModule,
|
|
sort: memberOrModule(natural),
|
|
sortNamedMembers: name(natural),
|
|
},
|
|
// absolute
|
|
{
|
|
match: isAbsoluteModule,
|
|
sort: memberOrModule(natural),
|
|
sortNamedMembers: name(natural),
|
|
},
|
|
// relative
|
|
{
|
|
match: isRelativeModule,
|
|
sort: [dotSegmentCount, memberOrModule(natural)],
|
|
sortNamedMembers: name(natural),
|
|
},
|
|
// fallback
|
|
{
|
|
match: always,
|
|
sort: [dotSegmentCount, memberOrModule(natural)],
|
|
sortNamedMembers: name(natural),
|
|
},
|
|
// add a blank line after import block
|
|
{
|
|
separator: true,
|
|
},
|
|
];
|
|
}
|