Coming from string-width
A string-width alternative with zero dependencies: linegauge's default export is string-width, graded 233 / 233 by its own suite — plus wrap-ansi, strip-ansi and slice-ansi paths, grapheme-correct over Intl.Segmenter and pure, so a pipe and a terminal get the same columns.
linegauge is a string-width alternative you adopt by changing one import. Its default
export is width, call-compatible with string-width's default, and string-width's own test
suite is the grade.
Migrate from string-width in one import
- import stringWidth from 'string-width';
+ import stringWidth from 'linegauge';It also answers the questions string-width's neighbours do, one subpath each:
| Incumbent | linegauge path |
|---|---|
string-width | linegauge (the default export) |
strip-ansi | linegauge/strip |
wrap-ansi | linegauge/wrap |
slice-ansi | linegauge/slice |
Because the default export is call-compatible, an overrides entry can move a transitive
string-width onto linegauge without a code change; the form is on the
linegauge page.
Is linegauge compatible with string-width?
Graded, not claimed. Each incumbent's own suite, vendored and unmodified apart from the import specifier, runs against its linegauge path beside a control that runs it against the real package:
| linegauge | control | |
|---|---|---|
string-width → linegauge | 233 / 233 | 233 / 233 |
strip-ansi → linegauge/strip | 8 / 8 | 8 / 8 |
wrap-ansi → linegauge/wrap | 85 / 85 | 85 / 85 |
slice-ansi → linegauge/slice | 106 / 106 | 106 / 106 |
From Compatibility, which npm run compat:page generates from the
oracle's last run; that page is the authority.
string-width's options carry over under their own names and defaults. Ambiguous-width
characters count narrow unless you pass ambiguousIsNarrow: false, which counts them two
columns wide for a terminal rendering with a CJK font; countAnsiEscapeCodes: true measures
escape sequences instead of removing them.
What you gain over string-width
linegauge has no output mode of its own, and that is its agent surface: it is pure. Nothing
in it reads process, so how wide the terminal is — and whether there is one — is the
caller's to pass, and the same input gives the same columns on a pipe, under --json and in
a test.
- The edge never frays. A cut that would land inside a grapheme drops the whole cluster; a style open at a cut is re-emitted and closed, so a slice pasted anywhere neither loses its colour nor leaks it.
- The ellipsis is inside the budget.
truncate(text, 10)occupies ten columns or fewer, never eleven — the property a table column depends on. - Grapheme-correct over the platform. Cluster boundaries come from the platform's own
Intl.Segmenter. - The family measures with it. burgee, caique and flagstaff build on linegauge, so what they write for a pipe or an agent is measured the same way a terminal draws it.
When to switch from string-width
- Your dependency tree carries several of string-width, strip-ansi, wrap-ansi and slice-ansi, and you would rather it carried one package.
- A table or box in your CLI gains a phantom column under emoji, CJK or styled input.
The API and the design notes are on linegauge.
Compatibility
How linegauge's four drop-ins are graded — each incumbent's own test suite, unedited — the current grades, and the differences that remain.
Coming from wrap-ansi
A wrap-ansi alternative with a drop-in path: import wrapAnsi from linegauge/wrap, graded 85 / 85 by wrap-ansi's own test suite — then zero dependencies, one style stack shared with slice, and the same grapheme-correct width string-width is graded on, so a wrapped row measures the way a terminal draws it.