ansicolor

A dependency-free JavaScript library for ANSI color styling, parsing, and ANSI-to-CSS/Chrome DevTools conversion.

Library
npm
v2.0.3
126stars
Unlicense

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
41/100Fair
Development Activity0
Maintenance20
Community64
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
72/100Good
Architecture78
Code Quality68
Innovation62
Learning Curve80

ansicolor is a small, dependency-free JavaScript library for working with ANSI escape codes. It lets you apply terminal colors and styles to strings through a chainable API (.red, .bgGreen, .underline, method chaining like underline.bright.green(...)), while correctly solving the “style hierarchy” problem that trips up other color libraries: nesting a colored substring inside another color no longer clobbers the surrounding style once the inner span ends.

Beyond just coloring output, ansicolor can parse arbitrary ANSI-escaped strings into structured spans (color, background, bold, italic, underline flags plus a computed CSS string), strip ANSI codes entirely, detect whether a string contains escape codes, and convert parsed spans into Chrome DevTools-compatible console.log argument lists (%c format strings) — making it useful as the rendering layer for platform-agnostic loggers that need to look right in both a terminal and a browser console.

It has no runtime dependencies, ships TypeScript type definitions, and is used as the color engine behind the ololog logging library as well as by projects like CCXT and Grafana for colorized log output.

What You Get

  • A chainable string-styling API covering standard, light, and background ANSI colors plus bright/dim/italic/underline/inverse styles (e.g. underline.bright.green('foo'))
  • Correct handling of nested/overlapping styles (the ‘style hierarchy problem’) that naive ANSI concatenation gets wrong
  • A parse() function that turns an ANSI-escaped string into structured spans with color, bgColor, bold, italic, underline, and a computed css string per span
  • strip() and isEscaped() helpers for removing or detecting ANSI codes in arbitrary strings
  • asChromeConsoleLogArguments output for rendering ANSI-styled strings with real colors in the Chrome DevTools console
  • An opt-in .nice mode that extends String.prototype for infix-style coloring ('foo'.red.bright)
  • Zero runtime dependencies and bundled TypeScript type definitions

Common Use Cases

  • Coloring CLI output (errors, warnings, log levels) without pulling in a heavier dependency tree
  • Building a platform-agnostic logger that needs to render the same colored output correctly in both a terminal and a browser DevTools console
  • Parsing already-ANSI-colored strings (e.g. captured subprocess output) into structured data for re-rendering as HTML/CSS or JSON
  • Stripping ANSI escape codes from captured terminal output before storing, diffing, or displaying it as plain text
  • Detecting whether a string already contains ANSI styling before deciding whether to re-color it

Under The Hood

Architecture The library is a single flat module (ansicolor.js) built around three cooperating pieces: a Code class that decodes a numeric ANSI value into its type/subtype (color, bgColor, style, unstyle) and its raw escape string; a Color class that tracks foreground/background state (name, brightness, inverse) and can render itself to a CSS rgba() declaration; and a Colors class that is both the public API surface and the ANSI string container. String styling flows through assignStringWrappingAPI, which recursively builds chainable getters (.red, .bright, .bgCyan, etc.) over a shared stringWrappingMethods table, wrapping text with open/close escape codes and re-normalizing brightness codes so nested/overlapping styles don’t clobber each other (denormalizeBrightness/normalizeBrightness). Parsing runs as a two-stage generator pipeline: rawParse walks the string char-by-char through a TEXT → BRACKET → CODE state machine (processing in 1MB chunks so large strings can be garbage-collected as they’re consumed) to yield raw Span objects, and parseAnsi consumes that stream to accumulate live style state (current color, bgColor, brightness, active style set) and yield fully-resolved spans carrying both flags and a computed css string. There is no external dependency graph to reason about — the entire behavior lives in this one file.

Tech Stack Plain ES2016+ JavaScript (class, generators, Object.defineProperty), transpiled through Babel (babel-preset-es2016) into a CommonJS build/ansicolor.js and, per package.json exports, an ESM build/ansicolor.mjs. TypeScript consumers get hand-written .d.ts definitions (ansicolor.d.ts) rather than a compiled .ts source. Tooling is ESLint + Prettier (via eslint-plugin-prettier) enforced through Husky + lint-staged pre-commit hooks, Mocha for tests with nyc/istanbul for coverage, and semantic-release for versioned npm publishing. CI (GitHub Actions, Node CI workflow) runs format, lint, and test on every push/PR, then builds and would deploy on pushes to master. No runtime dependencies at all — devDependencies only.

Code Quality Tests live in a single test.js (Mocha describe/it blocks) exercising the styling API, chaining, nice-mode string extensions, brightness hierarchy resolution, and hierarchy/nesting correctness through direct string-equality assertions against expected raw ANSI sequences — a reasonably thorough but example-based (not property-based) suite, run against the built output via ANSICOLOR_MODULE env var indirection. There’s no explicit error-handling layer since the library is pure string transformation with no I/O; malformed input largely falls through the state machine safely (e.g. incomplete escape sequences revert to plain text). Naming is terse but consistent with the domain (Code, Color, Span, rawParse, parseAnsi), and the codebase leans on const/arrow functions and functional array transforms throughout. Type safety for consumers comes from the maintained .d.ts file rather than compile-time checking of the implementation itself.

What Makes It Unique The library’s specific technical contribution is solving what its README calls the “style hierarchy problem”: because ANSI escape codes are linear resets rather than a nested/hierarchical model (unlike HTML/CSS), naively concatenating styled substrings causes an inner color’s reset code to also cancel an outer, still-active style. ansicolor’s denormalizeBrightness/normalizeBrightness code-insertion logic and its span-based re-parsing model specifically restore correct nesting behavior so ('foo'.cyan + 'bar').red renders bar in red as expected — a bug the README demonstrates several popular alternatives getting wrong. Its dual output modes (raw ANSI strings for terminals, and parsed spans convertible to Chrome DevTools %c-format console arguments) also let one styled string be reused unmodified for both terminal and browser console rendering, which is why it underlies the ololog cross-platform logger.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search