# printer ## Purpose Stdout / stderr renderers used by the `suaveplan-font-compress` bin. Owns the help screen, banner, per-file progress lines (success / skip / error), and the end-of-run summary block. Every renderer writes through an injected `NodeJS.WritableStream` so a host (test harness, CI dashboard, web preview) can capture the output without monkey-patching the global `process.stdout`. Lives in its own module so the entry can stay under the AGENTS.md §3 file size budget while keeping the operator-visible output independently inspectable and unit-testable. ## Features - `HELP_TEXT` — the full `--help` screen, including every flag in the spec delta plus the exit-code table. - `printBanner` — one-shot summary printed before any per-file work, showing input, output, format, and force state. - `printSuccessLine` — `✓` line with the family name and either the compressed byte count (`--format=json`) or the compression ratio (`--format=btf`). - `printSkipLine` — `⏭` line when an output already exists and `--force` was not set. - `printErrorLine` — `✗` line written to stderr with the file basename and the failure message. - `printSummary` — block with total / converted / errors / original size / compressed size / ratio / savings, terminated by the output path. ## Usage: Basic ```ts import { HELP_TEXT, printBanner, printSummary } from "./printer.js"; process.stdout.write(HELP_TEXT); printBanner(process.stdout, "/fonts", "/out", "btf", false); printSummary(process.stdout, summary, "/out"); ``` ## Usage: Advanced ```ts import { Writable } from "node:stream"; import { printSummary } from "./printer.js"; const chunks: string[] = []; const captured = new Writable({ write(chunk, _enc, cb) { chunks.push(chunk.toString("utf8")); cb(); }, }); printSummary(captured, summary, "/out"); // chunks.join("") now holds the rendered block — assert in tests / pipe // to a CI dashboard webhook. ``` ## API Reference | Name | Signature | Notes | |---|---|---| | `HELP_TEXT` | `string` | Pre-rendered help screen (ANSI tones included). | | `printBanner` | `(stdout, inputPath, outputPath, format, force) => void` | Writes the run-start block. | | `printSuccessLine` | `(stdout, font, originalBytes, compressedBytes, format) => void` | Emits `✓` line; format choice changes the tail. | | `printSkipLine` | `(stdout, file) => void` | Emits `⏭` for already-existing outputs. | | `printErrorLine` | `(stderr, file, message) => void` | Emits `✗` to stderr. | | `printSummary` | `(stdout, summary, outputRoot) => void` | Emits the end-of-run block. | | `RunSummary` | record | `{ totalFiles, successCount, errorCount, totalOriginalSize, totalCompressedSize }`. | ## Implementation Notes ANSI tones come from `format-utils.ts` so the palette is single-sourced. Every line is composed by `Array#join("\n")` rather than template literals with leading newlines — the test harness can split on `\n` and assert on exact strings without worrying about stray indentation. The summary block always renders the savings percentage even when no bytes were processed (`formatSavings` falls back to `"0.0%"` for non-positive inputs) so the output shape stays stable when an operator runs the bin against an empty directory.