Merge branch 'chalk:main' into main

This commit is contained in:
l198881 2021-05-13 22:43:45 -03:00
commit 3612ad2599
8 changed files with 80 additions and 141 deletions

View file

@ -1,11 +1,10 @@
import chalk from '../index.js';
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;
@ -19,7 +18,7 @@ function rainbow(string, offset) {
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;
}
}
@ -28,9 +27,8 @@ function rainbow(string, offset) {
}
async function animateString(string) {
console.log();
for (let index = 0; index < 360 * 5; index++) {
console.log('\u001B[1F\u001B[G', rainbow(string, index));
updateLog(rainbow(string, index));
await delay(2); // eslint-disable-line no-await-in-loop
}
}

View file

@ -1,5 +1,5 @@
import styles from 'ansi-styles';
import chalk from '../index.js';
import chalk from '../source/index.js';
// Generates screenshot
for (const key of Object.keys(styles)) {

105
index.d.ts vendored
View file

@ -61,6 +61,7 @@ export type Modifiers =
| 'dim'
| 'italic'
| 'underline'
| 'overline'
| 'inverse'
| 'hidden'
| 'strikethrough'
@ -163,6 +164,11 @@ export interface ChalkInstance extends ChalkFunction {
*/
level: ColorSupportLevel;
/**
Use RGB values to set text color.
*/
rgb: (red: number, green: number, blue: number) => this;
/**
Use HEX value to set text color.
@ -178,52 +184,15 @@ export interface ChalkInstance extends ChalkFunction {
hex: (color: string) => this;
/**
Use keyword color value to set text color.
@param color - Keyword value representing the desired color.
@example
```
import chalk from 'chalk';
chalk.keyword('orange');
```
*/
keyword: (color: string) => this;
/**
Use RGB values to set text color.
*/
rgb: (red: number, green: number, blue: number) => this;
/**
Use HSL values to set text color.
*/
hsl: (hue: number, saturation: number, lightness: number) => this;
/**
Use HSV values to set text color.
*/
hsv: (hue: number, saturation: number, value: number) => this;
/**
Use HWB values to set text color.
*/
hwb: (hue: number, whiteness: number, blackness: number) => this;
/**
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) => this;
/**
Use a [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set text color.
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.
@ -238,49 +207,6 @@ export interface ChalkInstance extends ChalkFunction {
*/
bgHex: (color: string) => this;
/**
Use keyword color value to set background color.
@param color - Keyword value representing the desired color.
@example
```
import chalk from 'chalk';
chalk.bgKeyword('orange');
```
*/
bgKeyword: (color: string) => this;
/**
Use RGB values to set background color.
*/
bgRgb: (red: number, green: number, blue: number) => this;
/**
Use HSL values to set background color.
*/
bgHsl: (hue: number, saturation: number, lightness: number) => this;
/**
Use HSV values to set background color.
*/
bgHsv: (hue: number, saturation: number, value: number) => this;
/**
Use HWB values to set background color.
*/
bgHwb: (hue: number, whiteness: number, blackness: number) => this;
/**
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) => this;
/**
Use a [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set background color.
*/
@ -297,7 +223,7 @@ export interface ChalkInstance extends ChalkFunction {
readonly bold: this;
/**
Modifier: Emitting only a small amount of light.
Modifier: Make text slightly darker. (Inconsistent across terminals; might do nothing)
*/
readonly dim: this;
@ -311,6 +237,11 @@ export interface ChalkInstance extends ChalkFunction {
*/
readonly underline: this;
/**
Modifier: Make text overline. (Not widely supported)
*/
readonly overline: this;
/**
Modifier: Inverse background and foreground colors.
*/

View file

@ -41,21 +41,11 @@ expectType<string>(chalk`Hello {bold.red ${name}}`);
expectType<string>(chalk`Works with numbers {bold.red ${1}}`);
// -- Color methods --
expectAssignable<colorReturn>(chalk.hex('#DEADED'));
expectAssignable<colorReturn>(chalk.keyword('orange'));
expectAssignable<colorReturn>(chalk.rgb(0, 0, 0));
expectAssignable<colorReturn>(chalk.hsl(0, 0, 0));
expectAssignable<colorReturn>(chalk.hsv(0, 0, 0));
expectAssignable<colorReturn>(chalk.hwb(0, 0, 0));
expectAssignable<colorReturn>(chalk.ansi(30));
expectAssignable<colorReturn>(chalk.hex('#DEADED'));
expectAssignable<colorReturn>(chalk.ansi256(0));
expectAssignable<colorReturn>(chalk.bgHex('#DEADED'));
expectAssignable<colorReturn>(chalk.bgKeyword('orange'));
expectAssignable<colorReturn>(chalk.bgRgb(0, 0, 0));
expectAssignable<colorReturn>(chalk.bgHsl(0, 0, 0));
expectAssignable<colorReturn>(chalk.bgHsv(0, 0, 0));
expectAssignable<colorReturn>(chalk.bgHwb(0, 0, 0));
expectAssignable<colorReturn>(chalk.bgAnsi(30));
expectAssignable<colorReturn>(chalk.bgHex('#DEADED'));
expectAssignable<colorReturn>(chalk.bgAnsi256(0));
// -- Modifiers --
@ -64,6 +54,7 @@ expectType<string>(chalk.bold('foo'));
expectType<string>(chalk.dim('foo'));
expectType<string>(chalk.italic('foo'));
expectType<string>(chalk.underline('foo'));
expectType<string>(chalk.overline('foo'));
expectType<string>(chalk.inverse('foo'));
expectType<string>(chalk.hidden('foo'));
expectType<string>(chalk.strikethrough('foo'));

View file

@ -8,7 +8,7 @@
"type": "module",
"exports": "./source/index.js",
"engines": {
"node": ">=12"
"node": ">=12.17"
},
"scripts": {
"test": "xo && nyc ava && tsd",
@ -42,17 +42,20 @@
"text"
],
"dependencies": {
"ansi-styles": "^4.1.0",
"ansi-styles": "^6.1.0",
"supports-color": "^9.0.0"
},
"devDependencies": {
"ava": "^3.15.0",
"color-convert": "^2.0.1",
"coveralls": "^3.1.0",
"execa": "^5.0.0",
"log-update": "^4.0.0",
"matcha": "^0.7.0",
"nyc": "^15.1.0",
"tsd": "^0.14.0",
"xo": "^0.38.2"
"xo": "^0.39.1",
"yoctodelay": "^1.2.0"
},
"xo": {
"rules": {

View file

@ -125,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!'));
```
@ -136,7 +135,7 @@ Easily define your own themes:
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!'));
@ -275,7 +274,7 @@ 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.
@ -288,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

View file

@ -9,6 +9,10 @@ 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',
@ -59,7 +63,7 @@ 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;
}
@ -68,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]);
};
}
};
@ -92,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]);
};
}
};
@ -104,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;
}
}
});
@ -148,19 +172,19 @@ 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;

View file

@ -150,18 +150,18 @@ test('correctly parses unicode/hex escapes', t => {
test('correctly parses string arguments', t => {
const instance = new Chalk({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');
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({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\')');
}
});