diff --git a/CHANGELOG.md b/CHANGELOG.md
index 57bc0fa..8b16ea4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,19 @@
# Change log
+## 3.4.0-beta.1 (2024-12-12)
+
+- fix: url to GitHub in readme for npm package
+
+## 3.4.0-beta.0 (2024-12-12)
+
+- refactor: invisible code optimisations
+- refactor: optimize readme for npm package to save ~400 bytes
+- refactor: optimize index.d.ts for npm package to save ~500 bytes
+- test: refactor benchmark tests
+- test: add new representative benchmark tests for using 1, 2, 3 and 4 styles
+- test: add picocolors complex benchmark test
+- docs: update readme
+
## 3.3.2 (2024-07-23)
- fix: correct detect TTY on Windows platform
diff --git a/README.md b/README.md
index 5a39679..7281b99 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+
@@ -30,22 +31,20 @@ ansi256(214)`Orange`
hex('#E0115F').bold.underline('TrueColor!')
```
-
-
## 👀 Why yet one lib?
- Quality is first, test coverage 100%.
-- Ansis has all [features](#features) that you need, compare with [other libraries](#compare).
-- Ansis is one of the smallest, [3.5 KB](https://bundlephobia.com/package/ansis@3.2.0) only.
-- Ansis is one of the [fastest](#benchmark), up to **x3 faster** than **Chalk**, [see benchmarks](#benchmark).
-- Ansis is stable, continuously developing and improving.
+- Ansis has all [features](#features) that you need, compare with [similar libraries](#compare).
+- Ansis is one of the smallest, [3.5 kB](https://bundlephobia.com/package/ansis@3.2.0) minified and only [2 kB](https://bundlephobia.com/package/ansis@3.2.0) minzipped.
+- Ansis is one of the [fastest](#benchmark), faster than **Chalk** and **Picocolors** (in some use cases), see [benchmarks](#benchmark).
- Ansis is open for your [feature requests](https://github.com/webdiscus/ansis/issues).
-- Quick response to issues.
- Long term support.
+- Used
+ by [NestJS](https://github.com/nestjs/nest), [Facebook/StyleX](https://github.com/facebook/stylex), [Sequelize](https://github.com/sequelize/sequelize), [Salesforce](https://github.com/salesforcecli/cli), [WebpackBar](https://github.com/unjs/webpackbar).
## ⚖️ Similar packages
-Most popular ANSI libraries for Node.js:
+The most popular similar libraries for Node.js:
[chalk][chalk], [kleur][kleur], [ansi-colors][ansi-colors], [kolorist][kolorist], [colorette][colorette], [picocolors][picocolors], [cli-color][cli-color], [colors-cli][colors-cli], [colors.js][colors.js]
@@ -53,6 +52,17 @@ Most popular ANSI libraries for Node.js:
- 💾 [Compare package sizes](#compare-size)
- 📊 [Benchmarks](#benchmark)
+## 🔄 [Switch to Ansis](#switch-to-ansis)
+
+Ansis provides a powerful, small, and fast solution, enabling seamless replacement of heavy, legacy libraries.
+
+- [Replacing `chalk`](#replacing-chalk)
+- [Replacing `colorette`](#replacing-colorette)
+- [Replacing `picocolors`](#replacing-picocolors)
+- [Replacing `ansi-colors`](#replacing-ansi-colors)
+- [Replacing `kleur`](#replacing-kleur)
+- [Replacing `cli-color`](#replacing-cli-color)
+
## 💡 Highlights
@@ -68,19 +78,14 @@ Most popular ANSI libraries for Node.js:
- Supports both **ESM** and **CommonJS**
- Supports **TypeScript**
- Supports **Bun**, **Deno**, **Next.JS** runtimes
-- [Standard API](#base-colors), drop-in replacement for **Chalk**
- ```diff
- - import chalk from 'chalk';
- + import chalk, { red } from 'ansis';
- ```
- ```js
- chalk.red.bold('Error!'); // <- Chalk like syntax works fine with Ansis
- red.bold('Error!'); // <- the same result with Ansis
- red.bold`Error!`; // <- the same result with Ansis
- ```
+- [Standard API](#base-colors)
+- Drop-in replacement for [`chalk`](#replacing-chalk)
+- Drop-in replacement for [`colorette`](#replacing-colorette)
+- Drop-in replacement for [`picocolors`](#replacing-picocolors)
+- Drop-in replacement for [`ansi-colors`](#replacing-ansi-colors)
- Default and [named import](#named-import) `import ansis, { red, bold, ansi256, hex } from 'ansis'`
- [Chained syntax](#chained-syntax) `red.bold.underline('text')`
-- [Nested **template strings**](#nested-syntax) ``` red`RED ${green`GREEN`} RED` ```
+- [Nested **template strings**](#nested-syntax) ``` red`Error: ${blue`file.js`} not found!` ```
- [ANSI styles](#base-colors) `dim` **`bold`** _`italic`_ `underline` `strikethrough`
- [ANSI 16 colors](#base-colors) ``` red`Error!` ``` ``` redBright`Error!` ``` ``` bgRed`Error!` ``` ``` bgRedBright`Error!` ```
- [ANSI 256 colors](#256-colors) ``` fg(56)`violet` ``` ``` bg(208)`orange` ```
@@ -95,6 +100,7 @@ Most popular ANSI libraries for Node.js:
- Doesn't extend `String.prototype`
- Zero dependencies
+
## ❓Question / Feature Request / Bug
@@ -309,7 +316,7 @@ Output:\
## Base ANSI 16 colors and styles
Colors and styles have standard names used by many popular libraries, such
-as [chalk][chalk], [colorette][colorette], [kleur][kleur].
+as [chalk], [colorette], [picocolors], [kleur].
| Foreground colors | Background colors | Styles |
|:----------------------------------------------------------|:----------------------------------------------------------------|-----------------------------------------|
@@ -776,9 +783,9 @@ npm run compare
| Npm package | Require size | Install size | Download size |
|:-----------------------------|-------------:|-------------------------------:|----------------------------------------------------------------------:|
-| [`picocolors`][picocolors] | 2.6 kB | [11.4 kB][npm-picocolors] | [2.6 kB](https://arve0.github.io/npm-download-size/#picocolors) |
+| [`picocolors`][picocolors] | 2.6 kB | [6.4 kB][npm-picocolors] | [2.6 kB](https://arve0.github.io/npm-download-size/#picocolors) |
| [`kleur`][kleur] | 2.7 kB | [20.3 kB][npm-kleur] | [6.0 kB](https://arve0.github.io/npm-download-size/#kleur) |
-| [`ansis`][ansis] | 3.4 kB | [11.4 kB][npm-ansis] | [4.6 kB](https://arve0.github.io/npm-download-size/#ansis) |
+| [`ansis`][ansis] | 3.4 kB | [10.3 kB][npm-ansis] | [4.6 kB](https://arve0.github.io/npm-download-size/#ansis) |
| [`colorette`][colorette] | 3.4 kB | [17.0 kB][npm-colorette] | [4.9 kB](https://arve0.github.io/npm-download-size/#colorette) |
| [`ansi-colors`][ansi-colors] | 5.8 kB | [26.1 kB][npm-ansi-colors] | [8.5 kB](https://arve0.github.io/npm-download-size/#ansi-colors) |
| [`kolorist`][kolorist] | 6.8 kB | [51.0 kB][npm-kolorist] | [8.7 kB](https://arve0.github.io/npm-download-size/#kolorist) |
@@ -834,177 +841,444 @@ To measure performance is used [benchmark.js](https://github.com/bestiejs/benchm
git clone https://github.com/webdiscus/ansis.git
cd ./ansis
npm i
+npm run build
npm run bench
```
> ### Tested on
>
> MacBook Pro 16" M1 Max 64GB\
-> macOS Monterey 12.1\
-> Node.js v16.13.1\
+> macOS Sequoia 15.1\
+> Node.js v22.11.0\
> Terminal `iTerm2`
+---
+
+### Simple bench
+
+The simple test uses only single style.
+Picocolors, Colorette and Kleur do not support [chained syntax](#chained-syntax) or [correct style break](#new-line) (wenn used ``` `\n` ``` in a string),
+so they are the fastest in this simple use case. No function - no performance overhead.
+
+```js
+ansis.red('foo')
+chalk.red('foo')
+picocolors.red('foo')
+...
+```
+
+```diff
++ colorette@2.0.20 109.829.822 ops/sec
+- picocolors@1.1.1 108.598.201 ops/sec
+ kleur@4.1.5 85.231.268 ops/sec
+-> ansis@3.3.3 59.923.848 ops/sec -45.4% (~2x slower than 1st place)
+- chalk@5.3.0 55.828.562 ops/sec -49.2%
+ kolorist@1.8.0 37.159.398 ops/sec
+ ansi-colors@4.1.3 14.202.622 ops/sec
+ colors@1.4.0 6.999.011 ops/sec
+ cli-color@2.0.4 2.742.775 ops/sec
+ colors-cli@1.0.33 913.542 ops/sec
+```
+
+### Using 2 styles
+
+Using only 2 styles, picocolors is already a bit slower, because using the [chained syntax](#chained-syntax) is faster than nested calls.
+
+```js
+ansis.red.bold('foo')
+chalk.red.bold('foo')
+picocolors.red(picocolors.bold('foo')) // chained syntax is not supported
+...
+```
+
+```diff
++ ansis@3.3.3 59.838.727 ops/sec
+- picocolors@1.1.1 58.180.994 ops/sec -2.8%
+- chalk@5.3.0 48.213.743 ops/sec -19.4%
+ colorette@2.0.20 33.308.706 ops/sec
+ kolorist@1.8.0 13.320.722 ops/sec
+ kleur@4.1.5 5.977.286 ops/sec
+ ansi-colors@4.1.3 4.123.687 ops/sec
+ colors@1.4.0 2.986.743 ops/sec
+ cli-color@2.0.4 1.783.370 ops/sec
+ colors-cli@1.0.33 690.808 ops/sec
+```
+
+### Using 3 styles
+
+Using 3 styles, picocolors is 2x slower than ansis.
+
+```js
+ansis.red.bold.underline('foo')
+chalk.red.bold.underline('foo')
+picocolors.red(picocolors.bold(picocolors.underline('foo'))) // chained syntax is not supported
+...
+```
+
+```diff
++ ansis@3.3.3 59.602.490 ops/sec
+- chalk@5.3.0 42.015.098 ops/sec -29.5%
+- picocolors@1.1.1 31.657.041 ops/sec -46.9% (~2x slower than Ansis)
+ colorette@2.0.20 14.499.195 ops/sec
+ kolorist@1.8.0 6.902.305 ops/sec
+ kleur@4.1.5 5.316.469 ops/sec
+ ansi-colors@4.1.3 2.231.060 ops/sec
+ colors@1.4.0 1.772.706 ops/sec
+ cli-color@2.0.4 1.461.792 ops/sec
+ colors-cli@1.0.33 555.396 ops/sec
+```
+
+### Using 4 styles
+
+In rare cases, when using 4 styles, picocolors becomes 3.4x slower than ansis.
+
+```js
+ansis.red.bold.italic.underline('foo')
+chalk.red.bold.italic.underline('foo')
+picocolors.red(picocolors.bold(picocolors.italic(picocolors.underline('foo')))) // chained syntax is not supported
+...
+```
+
+```diff
++ ansis@3.3.3 58.094.313 ops/sec
+- chalk@5.3.0 36.304.684 ops/sec -37.5%
+- picocolors@1.1.1 17.335.630 ops/sec -70.2% (~3.4x slower than Ansis)
+ colorette@2.0.20 8.705.424 ops/sec
+ kleur@4.1.5 4.801.696 ops/sec
+ kolorist@1.8.0 4.324.112 ops/sec
+ ansi-colors@4.1.3 1.524.480 ops/sec
+ colors@1.4.0 1.263.322 ops/sec
+ cli-color@2.0.4 1.210.104 ops/sec
+ colors-cli@1.0.33 484.108 ops/sec
+```
+
+### Deeply nested styles
+
+The complex test with deeply nested styles.
+
+```js
+c.green(
+ `green ${c.cyan(
+ `cyan ${c.red(
+ `red ${c.yellow(
+ `yellow ${c.blue(
+ `blue ${c.magenta(`magenta ${c.underline(`underline ${c.italic(`italic`)} underline`)} magenta`)} blue`,
+ )} yellow`,
+ )} red`,
+ )} cyan`,
+ )} green`,
+)
+```
+
+```diff
++ colorette@2.0.20 1.101.447 ops/sec
+- picocolors@1.1.1 1.058.215 ops/sec
+-> ansis@3.3.3 852.390 ops/sec -22.6%
+ kolorist@1.8.0 837.577 ops/sec
+- chalk@5.3.0 571.903 ops/sec -48.0%
+ kleur@4.1.5 466.172 ops/sec
+ colors@1.4.0 452.397 ops/sec
+ ansi-colors@4.1.3 380.633 ops/sec
+ cli-color@2.0.4 215.335 ops/sec
+ colors-cli@1.0.33 41.589 ops/sec
+```
+
### Colorette bench
The benchmark used in [`colorette`](https://github.com/jorgebucaran/colorette/blob/main/bench/index.js).
```js
-c.red(`${c.bold(`${c.cyan(`${c.yellow('yellow')}cyan`)}`)}red`);
+c.red(`${c.bold(`${c.cyan(`${c.yellow('yellow')}cyan`)}`)}red`)
```
```diff
-+ colorette 4,572,582 ops/sec very fast
- picocolors 3,841,124 ops/sec very fast
--> ansis 2,725,758 ops/sec fast
- chalk 2,287,146 ops/sec fast
- kleur/colors 2,281,415 ops/sec fast
- kleur 2,228,639 ops/sec fast
- ansi-colors 1,265,615 ops/sec slow
- colors.js 1,158,572 ops/sec slow
- cli-color 470,320 ops/sec too slow
- colors-cli 109,811 ops/sec too slow
++ picocolors@1.1.1 3.911.687 ops/sec
+ colorette@2.0.20 3.901.652 ops/sec
+-> ansis@3.3.3 2.992.624 ops/sec -23.5%
+ kolorist@1.8.0 2.555.819 ops/sec
+- chalk@5.3.0 2.544.110 ops/sec -35.0%
+ kleur@4.1.5 2.258.746 ops/sec
+ ansi-colors@4.1.3 1.457.300 ops/sec
+ colors@1.4.0 1.121.523 ops/sec
+ cli-color@2.0.4 481.131 ops/sec
+ colors-cli@1.0.33 115.755 ops/sec
```
-### Base colors
+### Picocolors complex bench
+
+The [`picocolors`](https://github.com/alexeyraspopov/picocolors/blob/main/benchmarks/complex.mjs) benchmark, slightly modified.
+Added a bit more complexity by applying 2 styles to the colorized word instead of one.
```js
-const colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'];
-colors.forEach((color) => c[color]('foo'));
+let index = 1e8;
+c.red('.') +
+c.yellow('.') +
+c.green('.') +
+c.red.bold(' ERROR ') +
+c.red('Add plugin ' + c.cyan.underline('name') + ' to use time limit with ' + c.cyan(++index));
```
```diff
-+ picocolors 8,265,628 ops/sec very fast
--> ansis 6,197,754 ops/sec fast
- kleur 5,455,121 ops/sec fast
- chalk 4,428,884 ops/sec fast
- kleur/colors 2,074,111 ops/sec slow
- colorette 1,874,506 ops/sec slow
- ansi-colors 1,010,628 ops/sec slow
- colors.js 640,101 ops/sec too slow
- cli-color 305,690 ops/sec too slow
- colors-cli 104,962 ops/sec too slow
++ picocolors@1.1.1 2,552,271 ops/sec
+-> ansis@3.3.3 2,449,720 ops/sec -4.0%
+- chalk@5.3.0 2,320,215 ops/sec -9.0%
+ colorette@2.0.20 2,279,859 ops/sec
+ kleur@4.1.5 1,729,928 ops/sec
+ kolorist@1.8.0 1,651,713 ops/sec
+ ansi-colors@4.1.3 807,154 ops/sec
+ colors@1.4.0 530,762 ops/sec
+ cli-color@2.0.4 289,246 ops/sec
+ colors-cli@1.0.33 96,758 ops/sec
```
-### Chained styles
+> [!NOTE]
+> In this near real test, each library uses the fastest possible styling method.\
+> So, `chalk`, `ansis`, `ansi-colors`, `cli-color`, `colors-cli` and `colors` uses chained method, e.g. `c.red.bold(' ERROR ')`.
+> While `picocolors`, `colorette` and `kolorist` uses nested calls, e.g. `c.red(c.bold(' ERROR '))`, because doesn't support the chained syntax.
+
+
+---
+
+#### [↑ top](#top)
+
+
+
+## How to switch to `ansis`
+
+Ansis is a powerful, small, and fast replacement that requires **no code migration** for many similar libraries.\
+Just replace your `import ... from ...` or `require(...)` to `ansis`.
+
+
+
+### Drop-in replacement for [chalk], no migration required
+
+```diff
+- import chalk from 'chalk';
++ import chalk from 'ansis';
+```
+
+Ansis supports the Chalk syntax and is compatible* with [styles and color names](https://github.com/chalk/chalk?tab=readme-ov-file#styles), so you don't need to modify the
+original code:
+
+```js
+chalk.red.bold('Error!');
+
+// colorize "Error: file not found!"
+chalk.red(`Error: ${chalk.cyan.bold('file')} not found!`);
+
+// ANSI 256 colors
+chalk.ansi256(93)('Violet color');
+chalk.bgAnsi256(194)('Honeydew, more or less');
+
+// truecolor
+chalk.hex('#FFA500').bold('Bold orange color');
+chalk.rgb(123, 45, 67).underline('Underlined reddish color');
+chalk.bgHex('#E0115F')('Ruby');
+chalk.bgHex('#96C')('Amethyst');
+```
+
+> [!WARNING]
+>
+> Ansis doesn't not support the `overline` style, because it's **not widely supported** and no one uses it.\
+> Check you code and remove the `overline` style:
+>
+> ```diff
+> - chalk.red.overline('text');
+> + chalk.red('text');
+> ```
+
+Optionally, you can rewrite the same code to make it even shorter and cleaner:
```js
-const colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'];
-colors.forEach((color) => c[color].bold.underline.italic('foo'));
+import { red, cyan, ansi256, bgAnsi256, fg, bg, hex, rgb, bgHex, bgRgb } from 'ansis';
+
+red.bold('Error!'); // using parentheses
+red.bold`Error!`; // using template string
+
+// colorize "Error: file not found!"
+red`Error: ${cyan.bold`file`} not found!`;
+
+// ANSI 256 colors
+ansi256(93)`Violet color`;
+bgAnsi256(194)`Honeydew, more or less`;
+fg(93)`Violet color`; // alias for ansi256
+bg(194)`Honeydew, more or less`; // alias for bgAnsi256
+
+// truecolor
+hex('#FFA500').bold`Bold orange color`;
+rgb(123, 45, 67).underline`Underlined reddish color`;
+bgHex('#E0115F')`Ruby`;
+bgHex('#96C')`Amethyst`;
```
+
+
+### Drop-in replacement for [colorette], no migration required
+
```diff
-+ ansis 5,515,868 ops/sec very fast
- chalk 1,234,573 ops/sec fast
- kleur 514,035 ops/sec slow
- ansi-colors 158,921 ops/sec too slow
- cli-color 144,837 ops/sec too slow
- colors.js 138,219 ops/sec too slow
- colors-cli 52,732 ops/sec too slow
- kleur/colors (not supported)
- colorette (not supported)
- picocolors (not supported)
+- import { red, bold, underline } from 'colorette';
++ import { red, bold, underline } from 'ansis';
```
-### Nested calls
+Ansis is fully compatible with `colorette` [styles and color names](https://github.com/jorgebucaran/colorette#supported-colors), so you don't need to modify the
+original code:
```js
-const colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'];
-colors.forEach((color) => c[color](c.bold(c.underline(c.italic('foo')))));
+red.bold('Error!');
+bold(`I'm ${red(`da ba ${underline("dee")} da ba`)} daa`);
```
+Optionally, you can rewrite the same code to make it even shorter and cleaner:
+
+```js
+red.bold`Error!`;
+bold`I'm ${red`da ba ${underline`dee`} da ba`} daa`;
+```
+
+
+
+### Drop-in replacement for [picocolors], no migration required
+
```diff
-+ picocolors 942,592 ops/sec very fast
- colorette 695,350 ops/sec fast
- kleur 648,195 ops/sec fast
- kleur/colors 561,111 ops/sec fast
--> ansis 558,575 ops/sec fast
- chalk 497,292 ops/sec fast
- ansi-colors 260,316 ops/sec slow
- colors.js 166,425 ops/sec slow
- cli-color 65,561 ops/sec too slow
- colors-cli 13,800 ops/sec too slow
+- import pico from 'picocolors';
++ import pico from 'ansis';
```
-### Nested styles
+Ansis is fully compatible with `picocolors` [styles and color names](https://github.com/alexeyraspopov/picocolors#usage), so you don't need to modify the
+original code:
```js
-c.red(
- `a red ${c.white('white')} red ${c.red('red')} red ${c.cyan('cyan')} red ${c.black('black')} red ${c.red('red')} red
- ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red
- ${c.green('green')} red ${c.red('red')} red ${c.yellow('yellow')} red ${c.blue('blue')} red ${c.red('red')} red
- ${c.magenta('magenta')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red
- ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red
- ${c.black('black')} red ${c.yellow('yellow')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red
- ${c.yellow('yellow')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red
- ${c.green('green')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red
- ${c.magenta('magenta')} red ${c.red('red')} red ${c.red('red')} red ${c.cyan('cyan')} red ${c.red('red')} red
- ${c.cyan('cyan')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red message`
-);
+pico.red(pico.bold('text'));
+pico.red(pico.bold(variable));
+
+// colorize "Error: file not found!"
+pico.red('Error: ' + pico.cyan(pico.bold('file')) + ' not found!');
```
+Optionally, you can rewrite the same code to make it even shorter and cleaner:
+
+```js
+import { red, cyan } from 'ansis';
+
+red.bold`text`;
+red.bold(variable);
+
+// colorize "Error: file not found!"
+red`Error: ${cyan.bold`file`} not found!`
+```
+
+
+
+### Drop-in replacement for [ansi-colors], no migration required
+
```diff
-+ picocolors 243,975 ops/sec very fast
- colorette 243,139 ops/sec very fast
- kleur/colors 234,132 ops/sec very fast
- kleur 221,446 ops/sec very fast
--> ansis 211,868 ops/sec very fast
- chalk 189,960 ops/sec fast
- ansi-colors 121,451 ops/sec slow
- colors.js 89,633 ops/sec too slow
- cli-color 41,657 ops/sec too slow
- colors-cli 14,264 ops/sec too slow
+- const c = require('ansi-colors');
++ const c = require('ansis');
```
-### Deep nested styles
+Ansis is fully compatible with `ansi-color` [styles and color names](https://github.com/doowb/ansi-colors#available-styles), so you don't need to modify the
+original code:
```js
-c.green(
- `green ${c.cyan(
- `cyan ${c.red(
- `red ${c.yellow(
- `yellow ${c.blue(
- `blue ${c.magenta(`magenta ${c.underline(`underline ${c.italic(`italic`)} underline`)} magenta`)} blue`
- )} yellow`
- )} red`
- )} cyan`
- )} green`
-);
+c.red.bold('Error!');
+
+// colorize "Error: file not found!"
+c.red(`Error: ${c.cyan.bold('file')} not found!`);
+```
+
+Optionally, you can rewrite the same code to make it even shorter and cleaner:
+
+```js
+import { red, cyan } from 'ansis';
+
+red.bold('Error!'); // using parentheses
+red.bold`Error!`; // using template string
+
+// colorize "Error: file not found!"
+red`Error: ${cyan.bold`file`} not found!`;
```
+
+
+### Migration from [kleur]
+
```diff
-+ colorette 1,131,757 ops/sec very fast
- picocolors 1,002,649 ops/sec very fast
--> ansis 882,220 ops/sec very fast
- chalk 565,965 ops/sec fast
- kleur/colors 478,547 ops/sec fast
- kleur 464,004 ops/sec fast
- colors.js 451,592 ops/sec fast
- ansi-colors 362,733 ops/sec slow
- cli-color 213,441 ops/sec slow
- colors-cli 40,340 ops/sec too slow
+- import { red, green, yellow, cyan } from 'kleur';
++ import { red, green, yellow, cyan } from 'ansis';
+```
+
+Ansis is fully compatible with `kleur` [styles and color names](https://github.com/lukeed/kleur#api),
+but Kleur `v3.0` no longer uses Chalk-style syntax (magical getter):
+
+```js
+green().bold().underline('this is a bold green underlined message');
+yellow(`foo ${red().bold('red')} bar ${cyan('cyan')} baz`);
```
-### HEX colors
+If you uses chained methods then it requires a simple code modification.
+Just replace `().` with `.`:
+
+```js
+green.bold.underline('this is a bold green underlined message');
+yellow(`foo ${red.bold('red')} bar ${cyan('cyan')} baz`);
+```
-Only two libraries support TrueColor: `ansis` and `chalk`
+Optionally, you can rewrite the same code to make it even shorter and cleaner:
```js
-c.hex('#FBA')('foo');
+yellow`foo ${red.bold`red`} bar ${cyan`cyan`} baz`;
```
+
+
+### Migration from [cli-color]
+
```diff
-+ ansis 4,944,572 ops/sec very fast
- chalk 2,891,684 ops/sec fast
- colors.js (not supported)
- colorette (not supported)
- picocolors (not supported)
- cli-color (not supported)
- colors-cli (not supported)
- ansi-colors (not supported)
- kleur/colors (not supported)
- kleur (not supported)
+- const clc = require('cli-color');
++ const clc = require('ansis');
+```
+
+Ansis is compatible* with `cli-color` [styles and color names](https://github.com/medikoo/cli-color#colors):
+
+```js
+clc.red.bold('Error!');
+
+// colorize "Error: file not found!"
+clc.red(`Error: ${c.cyan.bold('file')} not found!`);
```
+> [!WARNING]
+>
+> Ansis doesn't not support the `blink` style, because it's **not widely supported** and no one uses it.\
+> Check you code and remove the `blink` style:
+>
+> ```diff
+> - clc.red.blink('text');
+> + clc.red('text');
+> ```
+
+If you use ANSI 256 color functions `xterm` or `bgXterm`, these must be replaced with `ansi256` `fn` or `bgAnsi256` `bg`:
+
+```diff
+- clc.xterm(202).bgXterm(236)('Orange text on dark gray background');
++ clc.ansi256(202).bgAnsi256(236)('Orange text on dark gray background');
+```
+
+Optionally, you can rewrite the same code to make it even shorter and cleaner:
+
+```js
+import { red, cyan, fg, bg } from 'ansis';
+
+red.bold`Error!`;
+
+// colorize "Error: file not found!"
+red`Error: ${cyan.bold`file`} not found!`;
+
+fg(202).bg(236)`Orange text on dark gray background`;
+```
+
+---
+
#### [↑ top](#top)
## Testing
@@ -1012,6 +1286,10 @@ c.hex('#FBA')('foo');
`npm run test` will run the unit and integration tests.\
`npm run test:coverage` will run the tests with coverage.
+---
+
+#### [↑ top](#top)
+
## License
[ISC](https://github.com/webdiscus/ansis/blob/master/LICENSE)
@@ -1036,7 +1314,6 @@ c.hex('#FBA')('foo');
[ansis]: https://github.com/webdiscus/ansis
-
[npm-colors.js]: https://www.npmjs.com/package/colors
[npm-colorette]: https://www.npmjs.com/package/colorette
diff --git a/README.npm.md b/README.npm.md
index 7df2811..de4c162 100644
--- a/README.npm.md
+++ b/README.npm.md
@@ -1,25 +1,13 @@
-
-
-
- ANSI Styling
-
-
+
----
-[![codecov](https://codecov.io/gh/webdiscus/ansis/branch/master/graph/badge.svg?token=H7SFJONX1X)](https://codecov.io/gh/webdiscus/ansis)
-[![node](https://img.shields.io/npm/dm/ansis)](https://www.npmjs.com/package/ansis)
-[![size](https://img.shields.io/bundlephobia/minzip/ansis)](https://bundlephobia.com/package/ansis)
+[![](https://codecov.io/gh/webdiscus/ansis/branch/master/graph/badge.svg?token=H7SFJONX1X)](https://codecov.io/gh/webdiscus/ansis)
+[![](https://img.shields.io/npm/dm/ansis)](https://www.npmjs.com/package/ansis)
+[![](https://img.shields.io/bundlephobia/minzip/ansis)](https://bundlephobia.com/package/ansis)
Colorize terminal with ANSI colors & styles, smaller and faster alternative to Chalk.
-🚀 [Install and Quick Start](https://github.com/webdiscus/ansis#install)
-
-✅ [Compare features](https://github.com/webdiscus/ansis#compare) with similar packages
-
-📊 [Benchmarks](https://github.com/webdiscus/ansis#benchmark)
-
-📖 [Read full docs on GitHub](https://github.com/webdiscus/ansis)
+📖 [Docs on GitHub](https://github.com/webdiscus/ansis)
---
-![ANSI demo](https://github.com/webdiscus/ansis/raw/master/docs/img/screenshot-readme-npm.png)
+![](docs/img/screenshot-readme-npm.png)
diff --git a/bench/index.js b/bench/index.js
index d2ed33b..9e47b6b 100644
--- a/bench/index.js
+++ b/bench/index.js
@@ -26,7 +26,6 @@
'use strict';
import Bench from './lib/bench.js';
-import { createFixture } from './lib/utils.js';
// vendor libraries
import chalk from 'chalk';
@@ -36,7 +35,6 @@ import ansiColors from 'ansi-colors';
import cliColor from 'cli-color';
import colorCli from 'colors-cli/safe.js';
import kleur from 'kleur';
-import * as kleurColors from 'kleur/colors';
import * as kolorist from 'kolorist';
import picocolors from 'picocolors';
import { Ansis, green, red, yellow, hex, rgb } from 'ansis';
@@ -58,21 +56,6 @@ if (colorSpace < 3) {
log('The result of some tests can be NOT correct! Choose a modern terminal, e.g. iTerm.\n');
}
-// All vendor libraries to be tested
-const vendors = [
- { name: packages['chalk'], lib: chalk },
- { name: packages['ansis'], lib: ansis },
- { name: packages['colorette'], lib: colorette },
- { name: packages['picocolors'], lib: picocolors },
- { name: packages['kleur'], lib: kleur },
- { name: 'kleur/colors', lib: kleurColors },
- { name: packages['ansi-colors'], lib: ansiColors },
- { name: packages['kolorist'], lib: kolorist },
- { name: packages['cli-color'], lib: cliColor },
- { name: packages['colors-cli'], lib: colorCli },
- { name: packages['colors'], lib: colorsJs },
-];
-
const benchStyle = new Ansis();
const bench = new Bench({
minOpsWidth: 12,
@@ -85,17 +68,14 @@ const bench = new Bench({
failColor: benchStyle.red.bold,
});
-// colors present in all libraries
-const baseColors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'];
-let fixture;
-
log(hex('#F88').inverse.bold` -= Benchmark =- `);
-bench('Using 1 style (red)').
+// Simple bench
+bench('Simple, using 1 style').
add(packages['chalk'], () => chalk.red('foo')).
add(packages['ansis'], () => ansis.red('foo')).
- add(packages['colorette'], () => colorette.red('foo')).
add(packages['picocolors'], () => picocolors.red('foo')).
+ add(packages['colorette'], () => colorette.red('foo')).
add(packages['kleur'], () => kleur.red('foo')).
add(packages['ansi-colors'], () => ansiColors.red('foo')).
add(packages['kolorist'], () => kolorist.red('foo')).
@@ -104,246 +84,192 @@ bench('Using 1 style (red)').
add(packages['colors'], () => colorsJs.red('foo')).
run();
-bench(`Using 2 styles (bgWhite, red)`).
- add(packages['chalk'], () => chalk.bgWhite.red('foo')).
- add(packages['ansis'], () => ansis.bgWhite.red('foo')).
- add(packages['colorette'], () => colorette.bgWhite(colorette.red('foo'))).
- add(packages['picocolors'], () => picocolors.bgWhite(picocolors.red('foo'))).
- add(packages['kleur'], () => kleur.bgWhite().red('foo')).
- add(packages['ansi-colors'], () => ansiColors.bgWhite.red('foo')).
- add(packages['kolorist'], () => kolorist.bgWhite(kolorist.red('foo'))).
- add(packages['cli-color'], () => cliColor.bgWhite.red('foo')).
- add(packages['colors-cli'], () => colorCli.white_b.red('foo')).
- add(packages['colors'], () => colorsJs.bgWhite.red('foo')).
- run();
-
-bench(`Using 3 styles (bgWhite, red, bold)`).
- add(packages['chalk'], () => chalk.bgWhite.red.bold('foo')).
- add(packages['ansis'], () => ansis.bgWhite.red.bold('foo')).
- add(packages['colorette'], () => colorette.bgWhite(colorette.red(colorette.bold('foo')))).
- add(packages['picocolors'], () => picocolors.bgWhite(picocolors.red(picocolors.bold('foo')))).
- add(packages['kleur'], () => kleur.bgWhite().red().bold('foo')).
- add(packages['ansi-colors'], () => ansiColors.bgWhite.red.bold('foo')).
- add(packages['kolorist'], () => kolorist.bgWhite(kolorist.red(kolorist.bold('foo')))).
- add(packages['cli-color'], () => cliColor.bgWhite.red.bold('foo')).
- add(packages['colors-cli'], () => colorCli.white_b.red.bold('foo')).
- add(packages['colors'], () => colorsJs.bgWhite.red.bold('foo')).
- run();
-
-bench(`Using 4 styles (bgWhite red, bold, underline)`).
- add(packages['chalk'], () => chalk.bgWhite.red.bold.underline('foo')).
- add(packages['ansis'], () => ansis.bgWhite.red.bold.underline('foo')).
- add(packages['colorette'], () => colorette.bgWhite(colorette.red(colorette.bold(colorette.underline('foo'))))).
- add(packages['picocolors'], () => picocolors.bgWhite(picocolors.red(picocolors.bold(picocolors.underline('foo'))))).
- add(packages['kleur'], () => kleur.bgWhite().red().bold().underline('foo')).
- add(packages['ansi-colors'], () => ansiColors.bgWhite.red.bold.underline('foo')).
- add(packages['kolorist'], () => kolorist.bgWhite(kolorist.red(kolorist.bold(kolorist.underline('foo'))))).
- add(packages['cli-color'], () => cliColor.bgWhite.red.bold.underline('foo')).
- add(packages['colors-cli'], () => colorCli.white_b.red.bold.underline('foo')).
- add(packages['colors'], () => colorsJs.bgWhite.red.bold.underline('foo')).
+// Fastest way for 2 styles
+bench(`Use 2 styles`).
+ add(packages['chalk'], () => chalk.red.bold('foo')).
+ add(packages['ansis'], () => ansis.red.bold('foo')).
+ add(packages['picocolors'], () => picocolors.red(picocolors.bold('foo'))).
+ add(packages['colorette'], () => colorette.red(colorette.bold('foo'))).
+ add(packages['kleur'], () => kleur.red().bold('foo')).
+ add(packages['ansi-colors'], () => ansiColors.red.bold('foo')).
+ add(packages['kolorist'], () => kolorist.red(kolorist.bold('foo'))).
+ add(packages['cli-color'], () => cliColor.red.bold('foo')).
+ add(packages['colors-cli'], () => colorCli.red.bold('foo')).
+ add(packages['colors'], () => colorsJs.red.bold('foo')).
run();
-// Colorette bench
-// https://github.com/jorgebucaran/colorette/blob/main/bench/index.js
-fixture = createFixture(vendors, coloretteBench);
-bench('Colorette bench').
- add(vendors[0].name, () => fixture[0](vendors[0].lib)).
- add(vendors[1].name, () => fixture[1](vendors[1].lib)).
- add(vendors[2].name, () => fixture[2](vendors[2].lib)).
- add(vendors[3].name, () => fixture[3](vendors[3].lib)).
- add(vendors[4].name, () => fixture[4](vendors[4].lib)).
- add(vendors[5].name, () => fixture[5](vendors[5].lib)).
- add(vendors[6].name, () => fixture[6](vendors[6].lib)).
- add(vendors[7].name, () => fixture[7](vendors[7].lib)).
- add(vendors[8].name, () => fixture[8](vendors[8].lib)).
- add(vendors[9].name, () => fixture[9](vendors[9].lib)).
- add(vendors[10].name, () => fixture[10](vendors[10].lib)).
- run();
-
-// Base colors
-bench('Base colors').
- add(packages['chalk'], () => baseColors.forEach((style) => chalk[style]('foo'))).
- add(packages['ansis'], () => baseColors.forEach((style) => ansis[style]('foo'))).
- add(packages['colorette'], () => baseColors.forEach((style) => colorette[style]('foo'))).
- add(packages['picocolors'], () => baseColors.forEach((style) => picocolors[style]('foo'))).
- add(packages['kleur'], () => baseColors.forEach((style) => kleur[style]('foo'))).
- add('kleur/colors', () => baseColors.forEach((style) => kleurColors[style]('foo'))).
- add(packages['ansi-colors'], () => baseColors.forEach((style) => ansiColors[style]('foo'))).
- add(packages['kolorist'], () => baseColors.forEach((style) => kolorist[style]('foo'))).
- add(packages['cli-color'], () => baseColors.forEach((style) => cliColor[style]('foo'))).
- add(packages['colors-cli'], () => baseColors.forEach((style) => colorCli[style]('foo'))).
- add(packages['colors'], () => baseColors.forEach((style) => colorsJs[style]('foo'))).
+// Fastest way for 3 styles
+bench('Use 3 styles').
+ add(packages['chalk'], () => chalk.red.bold.underline('foo')).
+ add(packages['ansis'], () => ansis.red.bold.underline('foo')).
+ add(packages['picocolors'], () => picocolors.red(picocolors.bold(picocolors.underline('foo')))).
+ add(packages['colorette'], () => colorette.red(colorette.bold(colorette.underline('foo')))).
+ add(packages['kleur'], () => kleur.red().bold().underline('foo')).
+ add(packages['ansi-colors'], () => ansiColors.red.bold.underline('foo')).
+ add(packages['kolorist'], () => kolorist.red(kolorist.bold(kolorist.underline('foo')))).
+ add(packages['cli-color'], () => cliColor.red.bold.underline('foo')).
+ add(packages['colors-cli'], () => colorCli.red.bold.underline('foo')).
+ add(packages['colors'], () => colorsJs.red.bold.underline('foo')).
run();
-// Chained styles
-bench('Chained styles').
- add(packages['chalk'], () => baseColors.forEach((style) => chalk[style].bold.underline.italic('foo'))).
- add(packages['ansis'], () => baseColors.forEach((style) => ansis[style].bold.underline.italic('foo'))).
- add('colorette (not supported)', () => baseColors.forEach((style) => colorette[style].bold.underline.italic('foo'))).
- add('picocolors (not supported)', () =>
- baseColors.forEach((style) => picocolors[style].bold.underline.italic('foo')),
- ).
- add(packages['kleur'], () => baseColors.forEach((style) => kleur[style]().bold().underline().italic('foo'))). // alternate syntax
- add('kleur/colors (not supported)', () =>
- baseColors.forEach((style) => kleurColors[style].bold.underline.italic('foo')),
- ).
- add(packages['ansi-colors'], () => baseColors.forEach((style) => ansiColors[style].bold.underline.italic('foo'))).
- add('kolorist (not supported)', () => baseColors.forEach((style) => kolorist[style].bold.underline.italic('foo'))).
- add(packages['cli-color'], () => baseColors.forEach((style) => cliColor[style].bold.underline.italic('foo'))).
- add(packages['colors-cli'], () => baseColors.forEach((style) => colorCli[style].bold.underline.italic('foo'))).
- add(packages['colors'], () => baseColors.forEach((style) => colorsJs[style].bold.underline.italic('foo'))).
+// Fastest way for 4 styles
+bench('Use 4 styles').
+ add(packages['chalk'], () => chalk.red.bold.italic.underline('foo')).
+ add(packages['ansis'], () => ansis.red.bold.italic.underline('foo')).
+ add(packages['picocolors'], () => picocolors.red(picocolors.bold(picocolors.italic(picocolors.underline('foo'))))).
+ add(packages['colorette'], () => colorette.red(colorette.bold(colorette.italic(colorette.underline('foo'))))).
+ add(packages['kleur'], () => kleur.red().bold().italic().underline('foo')).
+ add(packages['ansi-colors'], () => ansiColors.red.bold.italic.underline('foo')).
+ add(packages['kolorist'], () => kolorist.red(kolorist.bold(kolorist.italic(kolorist.underline('foo'))))).
+ add(packages['cli-color'], () => cliColor.red.bold.italic.underline('foo')).
+ add(packages['colors-cli'], () => colorCli.red.bold.italic.underline('foo')).
+ add(packages['colors'], () => colorsJs.red.bold.italic.underline('foo')).
run();
-// Nested calls
-bench('Nested calls').
- add(packages['chalk'], () => baseColors.forEach((style) => chalk[style](chalk.bold(chalk.underline(chalk.italic('foo')))))).
- add(packages['ansis'], () => baseColors.forEach((style) => ansis[style](ansis.bold(ansis.underline(ansis.italic('foo')))))).
- add(packages['colorette'], () =>
- baseColors.forEach((style) => colorette[style](colorette.bold(colorette.underline(colorette.italic('foo'))))),
- ).
- add(packages['picocolors'], () =>
- baseColors.forEach((style) => picocolors[style](picocolors.bold(picocolors.underline(picocolors.italic('foo'))))),
- ).
- add(packages['kleur'], () => baseColors.forEach((style) => kleur[style](kleur.bold(kleur.underline(kleur.italic('foo')))))).
- add('kleur/colors', () =>
- baseColors.forEach((style) =>
- kleurColors[style](kleurColors.bold(kleurColors.underline(kleurColors.italic('foo')))),
- ),
- ).
- add(packages['ansi-colors'], () =>
- baseColors.forEach((style) => ansiColors[style](ansiColors.bold(ansiColors.underline(ansiColors.italic('foo'))))),
- ).
- add(packages['kolorist'], () =>
- baseColors.forEach((style) => kolorist[style](kolorist.bold(kolorist.underline(kolorist.italic('foo'))))),
- ).
- add(packages['cli-color'], () =>
- baseColors.forEach((style) => cliColor[style](cliColor.bold(cliColor.underline(cliColor.italic('foo'))))),
- ).
- add(packages['colors-cli'], () =>
- baseColors.forEach((style) => colorCli[style](colorCli.bold(colorCli.underline(colorCli.italic('foo'))))),
- ).
- add(packages['colors'], () =>
- baseColors.forEach((style) => colorsJs[style](colorsJs.bold(colorsJs.underline(colorsJs.italic('foo'))))),
- ).
+// Chained syntax
+bench('Chained syntax').
+ add(packages['chalk'], () => chalk.red.bold.italic.underline('foo')).
+ add(packages['ansis'], () => ansis.red.bold.italic.underline('foo')).
+ add(packages['kleur'], () => kleur.red().bold().underline('foo')).
+ add(packages['ansi-colors'], () => ansiColors.red.bold.underline('foo')).
+ add(packages['cli-color'], () => cliColor.red.bold.underline('foo')).
+ add(packages['colors-cli'], () => colorCli.red.bold.underline('foo')).
+ add(packages['colors'], () => colorsJs.red.bold.underline('foo')).
+ // colorette - (not supported)
+ // picocolors - (not supported)
+ // kolorist - (not supported)
run();
-// Nested styles
-fixture = createFixture(vendors, nestedFixture);
+// Nested styles, like picocolors recursion
bench('Nested styles').
- add(packages['chalk'], () => fixture[0](chalk)).
- add(packages['ansis'], () => fixture[1](ansis)).
- add(packages['colorette'], () => fixture[2](colorette)).
- add(packages['picocolors'], () => fixture[3](picocolors)).
- add(packages['kleur'], () => fixture[4](kleur)).
- add('kleur/colors', () => fixture[5](kleurColors)).
- add(packages['ansi-colors'], () => fixture[6](ansiColors)).
- add(packages['kolorist'], () => fixture[7](kolorist)).
- add(packages['cli-color'], () => fixture[8](cliColor)).
- add(packages['colors-cli'], () => fixture[9](colorCli)).
- add(packages['colors'], () => fixture[10](colorsJs)).
+ add(packages['chalk'], () => chalk.red(chalk.bold(chalk.underline(chalk.italic('foo'))))).
+ add(packages['ansis'], () => ansis.red(ansis.bold(ansis.underline(ansis.italic('foo'))))).
+ add(packages['picocolors'], () => picocolors.red(picocolors.bold(picocolors.italic(picocolors.underline('foo'))))).
+ add(packages['colorette'], () => colorette.red(colorette.bold(colorette.underline(colorette.italic('foo'))))).
+ add(packages['kleur'], () => kleur.red(kleur.bold(kleur.underline(kleur.italic('foo'))))).
+ add(packages['ansi-colors'], () => ansiColors.red(ansiColors.bold(ansiColors.underline(ansiColors.italic('foo'))))).
+ add(packages['kolorist'], () => kolorist.red(kolorist.bold(kolorist.underline(kolorist.italic('foo'))))).
+ add(packages['cli-color'], () => cliColor.red(cliColor.bold(cliColor.underline(cliColor.italic('foo'))))).
+ add(packages['colors-cli'], () => colorCli.red(colorCli.bold(colorCli.underline(colorCli.italic('foo'))))).
+ add(packages['colors'], () => colorsJs.red(colorsJs.bold(colorsJs.underline(colorsJs.italic('foo'))))).
run();
// Deep nested styles
-fixture = createFixture(vendors, deepNestedFixture);
+const deepNestedBench = (c) => c.green(
+ `green ${c.cyan(
+ `cyan ${c.red(
+ `red ${c.yellow(
+ `yellow ${c.blue(
+ `blue ${c.magenta(`magenta ${c.underline(`underline ${c.italic(`italic`)} underline`)} magenta`)} blue`,
+ )} yellow`,
+ )} red`,
+ )} cyan`,
+ )} green`,
+);
+
bench('Deep nested styles').
- add(packages['chalk'], () => fixture[0](chalk)).
- add(packages['ansis'], () => fixture[1](ansis)).
- add(packages['colorette'], () => fixture[2](colorette)).
- add(packages['picocolors'], () => fixture[3](picocolors)).
- add(packages['kleur'], () => fixture[4](kleur)).
- add('kleur/colors', () => fixture[5](kleurColors)).
- add(packages['ansi-colors'], () => fixture[6](ansiColors)).
- add(packages['kolorist'], () => fixture[7](kolorist)).
- add(packages['cli-color'], () => fixture[8](cliColor)).
- add(packages['colors-cli'], () => fixture[9](colorCli)).
- add(packages['colors'], () => fixture[10](colorsJs)).
+ add(packages['chalk'], () => deepNestedBench(chalk)).
+ add(packages['ansis'], () => deepNestedBench(ansis)).
+ add(packages['picocolors'], () => deepNestedBench(picocolors)).
+ add(packages['colorette'], () => deepNestedBench(colorette)).
+ add(packages['kleur'], () => deepNestedBench(kleur)).
+ add(packages['ansi-colors'], () => deepNestedBench(ansiColors)).
+ add(packages['kolorist'], () => deepNestedBench(kolorist)).
+ add(packages['cli-color'], () => deepNestedBench(cliColor)).
+ add(packages['colors-cli'], () => deepNestedBench(colorCli)).
+ add(packages['colors'], () => deepNestedBench(colorsJs)).
run();
-// Check support of correct break style at new line
-
-// Break style at new line
-//const breakStyleAtNewLineFixture = `\nAnsis\nNEW LINE\nNEXT NEW LINE\n`;
-// bench('New Line')
-// .add('colors.js', () => colorsJs.bgGreen(breakStyleAtNewLineFixture))
-// .add(packages['ansi-colors'], () => ansiColors.bgGreen(breakStyleAtNewLineFixture))
-// .add(packages['chalk'], () => chalk.bgGreen(breakStyleAtNewLineFixture))
-// .add(packages['ansis'], () => ansis.bgGreen(breakStyleAtNewLineFixture))
-// .run();
-
-bench('RGB colors').add(packages['chalk'], () => {
- for (let i = 0; i < 256; i++) chalk.rgb(i, 150, 200)('foo');
-}).add(packages['ansis'], () => {
- for (let i = 0; i < 256; i++) rgb(i, 150, 200)('foo');
-}).run();
-
-// HEX colors
-// the hex(), rgb(), bgHex(), bgRgb() methods support only chalk and ansis
-bench('HEX colors').
- add(packages['chalk'], () => chalk.hex('#FBA')('foo')).
- add(packages['ansis'], () => hex('#FBA')('foo')).
- run();
+// Colorette bench
+// https://github.com/jorgebucaran/colorette/blob/main/bench/index.js
+const coloretteBanch = (c) => c.red(`${c.bold(`${c.cyan(`${c.yellow('yellow')}cyan`)}`)}red`);
-// Spectrum HEX colors
-bench('Spectrum HEX colors').
- add(packages['chalk'], () => {
- let str = '';
- spectrum.forEach(color => {
- str += chalk.hex(color)('█');
- });
- return str;
- }).
- add(packages['ansis'], () => {
- let str = '';
- spectrum.forEach(color => {
- str += hex(color)('█');
- });
- return str;
- }).
+bench('Colorette bench').
+ add(packages['chalk'], () => coloretteBanch(chalk)).
+ add(packages['ansis'], () => coloretteBanch(ansis)).
+ add(packages['picocolors'], () => coloretteBanch(picocolors)).
+ add(packages['colorette'], () => coloretteBanch(colorette)).
+ add(packages['kleur'], () => coloretteBanch(kleur)).
+ add(packages['ansi-colors'], () => coloretteBanch(ansiColors)).
+ add(packages['kolorist'], () => coloretteBanch(kolorist)).
+ add(packages['cli-color'], () => coloretteBanch(cliColor)).
+ add(packages['colors-cli'], () => coloretteBanch(colorCli)).
+ add(packages['colors'], () => coloretteBanch(colorsJs)).
run();
-// Template literals
-bench('Template literals').
- add(packages['ansis'], () => red`red ${yellow`yellow ${green`green`} yellow`} red`).
+// Picocolors complex bench, slightly modified
+// Added a bit more complexity by applying 2 styles to the colorized word instead of one.
+let index = 1e8;
+const picoComplex = (c) => c.red('.') +
+ c.yellow('.') +
+ c.green('.') +
+ c.red(c.bold(' ERROR ')) + // <= here is used nested calls, because picocolors doesn't support the chained syntax.
+ c.red('Add plugin ' + c.cyan(c.underline('name')) + ' to use time limit with ' + c.cyan(++index));
+
+const ansisComplex = (c) => c.red('.') +
+ c.yellow('.') +
+ c.green('.') +
+ c.red.bold(' ERROR ') + // <= use chained syntax where is possible to improve readability and performance
+ c.red('Add plugin ' + c.cyan.underline('name') + ' to use time limit with ' + c.cyan(++index));
+
+bench('Picocolors complex bench').
+ add(packages['chalk'], () => ansisComplex(chalk)).
+ add(packages['ansis'], () => picoComplex(ansis)).
+ add(packages['ansis'], () => ansisComplex(ansis)).
+ add(packages['picocolors'], () => picoComplex(picocolors)).
+ add(packages['colorette'], () => picoComplex(colorette)).
+ add(packages['kleur'], () => picoComplex(kleur)).
+ add(packages['kolorist'], () => picoComplex(kolorist)).
+ add(packages['ansi-colors'], () => ansisComplex(ansiColors)).
+ add(packages['cli-color'], () => ansisComplex(cliColor)).
+ add(packages['colors-cli'], () => ansisComplex(colorCli)).
+ add(packages['colors'], () => ansisComplex(colorsJs)).
run();
-function coloretteBench(c) {
- return c.red(`${c.bold(`${c.cyan(`${c.yellow('yellow')}cyan`)}`)}red`);
-}
-
-function nestedFixture(c) {
- return c.red(
- `a red ${c.white('white')} red ${c.red('red')} red ${c.cyan('cyan')} red ${c.black('black')} red ${c.red(
- 'red',
- )} red ${c.green('green')} red ${c.red('red')} red ${c.yellow('yellow')} red ${c.blue('blue')} red ${c.red(
- 'red',
- )} red ${c.magenta('magenta')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red(
- 'red',
- )} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red(
- 'red',
- )} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red(
- 'red',
- )} red ${c.green('green')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red(
- 'red',
- )} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red(
- 'red',
- )} red ${c.magenta('magenta')} red ${c.red('red')} red ${c.red('red')} red ${c.cyan('cyan')} red ${c.red(
- 'red',
- )} red ${c.red('red')} red ${c.yellow('yellow')} red ${c.red('red')} red ${c.red('red')} red ${c.red(
- 'red',
- )} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} message`,
- );
-}
+// Check support of correct break style at new line
-function deepNestedFixture(c) {
- return c.green(
- `green ${c.cyan(
- `cyan ${c.red(
- `red ${c.yellow(
- `yellow ${c.blue(
- `blue ${c.magenta(`magenta ${c.underline(`underline ${c.italic(`italic`)} underline`)} magenta`)} blue`,
- )} yellow`,
- )} red`,
- )} cyan`,
- )} green`,
- );
-}
+// Break style at new line
+// const breakStyleAtNewLineFixture = `\nAnsis\nNEW LINE\nNEXT NEW LINE\n`;
+// bench('New Line').
+// add('colors.js', () => colorsJs.bgGreen(breakStyleAtNewLineFixture)).
+// add(packages['ansi-colors'], () => ansiColors.bgGreen(breakStyleAtNewLineFixture)).
+// add(packages['chalk'], () => chalk.bgGreen(breakStyleAtNewLineFixture)).
+// // 2x slower as chalk because chalk use own implementation, but ansis save 400 bytes and uses regexp, this speed is not critical
+// add(packages['ansis'], () => ansis.bgGreen(breakStyleAtNewLineFixture)).
+// run();
+
+// bench('RGB colors').add(packages['chalk'], () => {
+// for (let i = 0; i < 256; i++) chalk.rgb(i, 150, 200)('foo');
+// }).add(packages['ansis'], () => {
+// for (let i = 0; i < 256; i++) rgb(i, 150, 200)('foo');
+// }).run();
+//
+// // HEX colors
+// // the hex(), rgb(), bgHex(), bgRgb() methods support only chalk and ansis
+// bench('HEX colors').
+// add(packages['chalk'], () => chalk.hex('#FBA')('foo')).
+// add(packages['ansis'], () => hex('#FBA')('foo')).
+// run();
+//
+// // Spectrum HEX colors
+// bench('Spectrum HEX colors').
+// add(packages['chalk'], () => {
+// let str = '';
+// spectrum.forEach(color => {
+// str += chalk.hex(color)('█');
+// });
+// return str;
+// }).
+// add(packages['ansis'], () => {
+// let str = '';
+// spectrum.forEach(color => {
+// str += hex(color)('█');
+// });
+// return str;
+// }).
+// run();
+
+// // Template literals
+// bench('Template literals').
+// add(packages['ansis'], () => red`red ${yellow`yellow ${green`green`} yellow`} red`).
+// run();
diff --git a/bench/package.json b/bench/package.json
index c6d4366..05ef2dd 100644
--- a/bench/package.json
+++ b/bench/package.json
@@ -19,7 +19,7 @@
"colors-cli": "1.0.33",
"kleur": "4.1.5",
"kolorist": "1.8.0",
- "picocolors": "1.1.0",
+ "picocolors": "1.1.1",
"vitest": "^2.1.1"
}
}
diff --git a/bench/packages.js b/bench/packages.js
index 9f01373..6b63bf3 100644
--- a/bench/packages.js
+++ b/bench/packages.js
@@ -1,5 +1,5 @@
-import pkgJson from './package.json' assert { type: 'json' };
-import mainPkgJson from '../package.json' assert { type: 'json' };
+import pkgJson from './package.json' with { type: 'json' };
+import mainPkgJson from '../package.json' with { type: 'json' };
const packages = Object.fromEntries(
Object.entries(pkgJson.dependencies).map(([name, version]) => [name, `${name}@${version}`]));
diff --git a/bench/yoctocolors/README.md b/bench/yoctocolors/README.md
new file mode 100644
index 0000000..ac7ea63
--- /dev/null
+++ b/bench/yoctocolors/README.md
@@ -0,0 +1,9 @@
+# yoctocolors benchmark
+
+The benchmark from the [yoctocolors](https://github.com/sindresorhus/yoctocolors) GitHub repo.
+
+Run bench:
+
+```
+./benchmark.js
+```
diff --git a/bench/yoctocolors/benchmark.js b/bench/yoctocolors/benchmark.js
new file mode 100755
index 0000000..c654178
--- /dev/null
+++ b/bench/yoctocolors/benchmark.js
@@ -0,0 +1,87 @@
+#!/usr/bin/env node
+import { Suite } from '@jonahsnider/benchmark';
+import ansi from 'ansi-colors';
+import ansis from 'ansis';
+import chalk from 'chalk';
+import cliColor from 'cli-color';
+import * as colorette from 'colorette';
+import kleur from 'kleur';
+import * as kleurColors from 'kleur/colors';
+import * as nanocolors from 'nanocolors';
+import picocolors from 'picocolors';
+import * as yoctocolors from 'yoctocolors';
+
+const suite = new Suite('simple', {
+ warmup: { trials: 10_000_000 },
+ run: { trials: 1_000_000 },
+});
+
+// eslint-disable-next-line no-unused-vars
+let out;
+
+suite.addTest('yoctocolors', () => {
+ out = yoctocolors.red('Add plugin to use time limit');
+ out = yoctocolors.green('Add plugin to use time limit');
+ out = yoctocolors.blue(`Add plugin to ${yoctocolors.cyan('use')} time limit`);
+})
+ // .addTest('cli-color', () => {
+ // out = cliColor.red('Add plugin to use time limit');
+ // out = cliColor.green('Add plugin to use time limit');
+ // out = cliColor.blue(`Add plugin to ${cliColor.cyan('use')} time limit`);
+ // }).addTest('ansi-colors', () => {
+ // out = ansi.red('Add plugin to use time limit');
+ // out = ansi.green('Add plugin to use time limit');
+ // out = ansi.blue(`Add plugin to ${ansi.cyan('use')} time limit`);
+ // }).addTest('chalk', () => {
+ // out = chalk.red('Add plugin to use time limit');
+ // out = chalk.green('Add plugin to use time limit');
+ // out = chalk.blue(`Add plugin to ${chalk.cyan('use')} time limit`);
+ // }).addTest('kleur', () => {
+ // out = kleur.red('Add plugin to use time limit');
+ // out = kleur.green('Add plugin to use time limit');
+ // out = kleur.blue(`Add plugin to ${kleur.cyan('use')} time limit`);
+ // }).addTest('kleur/colors', () => {
+ // out = kleurColors.red('Add plugin to use time limit');
+ // out = kleurColors.green('Add plugin to use time limit');
+ // out = kleurColors.blue(`Add plugin to ${kleurColors.cyan('use')} time limit`);
+ // }).addTest('colorette', () => {
+ // out = colorette.red('Add plugin to use time limit');
+ // out = colorette.green('Add plugin to use time limit');
+ // out = colorette.blue(`Add plugin to ${colorette.cyan('use')} time limit`);
+ // }).addTest('nanocolors', () => {
+ // out = nanocolors.red('Add plugin to use time limit');
+ // out = nanocolors.green('Add plugin to use time limit');
+ // out = nanocolors.blue(`Add plugin to ${nanocolors.cyan('use')} time limit`);
+ // }).addTest('picocolors', () => {
+ // out = picocolors.red('Add plugin to use time limit');
+ // out = picocolors.green('Add plugin to use time limit');
+ // out = picocolors.blue(`Add plugin to ${picocolors.cyan('use')} time limit`);
+ // })
+ .addTest('ansis', () => {
+ out = ansis.red('Add plugin to use time limit');
+ out = ansis.green('Add plugin to use time limit');
+ out = ansis.blue(`Add plugin to ${ansis.cyan('use')} time limit`);
+ });
+
+out = ansis.red('Add plugin to use time limit');
+out = ansis.green('Add plugin to use time limit');
+out = ansis.blue(`Add plugin to ${ansis.cyan('use')} time limit`);
+console.log(ansis.blue(`Add plugin to ${ansis.cyan('use')} time limit`));
+
+const results = await suite.run();
+
+const table = [...results]
+ // Convert median execution time to mean ops/sec
+ .map(([library, histogram]) => [
+ library,
+ Math.round(1e9 / histogram.percentile(50)),
+ ])
+ // Sort fastest to slowest
+ .sort(([, a], [, b]) => b - a)
+ // Convert to object for console.table
+ .map(([library, opsPerSec]) => ({
+ library,
+ 'ops/sec': opsPerSec.toLocaleString(),
+ }));
+
+console.table(table);
diff --git a/bench/yoctocolors/package.json b/bench/yoctocolors/package.json
new file mode 100644
index 0000000..d2f8fe1
--- /dev/null
+++ b/bench/yoctocolors/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "bench-yoctocolors",
+ "version": "2.1.1",
+ "description": "Benchmark from yoctocolors package",
+ "license": "MIT",
+ "repository": "sindresorhus/yoctocolors",
+ "funding": "https://github.com/sponsors/sindresorhus",
+ "author": {
+ "name": "Sindre Sorhus",
+ "email": "sindresorhus@gmail.com",
+ "url": "https://sindresorhus.com"
+ },
+ "type": "module",
+ "exports": {
+ "types": "./index.d.ts",
+ "default": "./index.js"
+ },
+ "sideEffects": false,
+ "engines": {
+ "node": ">=18"
+ },
+ "files": [
+ "index.js",
+ "index.d.ts",
+ "base.js",
+ "base.d.ts"
+ ],
+ "devDependencies": {
+ "@jonahsnider/benchmark": "^5.0.3",
+ "ansi-colors": "^4.1.3",
+ "ansis": "file:../../",
+ "chalk": "^5.3.0",
+ "cli-color": "^2.0.4",
+ "colorette": "^2.0.20",
+ "kleur": "^4.1.5",
+ "nanocolors": "^0.2.13",
+ "picocolors": "^1.0.1",
+ "yoctocolors": "^2.1.1"
+ },
+ "ava": {
+ "environmentVariables": {
+ "FORCE_COLOR": "1"
+ }
+ }
+}
diff --git a/docs/README.md b/docs/README.md
index c3f6ec9..d806c5c 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -5,7 +5,7 @@
The files from the `package/` will be coped to `dist/` via `rollup`, see the `rollup.config.js`.
> Note:
-> - the `./package/package.json` work only from installed package via `npm install ansis`.
+> - the `./package.npm.json` works only from installed package via `npm install ansis`.
> - the `./package.json` configured for local usage, e.g. to build distributive, run test, bench.
The files for NPM package will be published from the `dist/` directory.
@@ -13,16 +13,19 @@ The files for NPM package will be published from the `dist/` directory.
This allows you to reduce the package size and use a different `package.json` optimized only for the NPM package.
### Publish for public access
+
```
npm run publish:public
```
### Publish beta version
+
```
npm run publish:beta
```
### Unpublish beta
+
```
npm deprecate ansis@ "remove beta version"
```
diff --git a/package.json b/package.json
index 6cbfb88..2b36125 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ansis",
- "version": "3.3.2",
+ "version": "3.4.0",
"description": "Colorize terminal output with ANSI colors & styles",
"keywords": [
"ansi",
@@ -14,7 +14,6 @@
"cli",
"log",
"logging",
- "strip-color",
"truecolor",
"rgb",
"red",
diff --git a/package.npm.json b/package.npm.json
index daa513e..48ff19a 100644
--- a/package.npm.json
+++ b/package.npm.json
@@ -1,15 +1,13 @@
{
"name": "ansis",
- "version": "3.3.2",
+ "version": "3.4.0-beta.1",
"description": "Colorize terminal output with ANSI colors & styles",
"keywords": [
"ansi",
"color",
- "truecolor",
"console",
"terminal",
- "cli",
- "chalk"
+ "cli"
],
"license": "ISC",
"author": "webdiscus",
@@ -25,7 +23,7 @@
},
"sideEffects": false,
"engines": {
- "node": ">=15"
+ "node": ">=16"
},
"files": [
"index.*"
diff --git a/rollup.config.js b/rollup.config.js
index d04dba8..cbc5b4a 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -61,7 +61,21 @@ export default [
{
src: 'dist/index.d.ts',
dest: 'dist/',
- transform: (contents, name) => { return contents.toString().replaceAll(/\n/g, '');},
+ transform: (contents, name) => {
+ return contents.toString().
+ // remove insignificant spaces
+ replaceAll(/\n/g, '').
+ replaceAll(/\s{2}/g, ' ').
+ replaceAll(' | ', '|').
+ replaceAll(' = ', '=').
+ replaceAll(' => ', '=>').
+ replaceAll(', ', ',').
+ replaceAll(': ', ':').
+ replaceAll('{ ', '{').
+ replaceAll(' {', '{').
+ replaceAll(' }', '}').
+ replaceAll('; ', ';');
+ },
},
{ src: 'package.npm.json', dest: 'dist/', rename: 'package.json' },
diff --git a/src/index.d.ts b/src/index.d.ts
index a081c3a..22d71bd 100644
--- a/src/index.d.ts
+++ b/src/index.d.ts
@@ -1,3 +1,63 @@
+/**
+ * Base ANSI Styles
+ */
+type AnsiStyles = (
+ | 'reset'
+ | 'inverse'
+ | 'hidden'
+ | 'visible'
+ | 'bold'
+ | 'dim'
+ | 'italic'
+ | 'underline'
+ | 'strikethrough'
+ | 'strike'
+ );
+
+/**
+ * Base ANSI Colors
+ */
+type AnsiColors = (
+ | 'black'
+ | 'red'
+ | 'green'
+ | 'yellow'
+ | 'blue'
+ | 'magenta'
+ | 'cyan'
+ | 'white'
+ | 'grey'
+ | 'gray'
+ | 'blackBright'
+ | 'redBright'
+ | 'greenBright'
+ | 'yellowBright'
+ | 'blueBright'
+ | 'magentaBright'
+ | 'cyanBright'
+ | 'whiteBright'
+ | 'bgBlack'
+ | 'bgRed'
+ | 'bgGreen'
+ | 'bgYellow'
+ | 'bgBlue'
+ | 'bgMagenta'
+ | 'bgCyan'
+ | 'bgWhite'
+ | 'bgGrey'
+ | 'bgGray'
+ | 'bgBlackBright'
+ | 'bgRedBright'
+ | 'bgGreenBright'
+ | 'bgYellowBright'
+ | 'bgBlueBright'
+ | 'bgMagentaBright'
+ | 'bgCyanBright'
+ | 'bgWhiteBright'
+ );
+
+type StringUnion = T | (B & Record);
+type AnsiColorsExtend = StringUnion;
type ColorExtend = Record;
interface Ansis {
@@ -6,7 +66,7 @@ interface Ansis {
*
* @return {boolean}
*/
- isSupported: () => boolean;
+ isSupported(): boolean;
/**
* Return styled string.
@@ -30,14 +90,14 @@ interface Ansis {
*
* @param {number} code in range [0, 255].
*/
- ansi256: (code: number) => this;
+ ansi256(code: number): this;
/**
* Alias for ansi256.
*
* @param {number} code in range [0, 255].
*/
- fg: (code: number) => this;
+ fg(code: number): this;
/**
* Set [256-color ANSI code](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) for background color.
@@ -52,14 +112,14 @@ interface Ansis {
*
* @param {number} code in range [0, 255].
*/
- bgAnsi256: (code: number) => this;
+ bgAnsi256(code: number): this;
/**
* Alias for bgAnsi256.
*
* @param {number} code in range [0, 255].
*/
- bg: (code: number) => this;
+ bg(code: number): this;
/**
* Set RGB values for foreground color.
@@ -68,14 +128,7 @@ interface Ansis {
* @param {number} green The green value, in range [0, 255].
* @param {number} blue The blue value, in range [0, 255].
*/
- rgb: (red: number, green: number, blue: number) => this;
-
- /**
- * Set HEX value for foreground color.
- *
- * @param {string} hex
- */
- hex: (color: string) => this;
+ rgb(red: number, green: number, blue: number): this;
/**
* Set RGB values for background color.
@@ -84,14 +137,21 @@ interface Ansis {
* @param {number} green The green value, in range [0, 255].
* @param {number} blue The blue value, in range [0, 255].
*/
- bgRgb: (red: number, green: number, blue: number) => this;
+ bgRgb(red: number, green: number, blue: number): this;
+
+ /**
+ * Set HEX value for foreground color.
+ *
+ * @param {string} hex
+ */
+ hex(hex: string): this;
/**
* Set HEX value for background color.
*
* @param {string} hex
*/
- bgHex: (color: string) => this;
+ bgHex(hex: string): this;
/**
* Remove ANSI styling codes.
@@ -99,7 +159,7 @@ interface Ansis {
* @param {string} str
* @return {string}
*/
- strip: (string: string) => string;
+ strip(str: string): string;
/**
* Extend base colors with custom ones.
@@ -107,7 +167,7 @@ interface Ansis {
* @param {Object.} colors The object with key as color name
* and value as hex code of custom color or the object with 'open' and 'close' codes.
*/
- extend: (colors: ColorExtend) => void;
+ extend(colors: ColorExtend): void;
/** The ANSI escape sequences for starting the current style. */
readonly open: string;
@@ -142,9 +202,10 @@ interface Ansis {
/** S̶t̶r̶i̶k̶e̶t̶h̶r̶o̶u̶g̶h̶ style. (Not widely supported) */
readonly strikethrough: this;
- /** S̶t̶r̶i̶k̶e̶t̶h̶r̶o̶u̶g̶h̶ style. (Not widely supported) The alias for `strikethrough`. */
+ /** S̶t̶r̶i̶k̶e̶t̶h̶r̶o̶u̶g̶h̶ style. (Not widely supported) Alias for `strikethrough`. */
readonly strike: this;
+ // Colors
readonly black: this;
readonly red: this;
readonly green: this;
@@ -154,7 +215,7 @@ interface Ansis {
readonly cyan: this;
readonly white: this;
readonly grey: this;
- readonly gray: this;
+ readonly gray: this; // Alias for grey
readonly blackBright: this;
readonly redBright: this;
readonly greenBright: this;
@@ -163,6 +224,8 @@ interface Ansis {
readonly magentaBright: this;
readonly cyanBright: this;
readonly whiteBright: this;
+
+ // Background colors
readonly bgBlack: this;
readonly bgRed: this;
readonly bgGreen: this;
@@ -172,7 +235,7 @@ interface Ansis {
readonly bgCyan: this;
readonly bgWhite: this;
readonly bgGrey: this;
- readonly bgGray: this;
+ readonly bgGray: this; // Alias for bgGrey
readonly bgBlackBright: this;
readonly bgRedBright: this;
readonly bgGreenBright: this;
@@ -184,70 +247,15 @@ interface Ansis {
}
declare const ansis: Ansis;
-declare const Ansis: new () => Ansis;
-
-/**
- * Base ANSI Styles
- */
-type AnsiStyles = (
- | 'reset'
- | 'inverse'
- | 'hidden'
- | 'visible'
- | 'bold'
- | 'dim'
- | 'italic'
- | 'underline'
- | 'strikethrough'
- | 'strike'
- );
-
-/**
- * Base ANSI Colors
- */
-type AnsiColors = (
- | 'black'
- | 'red'
- | 'green'
- | 'yellow'
- | 'blue'
- | 'magenta'
- | 'cyan'
- | 'white'
- | 'grey'
- | 'gray'
- | 'blackBright'
- | 'redBright'
- | 'greenBright'
- | 'yellowBright'
- | 'blueBright'
- | 'magentaBright'
- | 'cyanBright'
- | 'whiteBright'
- | 'bgBlack'
- | 'bgRed'
- | 'bgGreen'
- | 'bgYellow'
- | 'bgBlue'
- | 'bgMagenta'
- | 'bgCyan'
- | 'bgWhite'
- | 'bgGrey'
- | 'bgGray'
- | 'bgBlackBright'
- | 'bgRedBright'
- | 'bgGreenBright'
- | 'bgYellowBright'
- | 'bgBlueBright'
- | 'bgMagentaBright'
- | 'bgCyanBright'
- | 'bgWhiteBright'
- );
-type StringUnion = T | (B & Record);
-type AnsiColorsExtend = StringUnion;
+export {
+ type AnsiColors,
+ type AnsiColorsExtend,
+ type AnsiStyles,
+ ansis as default,
+};
-export { AnsiColors, AnsiColorsExtend, AnsiStyles, Ansis, ansis as default };
+export const Ansis: new () => Ansis;
export declare function ansi256(code: number): Ansis;
diff --git a/src/index.js b/src/index.js
index 49578f5..dced330 100644
--- a/src/index.js
+++ b/src/index.js
@@ -5,16 +5,16 @@ import { hexToRgb } from './utils.js';
* @typedef {Object} AnsisProps
* @property {string} open
* @property {string} close
- * @property {string?} openStack
- * @property {string?} closeStack
- * @property {null | AnsisProps} props
+ * @property {string?} _a The openStack.
+ * @property {string?} _b The closeStack.
+ * @property {null | AnsisProps} _p The props.
*/
const { defineProperty, defineProperties, setPrototypeOf } = Object;
const stripANSIRegEx = /[][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
const regexLFCR = /(\r?\n)/g;
-const ESC = '\x1b';
-const LF = '\x0a';
+const ESC = '';
+const LF = '\n';
const styles = {};
/**
@@ -38,29 +38,30 @@ const createStyle = ({ _p: props }, { open, close }) => {
let props = style._p;
let { _a: openStack, _b: closeStack } = props;
- let str = strings.raw != null
+ let str = strings.raw
// render template strings
? String.raw(strings, ...values)
// convert the number to the string
: '' + strings;
+ // --> detect nested styles
// on node.js, the performance of `includes()` and `~indexOf()` is the same, no difference
if (str.includes(ESC)) {
- while (props != null) {
- // this implementation is over 30% faster than String.replaceAll()
+ while (props) {
+ // this implementation is over 30% faster than native String.replaceAll()
+ //str = str.replaceAll(props.close, props.open);
// -- begin replaceAll
let search = props.close;
+ let replacement = props.open;
let searchLength = search.length;
+ let result = '';
+ let lastPos;
+ let pos;
// the `visible` style has empty open/close props
if (searchLength) {
- let lastPos = 0;
- let result = '';
- let pos;
-
- while (~(pos = str.indexOf(search, lastPos))) {
- result += str.slice(lastPos, pos) + props.open;
- lastPos = pos + searchLength;
+ for (lastPos = 0; ~(pos = str.indexOf(search, lastPos)); lastPos = pos + searchLength) {
+ result += str.slice(lastPos, pos) + replacement;
}
if (lastPos) str = result + str.slice(lastPos);
@@ -71,6 +72,7 @@ const createStyle = ({ _p: props }, { open, close }) => {
}
}
+ // --> detect new line
if (str.includes(LF)) {
str = str.replace(regexLFCR, closeStack + '$1' + openStack);
}
@@ -81,7 +83,7 @@ const createStyle = ({ _p: props }, { open, close }) => {
let openStack = open;
let closeStack = close;
- if (props != null) {
+ if (props) {
openStack = props._a + open;
closeStack = close + props._b;
}
@@ -124,17 +126,17 @@ const Ansis = function() {
*/
self.extend = (colors) => {
for (let name in colors) {
- let value = colors[name];
- let type = typeof value;
+ let color = colors[name];
+ let type = typeof color;
// detect whether the value is style property Object {open, close}
// or a string with hex code of a color, e.g.: '#FF0000'
- let styleProps = type === 'string' ? fnRgb(...hexToRgb(value)) : value;
+ let styleProps = type === 'string' ? fnRgb(...hexToRgb(color)) : color;
if (type === 'function') {
styles[name] = {
get() {
- return (...args) => createStyle(this, value(...args));
+ return (...args) => createStyle(this, color(...args));
},
};
} else {