Skip to content

Commit

Permalink
- added supports the environment variables NO_COLOR FORCE_COLOR a…
Browse files Browse the repository at this point in the history
…nd flags `--no-color` `--color`

- added aliases `ansi` for `ansi256` and `bgAnsi` for `bgAnsi256`
- added to readme the compare of most popular ANSI libraries
  • Loading branch information
webdiscus committed Dec 28, 2021
1 parent a7e6963 commit 3930fb7
Show file tree
Hide file tree
Showing 12 changed files with 409 additions and 174 deletions.
13 changes: 9 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
# Change log

## 1.2.0 (2021-12-27)
- added supports the environment variables `NO_COLOR` `FORCE_COLOR` and flags `--no-color` `--color`
- added aliases `ansi` for `ansi256` and `bgAnsi` for `bgAnsi256`
- added to readme the compare of most popular ANSI libraries

## 1.1.1 (2021-12-27)
- add the class Ansis to create more independent instances to increase the performance by benchmark
- added the class Ansis to create more independent instances to increase the performance by benchmark
- improve performance
- code refactoring
- update readme

## 1.1.0 (2021-12-25)
- add supports the use of `open` and `close` properties for each style
- fix codes for methods ansi256() and bgAnsi256()
- add demo to npm package
- added supports the use of `open` and `close` properties for each style
- added demo to npm package
- fixed codes for methods ansi256() and bgAnsi256()
- update package.json
- update readme

Expand Down
151 changes: 106 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
</h1>

---
[![npm version](https://badge.fury.io/js/ansis.svg)](https://www.npmjs.com/package/ansis)
[![npm](https://img.shields.io/npm/v/ansis?logo=npm&color=brightgreen "npm package")](https://www.npmjs.com/package/ansis "download npm package")
[![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)


Color styling of text for ANSI terminals using the SGR (Select Graphic Rendition) codes defined in the [ECMA-48](https://www.ecma-international.org/publications-and-standards/standards/ecma-48/) standard.\
This is improved and faster implementation for `Node.js`.

Expand Down Expand Up @@ -44,6 +43,7 @@ Output:
- powerful and lightweight library is faster than many others such as `chalk` `kleur` `ansi-colors` etc.
- supports the standard de facto API of the `chalk`
- supports 256 color and Truecolor
- supports the environment variables [`NO_COLOR`](https://no-color.org) `FORCE_COLOR` and flags `--no-color` `--color`
- supports styles like: `bold` `red` `yellowBright` `bgGreen` `bgCyanBright` ect.
- supports chained styles, e.g.:
```js
Expand Down Expand Up @@ -151,6 +151,11 @@ ansis.ansi256(96).bold('bold Bright Cyan');
// background color
ansis.bgAnsi256(105)('Bright Magenta');
```
> Aliases
>
> `ansis.ansi()` is alias for `ansis.ansi256()`\
> `ansis.bgAnsi()` is alias for `ansis.bgAnsi256()`


## Truecolor

Expand All @@ -166,6 +171,31 @@ ansis.bgHex('#96C')('Amethyst');
ansis.bgRgb(224, 17, 95)('Ruby');
```

## Compare most popular ANSI libraries

| Library | Standard<br>style / color<br>naming | Chain<br>styles | Nested<br>styles | New<br>Line | ANSI 256<br>colors | Truecolor<br>RGB / HEX | NO_COLOR |
|------------------------------|-------------------|-----------------|------------------|-------------|---------------------------------|------------------------|:---------------------------------------------------------|
| [`colors.js`][colors.js] | no, e.g.<br>`brightRed` | yes | yes | yes | - | - | only<br>`FORCE_COLOR`<br>`--no-color`<br>`--color` |
| [`colorette`][colorette] | yes<br>(16 colors) | - | yes | - | - | - | yes |
| [`picocolors`][picocolors] | yes<br>(8 colors) | - | yes | - | - | - | yes |
| [`cli-color`][cli-color] | yes<br>(16 colors) | yes | yes | - | `.xterm(num)` | - | yes |
| [`color-cli`][color-cli] | no, e.g.<br>`red_bbt` | yes | buggy | yes | `.x<num>` | - | only<br>`--no-color`<br>`--color` |
| [`ansi-colors`][ansi-colors] | yes<br>(16 colors) | yes | yes | yes | - | - | only<br>`FORCE_COLOR` |
| [`kleur`][kleur] | yes<br>(8 colors) | yes* | yes | - | - | - | yes |
| [`chalk`][chalk] | yes<br>(16 colors) | yes | yes | yes | `.ansi256(num)` | `.hex()` `.rgb()` | yes |
| **+ ansis** | yes<br>(16 colors) | yes | yes | yes | `.ansi256(num)`<br>`.ansi(num)` | `.hex()` `.rgb()` | yes |

### Column description
- **Standard style and color naming**: `red` `redBright` `bgRed` `bgRedBright` etc., see above the **Foreground / Background colors**.
- **Chain styles**: `ansis.red.bold.underline('text')`.\
`kleur` use the chain of functions: `kleur.red().bold().underline('text')`.
- **Nested styles**:
```js
c.red(`red ${c.green(`green ${c.underline(`underline`)} green`)} red`)
- **New Line**: correct break of escape sequences at `end of line`\
<img width="128" src="doc/img/break-style-nl.png" alt="new line">
- **NO_COLOR**: supports the environment variables [`NO_COLOR`](https://no-color.org) `FORCE_COLOR` and flags `--no-color` `--color`
## Benchmark
### Initialize
Expand All @@ -179,7 +209,6 @@ npm i
npm run bench
```

> ### Tested on
>
> MacBook Pro 16" M1 Max 64GB\
Expand All @@ -194,33 +223,33 @@ c.red(`${c.bold(`${c.cyan(`${c.yellow('yellow')}cyan`)}`)}red`);
```
```diff
colors-js 1,152,114 ops/sec
colorette 4,548,418 ops/sec
picocolors 3,832,593 ops/sec
cli-color 471,929 ops/sec
color-cli 110,282 ops/sec
ansi-colors 1,272,164 ops/sec
kleur/colors 2,278,569 ops/sec
kleur 2,223,929 ops/sec
chalk 2,255,589 ops/sec
+ ansis 2,674,316 ops/sec
colors-js 1,158,572 ops/sec
colorette 4,572,582 ops/sec
picocolors 3,841,124 ops/sec
cli-color 470,320 ops/sec
color-cli 109,811 ops/sec
ansi-colors 1,265,615 ops/sec
kleur/colors 2,281,415 ops/sec
kleur 2,228,639 ops/sec
chalk 2,287,146 ops/sec
+ ansis 2,669,734 ops/sec
```
### Base styles
```js
styles.forEach((style) => c[style]('foo'));
```
```diff
colors-js 475,774 ops/sec
colorette 1,174,392 ops/sec
picocolors 5,724,714 ops/sec
cli-color 220,577 ops/sec
color-cli 73,535 ops/sec
ansi-colors 727,414 ops/sec
kleur/colors 1,275,337 ops/sec
kleur 3,843,212 ops/sec
chalk 3,144,045 ops/sec
+ ansis 4,360,629 ops/sec
colors-js 471,395 ops/sec
colorette 1,103,314 ops/sec
picocolors 5,725,578 ops/sec
cli-color 221,282 ops/sec
color-cli 73,725 ops/sec
ansi-colors 716,280 ops/sec
kleur/colors 1,259,858 ops/sec
kleur 3,829,838 ops/sec
chalk 3,165,933 ops/sec
+ ansis 4,483,217 ops/sec
```
### Chained styles
Expand All @@ -246,16 +275,16 @@ colors.forEach((color) => c[color].bold.underline.italic('foo'));
colors.forEach((color) => c[color](c.bold(c.underline(c.italic('foo')))));
```
```diff
colors-js 165,202 ops/sec
colorette 712,604 ops/sec
picocolors 939,536 ops/sec
cli-color 64,758 ops/sec
color-cli 13,833 ops/sec
ansi-colors 258,930 ops/sec
kleur/colors 563,266 ops/sec
kleur 646,985 ops/sec
chalk 385,590 ops/sec
+ ansis 554,813 ops/sec
colors-js 166,425 ops/sec
colorette 695,350 ops/sec
picocolors 942,592 ops/sec
cli-color 65,561 ops/sec
color-cli 13,800 ops/sec
ansi-colors 260,316 ops/sec
kleur/colors 561,111 ops/sec
kleur 648,195 ops/sec
chalk 497,292 ops/sec
+ ansis 558,575 ops/sec

```
Expand All @@ -264,16 +293,48 @@ colors.forEach((color) => c[color](c.bold(c.underline(c.italic('foo')))));
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`);
```
```diff
colors-js 89,529 ops/sec
colorette 243,237 ops/sec
picocolors 242,528 ops/sec
cli-color 41,897 ops/sec
color-cli 14,245 ops/sec
ansi-colors 120,991 ops/sec
kleur/colors 233,875 ops/sec
kleur 220,233 ops/sec
chalk 157,450 ops/sec
+ ansis 205,393 ops/sec
colors-js 89,633 ops/sec
colorette 243,139 ops/sec
picocolors 243,975 ops/sec
cli-color 41,657 ops/sec
color-cli 14,264 ops/sec
ansi-colors 121,451 ops/sec
kleur/colors 234,132 ops/sec
kleur 221,446 ops/sec
chalk 189,960 ops/sec
+ ansis 211,868 ops/sec

```
### Deep 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
colors-js 451,592 ops/sec
colorette 1,131,757 ops/sec
picocolors 1,002,649 ops/sec
cli-color 213,441 ops/sec
color-cli 40,340 ops/sec
ansi-colors 362,733 ops/sec
kleur/colors 478,547 ops/sec
kleur 464,004 ops/sec
chalk 565,965 ops/sec
+ ansis 882,220 ops/sec

```
Expand All @@ -291,8 +352,8 @@ c.hex('#FBA')('foo');
ansi-colors (not supported)
kleur/colors (not supported)
kleur (not supported)
chalk 2,746,362 ops/sec
+ ansis 4,584,357 ops/sec
chalk 2,891,684 ops/sec
+ ansis 4,944,572 ops/sec
```
## Testing
Expand Down
118 changes: 90 additions & 28 deletions bench/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import kleur from 'kleur';
import * as kleurColors from 'kleur/colors';
import picocolors from 'picocolors';

const log = console.log;

// create new instance of Ansis for correct measure in benchmark
const ansis = new Ansis();

Expand Down Expand Up @@ -86,22 +88,9 @@ const colorStyles = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan

let fixture = [];

function outputNested(name, lib) {
const rgb = lib.hex('#80109f');

const str = lib.red(
`begin ${rgb.bold('RGB')} ${lib.yellow('yellow')} red ${lib.italic.cyan('italic cyan')} red ${lib.red(
'red'
)} red ${lib.underline.green.italic(
`underline italic green ${lib.hex('#e5850a')('underline italic blue')} underline italic green`
)} red ${lib.cyan('cyan')} red ${lib.bold.yellow('bold yellow')} red ${lib.green('green')} end`
);

console.log(` ${name}`, str);
}

outputNested('chalk\t', chalk);
outputNested('ansis\t', ansis);
//showSupportOfDeepNestedStyling();
//showSupportOfDeepNestedMultiStyling();
//showSupportOfBreakStyleAtNewLine();

// Colorette bench
// https://github.com/jorgebucaran/colorette/blob/main/bench/index.js
Expand Down Expand Up @@ -198,18 +187,38 @@ bench('Nested styles')
.add('ansis', () => fixture[8](ansis))
.run();

// reserved
bench('Break style')
.add('colors-js', () => colorsJs.green(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`))
.add('colorette', () => colorette.green(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`))
.add('picocolors', () => picocolors.green(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`))
.add('cli-color', () => cliColor.green(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`))
.add('color-cli', () => colorCli.green(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`))
.add('ansi-colors', () => ansiColors.green(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`))
.add('kleur/colors', () => kleurColors.green(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`))
.add('kleur', () => ansis.green(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`))
.add('chalk', () => kleur.green(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`))
.add('ansis', () => ansis.green(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`))
// Deep nested styles
fixture = createFixture(vendors, deepNestedFixture);
bench('Deep nested styles')
.add('colors-js', () => fixture[9](colorsJs))
.add('colorette', () => fixture[0](colorette))
.add('picocolors', () => fixture[1](picocolors))
.add('cli-color', () => fixture[2](cliColor))
.add('color-cli', () => fixture[3](colorCli))
.add('ansi-colors', () => fixture[4](ansiColors))
.add('kleur/colors', () => fixture[5](kleurColors))
.add('kleur', () => fixture[6](kleur))
.add('chalk', () => fixture[7](chalk))
.add('ansis', () => fixture[8](ansis))
.run();

// Check support of correct break style at new line

// Break style at new line
// bench('New Line')
// .add('colors-js', () => colorsJs.bgGreen(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`))
// .add('ansi-colors', () => ansiColors.bgGreen(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`))
// .add('chalk', () => chalk.bgGreen(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`))
// .add('ansis', () => ansis.bgGreen(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`))
// .run();

bench('RGB colors')
.add('chalk', () => {
for (let i = 0; i < 256; i++) chalk.rgb(i, 150, 200)('foo');
})
.add('ansis', () => {
for (let i = 0; i < 256; i++) ansis.rgb(i, 150, 200)('foo');
})
.run();

// HEX colors
Expand Down Expand Up @@ -246,3 +255,56 @@ function nestedFixture(c) {
)} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} red ${c.red('red')} message`
);
}

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`
);
}

function complexNestedFixture(c) {
return c.red(
`red ${c.yellow('yellow')} red ${c.italic.cyan('italic cyan')} red ${c.underline.green(
`underline green ${c.yellow('underline yellow')} underline green`
)} red ${c.cyan('cyan')} red ${c.bold.yellow('bold yellow')} red ${c.green('green')} red`
);
}

function showSupportOfDeepNestedStyling() {
log('colors-js: ', deepNestedFixture(colorsJs));
log('colorette: ', deepNestedFixture(colorette));
log('picocolors: ', deepNestedFixture(picocolors));
log('cli-color: ', deepNestedFixture(cliColor));
log('color-cli: ', deepNestedFixture(colorCli)); // buggy
log('ansi-colors: ', deepNestedFixture(ansiColors));
log('kleur/colors: ', deepNestedFixture(kleurColors));
log('kleur: ', deepNestedFixture(kleur));
log('chalk: ', deepNestedFixture(chalk));
log('ansis: ', deepNestedFixture(ansis));
}

function showSupportOfDeepNestedMultiStyling() {
log('chalk: ', complexNestedFixture(chalk));
log('ansis: ', complexNestedFixture(ansis));
}

function showSupportOfBreakStyleAtNewLine() {
log('colors-js: ', colorsJs.bgGreen(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`)); // OK
log('colorette: ', colorette.bgGreen(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`)); // (not supported)
log('picocolors: ', picocolors.bgGreen(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`)); // (not supported)
log('cli-color: ', cliColor.bgGreen(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`)); // (not supported)
log('color-cli: ', colorCli.green_b(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`)); // (not supported)
log('ansi-colors: ', ansiColors.bgGreen(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`)); // OK
log('kleur/colors: ', kleurColors.bgGreen(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`)); // (not supported)
log('kleur: ', kleur.bgGreen(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`)); // (not supported)
log('chalk: ', chalk.bgGreen(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`)); // OK
log('ansis: ', ansis.bgGreen(`\nAnsis\nNEW LINE\nNEXT NEW LINE\n`)); // OK
}
Binary file added doc/img/break-style-nl.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 3930fb7

Please sign in to comment.