From e14fa6bdce7e5ab857860af2962d89e2ed9a92f4 Mon Sep 17 00:00:00 2001 From: clover caruso Date: Sat, 28 Mar 2026 16:03:22 -0700 Subject: [PATCH] feat: expand `string.formatDurationLetters` cases resolves #100 --- lib/string.test.ts | 21 ++++++++++++++++++--- lib/string.ts | 40 +++++++++++++++++++++++++++++++--------- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/lib/string.test.ts b/lib/string.test.ts index 8db6f2008103f91af7a2e69b6ba761e6b49d0de7..ddf66e2b99d6320c1e037be33612c70a005df4fd 100644 --- a/lib/string.test.ts +++ b/lib/string.test.ts @@ -29,22 +29,37 @@ test("escapeShellArgument", () => { assert.equal(string.escapeShellArgument("'string"), "\"'string\""); assert.equal(string.escapeShellArgument("'str\"ing"), "\\''str\"ing'"); }); -test.todo("formatByteSize", () => { +test("formatByteSize", () => { assert.equal(string.formatByteSize(0), "0B"); assert.equal(string.formatByteSize(1), "1B"); assert.equal(string.formatByteSize(1000), "1kB"); assert.equal(string.formatByteSize(-1000), "-1kB"); assert.equal(string.formatByteSize(1500), "1.5kB"); assert.equal(string.formatByteSize(1578), "1.58kB"); - assert.equal(string.formatByteSize(5_100_000), "5.1MB"); + assert.equal(string.formatByteSize(5_100_000), "5.10MB"); assert.equal(string.formatByteSize(-7_231_692_881), "-7.23GB"); - assert.equal(string.formatByteSize(-4_294_967_296), "-7.23GB"); + assert.equal(string.formatByteSize(-4_294_967_296), "-4.29GB"); assert.equal(string.formatByteSize(53.251), "53.25B"); assert.equal(string.formatByteSize(Infinity), "Infinity"); assert.equal(string.formatByteSize(-Infinity), "-Infinity"); assert.equal(string.formatByteSize(NaN), "NaN"); }); +test("formatDurationLetters", () => { + assert.equal(string.formatDurationLetters(1), "1s"); + assert.equal(string.formatDurationLetters(1.542), "1.54s"); + assert.equal(string.formatDurationLetters(1.5), "1.5s"); + assert.equal(string.formatDurationLetters(60), "1m"); + assert.equal(string.formatDurationLetters(65), "1m5s"); + assert.equal(string.formatDurationLetters(10000), "2h46m"); + assert.equal(string.formatDurationLetters(421321378), "13y131d"); + + assert.equal(string.formatDurationLetters(0), "now"); + assert.equal(string.formatDurationLetters(-3000), "50m ago"); + assert.equal(string.formatDurationLetters(Infinity), "forever"); + assert.equal(string.formatDurationLetters(-Infinity), "forever ago"); + assert.equal(string.formatDurationLetters(NaN), "NaN"); +}); import assert from "node:assert"; import { test } from "vitest"; diff --git a/lib/string.ts b/lib/string.ts index e6081cbf57402c3c794008681d9dcb9aa21e9789..c69e3c431548f08b3337c500f8acd5c6641e2a8d 100644 --- a/lib/string.ts +++ b/lib/string.ts @@ -53,10 +53,11 @@ export function formatByteSize(bytes: number): string { bytes /= 1000; unit += 1; } while (bytes >= 1000); - return prefix - + bytes.toFixed( - Math.floor(bytes) === bytes || unit === 1 ? 0 : bytes > 100 ? 1 : 2, - ) + return prefix + (unit === 1 + ? String(+bytes.toFixed(bytes > 100 ? 1 : 2)) + : bytes.toFixed( + Math.floor(bytes) === bytes ? 0 : bytes > 100 ? 1 : 2, + )) + byteUnits.charAt(unit - 1) + "B"; } @@ -73,10 +74,31 @@ export function formatBinaryByteSize(bytes: number): string { + byteUnits.charAt(unit - 1) + "iB"; } -// TODO: export function formatDurationLetters(seconds: number): string { - const minutes = Math.floor(seconds / 60); - const remainingSeconds = seconds % 60; - if (minutes < 1) return `${remainingSeconds}s`; - return `${minutes}m${remainingSeconds}s`; + if (seconds === 0) return "now"; + if (!Number.isFinite(seconds)) { + if (seconds === Infinity) return "forever"; + if (seconds === -Infinity) return "forever ago"; + return "NaN"; + } + let ago = ""; + if (seconds < 0) seconds = -seconds, ago = " ago"; + const units = [ + [31536000, "y"], + [86400, "d"], + [3600, "h"], + [60, "m"], + ] as const; + let out = ""; + let remain = seconds; + let u = 0; + for (const [size, label] of units) { + if (remain < size) continue; + const value = Math.floor(remain / size); + remain -= value * size; + out += `${value}${label}`; + if ((u += 1) === 2) return out + ago; + } + if (remain > 0 || out === "") out += `${+remain.toFixed(2)}s`; + return out + ago; } -- 2.54.0