@bybrave/columnify2
v2.0.0
Published
Maintained fork of columnify — create text columns for the console. Zero dependencies (ReDoS advisory fixed), dual ESM + CJS, built-in TypeScript types
Maintainers
Readme
@bybrave/columnify2
A maintained, drop-in fork of columnify — create text-based columns suitable for console output from objects or arrays of objects. Automatically resizes columns to fit their content, and supports word wrapping, truncation, alignment, per-column configuration and ANSI colors.
The original columnify has been unmaintained since 2023. This fork keeps its exact output (verified byte-for-byte against the upstream test fixtures) while modernizing the packaging and fixing the most-requested bugs.
npm install @bybrave/columnify2Why this fork
| Feature | columnify | @bybrave/columnify2 |
|---|---|---|
| Runtime dependencies | 2 (wcwidth, strip-ansi) | 0 — everything vendored |
| ReDoS advisory (via ansi-regex) | flagged by npm audit | gone — no dependency tree |
| Module formats | CommonJS only | ESM + CommonJS (dual) |
| TypeScript types | separate @types/columnify | built-in index.d.ts |
| Output compatibility | — | byte-for-byte identical |
Fixes
| Issue | Problem | Fix |
|---|---|---|
| #61 | strip-ansi/ansi-regex pulled in a ReDoS-vulnerable dependency; npm audit complained whenever columnify was a transitive dep | Vendored wcwidth, strip-ansi and ansi-regex@5 into lib/ → zero dependencies, the advisory disappears with the tree |
| #64 | The options object was mutated in place (delete options.config), throwing on a frozen object and surprising callers who reused it | Work on a private copy; the caller's object is never touched |
| #58 | No bundled TypeScript types; needed the separate @types/columnify | Ships a hand-written index.d.ts |
| #52 | RangeError: Maximum call stack size exceeded on very wide columns (e.g. maxWidth: Infinity on long content) | Padding no longer uses Array.apply; built with String.repeat, which has no stack limit |
| #47 | Per-column paddingChr in config was ignored; only the global value worked | Padding character is now read per column, falling back to the global value |
| #17 | An ANSI-styled or wide padding char (e.g. chalk.gray('.')) was chopped mid-escape-sequence | Padding is measured by visual width and whole padding tokens are repeated, never sliced |
Usage
const columnify = require('@bybrave/columnify2')
// or, ESM:
import columnify from '@bybrave/columnify2'
const columns = columnify([{
name: 'mod1',
description: 'some description',
version: '0.0.1',
}, {
name: 'module-two',
description: 'another description',
version: '0.2.0',
}])
console.log(columns)NAME DESCRIPTION VERSION
mod1 some description 0.0.1
module-two another description 0.2.0Pass a plain object to render key/value rows:
columnify({ '[email protected]': 34, '[email protected]': 47 })Options
Global options (also usable per-column via config):
| Option | Default | Description |
|---|---|---|
| maxWidth | Infinity | Maximum column width; longer content wraps or truncates |
| minWidth | 0 | Minimum column width |
| truncate | false | Truncate instead of wrapping |
| truncateMarker | '…' | Marker appended to truncated content |
| align | 'left' | 'left' | 'right' | 'center' |
| paddingChr | ' ' | Character used to pad cells (per-column aware) |
| preserveNewLines | false | Keep existing newlines within a cell |
| showHeaders | true | Show column headers |
| headingTransform | UPPERCASE | Transform applied to each heading |
| dataTransform | identity | Transform applied to each data cell |
Top-level only:
| Option | Default | Description |
|---|---|---|
| columns / include | all keys | Ordered subset of columns to render |
| columnSplitter | ' ' | String between columns |
| maxLineWidth | Infinity | Wrap whole output to width; 'auto' uses process.stdout.columns |
| config | {} | Per-column option overrides, keyed by column name |
See the original documentation for full details — the API is unchanged.
Migration
@bybrave/columnify2 is a drop-in replacement. The public API and output are identical.
- const columnify = require('columnify')
+ const columnify = require('@bybrave/columnify2')If you had @types/columnify installed only for columnify, you can remove it — types are now built in.
npm uninstall columnify @types/columnify
npm install @bybrave/columnify2Known limitations (by design)
These match upstream behavior and are intentionally left unchanged to preserve compatibility:
- Whitespace is collapsed (#45, #37) — all whitespace within a cell is merged to single spaces (use
preserveNewLinesto keep newlines). Preserving arbitrary whitespace would change the output of existing users. - Wrapping is not ANSI-aware across line breaks (#26) — when a colored string wraps onto multiple lines, the escape codes are not re-applied per line. ANSI width is still measured correctly for column sizing.
Support
If this package saves you time, you can support maintenance:
Bitcoin (BTC): bc1q37557q5jpeaxqydzwvf3jgj7zhnfpn2td3q40q
License
MIT © Tim Oxley (original columnify), © bybrave (columnify2 fork).
