You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
95 lines
2.6 KiB
95 lines
2.6 KiB
// https://www.npmjs.com/package/better-directory-sort
|
|
|
|
function defaultComparator(a, b) {
|
|
return a.localeCompare(b, undefined, {
|
|
numeric: true,
|
|
sensitivity: "base",
|
|
});
|
|
}
|
|
|
|
function compareSafe(a, b, comparator) {
|
|
if (a == null && b == null) return 0;
|
|
if (a != null && b == null) return 1;
|
|
if (b != null && a == null) return -1;
|
|
return comparator(a, b);
|
|
}
|
|
|
|
type Comparator<T> = (a: T, b: T) => number;
|
|
type Entity = {
|
|
name: string;
|
|
isDirectory: boolean;
|
|
};
|
|
type Opts = {
|
|
comparator?: Comparator<string>;
|
|
kinds?: boolean;
|
|
};
|
|
|
|
function createBetterDirectorySort(opts: Opts = {}): Comparator<Entity> {
|
|
let comparator = opts.comparator || defaultComparator;
|
|
let kinds = opts.kinds || false;
|
|
|
|
return function betterDirectorySort(a, b) {
|
|
// directories should be placed before files
|
|
if (a.isDirectory && !b.isDirectory) return -1;
|
|
if (b.isDirectory && !a.isDirectory) return 1;
|
|
if (!a.name) return 1;
|
|
|
|
// dotsfiles should be placed before non-dotfiles
|
|
let aDot = a.name[0] === ".";
|
|
let bDot = b.name[0] === ".";
|
|
if (aDot && !bDot) return -1;
|
|
if (bDot && !aDot) return 1;
|
|
|
|
// names will be sorted in period-delimitted parts
|
|
let aParts = a.name.split(".");
|
|
let bParts = b.name.split(".");
|
|
|
|
// the first part of the name is the most important part
|
|
let aName = aParts.shift();
|
|
let bName = bParts.shift();
|
|
|
|
// final extension is only used when all else is the same
|
|
let aExt = aParts.pop();
|
|
let bExt = bParts.pop();
|
|
|
|
let comparedName = compareSafe(aName, bName, comparator);
|
|
if (comparedName !== 0) return comparedName;
|
|
|
|
// "kind" extension is used above other parts
|
|
if (kinds) {
|
|
let aKind = aParts.pop();
|
|
let bKind = bParts.pop();
|
|
|
|
let comparedKind = compareSafe(aKind, bKind, comparator);
|
|
if (comparedKind !== 0) return comparedKind;
|
|
}
|
|
|
|
// loop with an decrementing index
|
|
let i = 0;
|
|
while (true) {
|
|
let aPart = aParts[i];
|
|
let bPart = bParts[i];
|
|
|
|
// if there's no more parts on either name, break
|
|
if (aPart == null && bPart == null) break;
|
|
|
|
// compare the current part, if its the same, continue comparing parts
|
|
let comparedPart = compareSafe(aPart, bPart, comparator);
|
|
if (comparedPart !== 0) return comparedPart;
|
|
|
|
i++;
|
|
}
|
|
|
|
// compare the last extension as a final tie-breaker
|
|
return compareSafe(aExt, bExt, comparator);
|
|
};
|
|
}
|
|
|
|
const betterDirectorySort = createBetterDirectorySort();
|
|
|
|
// @ts-ignore
|
|
betterDirectorySort.custom = createBetterDirectorySort;
|
|
// @ts-ignore
|
|
betterDirectorySort.defaultComparator = defaultComparator;
|
|
|
|
export { betterDirectorySort };
|
|
|