This repository has been archived on 2026-04-20. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
chrom-tool/src/utils/sort.ts
2026-04-17 15:01:29 -04:00

124 lines
3.8 KiB
TypeScript

import type {
BookmarkSortKey,
BookmarkSummary,
ExtensionSortKey,
ExtensionSummary,
PasswordSiteSortKey,
PasswordSiteSummary,
AssociatedProfileSortKey,
AssociatedProfileSummary,
BookmarkAssociatedProfileSummary,
ExtensionAssociatedProfileSummary,
ProfileSortKey,
ProfileSummary,
} from "../types/browser";
export function compareText(left: string, right: string) {
return left.localeCompare(right, undefined, {
sensitivity: "base",
numeric: true,
});
}
function compareOptionalText(left: string | null | undefined, right: string | null | undefined) {
const leftValue = left?.trim() ?? "";
const rightValue = right?.trim() ?? "";
const leftEmpty = leftValue.length === 0;
const rightEmpty = rightValue.length === 0;
if (leftEmpty && rightEmpty) return 0;
if (leftEmpty) return 1;
if (rightEmpty) return -1;
return compareText(leftValue, rightValue);
}
export function compareProfileId(left: string, right: string) {
const leftKey = profileSortKeyValue(left);
const rightKey = profileSortKeyValue(right);
if (leftKey.group !== rightKey.group) return leftKey.group - rightKey.group;
if (leftKey.number !== rightKey.number) return leftKey.number - rightKey.number;
return compareText(leftKey.text, rightKey.text);
}
export function sortProfiles(items: ProfileSummary[], sortKey: ProfileSortKey) {
const profiles = [...items];
return profiles.sort((left, right) => {
if (sortKey === "email") {
return (
compareOptionalText(left.email, right.email) ||
compareText(left.name, right.name) ||
compareProfileId(left.id, right.id)
);
}
if (sortKey === "id") {
return compareProfileId(left.id, right.id);
}
return compareText(left.name, right.name) || compareProfileId(left.id, right.id);
});
}
export function sortExtensions(items: ExtensionSummary[], sortKey: ExtensionSortKey) {
const extensions = [...items];
return extensions.sort((left, right) => {
if (sortKey === "id") {
return compareText(left.id, right.id);
}
return compareText(left.name, right.name) || compareText(left.id, right.id);
});
}
export function sortBookmarks(items: BookmarkSummary[], sortKey: BookmarkSortKey) {
const bookmarks = [...items];
return bookmarks.sort((left, right) => {
if (sortKey === "url") {
return compareOptionalText(left.url, right.url) || compareText(left.title, right.title);
}
return compareOptionalText(left.title, right.title) || compareText(left.url, right.url);
});
}
export function sortPasswordSites(items: PasswordSiteSummary[], sortKey: PasswordSiteSortKey) {
const passwordSites = [...items];
return passwordSites.sort((left, right) => {
if (sortKey === "url") {
return compareOptionalText(left.url, right.url) || compareText(left.domain, right.domain);
}
return compareOptionalText(left.domain, right.domain) || compareText(left.url, right.url);
});
}
export function sortAssociatedProfiles(
items: (
| AssociatedProfileSummary
| BookmarkAssociatedProfileSummary
| ExtensionAssociatedProfileSummary
)[],
sortKey: AssociatedProfileSortKey,
) {
const profiles = [...items];
return profiles.sort((left, right) => {
if (sortKey === "name") {
return compareText(left.name, right.name) || compareProfileId(left.id, right.id);
}
return compareProfileId(left.id, right.id) || compareText(left.name, right.name);
});
}
function profileSortKeyValue(profileId: string) {
if (profileId === "Default") {
return { group: 0, number: 0, text: profileId };
}
const profileNumber = profileId.startsWith("Profile ")
? Number(profileId.slice("Profile ".length))
: Number.NaN;
if (!Number.isNaN(profileNumber)) {
return { group: 1, number: profileNumber, text: profileId };
}
return { group: 2, number: Number.MAX_SAFE_INTEGER, text: profileId };
}