import { dirname } from 'node:path'; import fs from 'node:fs'; import type { PathLike } from 'node:fs'; import fsp from 'node:fs/promises'; export type MaybePromise = T | Promise; export function fastStringCompare(a: string, b: string) { const lenA = a.length; const lenB = b.length; const minLen = lenA < lenB ? lenA : lenB; for (let i = 0; i < minLen; ++i) { const ca = a.charCodeAt(i); const cb = b.charCodeAt(i); if (ca > cb) return 1; if (ca < cb) return -1; } if (lenA === lenB) { return 0; } return lenA > lenB ? 1 : -1; }; interface Write { ( destination: string, input: NodeJS.TypedArray | string, ): Promise } export function mkdirp(dir: string) { if (fs.existsSync(dir)) { return; } return fsp.mkdir(dir, { recursive: true }); } export const writeFile: Write = async (destination: string, input, dir = dirname(destination)): Promise => { const p = mkdirp(dir); if (p) { await p; } return fsp.writeFile(destination, input, { encoding: 'utf-8' }); }; export const removeFiles = async (files: string[]) => Promise.all(files.map((file) => fsp.rm(file, { force: true }))); export function withBannerArray(title: string, description: string[] | readonly string[], date: Date, content: string[]) { return [ '#########################################', `# ${title}`, `# Last Updated: ${date.toISOString()}`, `# Size: ${content.length}`, ...description.map(line => (line ? `# ${line}` : '#')), '#########################################', ...content, '################## EOF ##################' ]; }; export function notSupported(name: string) { return (...args: unknown[]) => { console.error(`${name}: not supported.`, args); throw new Error(`${name}: not implemented.`); }; } export function withIdentityContent(title: string, description: string[] | readonly string[], date: Date, content: string[]) { return content; }; export function isDirectoryEmptySync(path: PathLike) { const directoryHandle = fs.opendirSync(path); try { return directoryHandle.readSync() === null; } finally { directoryHandle.closeSync(); } } export function fastIpVersion(ip: string) { return ip.includes(':') ? 6 : (ip.includes('.') ? 4 : 0); }