import memoizeOne from "memoize-one"; import { isIPAddress } from "./is_ip_address"; const collator = memoizeOne( (language: string | undefined) => new Intl.Collator(language, { numeric: true }) ); const caseInsensitiveCollator = memoizeOne( (language: string | undefined) => new Intl.Collator(language, { sensitivity: "accent", numeric: true }) ); const fallbackStringCompare = (a: string, b: string) => { if (a < b) { return -1; } if (a > b) { return 1; } return 0; }; export const stringCompare = ( a: string, b: string, language: string | undefined = undefined ) => { // @ts-ignore if (Intl?.Collator) { return collator(language).compare(a, b); } return fallbackStringCompare(a, b); }; export const ipCompare = (a: string, b: string) => { const aIsIpV4 = isIPAddress(a); const bIsIpV4 = isIPAddress(b); if (aIsIpV4 && bIsIpV4) { return ipv4Compare(a, b); } if (!aIsIpV4 && !bIsIpV4) { return ipV6Compare(a, b); } return aIsIpV4 ? -1 : 1; }; export const caseInsensitiveStringCompare = ( a: string, b: string, language: string | undefined = undefined ) => { // @ts-ignore if (Intl?.Collator) { return caseInsensitiveCollator(language).compare(a, b); } return fallbackStringCompare(a.toLowerCase(), b.toLowerCase()); }; export const orderCompare = (order: string[]) => (a: string, b: string) => { const idxA = order.indexOf(a); const idxB = order.indexOf(b); if (idxA === idxB) { return 0; } if (idxA === -1) { return 1; } if (idxB === -1) { return -1; } return idxA - idxB; }; function ipv4Compare(a: string, b: string) { const num1 = Number( a .split(".") .map((num) => num.padStart(3, "0")) .join("") ); const num2 = Number( b .split(".") .map((num) => num.padStart(3, "0")) .join("") ); return num1 - num2; } function ipV6Compare(a: string, b: string) { const ipv6a = normalizeIPv6(a) .split(":") .map((part) => part.padStart(4, "0")) .join(""); const ipv6b = normalizeIPv6(b) .split(":") .map((part) => part.padStart(4, "0")) .join(""); return ipv6a.localeCompare(ipv6b); } function normalizeIPv6(ip) { const parts = ip.split("::"); const head = parts[0].split(":"); const tail = parts[1] ? parts[1].split(":") : []; const totalParts = 8; const missing = totalParts - (head.length + tail.length); const zeros = new Array(missing).fill("0"); return [...head, ...zeros, ...tail].join(":"); }