wrap-ansi
Word-wraps strings containing ANSI escape codes without breaking color, style, or hyperlink sequences.
Repository Health
Technical Analysis
wrap-ansi word-wraps a string to a specified column width while correctly handling ANSI escape codes — the invisible sequences that terminal libraries like chalk use to add color, bold, underline, and hyperlinks. A naive word-wrap implementation would count escape codes as visible characters, corrupt sequences mid-code, or leave styles bleeding past the point they were meant to end. wrap-ansi instead parses each line into a sequence of plain-text tokens and complete ANSI/OSC control sequences, measures only the visible text against the target width, and reopens any interrupted SGR (color/style) sequence or OSC 8 hyperlink after every forced line break, so each wrapped row renders correctly in isolation.
It supports both soft wrapping (long unbreakable words may exceed the column width) and hard wrapping (nothing exceeds the width, splitting words mid-character if necessary), configurable trimming of leading/trailing whitespace per row, and a toggle for whether word boundaries are respected at all. Because it measures width over Unicode grapheme clusters via Intl.Segmenter rather than raw UTF-16 length, it correctly handles wide characters, combining marks, and emoji. This makes it a foundational building block across the chalk/sindresorhus terminal-tooling ecosystem — CLI libraries that lay out colorized text (boxes, tables, prompts, progress output) depend on it to wrap that text without dropping or misplacing escape sequences.
What You Get
- A single
wrapAnsi(string, columns, options)function with zero configuration required for the common case - Soft and hard wrap modes, controlled via the
hardoption - Automatic style and hyperlink continuation across wrapped lines, so colors and links never leak past their intended scope
- Grapheme-cluster-aware width measurement via
string-width, correctly handling wide, emoji, and combining characters - Shipped TypeScript type definitions (
index.d.ts) with no separate@typespackage needed
Common Use Cases
- CLI help text formatting - CLI tool authors wrap colorized usage/help output to the terminal’s width without breaking ANSI codes mid-sequence
- Terminal UI libraries - libraries that render boxes, tables, and progress displays use wrap-ansi internally to lay out styled text within a fixed width
- Log line wrapping - logging utilities wrap long colorized log messages to a fixed console width for readability
- Interactive prompt rendering - CLI prompt libraries wrap multi-line colored responses so they display correctly regardless of terminal width
Under The Hood
Architecture
The library is a single ESM module (index.js) organized as a linear pipeline rather than a class hierarchy: forEachSegment walks a string as alternating plain-text runs and complete escape sequences (matched via a sticky regex covering CSI/SGR and OSC 8 forms), getTokens/splitWords build on it to produce grapheme-aware tokens and word boundaries, exec performs the actual column-fitting logic row by row, and restoreStylesAcrossRows does a final pass that tracks active SGR styles and any open OSC 8 hyperlink so it can close them before a forced line break and reopen them after. The public wrapAnsi export just normalizes line endings, expands tabs, and maps exec over each input line. Changing the core escape-sequence regex would ripple through every downstream function, since all of them assume sequences are matched as complete, zero-width units.
Tech Stack
Pure ESM with no build step or bundler — package.json declares "type": "module" and ships index.js/index.d.ts directly via the exports map, targeting Node >=20. Runtime dependencies are minimal and both from the same author’s ecosystem: ansi-styles (^6.2.3) for the set of known SGR close codes, and string-width (^8.2.0) for visible-width measurement. Dev dependencies are test/lint-only: chalk, has-ansi, and strip-ansi for fixtures and assertions, tsd for type-definition testing, and xo (an opinionated ESLint preset) for linting. CI (GitHub Actions) runs the test suite against Node 20 and 24.
Code Quality
Tests live in a single test.js using Node’s built-in node:test runner and assert/strict, with dozens of cases covering soft/hard wrap, trim, wordWrap, tab expansion, multi-line style/hyperlink continuation, and edge cases like empty or whitespace-only input. npm test chains xo (lint), node --test (unit tests), and tsd (type-level tests against index.d.ts), so type correctness is checked as rigorously as runtime behavior. Naming is consistent and explicit — protocol constants are named (ANSI_SGR_RESET_FOREGROUND, ANSI_ESCAPE_LINK, etc.) rather than left as magic strings, and inline comments explain non-obvious algorithmic choices (why the regex is sticky, why ASCII text skips grapheme segmentation) throughout the source.
What Makes It Unique
Most naive ANSI-aware wrapping implementations strip escape codes before measuring and reinsert them by position, which breaks down once styles need to be closed and reopened across an inserted line break. wrap-ansi instead treats sequences as complete, zero-width tokens from the start and does an explicit state-tracking pass (restoreStylesAcrossRows) that models active SGR parameters and OSC 8 hyperlinks as a small state machine, closing and reopening them precisely at each row boundary — including the colon-delimited RGB/256-color and underline-color SGR forms, not just the common numeric codes. It also takes a deliberate ASCII fast path (ASCII_PRINTABLE_REGEX) to avoid grapheme segmentation for plain text, trading a small amount of code for a real performance win on the common case.
Used by 3 apps in this directory
Bun
Developer Tools
An all-in-one JavaScript and TypeScript toolkit — one Rust-and-JavaScriptCore binary that replaces Node.js, npm, a bundler, and a test runner with faster equivalents.
openclaude
AI Agents · AI Code Assistants
Run Claude Code workflows against any LLM — OpenAI, Gemini, Ollama, and 200+ backends — from a single terminal-first CLI.
Plasmic
CMS · Low Code Platforms · No Code Platforms
The open-source visual builder that lets teams design React apps and websites with drag-and-drop while integrating seamlessly with your codebase.