// Reference: // - https://docs.deno.com/runtime/fundamentals/testing/ import { assertEquals } from "jsr:@std/assert"; export function compareVersion(ver1: string, ver2: string): 0 | 1 | -1 { if (ver1 === ver2) return 0; const ver1Parts = ver1.split("."); const ver2Parts = ver2.split("."); const ver1Main = parseInt(ver1Parts[0]); const ver2Main = parseInt(ver2Parts[0]); if (ver1Main > ver2Main) return 1; if (ver1Main < ver2Main) return -1; const ver1Second = parseInt(ver1Parts[1]); const ver2Second = parseInt(ver2Parts[1]); if (ver1Second > ver2Second) return 1; if (ver1Second < ver2Second) return -1; const ver1Third = parseInt(ver1Parts[2]); const ver2Third = parseInt(ver2Parts[2]); if (ver1Third > ver2Third) return 1; if (ver1Third < ver2Third) return -1; return 0; } export function isOn(val: string | undefined): boolean { if ((val === null) || (val === undefined)) { return false; } const lowerVal = val.toLowerCase(); return lowerVal === "on" || lowerVal === "yes" || lowerVal === "1" || lowerVal === "true"; } export function isEnvOn(envKey: string): boolean { return isOn(Deno.env.get(envKey)); } export function formatHumanTime(timeMillis: number): string { const times = []; if (timeMillis < 1000) { return `${timeMillis}ms`; } const timeSecs = Math.floor(timeMillis / 1000); const timeSecsLow = timeSecs % 60; if (timeSecsLow > 0) { times.push(`${timeSecsLow}s`); } const timeMinutes = Math.floor(timeSecs / 60); const timeMinutesLow = timeMinutes % 60; if (timeMinutesLow > 0) { times.push(`${timeMinutesLow}m`); } const timeHours = Math.floor(timeMinutes / 60); const timeHoursLow = timeHours % 24; if (timeHoursLow > 0) { times.push(`${timeHoursLow}h`); } const timeDays = Math.floor(timeHours / 24); if (timeDays > 0) { times.push(`${timeDays}d`); } return times.reverse().join(" "); } export function formatSize(size: number): string { if (size < 0) { return "N/A"; } if (size == 0) { return "0B"; } const sizes = []; const bytesLow = size % 1024; if (bytesLow > 0) { sizes.push(`${bytesLow}B`); } const kb = Math.floor(size / 1024); const kbLow = kb % 1024; if (kbLow > 0) { sizes.push(`${kbLow}KiB`); } const mb = Math.floor(kb / 1024); const mbLow = mb % 1024; if (mbLow > 0) { sizes.push(`${mbLow}MiB`); } const gb = Math.floor(mb / 1024); if (gb > 0) { sizes.push(`${gb}GiB`); } return sizes.reverse().join(" "); } export function formatSize2(size: number): string { if (size < 0) { return "N/A"; } if (size < 1024) { return `${size}B`; } if (size < 1024 * 1024) { return `${formatNumber(size / 1024)}KiB`; } return `${formatNumber(size / (1024 * 1024))}MiB`; } export function formatPercent(a: number, b: number): string { if (b == null || b <= 0) { return "N/A"; } return formatNumber((a * 100) / b) + "%"; } export function formatNumber(num: number): string { const p = num.toString(); const pointIndex = p.indexOf("."); if (pointIndex < 0) { return p + ".00"; } const decimal = p.substring(pointIndex + 1); const decimalPart = decimal.length == 1 ? (decimal + "0") : decimal.substring(0, 2); return p.substring(0, pointIndex) + "." + decimalPart; } export async function clearLastLine() { await printLastLine(""); } export async function printLastLine(line: string) { await Deno.stdout.write( new TextEncoder().encode( `\x1b[1000D${line}\x1b[K`, ), ); } class Term { constructor() { } blink(message: string): string { return `\x1b[5m${message}\x1b[0m`; } bold(message: string): string { return `\x1b[1m${message}\x1b[0m`; } red(message: string): string { return `\x1b[31m${message}\x1b[0m`; } green(message: string): string { return `\x1b[32m${message}\x1b[0m`; } yellow(message: string): string { return `\x1b[33m${message}\x1b[0m`; } } export const term = new Term(); function pad(message: string, length: number): string { if (message.length >= length) { return message; } return message + " ".repeat(length - message.length); } const LOGGER_PREFIX_LEN: number = 8; class Logger { constructor() { } // deno-lint-ignore no-explicit-any success(...data: any[]) { this.log( term.bold(term.green(`[${pad("SUCCESS", LOGGER_PREFIX_LEN)}]`)), data, ); } // deno-lint-ignore no-explicit-any error(...data: any[]) { this.log( term.bold(term.red(`[${pad("ERROR", LOGGER_PREFIX_LEN)}]`)), data, ); } // deno-lint-ignore no-explicit-any warn(...data: any[]) { this.log( term.bold(term.yellow(`[${pad("WARN", LOGGER_PREFIX_LEN)}]`)), data, ); } // deno-lint-ignore no-explicit-any warning(...data: any[]) { this.log( term.blink( term.bold(term.yellow(`[${pad("WARN", LOGGER_PREFIX_LEN)}]`)), ), data, ); } // deno-lint-ignore no-explicit-any info(...data: any[]) { this.log(term.bold(`[${pad("INFO", LOGGER_PREFIX_LEN)}]`), data); } // deno-lint-ignore no-explicit-any debug(...data: any[]) { this.log(`[${pad("DEBUG", LOGGER_PREFIX_LEN)}]`, data); } // deno-lint-ignore no-explicit-any log(prefix: string, data: any[]) { const args = [prefix]; for (let i = 0; i < data.length; i++) { args.push(data[i]); } console.log.apply(console, args); } } export const log = new Logger(); Deno.test("isOn", () => { assertEquals(false, isOn(undefined)); assertEquals(false, isOn("")); assertEquals(true, isOn("true")); assertEquals(true, isOn("TRUE")); assertEquals(true, isOn("yes")); assertEquals(true, isOn("YES")); assertEquals(true, isOn("on")); assertEquals(true, isOn("ON")); assertEquals(true, isOn("1")); }); Deno.test("formatHumanTime", () => { assertEquals("0ms", formatHumanTime(0)); assertEquals("1ms", formatHumanTime(1)); assertEquals("1s", formatHumanTime(1000)); assertEquals("1s", formatHumanTime(1001)); assertEquals("1m", formatHumanTime(60001)); assertEquals("1m 1s", formatHumanTime(61001)); assertEquals("1h", formatHumanTime(3600000)); assertEquals("1h 1s", formatHumanTime(3601000)); assertEquals("1h 1m 1s", formatHumanTime(3661000)); }); Deno.test("formatSize", () => { assertEquals("N/A", formatSize(-1)); assertEquals("0B", formatSize(0)); assertEquals("1B", formatSize(1)); assertEquals("1KiB", formatSize(1024)); assertEquals("1KiB 1B", formatSize(1024 + 1)); assertEquals("1MiB 1KiB 1B", formatSize(1024 * 1024 + 1024 + 1)); assertEquals( "1GiB 1MiB 1KiB 1B", formatSize(1024 * 1024 * 1024 + 1024 * 1024 + 1024 + 1), ); }); Deno.test("formatSize2", () => { assertEquals("N/A", formatSize2(-1)); assertEquals("0B", formatSize2(0)); assertEquals("1B", formatSize2(1)); assertEquals("1.00KiB", formatSize2(1024)); assertEquals("10.00KiB", formatSize2(1024 * 10)); assertEquals("1.00MiB", formatSize2(1024 * 1024)); }); Deno.test("formatPercent", () => { assertEquals("N/A", formatPercent(100, -1)); assertEquals("N/A", formatPercent(100, 0)); assertEquals("N/A", formatPercent(100, 0)); assertEquals("10.00%", formatPercent(10, 100)); assertEquals("11.00%", formatPercent(11, 100)); assertEquals("1.10%", formatPercent(11, 1000)); assertEquals("0.10%", formatPercent(1, 1000)); assertEquals("0.00%", formatPercent(1, 100000)); assertEquals("100.00%", formatPercent(100, 100)); });