diff --git a/.github/funding.yml b/.github/funding.yml index 5692ede..1cd069f 100644 --- a/.github/funding.yml +++ b/.github/funding.yml @@ -1,4 +1,4 @@ -github: [sindresorhus,Qix-] +github: [sindresorhus, Qix-] open_collective: sindresorhus tidelift: npm/chalk custom: https://sindresorhus.com/donate diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c1870cf..d36e1a8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,10 +12,9 @@ jobs: node-version: - 14 - 12 - - 10 steps: - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} - run: npm install diff --git a/benchmark.js b/benchmark.js index 98ee5ee..c5c6e27 100644 --- a/benchmark.js +++ b/benchmark.js @@ -1,6 +1,5 @@ /* globals suite, bench */ -'use strict'; -const chalk = require('.'); +import chalk from './index.js'; suite('chalk', () => { const chalkRed = chalk.red; diff --git a/examples/rainbow.js b/examples/rainbow.js index 6e0664c..9ea1d72 100644 --- a/examples/rainbow.js +++ b/examples/rainbow.js @@ -1,12 +1,10 @@ -'use strict'; -const chalk = require('..'); +import chalk from '../source/index.js'; +import convertColor from 'color-convert'; +import updateLog from 'log-update'; +import delay from 'yoctodelay'; const ignoreChars = /[^!-~]/g; -const delay = milliseconds => new Promise(resolve => { - setTimeout(resolve, milliseconds); -}); - function rainbow(string, offset) { if (!string || string.length === 0) { return string; @@ -17,10 +15,10 @@ function rainbow(string, offset) { let hue = offset % 360; const characters = []; for (const character of string) { - if (character.match(ignoreChars)) { + if (ignoreChars.test(character)) { characters.push(character); } else { - characters.push(chalk.hsl(hue, 100, 50)(character)); + characters.push(chalk.hex(convertColor.hsl.hex(hue, 100, 50))(character)); hue = (hue + hueStep) % 360; } } @@ -29,9 +27,8 @@ function rainbow(string, offset) { } async function animateString(string) { - console.log(); - for (let i = 0; i < 360 * 5; i++) { - console.log('\u001B[1F\u001B[G', rainbow(string, i)); + for (let index = 0; index < 360 * 5; index++) { + updateLog(rainbow(string, index)); await delay(2); // eslint-disable-line no-await-in-loop } } diff --git a/examples/screenshot.js b/examples/screenshot.js index fc64030..6d5ed15 100644 --- a/examples/screenshot.js +++ b/examples/screenshot.js @@ -1,6 +1,5 @@ -'use strict'; -const styles = require('ansi-styles'); -const chalk = require('..'); +import styles from 'ansi-styles'; +import chalk from '../source/index.js'; // Generates screenshot for (const key of Object.keys(styles)) { diff --git a/index.d.ts b/index.d.ts index ddaf8d4..6f7ff2e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -3,7 +3,7 @@ Basic foreground colors. [More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support) */ -declare type ForegroundColor = +export type ForegroundColor = | 'black' | 'red' | 'green' @@ -28,7 +28,7 @@ Basic background colors. [More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support) */ -declare type BackgroundColor = +export type BackgroundColor = | 'bgBlack' | 'bgRed' | 'bgGreen' @@ -53,363 +53,287 @@ Basic colors. [More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support) */ -declare type Color = ForegroundColor | BackgroundColor; +export type Color = ForegroundColor | BackgroundColor; -declare type Modifiers = +export type Modifiers = | 'reset' | 'bold' | 'dim' | 'italic' | 'underline' + | 'overline' | 'inverse' | 'hidden' | 'strikethrough' | 'visible'; -declare namespace chalk { +/** +Levels: +- `0` - All colors disabled. +- `1` - Basic 16 colors support. +- `2` - ANSI 256 colors support. +- `3` - Truecolor 16 million colors support. +*/ +export type ColorSupportLevel = 0 | 1 | 2 | 3; + +export interface Options { /** + Specify the color support for Chalk. + + By default, color support is automatically detected based on the environment. + Levels: - `0` - All colors disabled. - `1` - Basic 16 colors support. - `2` - ANSI 256 colors support. - `3` - Truecolor 16 million colors support. */ - type Level = 0 | 1 | 2 | 3; + readonly level?: ColorSupportLevel; +} - interface Options { - /** - Specify the color support for Chalk. +/** +Return a new Chalk instance. +*/ +export const Chalk: new (options?: Options) => ChalkInstance; + +/** +Detect whether the terminal supports color. +*/ +export interface ColorSupport { + /** + The color level used by Chalk. + */ + level: ColorSupportLevel; - By default, color support is automatically detected based on the environment. + /** + Return whether Chalk supports basic 16 colors. + */ + hasBasic: boolean; - Levels: - - `0` - All colors disabled. - - `1` - Basic 16 colors support. - - `2` - ANSI 256 colors support. - - `3` - Truecolor 16 million colors support. - */ - level?: Level; - } + /** + Return whether Chalk supports ANSI 256 colors. + */ + has256: boolean; /** - Return a new Chalk instance. + Return whether Chalk supports Truecolor 16 million colors. */ - type Instance = new (options?: Options) => Chalk; + has16m: boolean; +} +interface ChalkFunction { /** - Detect whether the terminal supports color. + Use a template string. + + @remarks Template literals are unsupported for nested calls (see [issue #341](https://github.com/chalk/chalk/issues/341)) + + @example + ``` + import chalk from 'chalk'; + + log(chalk` + CPU: {red ${cpu.totalPercent}%} + RAM: {green ${ram.used / ram.total * 100}%} + DISK: {rgb(255,131,0) ${disk.used / disk.total * 100}%} + `); + ``` + + @example + ``` + import chalk from 'chalk'; + + log(chalk.red.bgBlack`2 + 3 = {bold ${2 + 3}}`) + ``` */ - interface ColorSupport { - /** - The color level used by Chalk. - */ - level: Level; - - /** - Return whether Chalk supports basic 16 colors. - */ - hasBasic: boolean; - - /** - Return whether Chalk supports ANSI 256 colors. - */ - has256: boolean; - - /** - Return whether Chalk supports Truecolor 16 million colors. - */ - has16m: boolean; - } - - interface ChalkFunction { - /** - Use a template string. - - @remarks Template literals are unsupported for nested calls (see [issue #341](https://github.com/chalk/chalk/issues/341)) - - @example - ``` - import chalk = require('chalk'); - - log(chalk` - CPU: {red ${cpu.totalPercent}%} - RAM: {green ${ram.used / ram.total * 100}%} - DISK: {rgb(255,131,0) ${disk.used / disk.total * 100}%} - `); - ``` - - @example - ``` - import chalk = require('chalk'); - - log(chalk.red.bgBlack`2 + 3 = {bold ${2 + 3}}`) - ``` - */ - (text: TemplateStringsArray, ...placeholders: unknown[]): string; - - (...text: unknown[]): string; - } - - interface Chalk extends ChalkFunction { - /** - Return a new Chalk instance. - */ - Instance: Instance; - - /** - The color support for Chalk. - - By default, color support is automatically detected based on the environment. - - Levels: - - `0` - All colors disabled. - - `1` - Basic 16 colors support. - - `2` - ANSI 256 colors support. - - `3` - Truecolor 16 million colors support. - */ - level: Level; - - /** - Use HEX value to set text color. - - @param color - Hexadecimal value representing the desired color. - - @example - ``` - import chalk = require('chalk'); - - chalk.hex('#DEADED'); - ``` - */ - hex: (color: string) => Chalk; - - /** - Use keyword color value to set text color. - - @param color - Keyword value representing the desired color. - - @example - ``` - import chalk = require('chalk'); - - chalk.keyword('orange'); - ``` - */ - keyword: (color: string) => Chalk; - - /** - Use RGB values to set text color. - */ - rgb: (red: number, green: number, blue: number) => Chalk; - - /** - Use HSL values to set text color. - */ - hsl: (hue: number, saturation: number, lightness: number) => Chalk; - - /** - Use HSV values to set text color. - */ - hsv: (hue: number, saturation: number, value: number) => Chalk; - - /** - Use HWB values to set text color. - */ - hwb: (hue: number, whiteness: number, blackness: number) => Chalk; - - /** - Use a [Select/Set Graphic Rendition](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters) (SGR) [color code number](https://en.wikipedia.org/wiki/ANSI_escape_code#3/4_bit) to set text color. - - 30 <= code && code < 38 || 90 <= code && code < 98 - For example, 31 for red, 91 for redBright. - */ - ansi: (code: number) => Chalk; - - /** - Use a [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set text color. - */ - ansi256: (index: number) => Chalk; - - /** - Use HEX value to set background color. - - @param color - Hexadecimal value representing the desired color. - - @example - ``` - import chalk = require('chalk'); - - chalk.bgHex('#DEADED'); - ``` - */ - bgHex: (color: string) => Chalk; - - /** - Use keyword color value to set background color. - - @param color - Keyword value representing the desired color. - - @example - ``` - import chalk = require('chalk'); - - chalk.bgKeyword('orange'); - ``` - */ - bgKeyword: (color: string) => Chalk; - - /** - Use RGB values to set background color. - */ - bgRgb: (red: number, green: number, blue: number) => Chalk; - - /** - Use HSL values to set background color. - */ - bgHsl: (hue: number, saturation: number, lightness: number) => Chalk; - - /** - Use HSV values to set background color. - */ - bgHsv: (hue: number, saturation: number, value: number) => Chalk; - - /** - Use HWB values to set background color. - */ - bgHwb: (hue: number, whiteness: number, blackness: number) => Chalk; - - /** - Use a [Select/Set Graphic Rendition](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters) (SGR) [color code number](https://en.wikipedia.org/wiki/ANSI_escape_code#3/4_bit) to set background color. - - 30 <= code && code < 38 || 90 <= code && code < 98 - For example, 31 for red, 91 for redBright. - Use the foreground code, not the background code (for example, not 41, nor 101). - */ - bgAnsi: (code: number) => Chalk; - - /** - Use a [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set background color. - */ - bgAnsi256: (index: number) => Chalk; - - /** - Modifier: Resets the current color chain. - */ - readonly reset: Chalk; - - /** - Modifier: Make text bold. - */ - readonly bold: Chalk; - - /** - Modifier: Emitting only a small amount of light. - */ - readonly dim: Chalk; - - /** - Modifier: Make text italic. (Not widely supported) - */ - readonly italic: Chalk; - - /** - Modifier: Make text underline. (Not widely supported) - */ - readonly underline: Chalk; - - /** - Modifier: Inverse background and foreground colors. - */ - readonly inverse: Chalk; - - /** - Modifier: Prints the text, but makes it invisible. - */ - readonly hidden: Chalk; - - /** - Modifier: Puts a horizontal line through the center of the text. (Not widely supported) - */ - readonly strikethrough: Chalk; - - /** - Modifier: Prints the text only when Chalk has a color support level > 0. - Can be useful for things that are purely cosmetic. - */ - readonly visible: Chalk; - - readonly black: Chalk; - readonly red: Chalk; - readonly green: Chalk; - readonly yellow: Chalk; - readonly blue: Chalk; - readonly magenta: Chalk; - readonly cyan: Chalk; - readonly white: Chalk; - - /* - Alias for `blackBright`. - */ - readonly gray: Chalk; - - /* - Alias for `blackBright`. - */ - readonly grey: Chalk; - - readonly blackBright: Chalk; - readonly redBright: Chalk; - readonly greenBright: Chalk; - readonly yellowBright: Chalk; - readonly blueBright: Chalk; - readonly magentaBright: Chalk; - readonly cyanBright: Chalk; - readonly whiteBright: Chalk; - - readonly bgBlack: Chalk; - readonly bgRed: Chalk; - readonly bgGreen: Chalk; - readonly bgYellow: Chalk; - readonly bgBlue: Chalk; - readonly bgMagenta: Chalk; - readonly bgCyan: Chalk; - readonly bgWhite: Chalk; - - /* - Alias for `bgBlackBright`. - */ - readonly bgGray: Chalk; - - /* - Alias for `bgBlackBright`. - */ - readonly bgGrey: Chalk; - - readonly bgBlackBright: Chalk; - readonly bgRedBright: Chalk; - readonly bgGreenBright: Chalk; - readonly bgYellowBright: Chalk; - readonly bgBlueBright: Chalk; - readonly bgMagentaBright: Chalk; - readonly bgCyanBright: Chalk; - readonly bgWhiteBright: Chalk; - } + (text: TemplateStringsArray, ...placeholders: unknown[]): string; + + (...text: unknown[]): string; +} + +export interface ChalkInstance extends ChalkFunction { + /** + The color support for Chalk. + + By default, color support is automatically detected based on the environment. + + Levels: + - `0` - All colors disabled. + - `1` - Basic 16 colors support. + - `2` - ANSI 256 colors support. + - `3` - Truecolor 16 million colors support. + */ + level: ColorSupportLevel; + + /** + Use RGB values to set text color. + */ + rgb: (red: number, green: number, blue: number) => this; + + /** + Use HEX value to set text color. + + @param color - Hexadecimal value representing the desired color. + + @example + ``` + import chalk from 'chalk'; + + chalk.hex('#DEADED'); + ``` + */ + hex: (color: string) => this; + + /** + Use an [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set text color. + */ + ansi256: (index: number) => this; + + /** + Use RGB values to set background color. + */ + bgRgb: (red: number, green: number, blue: number) => this; + + /** + Use HEX value to set background color. + + @param color - Hexadecimal value representing the desired color. + + @example + ``` + import chalk from 'chalk'; + + chalk.bgHex('#DEADED'); + ``` + */ + bgHex: (color: string) => this; + + /** + Use a [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set background color. + */ + bgAnsi256: (index: number) => this; + + /** + Modifier: Resets the current color chain. + */ + readonly reset: this; + + /** + Modifier: Make text bold. + */ + readonly bold: this; + + /** + Modifier: Make text slightly darker. (Inconsistent across terminals; might do nothing) + */ + readonly dim: this; + + /** + Modifier: Make text italic. (Not widely supported) + */ + readonly italic: this; + + /** + Modifier: Make text underline. (Not widely supported) + */ + readonly underline: this; + + /** + Modifier: Make text overline. (Not widely supported) + */ + readonly overline: this; + + /** + Modifier: Inverse background and foreground colors. + */ + readonly inverse: this; + + /** + Modifier: Prints the text, but makes it invisible. + */ + readonly hidden: this; + + /** + Modifier: Puts a horizontal line through the center of the text. (Not widely supported) + */ + readonly strikethrough: this; + + /** + Modifier: Prints the text only when Chalk has a color support level > 0. + Can be useful for things that are purely cosmetic. + */ + readonly visible: this; + + readonly black: this; + readonly red: this; + readonly green: this; + readonly yellow: this; + readonly blue: this; + readonly magenta: this; + readonly cyan: this; + readonly white: this; + + /* + Alias for `blackBright`. + */ + readonly gray: this; + + /* + Alias for `blackBright`. + */ + readonly grey: this; + + readonly blackBright: this; + readonly redBright: this; + readonly greenBright: this; + readonly yellowBright: this; + readonly blueBright: this; + readonly magentaBright: this; + readonly cyanBright: this; + readonly whiteBright: this; + + readonly bgBlack: this; + readonly bgRed: this; + readonly bgGreen: this; + readonly bgYellow: this; + readonly bgBlue: this; + readonly bgMagenta: this; + readonly bgCyan: this; + readonly bgWhite: this; + + /* + Alias for `bgBlackBright`. + */ + readonly bgGray: this; + + /* + Alias for `bgBlackBright`. + */ + readonly bgGrey: this; + + readonly bgBlackBright: this; + readonly bgRedBright: this; + readonly bgGreenBright: this; + readonly bgYellowBright: this; + readonly bgBlueBright: this; + readonly bgMagentaBright: this; + readonly bgCyanBright: this; + readonly bgWhiteBright: this; } /** Main Chalk object that allows to chain styles together. + Call the last one as a method with a string argument. + Order doesn't matter, and later styles take precedent in case of a conflict. + This simply means that `chalk.red.yellow.green` is equivalent to `chalk.green`. */ -declare const chalk: chalk.Chalk & chalk.ChalkFunction & { - supportsColor: chalk.ColorSupport | false; - Level: chalk.Level; - Color: Color; - ForegroundColor: ForegroundColor; - BackgroundColor: BackgroundColor; - Modifiers: Modifiers; - stderr: chalk.Chalk & {supportsColor: chalk.ColorSupport | false}; -}; - -export = chalk; +declare const chalk: ChalkInstance & ChalkFunction; + +export const supportsColor: ColorSupport | false; + +export const chalkStderr: typeof chalk; +export const supportsColorStderr: typeof supportsColor; + +export default chalk; diff --git a/index.test-d.ts b/index.test-d.ts index ba91b63..45299d6 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1,38 +1,38 @@ import {expectType, expectAssignable, expectError} from 'tsd'; -import chalk = require('.'); +import chalk, {Chalk, ChalkInstance, Color, ColorSupport, ColorSupportLevel, chalkStderr, supportsColor, supportsColorStderr} from './index.js'; // - Helpers - -type colorReturn = chalk.Chalk & {supportsColor?: never}; +type colorReturn = ChalkInstance & {supportsColor?: never}; // - supportsColor - -expectType(chalk.supportsColor); -if (chalk.supportsColor) { - expectType(chalk.supportsColor.hasBasic); - expectType(chalk.supportsColor.has256); - expectType(chalk.supportsColor.has16m); +expectType(supportsColor); +if (supportsColor) { + expectType(supportsColor.hasBasic); + expectType(supportsColor.has256); + expectType(supportsColor.has16m); } // - stderr - -expectAssignable(chalk.stderr); -expectType(chalk.stderr.supportsColor); -if (chalk.stderr.supportsColor) { - expectType(chalk.stderr.supportsColor.hasBasic); - expectType(chalk.stderr.supportsColor.has256); - expectType(chalk.stderr.supportsColor.has16m); +expectAssignable(chalkStderr); +expectType(supportsColorStderr); +if (supportsColorStderr) { + expectType(supportsColorStderr.hasBasic); + expectType(supportsColorStderr.has256); + expectType(supportsColorStderr.has16m); } -// -- `stderr` is not a member of the Chalk interface -- -expectError(chalk.reset.stderr); +// -- `supportsColorStderr` is not a member of the Chalk interface -- +expectError(chalk.reset.supportsColorStderr); // -- `supportsColor` is not a member of the Chalk interface -- expectError(chalk.reset.supportsColor); // - Chalk - // -- Instance -- -expectType(new chalk.Instance({level: 1})); +expectType(new Chalk({level: 1})); // -- Properties -- -expectType(chalk.level); +expectType(chalk.level); // -- Template literal -- expectType(chalk``); @@ -41,21 +41,11 @@ expectType(chalk`Hello {bold.red ${name}}`); expectType(chalk`Works with numbers {bold.red ${1}}`); // -- Color methods -- -expectAssignable(chalk.hex('#DEADED')); -expectAssignable(chalk.keyword('orange')); expectAssignable(chalk.rgb(0, 0, 0)); -expectAssignable(chalk.hsl(0, 0, 0)); -expectAssignable(chalk.hsv(0, 0, 0)); -expectAssignable(chalk.hwb(0, 0, 0)); -expectAssignable(chalk.ansi(30)); +expectAssignable(chalk.hex('#DEADED')); expectAssignable(chalk.ansi256(0)); -expectAssignable(chalk.bgHex('#DEADED')); -expectAssignable(chalk.bgKeyword('orange')); expectAssignable(chalk.bgRgb(0, 0, 0)); -expectAssignable(chalk.bgHsl(0, 0, 0)); -expectAssignable(chalk.bgHsv(0, 0, 0)); -expectAssignable(chalk.bgHwb(0, 0, 0)); -expectAssignable(chalk.bgAnsi(30)); +expectAssignable(chalk.bgHex('#DEADED')); expectAssignable(chalk.bgAnsi256(0)); // -- Modifiers -- @@ -64,6 +54,7 @@ expectType(chalk.bold('foo')); expectType(chalk.dim('foo')); expectType(chalk.italic('foo')); expectType(chalk.underline('foo')); +expectType(chalk.overline('foo')); expectType(chalk.inverse('foo')); expectType(chalk.hidden('foo')); expectType(chalk.strikethrough('foo')); @@ -158,5 +149,5 @@ expectType(chalk.red.bgGreen.bold`Hello {italic.blue ${name}}`); expectType(chalk.strikethrough.cyanBright.bgBlack`Works with {reset {bold numbers}} {bold.red ${1}}`); // -- Color types == -expectAssignable('red'); -expectError('hotpink'); +expectAssignable('red'); +expectError('hotpink'); diff --git a/license b/license index e7af2f7..fa7ceba 100644 --- a/license +++ b/license @@ -1,6 +1,6 @@ MIT License -Copyright (c) Sindre Sorhus (sindresorhus.com) +Copyright (c) Sindre Sorhus (https://sindresorhus.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/package.json b/package.json index 7a3bd25..a205ed7 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,10 @@ "license": "MIT", "repository": "chalk/chalk", "funding": "https://github.com/chalk/chalk?sponsor=1", - "main": "source", + "type": "module", + "exports": "./source/index.js", "engines": { - "node": ">=10" + "node": ">=12.17" }, "scripts": { "test": "xo && nyc ava && tsd", @@ -41,27 +42,24 @@ "text" ], "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-styles": "^6.1.0", + "supports-color": "^9.0.0" }, "devDependencies": { - "ava": "^2.4.0", + "ava": "^3.15.0", + "color-convert": "^2.0.1", "coveralls": "^3.1.0", - "execa": "^4.0.3", - "import-fresh": "^3.2.1", + "execa": "^5.0.0", + "log-update": "^4.0.0", "matcha": "^0.7.0", "nyc": "^15.1.0", - "resolve-from": "^5.0.0", - "tsd": "^0.13.1", - "xo": "^0.33.1" + "tsd": "^0.14.0", + "xo": "^0.39.1", + "yoctodelay": "^1.2.0" }, "xo": { "rules": { "unicorn/prefer-string-slice": "off", - "unicorn/prefer-includes": "off", - "@typescript-eslint/member-ordering": "off", - "no-redeclare": "off", - "unicorn/string-content": "off", "unicorn/better-regex": "off" } } diff --git a/readme.md b/readme.md index f1c9b9e..6d92165 100644 --- a/readme.md +++ b/readme.md @@ -38,6 +38,19 @@ +
+
+ +
+ Doppler +
+ All your environment variables, in one place +
+ Stop struggling with scattered API keys, hacking together home-brewed tools, +
+ and avoiding access controls. Keep your team and servers in sync with Doppler. +
+

@@ -66,7 +79,7 @@ $ npm install chalk ## Usage ```js -const chalk = require('chalk'); +import chalk from 'chalk'; console.log(chalk.blue('Hello world!')); ``` @@ -74,7 +87,8 @@ console.log(chalk.blue('Hello world!')); Chalk comes with an easy to use composable API where you just chain and nest the styles you want. ```js -const chalk = require('chalk'); +import chalk from 'chalk'; + const log = console.log; // Combine styled and normal strings @@ -111,7 +125,6 @@ DISK: {rgb(255,131,0) ${disk.used / disk.total * 100}%} `); // Use RGB colors in terminal emulators that support it. -log(chalk.keyword('orange')('Yay for orange colored text!')); log(chalk.rgb(123, 45, 67).underline('Underlined reddish color')); log(chalk.hex('#DEADED').bold('Bold gray!')); ``` @@ -119,10 +132,10 @@ log(chalk.hex('#DEADED').bold('Bold gray!')); Easily define your own themes: ```js -const chalk = require('chalk'); +import chalk from 'chalk'; const error = chalk.bold.red; -const warning = chalk.keyword('orange'); +const warning = chalk.hex('#FFA500'); // Orange color console.log(error('Error!')); console.log(warning('Warning!')); @@ -131,6 +144,8 @@ console.log(warning('Warning!')); Take advantage of console.log [string substitution](https://nodejs.org/docs/latest/api/console.html#console_console_log_data_args): ```js +import chalk from 'chalk'; + const name = 'Sindre'; console.log(chalk.green('Hello %s'), name); //=> 'Hello Sindre' @@ -155,7 +170,9 @@ Color support is automatically detected, but you can override it by setting the If you need to change this in a reusable module, create a new instance: ```js -const ctx = new chalk.Instance({level: 0}); +import {Chalk} from 'chalk'; + +const customChalk = new Chalk({level: 0}); ``` | Level | Description | @@ -165,7 +182,7 @@ const ctx = new chalk.Instance({level: 0}); | `2` | 256 color support | | `3` | Truecolor support (16 million colors) | -### chalk.supportsColor +### supportsColor Detect whether the terminal [supports color](https://github.com/chalk/supports-color). Used internally and handled for you, but exposed for convenience. @@ -173,9 +190,9 @@ Can be overridden by the user with the flags `--color` and `--no-color`. For sit Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color=16m` flags, respectively. -### chalk.stderr and chalk.stderr.supportsColor +### chalkStderr and supportsColorStderr -`chalk.stderr` contains a separate instance configured with color support detected for `stderr` stream instead of `stdout`. Override rules from `chalk.supportsColor` apply to this too. `chalk.stderr.supportsColor` is exposed for convenience. +`chalkStderr` contains a separate instance configured with color support detected for `stderr` stream instead of `stdout`. Override rules from `supportsColor` apply to this too. `supportsColorStderr` is exposed for convenience. ## Styles @@ -234,7 +251,7 @@ Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color= Chalk can be used as a [tagged template literal](https://exploringjs.com/es6/ch_template-literals.html#_tagged-template-literals). ```js -const chalk = require('chalk'); +import chalk from 'chalk'; const miles = 18; const calculateFeet = miles => miles * 5280; @@ -250,12 +267,14 @@ Blocks are delimited by an opening curly brace (`{`), a style, some content, and Template styles are chained exactly like normal Chalk styles. The following three statements are equivalent: ```js +import chalk from 'chalk'; + console.log(chalk.bold.rgb(10, 100, 200)('Hello!')); console.log(chalk.bold.rgb(10, 100, 200)`Hello!`); console.log(chalk`{bold.rgb(10,100,200) Hello!}`); ``` -Note that function styles (`rgb()`, `hsl()`, `keyword()`, etc.) may not contain spaces between parameters. +Note that function styles (`rgb()`, `hex()`, etc.) may not contain spaces between parameters. All interpolated values (`` chalk`${foo}` ``) are converted to strings via the `.toString()` method. All curly braces (`{` and `}`) in interpolated value strings are escaped. @@ -268,24 +287,17 @@ Colors are downsampled from 16 million RGB values to an ANSI color format that i Examples: - `chalk.hex('#DEADED').underline('Hello, world!')` -- `chalk.keyword('orange')('Some orange text')` - `chalk.rgb(15, 100, 204).inverse('Hello!')` -Background versions of these models are prefixed with `bg` and the first level of the module capitalized (e.g. `keyword` for foreground colors and `bgKeyword` for background colors). +Background versions of these models are prefixed with `bg` and the first level of the module capitalized (e.g. `hex` for foreground colors and `bgHex` for background colors). - `chalk.bgHex('#DEADED').underline('Hello, world!')` -- `chalk.bgKeyword('orange')('Some orange text')` - `chalk.bgRgb(15, 100, 204).inverse('Hello!')` The following color models can be used: - [`rgb`](https://en.wikipedia.org/wiki/RGB_color_model) - Example: `chalk.rgb(255, 136, 0).bold('Orange!')` - [`hex`](https://en.wikipedia.org/wiki/Web_colors#Hex_triplet) - Example: `chalk.hex('#FF8800').bold('Orange!')` -- [`keyword`](https://www.w3.org/wiki/CSS/Properties/color/keywords) (CSS keywords) - Example: `chalk.keyword('orange').bold('Orange!')` -- [`hsl`](https://en.wikipedia.org/wiki/HSL_and_HSV) - Example: `chalk.hsl(32, 100, 50).bold('Orange!')` -- [`hsv`](https://en.wikipedia.org/wiki/HSL_and_HSV) - Example: `chalk.hsv(32, 100, 100).bold('Orange!')` -- [`hwb`](https://en.wikipedia.org/wiki/HWB_color_model) - Example: `chalk.hwb(32, 0, 50).bold('Orange!')` -- [`ansi`](https://en.wikipedia.org/wiki/ANSI_escape_code#3/4_bit) - Example: `chalk.ansi(31).bgAnsi(93)('red on yellowBright')` - [`ansi256`](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) - Example: `chalk.bgAnsi256(194)('Honeydew, more or less')` ## Browser support diff --git a/source/index.js b/source/index.js index 6313bde..8a3785b 100644 --- a/source/index.js +++ b/source/index.js @@ -1,13 +1,18 @@ -'use strict'; -const ansiStyles = require('ansi-styles'); -const {stdout: stdoutColor, stderr: stderrColor} = require('supports-color'); -const { +import ansiStyles from 'ansi-styles'; +import supportsColor from 'supports-color'; +import { stringReplaceAll, stringEncaseCRLFWithFirstIndex -} = require('./util'); +} from './util.js'; +import template from './templates.js'; +const {stdout: stdoutColor, stderr: stderrColor} = supportsColor; const {isArray} = Array; +const GENERATOR = Symbol('GENERATOR'); +const STYLER = Symbol('STYLER'); +const IS_EMPTY = Symbol('IS_EMPTY'); + // `supportsColor.level` → `ansiStyles.color[name]` mapping const levelMapping = [ 'ansi', @@ -28,7 +33,7 @@ const applyOptions = (object, options = {}) => { object.level = options.level === undefined ? colorLevel : options.level; }; -class ChalkClass { +export class Chalk { constructor(options) { // eslint-disable-next-line no-constructor-return return chalkFactory(options); @@ -41,26 +46,24 @@ const chalkFactory = options => { chalk.template = (...arguments_) => chalkTag(chalk.template, ...arguments_); - Object.setPrototypeOf(chalk, Chalk.prototype); + Object.setPrototypeOf(chalk, createChalk.prototype); Object.setPrototypeOf(chalk.template, chalk); - chalk.template.constructor = () => { - throw new Error('`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.'); - }; - - chalk.template.Instance = ChalkClass; + chalk.template.Chalk = Chalk; return chalk.template; }; -function Chalk(options) { +function createChalk(options) { return chalkFactory(options); } +Object.setPrototypeOf(createChalk.prototype, Function.prototype); + for (const [styleName, style] of Object.entries(ansiStyles)) { styles[styleName] = { get() { - const builder = createBuilder(this, createStyler(style.open, style.close, this._styler), this._isEmpty); + const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]); Object.defineProperty(this, styleName, {value: builder}); return builder; } @@ -69,21 +72,41 @@ for (const [styleName, style] of Object.entries(ansiStyles)) { styles.visible = { get() { - const builder = createBuilder(this, this._styler, true); + const builder = createBuilder(this, this[STYLER], true); Object.defineProperty(this, 'visible', {value: builder}); return builder; } }; -const usedModels = ['rgb', 'hex', 'keyword', 'hsl', 'hsv', 'hwb', 'ansi', 'ansi256']; +const getModelAnsi = (model, level, type, ...arguments_) => { + if (model === 'rgb') { + if (level === 'ansi16m') { + return ansiStyles[type].ansi16m(...arguments_); + } + + if (level === 'ansi256') { + return ansiStyles[type].ansi256(ansiStyles.rgbToAnsi256(...arguments_)); + } + + return ansiStyles[type].ansi(ansiStyles.rgbToAnsi(...arguments_)); + } + + if (model === 'hex') { + return getModelAnsi('rgb', level, type, ...ansiStyles.hexToRgb(...arguments_)); + } + + return ansiStyles[type][model](...arguments_); +}; + +const usedModels = ['rgb', 'hex', 'ansi256']; for (const model of usedModels) { styles[model] = { get() { const {level} = this; return function (...arguments_) { - const styler = createStyler(ansiStyles.color[levelMapping[level]][model](...arguments_), ansiStyles.color.close, this._styler); - return createBuilder(this, styler, this._isEmpty); + const styler = createStyler(getModelAnsi(model, levelMapping[level], 'color', ...arguments_), ansiStyles.color.close, this[STYLER]); + return createBuilder(this, styler, this[IS_EMPTY]); }; } }; @@ -93,8 +116,8 @@ for (const model of usedModels) { get() { const {level} = this; return function (...arguments_) { - const styler = createStyler(ansiStyles.bgColor[levelMapping[level]][model](...arguments_), ansiStyles.bgColor.close, this._styler); - return createBuilder(this, styler, this._isEmpty); + const styler = createStyler(getModelAnsi(model, levelMapping[level], 'bgColor', ...arguments_), ansiStyles.bgColor.close, this[STYLER]); + return createBuilder(this, styler, this[IS_EMPTY]); }; } }; @@ -105,10 +128,10 @@ const proto = Object.defineProperties(() => {}, { level: { enumerable: true, get() { - return this._generator.level; + return this[GENERATOR].level; }, set(level) { - this._generator.level = level; + this[GENERATOR].level = level; } } }); @@ -149,26 +172,26 @@ const createBuilder = (self, _styler, _isEmpty) => { // no way to create a function with a different prototype Object.setPrototypeOf(builder, proto); - builder._generator = self; - builder._styler = _styler; - builder._isEmpty = _isEmpty; + builder[GENERATOR] = self; + builder[STYLER] = _styler; + builder[IS_EMPTY] = _isEmpty; return builder; }; const applyStyle = (self, string) => { if (self.level <= 0 || !string) { - return self._isEmpty ? '' : string; + return self[IS_EMPTY] ? '' : string; } - let styler = self._styler; + let styler = self[STYLER]; if (styler === undefined) { return string; } const {openAll, closeAll} = styler; - if (string.indexOf('\u001B') !== -1) { + if (string.includes('\u001B')) { while (styler !== undefined) { // Replace any instances already present with a re-opening code // otherwise only the part of the string until said closing code @@ -190,7 +213,6 @@ const applyStyle = (self, string) => { return openAll + string + closeAll; }; -let template; const chalkTag = (chalk, ...strings) => { const [firstString] = strings; @@ -210,18 +232,17 @@ const chalkTag = (chalk, ...strings) => { ); } - if (template === undefined) { - template = require('./templates'); - } - return template(chalk, parts.join('')); }; -Object.defineProperties(Chalk.prototype, styles); +Object.defineProperties(createChalk.prototype, styles); -const chalk = Chalk(); // eslint-disable-line new-cap -chalk.supportsColor = stdoutColor; -chalk.stderr = Chalk({level: stderrColor ? stderrColor.level : 0}); // eslint-disable-line new-cap -chalk.stderr.supportsColor = stderrColor; +const chalk = createChalk(); +export const chalkStderr = createChalk({level: stderrColor ? stderrColor.level : 0}); + +export { + stdoutColor as supportsColor, + stderrColor as supportsColorStderr +}; -module.exports = chalk; +export default chalk; diff --git a/source/templates.js b/source/templates.js index bfdaba8..1a2f95c 100644 --- a/source/templates.js +++ b/source/templates.js @@ -1,4 +1,3 @@ -'use strict'; const TEMPLATE_REGEX = /(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; @@ -62,7 +61,7 @@ function parseStyle(style) { if (matches[2]) { const args = parseArguments(name, matches[2]); - results.push([name].concat(args)); + results.push([name, ...args]); } else { results.push([name]); } @@ -96,7 +95,7 @@ function buildStyle(chalk, styles) { return current; } -module.exports = (chalk, temporary) => { +export default function template(chalk, temporary) { const styles = []; const chunks = []; let chunk = []; @@ -126,9 +125,9 @@ module.exports = (chalk, temporary) => { chunks.push(chunk.join('')); if (styles.length > 0) { - const errMessage = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`; - throw new Error(errMessage); + const errorMessage = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`; + throw new Error(errorMessage); } return chunks.join(''); -}; +} diff --git a/source/util.js b/source/util.js index ca466fd..4d8bc4a 100644 --- a/source/util.js +++ b/source/util.js @@ -1,6 +1,4 @@ -'use strict'; - -const stringReplaceAll = (string, substring, replacer) => { +export function stringReplaceAll(string, substring, replacer) { let index = string.indexOf(substring); if (index === -1) { return string; @@ -15,11 +13,11 @@ const stringReplaceAll = (string, substring, replacer) => { index = string.indexOf(substring, endIndex); } while (index !== -1); - returnValue += string.substr(endIndex); + returnValue += string.slice(endIndex); return returnValue; -}; +} -const stringEncaseCRLFWithFirstIndex = (string, prefix, postfix, index) => { +export function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) { let endIndex = 0; let returnValue = ''; do { @@ -29,11 +27,6 @@ const stringEncaseCRLFWithFirstIndex = (string, prefix, postfix, index) => { index = string.indexOf('\n', endIndex); } while (index !== -1); - returnValue += string.substr(endIndex); + returnValue += string.slice(endIndex); return returnValue; -}; - -module.exports = { - stringReplaceAll, - stringEncaseCRLFWithFirstIndex -}; +} diff --git a/test/_fixture.js b/test/_fixture.js index 29f34b0..c3e5b15 100644 --- a/test/_fixture.js +++ b/test/_fixture.js @@ -1,4 +1,3 @@ -'use strict'; -const chalk = require('../source'); +import chalk, {chalkStderr} from '../source/index.js'; -console.log(`${chalk.hex('#ff6159')('testout')} ${chalk.stderr.hex('#ff6159')('testerr')}`); +console.log(`${chalk.hex('#ff6159')('testout')} ${chalkStderr.hex('#ff6159')('testerr')}`); diff --git a/test/_supports-color.js b/test/_supports-color.js deleted file mode 100644 index b5c0f78..0000000 --- a/test/_supports-color.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; -const resolveFrom = require('resolve-from'); - -const DEFAULT = { - stdout: { - level: 3, - hasBasic: true, - has256: true, - has16m: true - }, - stderr: { - level: 3, - hasBasic: true, - has256: true, - has16m: true - } -}; - -module.exports = (dir, override) => { - require.cache[resolveFrom(dir, 'supports-color')] = {exports: override || DEFAULT}; -}; diff --git a/test/chalk.js b/test/chalk.js index 4e78565..af43558 100644 --- a/test/chalk.js +++ b/test/chalk.js @@ -1,9 +1,8 @@ import test from 'ava'; +import chalk, {Chalk, chalkStderr} from '../source/index.js'; -// Spoof supports-color -require('./_supports-color')(__dirname); - -const chalk = require('../source'); +chalk.level = 3; +chalkStderr.level = 3; console.log('TERM:', process.env.TERM || '[none]'); console.log('platform:', process.platform || '[unknown]'); @@ -95,26 +94,32 @@ test('line breaks should open and close colors with CRLF', t => { }); test('properly convert RGB to 16 colors on basic color terminals', t => { - t.is(new chalk.Instance({level: 1}).hex('#FF0000')('hello'), '\u001B[91mhello\u001B[39m'); - t.is(new chalk.Instance({level: 1}).bgHex('#FF0000')('hello'), '\u001B[101mhello\u001B[49m'); + t.is(new Chalk({level: 1}).hex('#FF0000')('hello'), '\u001B[91mhello\u001B[39m'); + t.is(new Chalk({level: 1}).bgHex('#FF0000')('hello'), '\u001B[101mhello\u001B[49m'); }); test('properly convert RGB to 256 colors on basic color terminals', t => { - t.is(new chalk.Instance({level: 2}).hex('#FF0000')('hello'), '\u001B[38;5;196mhello\u001B[39m'); - t.is(new chalk.Instance({level: 2}).bgHex('#FF0000')('hello'), '\u001B[48;5;196mhello\u001B[49m'); - t.is(new chalk.Instance({level: 3}).bgHex('#FF0000')('hello'), '\u001B[48;2;255;0;0mhello\u001B[49m'); + t.is(new Chalk({level: 2}).hex('#FF0000')('hello'), '\u001B[38;5;196mhello\u001B[39m'); + t.is(new Chalk({level: 2}).bgHex('#FF0000')('hello'), '\u001B[48;5;196mhello\u001B[49m'); + t.is(new Chalk({level: 3}).bgHex('#FF0000')('hello'), '\u001B[48;2;255;0;0mhello\u001B[49m'); }); test('don\'t emit RGB codes if level is 0', t => { - t.is(new chalk.Instance({level: 0}).hex('#FF0000')('hello'), 'hello'); - t.is(new chalk.Instance({level: 0}).bgHex('#FF0000')('hello'), 'hello'); + t.is(new Chalk({level: 0}).hex('#FF0000')('hello'), 'hello'); + t.is(new Chalk({level: 0}).bgHex('#FF0000')('hello'), 'hello'); }); test('supports blackBright color', t => { t.is(chalk.blackBright('foo'), '\u001B[90mfoo\u001B[39m'); }); -test('sets correct level for chalk.stderr and respects it', t => { - t.is(chalk.stderr.level, 3); - t.is(chalk.stderr.red.bold('foo'), '\u001B[31m\u001B[1mfoo\u001B[22m\u001B[39m'); +test('sets correct level for chalkStderr and respects it', t => { + t.is(chalkStderr.level, 3); + t.is(chalkStderr.red.bold('foo'), '\u001B[31m\u001B[1mfoo\u001B[22m\u001B[39m'); +}); + +test('keeps function prototype methods', t => { + t.is(chalk.apply(chalk, ['foo']), 'foo'); + t.is(chalk.bind(chalk, 'foo')(), 'foo'); + t.is(chalk.call(chalk, 'foo'), 'foo'); }); diff --git a/test/constructor.js b/test/constructor.js deleted file mode 100644 index f4e9ca1..0000000 --- a/test/constructor.js +++ /dev/null @@ -1,15 +0,0 @@ -import test from 'ava'; - -const chalk = require('../source'); - -test('Chalk.constructor should throw an expected error', t => { - const expectedError = t.throws(() => { - chalk.constructor(); - }); - - t.is(expectedError.message, '`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.'); - - t.throws(() => { - new chalk.constructor(); // eslint-disable-line no-new - }); -}); diff --git a/test/instance.js b/test/instance.js index 37c72eb..c3cc70b 100644 --- a/test/instance.js +++ b/test/instance.js @@ -1,12 +1,10 @@ import test from 'ava'; +import chalk, {Chalk} from '../source/index.js'; -// Spoof supports-color -require('./_supports-color')(__dirname); - -const chalk = require('../source'); +chalk.level = 1; test('create an isolated context where colors can be disabled (by level)', t => { - const instance = new chalk.Instance({level: 0}); + const instance = new Chalk({level: 0}); t.is(instance.red('foo'), 'foo'); t.is(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); instance.level = 2; @@ -16,11 +14,11 @@ test('create an isolated context where colors can be disabled (by level)', t => test('the `level` option should be a number from 0 to 3', t => { /* eslint-disable no-new */ t.throws(() => { - new chalk.Instance({level: 10}); + new Chalk({level: 10}); }, {message: /should be an integer from 0 to 3/}); t.throws(() => { - new chalk.Instance({level: -1}); + new Chalk({level: -1}); }, {message: /should be an integer from 0 to 3/}); /* eslint-enable no-new */ }); diff --git a/test/level.js b/test/level.js index 65d4720..4aab162 100644 --- a/test/level.js +++ b/test/level.js @@ -1,11 +1,9 @@ -import path from 'path'; +import {fileURLToPath} from 'url'; import test from 'ava'; import execa from 'execa'; +import chalk from '../source/index.js'; -// Spoof supports-color -require('./_supports-color')(__dirname); - -const chalk = require('../source'); +chalk.level = 1; test('don\'t output colors when manually disabled', t => { const oldLevel = chalk.level; @@ -40,6 +38,6 @@ test('propagate enable/disable changes from child colors', t => { }); test('disable colors if they are not supported', async t => { - const {stdout} = await execa.node(path.join(__dirname, '_fixture')); + const {stdout} = await execa.node(fileURLToPath(new URL('./_fixture.js', import.meta.url))); t.is(stdout, 'testout testerr'); }); diff --git a/test/no-color-support.js b/test/no-color-support.js index ae88ac9..0a5734d 100644 --- a/test/no-color-support.js +++ b/test/no-color-support.js @@ -1,22 +1,22 @@ import test from 'ava'; +import chalk from '../source/index.js'; +// TODO: Do this when ESM supports loader hooks // Spoof supports-color -require('./_supports-color')(__dirname, { - stdout: { - level: 0, - hasBasic: false, - has256: false, - has16m: false - }, - stderr: { - level: 0, - hasBasic: false, - has256: false, - has16m: false - } -}); - -const chalk = require('../source'); +// require('./_supports-color')(__dirname, { +// stdout: { +// level: 0, +// hasBasic: false, +// has256: false, +// has16m: false +// }, +// stderr: { +// level: 0, +// hasBasic: false, +// has256: false, +// has16m: false +// } +// }); test('colors can be forced by using chalk.level', t => { chalk.level = 1; diff --git a/test/template-literal.js b/test/template-literal.js index c918a5b..e8d5950 100644 --- a/test/template-literal.js +++ b/test/template-literal.js @@ -1,29 +1,27 @@ /* eslint-disable unicorn/no-hex-escape */ import test from 'ava'; +import chalk, {Chalk} from '../source/index.js'; -// Spoof supports-color -require('./_supports-color')(__dirname); - -const chalk = require('../source'); +chalk.level = 1; test('return an empty string for an empty literal', t => { - const instance = new chalk.Instance(); + const instance = new Chalk(); t.is(instance``, ''); }); test('return a regular string for a literal with no templates', t => { - const instance = new chalk.Instance({level: 0}); + const instance = new Chalk({level: 0}); t.is(instance`hello`, 'hello'); }); test('correctly perform template parsing', t => { - const instance = new chalk.Instance({level: 0}); + const instance = new Chalk({level: 0}); t.is(instance`{bold Hello, {cyan World!} This is a} test. {green Woo!}`, instance.bold('Hello,', instance.cyan('World!'), 'This is a') + ' test. ' + instance.green('Woo!')); }); test('correctly perform template substitutions', t => { - const instance = new chalk.Instance({level: 0}); + const instance = new Chalk({level: 0}); const name = 'Sindre'; const exclamation = 'Neat'; t.is(instance`{bold Hello, {cyan.inverse ${name}!} This is a} test. {green ${exclamation}!}`, @@ -31,7 +29,7 @@ test('correctly perform template substitutions', t => { }); test('correctly perform nested template substitutions', t => { - const instance = new chalk.Instance({level: 0}); + const instance = new Chalk({level: 0}); const name = 'Sindre'; const exclamation = 'Neat'; t.is(instance.bold`Hello, {cyan.inverse ${name}!} This is a` + ' test. ' + instance.green`${exclamation}!`, @@ -50,7 +48,7 @@ test('correctly perform nested template substitutions', t => { }); test('correctly parse and evaluate color-convert functions', t => { - const instance = new chalk.Instance({level: 3}); + const instance = new Chalk({level: 3}); t.is(instance`{bold.rgb(144,10,178).inverse Hello, {~inverse there!}}`, '\u001B[1m\u001B[38;2;144;10;178m\u001B[7mHello, ' + '\u001B[27m\u001B[39m\u001B[22m\u001B[1m' + @@ -63,13 +61,13 @@ test('correctly parse and evaluate color-convert functions', t => { }); test('properly handle escapes', t => { - const instance = new chalk.Instance({level: 3}); + const instance = new Chalk({level: 3}); t.is(instance`{bold hello \{in brackets\}}`, '\u001B[1mhello {in brackets}\u001B[22m'); }); test('throw if there is an unclosed block', t => { - const instance = new chalk.Instance({level: 3}); + const instance = new Chalk({level: 3}); try { console.log(instance`{bold this shouldn't appear ever\}`); t.fail(); @@ -86,7 +84,7 @@ test('throw if there is an unclosed block', t => { }); test('throw if there is an invalid style', t => { - const instance = new chalk.Instance({level: 3}); + const instance = new Chalk({level: 3}); try { console.log(instance`{abadstylethatdoesntexist this shouldn't appear ever}`); t.fail(); @@ -96,7 +94,7 @@ test('throw if there is an invalid style', t => { }); test('properly style multiline color blocks', t => { - const instance = new chalk.Instance({level: 3}); + const instance = new Chalk({level: 3}); t.is( instance`{bold Hello! This is a @@ -116,59 +114,59 @@ test('properly style multiline color blocks', t => { }); test('escape interpolated values', t => { - const instance = new chalk.Instance({level: 0}); + const instance = new Chalk({level: 0}); t.is(instance`Hello {bold hi}`, 'Hello hi'); t.is(instance`Hello ${'{bold hi}'}`, 'Hello {bold hi}'); }); test('allow custom colors (themes) on custom contexts', t => { - const instance = new chalk.Instance({level: 3}); + const instance = new Chalk({level: 3}); instance.rose = instance.hex('#F6D9D9'); t.is(instance`Hello, {rose Rose}.`, 'Hello, \u001B[38;2;246;217;217mRose\u001B[39m.'); }); test('correctly parse newline literals (bug #184)', t => { - const instance = new chalk.Instance({level: 0}); + const instance = new Chalk({level: 0}); t.is(instance`Hello {red there}`, 'Hello\nthere'); }); test('correctly parse newline escapes (bug #177)', t => { - const instance = new chalk.Instance({level: 0}); + const instance = new Chalk({level: 0}); t.is(instance`Hello\nthere!`, 'Hello\nthere!'); }); test('correctly parse escape in parameters (bug #177 comment 318622809)', t => { - const instance = new chalk.Instance({level: 0}); + const instance = new Chalk({level: 0}); const string = '\\'; t.is(instance`{blue ${string}}`, '\\'); }); test('correctly parses unicode/hex escapes', t => { - const instance = new chalk.Instance({level: 0}); + const instance = new Chalk({level: 0}); t.is(instance`\u0078ylophones are fo\x78y! {magenta.inverse \u0078ylophones are fo\x78y!}`, 'xylophones are foxy! xylophones are foxy!'); }); test('correctly parses string arguments', t => { - const instance = new chalk.Instance({level: 3}); - t.is(instance`{keyword('black').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); - t.is(instance`{keyword('blac\x6B').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); - t.is(instance`{keyword('blac\u006B').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); + const instance = new Chalk({level: 3}); + t.is(instance`{hex('#000000').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); + t.is(instance`{hex('#00000\x30').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); + t.is(instance`{hex('#00000\u0030').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); }); test('throws if a bad argument is encountered', t => { - const instance = new chalk.Instance({level: 3}); // Keep level at least 1 in case we optimize for disabled chalk instances + const instance = new Chalk({level: 3}); // Keep level at least 1 in case we optimize for disabled chalk instances try { - console.log(instance`{keyword(????) hi}`); + console.log(instance`{hex(????) hi}`); t.fail(); } catch (error) { - t.is(error.message, 'Invalid Chalk template style argument: ???? (in style \'keyword\')'); + t.is(error.message, 'Invalid Chalk template style argument: ???? (in style \'hex\')'); } }); test('throws if an extra unescaped } is found', t => { - const instance = new chalk.Instance({level: 0}); + const instance = new Chalk({level: 0}); try { console.log(instance`{red hi!}}`); t.fail(); @@ -178,18 +176,18 @@ test('throws if an extra unescaped } is found', t => { }); test('should not parse upper-case escapes', t => { - const instance = new chalk.Instance({level: 0}); + const instance = new Chalk({level: 0}); t.is(instance`\N\n\T\t\X07\x07\U000A\u000A\U000a\u000A`, 'N\nT\tX07\x07U000A\u000AU000a\u000A'); }); test('should properly handle undefined template interpolated values', t => { - const instance = new chalk.Instance({level: 0}); + const instance = new Chalk({level: 0}); t.is(instance`hello ${undefined}`, 'hello undefined'); t.is(instance`hello ${null}`, 'hello null'); }); test('should allow bracketed Unicode escapes', t => { - const instance = new chalk.Instance({level: 3}); + const instance = new Chalk({level: 3}); t.is(instance`\u{AB}`, '\u{AB}'); t.is(instance`This is a {bold \u{AB681}} test`, 'This is a \u001B[1m\u{AB681}\u001B[22m test'); t.is(instance`This is a {bold \u{10FFFF}} test`, 'This is a \u001B[1m\u{10FFFF}\u001B[22m test'); diff --git a/test/visible.js b/test/visible.js index 7987712..4d34af8 100644 --- a/test/visible.js +++ b/test/visible.js @@ -1,24 +1,22 @@ import test from 'ava'; +import chalk, {Chalk} from '../source/index.js'; -// Spoof supports-color -require('./_supports-color')(__dirname); - -const chalk = require('../source'); +chalk.level = 1; test('visible: normal output when level > 0', t => { - const instance = new chalk.Instance({level: 3}); + const instance = new Chalk({level: 3}); t.is(instance.visible.red('foo'), '\u001B[31mfoo\u001B[39m'); t.is(instance.red.visible('foo'), '\u001B[31mfoo\u001B[39m'); }); test('visible: no output when level is too low', t => { - const instance = new chalk.Instance({level: 0}); + const instance = new Chalk({level: 0}); t.is(instance.visible.red('foo'), ''); t.is(instance.red.visible('foo'), ''); }); test('test switching back and forth between level == 0 and level > 0', t => { - const instance = new chalk.Instance({level: 3}); + const instance = new Chalk({level: 3}); t.is(instance.red('foo'), '\u001B[31mfoo\u001B[39m'); t.is(instance.visible.red('foo'), '\u001B[31mfoo\u001B[39m'); t.is(instance.red.visible('foo'), '\u001B[31mfoo\u001B[39m');