authorgravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-03-28 16:03:22-07:00
committergravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-03-28 16:04:24-07:00
loge14fa6bdce7e5ab857860af2962d89e2ed9a92f4
tree0d308d5f920a359f4cbc4c5299760815e4bc3a51
parent8a3ea71b9f6ecd237d57fe181e2a7b8659ad7844
signature Signed by SSH key SHA256:xbd+BjjhyBfwk7GVoURf9Yx0gzDerHbvYv7SddNWmAs

feat: expand `string.formatDurationLetters` cases

resolves #100

2 files changed, 49 insertions(+), 12 deletions(-)

lib/string.test.ts+18-3
......@@ -29,22 +29,37 @@ test("escapeShellArgument", () => {
2929 assert.equal(string.escapeShellArgument("'string"), "\"'string\"");
3030 assert.equal(string.escapeShellArgument("'str\"ing"), "\\''str\"ing'");
3131});
32test.todo("formatByteSize", () => {
32test("formatByteSize", () => {
3333 assert.equal(string.formatByteSize(0), "0B");
3434 assert.equal(string.formatByteSize(1), "1B");
3535 assert.equal(string.formatByteSize(1000), "1kB");
3636 assert.equal(string.formatByteSize(-1000), "-1kB");
3737 assert.equal(string.formatByteSize(1500), "1.5kB");
3838 assert.equal(string.formatByteSize(1578), "1.58kB");
39 assert.equal(string.formatByteSize(5_100_000), "5.1MB");
39 assert.equal(string.formatByteSize(5_100_000), "5.10MB");
4040 assert.equal(string.formatByteSize(-7_231_692_881), "-7.23GB");
41 assert.equal(string.formatByteSize(-4_294_967_296), "-7.23GB");
41 assert.equal(string.formatByteSize(-4_294_967_296), "-4.29GB");
4242
4343 assert.equal(string.formatByteSize(53.251), "53.25B");
4444 assert.equal(string.formatByteSize(Infinity), "Infinity");
4545 assert.equal(string.formatByteSize(-Infinity), "-Infinity");
4646 assert.equal(string.formatByteSize(NaN), "NaN");
4747});
48test("formatDurationLetters", () => {
49 assert.equal(string.formatDurationLetters(1), "1s");
50 assert.equal(string.formatDurationLetters(1.542), "1.54s");
51 assert.equal(string.formatDurationLetters(1.5), "1.5s");
52 assert.equal(string.formatDurationLetters(60), "1m");
53 assert.equal(string.formatDurationLetters(65), "1m5s");
54 assert.equal(string.formatDurationLetters(10000), "2h46m");
55 assert.equal(string.formatDurationLetters(421321378), "13y131d");
56
57 assert.equal(string.formatDurationLetters(0), "now");
58 assert.equal(string.formatDurationLetters(-3000), "50m ago");
59 assert.equal(string.formatDurationLetters(Infinity), "forever");
60 assert.equal(string.formatDurationLetters(-Infinity), "forever ago");
61 assert.equal(string.formatDurationLetters(NaN), "NaN");
62});
4863
4964import assert from "node:assert";
5065import { test } from "vitest";
lib/string.ts+31-9
......@@ -53,10 +53,11 @@ export function formatByteSize(bytes: number): string {
5353 bytes /= 1000;
5454 unit += 1;
5555 } while (bytes >= 1000);
56 return prefix
57 + bytes.toFixed(
58 Math.floor(bytes) === bytes || unit === 1 ? 0 : bytes > 100 ? 1 : 2,
59 )
56 return prefix + (unit === 1
57 ? String(+bytes.toFixed(bytes > 100 ? 1 : 2))
58 : bytes.toFixed(
59 Math.floor(bytes) === bytes ? 0 : bytes > 100 ? 1 : 2,
60 ))
6061 + byteUnits.charAt(unit - 1) + "B";
6162}
6263
......@@ -73,10 +74,31 @@ export function formatBinaryByteSize(bytes: number): string {
7374 + byteUnits.charAt(unit - 1) + "iB";
7475}
7576
76// TODO:
7777export function formatDurationLetters(seconds: number): string {
78 const minutes = Math.floor(seconds / 60);
79 const remainingSeconds = seconds % 60;
80 if (minutes < 1) return `${remainingSeconds}s`;
81 return `${minutes}m${remainingSeconds}s`;
78 if (seconds === 0) return "now";
79 if (!Number.isFinite(seconds)) {
80 if (seconds === Infinity) return "forever";
81 if (seconds === -Infinity) return "forever ago";
82 return "NaN";
83 }
84 let ago = "";
85 if (seconds < 0) seconds = -seconds, ago = " ago";
86 const units = [
87 [31536000, "y"],
88 [86400, "d"],
89 [3600, "h"],
90 [60, "m"],
91 ] as const;
92 let out = "";
93 let remain = seconds;
94 let u = 0;
95 for (const [size, label] of units) {
96 if (remain < size) continue;
97 const value = Math.floor(remain / size);
98 remain -= value * size;
99 out += `${value}${label}`;
100 if ((u += 1) === 2) return out + ago;
101 }
102 if (remain > 0 || out === "") out += `${+remain.toFixed(2)}s`;
103 return out + ago;
82104}