From 55816cdd4d25a86cc35b18e1e578a5b164f71aee Mon Sep 17 00:00:00 2001 From: Steven Date: Wed, 15 Apr 2020 23:56:23 -0400 Subject: [PATCH 1/3] Update readme links to use https (#396) --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index a0ca2456..816b5cea 100644 --- a/readme.md +++ b/readme.md @@ -9,7 +9,7 @@ > Terminal string styling done right -[![Build Status](https://travis-ci.org/chalk/chalk.svg?branch=master)](https://travis-ci.org/chalk/chalk) [![Coverage Status](https://coveralls.io/repos/github/chalk/chalk/badge.svg?branch=master)](https://coveralls.io/github/chalk/chalk?branch=master) [![npm dependents](https://badgen.net/npm/dependents/chalk)](https://www.npmjs.com/package/chalk?activeTab=dependents) [![Downloads](https://badgen.net/npm/dt/chalk)](https://www.npmjs.com/package/chalk) [![](https://img.shields.io/badge/unicorn-approved-ff69b4.svg)](https://www.youtube.com/watch?v=9auOCbH5Ns4) [![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/xojs/xo) ![TypeScript-ready](https://img.shields.io/npm/types/chalk.svg) [![run on repl.it](http://repl.it/badge/github/chalk/chalk)](https://repl.it/github/chalk/chalk) +[![Build Status](https://travis-ci.org/chalk/chalk.svg?branch=master)](https://travis-ci.org/chalk/chalk) [![Coverage Status](https://coveralls.io/repos/github/chalk/chalk/badge.svg?branch=master)](https://coveralls.io/github/chalk/chalk?branch=master) [![npm dependents](https://badgen.net/npm/dependents/chalk)](https://www.npmjs.com/package/chalk?activeTab=dependents) [![Downloads](https://badgen.net/npm/dt/chalk)](https://www.npmjs.com/package/chalk) [![](https://img.shields.io/badge/unicorn-approved-ff69b4.svg)](https://www.youtube.com/watch?v=9auOCbH5Ns4) [![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/xojs/xo) ![TypeScript-ready](https://img.shields.io/npm/types/chalk.svg) [![run on repl.it](https://repl.it/badge/github/chalk/chalk)](https://repl.it/github/chalk/chalk) @@ -199,7 +199,7 @@ Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color= ## Tagged template literal -Chalk can be used as a [tagged template literal](http://exploringjs.com/es6/ch_template-literals.html#_tagged-template-literals). +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'); From 09ddbadcb5569f6d6ace11f54242c339d727d546 Mon Sep 17 00:00:00 2001 From: Toon Baeyens Date: Tue, 9 Jun 2020 09:36:34 +0200 Subject: [PATCH 2/3] Support template literals for nested calls (#392) Co-authored-by: Sindre Sorhus --- benchmark.js | 12 ++++++++++++ index.d.ts | 7 +++++++ index.test-d.ts | 5 +++++ readme.md | 3 ++- source/index.js | 9 ++++++++- test/chalk.js | 8 ++++++++ test/template-literal.js | 19 +++++++++++++++++++ 7 files changed, 61 insertions(+), 2 deletions(-) diff --git a/benchmark.js b/benchmark.js index dc246961..25b3f5df 100644 --- a/benchmark.js +++ b/benchmark.js @@ -47,4 +47,16 @@ suite('chalk', () => { bench('cached: 1 style nested non-intersecting', () => { chalkBgRed(blueStyledString); }); + + set('iterations', 10000); + + bench('cached: 1 style template literal', () => { + // eslint-disable-next-line no-unused-expressions + chalkRed`the fox jumps over the lazy dog`; + }); + + bench('cached: nested styles template literal', () => { + // eslint-disable-next-line no-unused-expressions + chalkRed`the fox {bold jumps} over the {underline lazy} dog`; + }); }); diff --git a/index.d.ts b/index.d.ts index df96b038..9cd88f38 100644 --- a/index.d.ts +++ b/index.d.ts @@ -137,6 +137,13 @@ declare namespace chalk { 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; diff --git a/index.test-d.ts b/index.test-d.ts index ad5dcf52..aa9e2f50 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -152,6 +152,11 @@ expectType(chalk.bgWhiteBright`foo`); expectType(chalk.red.bgGreen.underline('foo')); expectType(chalk.underline.red.bgGreen('foo')); +// -- Complex template literal -- +expectType(chalk.underline``); +expectType(chalk.red.bgGreen.bold`Hello {italic.blue ${name}}`); +expectType(chalk.strikethrough.cyanBright.bgBlack`Works with {reset {bold numbers}} {bold.red ${1}}`); + // -- Color types == expectType('red'); expectError('hotpink'); diff --git a/readme.md b/readme.md index 816b5cea..338f42cb 100644 --- a/readme.md +++ b/readme.md @@ -215,10 +215,11 @@ console.log(chalk` Blocks are delimited by an opening curly brace (`{`), a style, some content, and a closing curly brace (`}`). -Template styles are chained exactly like normal Chalk styles. The following two statements are equivalent: +Template styles are chained exactly like normal Chalk styles. The following three statements are equivalent: ```js 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!}`); ``` diff --git a/source/index.js b/source/index.js index e3b2f163..75ec6635 100644 --- a/source/index.js +++ b/source/index.js @@ -6,6 +6,8 @@ const { stringEncaseCRLFWithFirstIndex } = require('./util'); +const {isArray} = Array; + // `supportsColor.level` → `ansiStyles.color[name]` mapping const levelMapping = [ 'ansi', @@ -135,6 +137,11 @@ const createStyler = (open, close, parent) => { const createBuilder = (self, _styler, _isEmpty) => { const builder = (...arguments_) => { + if (isArray(arguments_[0]) && isArray(arguments_[0].raw)) { + // Called as a template literal, for example: chalk.red`2 + 3 = {bold ${2+3}}` + return applyStyle(builder, chalkTag(builder, ...arguments_)); + } + // Single argument is hot path, implicit coercion is faster than anything // eslint-disable-next-line no-implicit-coercion return applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' ')); @@ -189,7 +196,7 @@ let template; const chalkTag = (chalk, ...strings) => { const [firstString] = strings; - if (!Array.isArray(firstString)) { + if (!isArray(firstString) || !isArray(firstString.raw)) { // If chalk() was called by itself or with a string, // return the string itself as a string. return strings.join(' '); diff --git a/test/chalk.js b/test/chalk.js index 21f03460..4e78565f 100644 --- a/test/chalk.js +++ b/test/chalk.js @@ -16,6 +16,14 @@ test('support multiple arguments in base function', t => { t.is(chalk('hello', 'there'), 'hello there'); }); +test('support automatic casting to string', t => { + t.is(chalk(['hello', 'there']), 'hello,there'); + t.is(chalk(123), '123'); + + t.is(chalk.bold(['foo', 'bar']), '\u001B[1mfoo,bar\u001B[22m'); + t.is(chalk.green(98765), '\u001B[32m98765\u001B[39m'); +}); + test('style string', t => { t.is(chalk.underline('foo'), '\u001B[4mfoo\u001B[24m'); t.is(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); diff --git a/test/template-literal.js b/test/template-literal.js index 98e01c6b..2f75e039 100644 --- a/test/template-literal.js +++ b/test/template-literal.js @@ -30,6 +30,25 @@ test('correctly perform template substitutions', t => { instance.bold('Hello,', instance.cyan.inverse(name + '!'), 'This is a') + ' test. ' + instance.green(exclamation + '!')); }); +test('correctly perform nested template substitutions', t => { + const instance = new chalk.Instance({level: 0}); + const name = 'Sindre'; + const exclamation = 'Neat'; + t.is(instance.bold`Hello, {cyan.inverse ${name}!} This is a` + ' test. ' + instance.green`${exclamation}!`, + instance.bold('Hello,', instance.cyan.inverse(name + '!'), 'This is a') + ' test. ' + instance.green(exclamation + '!')); + + t.is(instance.red.bgGreen.bold`Hello {italic.blue ${name}}`, + instance.red.bgGreen.bold('Hello ' + instance.italic.blue(name))); + + t.is(instance.strikethrough.cyanBright.bgBlack`Works with {reset {bold numbers}} {bold.red ${1}}`, + instance.strikethrough.cyanBright.bgBlack('Works with ' + instance.reset.bold('numbers') + ' ' + instance.bold.red(1))); + + t.is(chalk.bold`Also works on the shared {bgBlue chalk} object`, + '\u001B[1mAlso works on the shared \u001B[1m' + + '\u001B[44mchalk\u001B[49m\u001B[22m' + + '\u001B[1m object\u001B[22m'); +}); + test('correctly parse and evaluate color-convert functions', t => { const instance = new chalk.Instance({level: 3}); t.is(instance`{bold.rgb(144,10,178).inverse Hello, {~inverse there!}}`, From 4c3df8847256f9f2471f0af74100b21afc12949f Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 9 Jun 2020 15:43:27 +0800 Subject: [PATCH 3/3] 4.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6231a2c6..0d99f0f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "4.0.0", + "version": "4.1.0", "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk",