import assert from "node:assert"; import { describe, it } from "node:test"; import { truncateToWidth, visibleWidth } from "../src/utils.js"; describe("truncateToWidth", () => { it("keeps output within width for very large unicode input", () => { const text = "๐Ÿ™‚็•Œ".repeat(100_000); const truncated = truncateToWidth(text, 40, "โ€ฆ"); assert.ok(visibleWidth(truncated) <= 40); assert.strictEqual(truncated.endsWith("โ€ฆ\x1b[0m"), true); }); it("preserves ANSI styling for kept text and resets before and after ellipsis", () => { const text = `\x1b[31m${"hello ".repeat(1000)}\x1b[0m`; const truncated = truncateToWidth(text, 20, "โ€ฆ"); assert.ok(visibleWidth(truncated) <= 20); assert.strictEqual(truncated.includes("\x1b[31m"), true); assert.strictEqual(truncated.endsWith("\x1b[0mโ€ฆ\x1b[0m"), true); }); it("handles malformed ANSI escape prefixes without hanging", () => { const text = `abc\x1bnot-ansi ${"๐Ÿ™‚".repeat(1000)}`; const truncated = truncateToWidth(text, 20, "โ€ฆ"); assert.ok(visibleWidth(truncated) <= 20); }); it("clips wide ellipsis safely and brackets it with resets", () => { assert.strictEqual(truncateToWidth("abcdef", 1, "๐Ÿ™‚"), ""); assert.strictEqual(truncateToWidth("abcdef", 2, "๐Ÿ™‚"), "\x1b[0m๐Ÿ™‚\x1b[0m"); assert.ok(visibleWidth(truncateToWidth("abcdef", 2, "๐Ÿ™‚")) <= 2); }); it("returns the original text when it already fits even if ellipsis is too wide", () => { assert.strictEqual(truncateToWidth("a", 2, "๐Ÿ™‚"), "a"); assert.strictEqual(truncateToWidth("็•Œ", 2, "๐Ÿ™‚"), "็•Œ"); }); it("pads truncated output to requested width", () => { const truncated = truncateToWidth("๐Ÿ™‚็•Œ๐Ÿ™‚็•Œ๐Ÿ™‚็•Œ", 8, "โ€ฆ", true); assert.strictEqual(visibleWidth(truncated), 8); }); it("adds a trailing reset when truncating without an ellipsis", () => { const truncated = truncateToWidth(`\x1b[31m${"hello".repeat(100)}`, 10, ""); assert.ok(visibleWidth(truncated) <= 10); assert.strictEqual(truncated.endsWith("\x1b[0m"), true); }); it("keeps a contiguous prefix instead of skipping a wide grapheme and resuming later", () => { const truncated = truncateToWidth("๐Ÿ™‚\t็•Œ \x1b_abc\x07", 7, "โ€ฆ", true); assert.strictEqual(truncated, "๐Ÿ™‚\t\x1b[0mโ€ฆ\x1b[0m "); }); }); describe("visibleWidth", () => { it("counts tabs inline and skips ANSI inline", () => { assert.strictEqual(visibleWidth("\t\x1b[31m็•Œ\x1b[0m"), 5); }); it("counts isolated Thai and Lao AM clusters conservatively", () => { assert.strictEqual(visibleWidth("เธณ"), 2); assert.strictEqual(visibleWidth("เบณ"), 2); assert.strictEqual(visibleWidth("เธเธณ"), 2); assert.strictEqual(visibleWidth("เบเบณ"), 2); }); });