From 14603cd0f527247d5bb36f35983f048b95376c87 Mon Sep 17 00:00:00 2001 From: Qix Date: Sun, 23 Aug 2015 17:33:33 -0600 Subject: [PATCH 001/235] =?UTF-8?q?5000=20dependents=20=F0=9F=8E=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 5cf111e..7ed1586 100644 --- a/readme.md +++ b/readme.md @@ -30,7 +30,7 @@ - Clean and focused - Auto-detects color support - Actively maintained -- [Used by ~4500 modules](https://www.npmjs.com/browse/depended/chalk) as of July 15, 2015 +- [Used by ~5000 modules](https://www.npmjs.com/browse/depended/chalk) as of August 23, 2015 ## Install From 641ae571b4d49a9f5d9b38a000b32f646f387dd3 Mon Sep 17 00:00:00 2001 From: Jorrit Schippers Date: Sun, 13 Sep 2015 22:19:40 +0200 Subject: [PATCH 002/235] New URL for cmder --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 7ed1586..4131b4e 100644 --- a/readme.md +++ b/readme.md @@ -194,7 +194,7 @@ Chalk does not support anything other than the base eight colors, which guarante ## Windows -If you're on Windows, do yourself a favor and use [`cmder`](http://bliker.github.io/cmder/) instead of `cmd.exe`. +If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) instead of `cmd.exe`. ## Related From 262274af864ada7c8170c577c528204be961f9a8 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 26 Sep 2015 15:15:59 +0700 Subject: [PATCH 003/235] add `slice-ansi` to related section in readme --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 4131b4e..6b5c8cc 100644 --- a/readme.md +++ b/readme.md @@ -206,6 +206,7 @@ If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) i - [has-ansi](https://github.com/chalk/has-ansi) - Check if a string has ANSI escape codes - [ansi-regex](https://github.com/chalk/ansi-regex) - Regular expression for matching ANSI escape codes - [wrap-ansi](https://github.com/chalk/wrap-ansi) - Wordwrap a string with ANSI escape codes +- [slice-ansi](https://github.com/chalk/slice-ansi) - Slice a string with ANSI escape codes ## License From 8d599972ee20ee46840bad0916dfda155bc829ae Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 5 Oct 2015 22:36:26 +0700 Subject: [PATCH 004/235] readme tweaks --- readme.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/readme.md b/readme.md index 6b5c8cc..d72d960 100644 --- a/readme.md +++ b/readme.md @@ -45,7 +45,7 @@ $ npm install --save chalk Chalk comes with an easy to use composable API where you just chain and nest the styles you want. ```js -var chalk = require('chalk'); +const chalk = require('chalk'); // style a string chalk.blue('Hello world!'); @@ -73,17 +73,17 @@ chalk.green( Easily define your own themes. ```js -var chalk = require('chalk'); -var error = chalk.bold.red; +const chalk = require('chalk'); +const error = chalk.bold.red; console.log(error('Error!')); ``` Take advantage of console.log [string substitution](http://nodejs.org/docs/latest/api/console.html#console_console_log_data). ```js -var name = 'Sindre'; +const name = 'Sindre'; console.log(chalk.green('Hello %s'), name); -//=> Hello Sindre +//=> 'Hello Sindre' ``` @@ -104,7 +104,7 @@ 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 -var ctx = new chalk.constructor({enabled: false}); +const ctx = new chalk.constructor({enabled: false}); ``` ### chalk.supportsColor @@ -120,7 +120,7 @@ Exposes the styles as [ANSI escape codes](https://github.com/chalk/ansi-styles). Generally not useful, but you might need just the `.open` or `.close` escape code if you're mixing externally styled strings with your own. ```js -var chalk = require('chalk'); +const chalk = require('chalk'); console.log(chalk.styles.red); //=> {open: '\u001b[31m', close: '\u001b[39m'} @@ -141,8 +141,8 @@ Can be useful in combination with `.supportsColor` to strip color on externally Example: ```js -var chalk = require('chalk'); -var styledString = getText(); +const chalk = require('chalk'); +let styledString = getText(); if (!chalk.supportsColor) { styledString = chalk.stripColor(styledString); From ed6e7d56daa9d756b3d644103e193db2a79fee9c Mon Sep 17 00:00:00 2001 From: Edvin Erikson Date: Fri, 9 Oct 2015 01:09:08 +0700 Subject: [PATCH 005/235] Close #86 PR: Add ES2015 template literal example. Fixes #77 --- readme.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/readme.md b/readme.md index d72d960..6bc57b9 100644 --- a/readme.md +++ b/readme.md @@ -68,6 +68,13 @@ chalk.green( chalk.blue.underline.bold('with a blue substring') + ' that becomes green again!' ); + +// ES2015 template literal +const systemStats = ` +CPU: ${chalk.red('90%')} +RAM: ${chalk.green('40%')} +DISK: ${chalk.yellow('70%')} +`; ``` Easily define your own themes. From 83615f2ed655486641ac13814cd21b36bd9cdfd3 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 5 Nov 2015 13:12:34 +0700 Subject: [PATCH 006/235] clarify docs about using console.log fixes #89 --- readme.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index 6bc57b9..17ff97c 100644 --- a/readme.md +++ b/readme.md @@ -42,13 +42,18 @@ $ npm install --save chalk ## Usage -Chalk comes with an easy to use composable API where you just chain and nest the styles you want. - ```js const chalk = require('chalk'); -// style a string -chalk.blue('Hello world!'); +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. + +Here without `console.log` for purity. + +```js +const chalk = require('chalk'); // combine styled and normal strings chalk.blue('Hello') + 'World' + chalk.red('!'); From 04cae226cc0fc11fd7898f3fa91fdc4a3b3e496b Mon Sep 17 00:00:00 2001 From: vdemedes Date: Sat, 12 Dec 2015 23:38:55 +0100 Subject: [PATCH 007/235] remove has-ansi and strip-ansi dependencies --- index.js | 4 ---- package.json | 2 -- readme.md | 21 --------------------- test.js | 13 ------------- 4 files changed, 40 deletions(-) diff --git a/index.js b/index.js index 2d85a91..d2ec92d 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,6 @@ 'use strict'; var escapeStringRegexp = require('escape-string-regexp'); var ansiStyles = require('ansi-styles'); -var stripAnsi = require('strip-ansi'); -var hasAnsi = require('has-ansi'); var supportsColor = require('supports-color'); var defineProps = Object.defineProperties; var isSimpleWindowsTerm = process.platform === 'win32' && !/^xterm/i.test(process.env.TERM); @@ -111,6 +109,4 @@ defineProps(Chalk.prototype, init()); module.exports = new Chalk(); module.exports.styles = ansiStyles; -module.exports.hasColor = hasAnsi; -module.exports.stripColor = stripAnsi; module.exports.supportsColor = supportsColor; diff --git a/package.json b/package.json index 7054997..441a2d9 100644 --- a/package.json +++ b/package.json @@ -47,8 +47,6 @@ "dependencies": { "ansi-styles": "^2.1.0", "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", "supports-color": "^2.0.0" }, "devDependencies": { diff --git a/readme.md b/readme.md index 17ff97c..1740c87 100644 --- a/readme.md +++ b/readme.md @@ -140,27 +140,6 @@ console.log(chalk.styles.red); console.log(chalk.styles.red.open + 'Hello' + chalk.styles.red.close); ``` -### chalk.hasColor(string) - -Check whether a string [has color](https://github.com/chalk/has-ansi). - -### chalk.stripColor(string) - -[Strip color](https://github.com/chalk/strip-ansi) from a string. - -Can be useful in combination with `.supportsColor` to strip color on externally styled text when it's not supported. - -Example: - -```js -const chalk = require('chalk'); -let styledString = getText(); - -if (!chalk.supportsColor) { - styledString = chalk.stripColor(styledString); -} -``` - ## Styles diff --git a/test.js b/test.js index 1e6d75e..998d93d 100644 --- a/test.js +++ b/test.js @@ -142,16 +142,3 @@ describe('chalk.styles', function () { assert.equal(chalk.styles.red.open, '\u001b[31m'); }); }); - -describe('chalk.hasColor()', function () { - it('should detect whether a string has color', function () { - assert(chalk.hasColor(chalk.green('foo'))); - assert(!chalk.hasColor(chalk.stripColor(chalk.green('foo')))); - }); -}); - -describe('chalk.stripColor()', function () { - it('should strip color from string', function () { - assert.equal(chalk.stripColor(chalk.underline.red.bgGreen('foo')), 'foo'); - }); -}); From 7c40059a030f24eda97867dee773cdfd48abb7af Mon Sep 17 00:00:00 2001 From: Christopher Venning Date: Thu, 31 Dec 2015 15:28:46 -0500 Subject: [PATCH 008/235] Use HTTPS for shields.io unicorn badge; raises mixed-content warning on npmjs.com --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 1740c87..c6f4433 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ [![Build Status](https://travis-ci.org/chalk/chalk.svg?branch=master)](https://travis-ci.org/chalk/chalk) [![Coverage Status](https://coveralls.io/repos/chalk/chalk/badge.svg?branch=master)](https://coveralls.io/r/chalk/chalk?branch=master) -[![](http://img.shields.io/badge/unicorn-approved-ff69b4.svg)](https://www.youtube.com/watch?v=9auOCbH5Ns4) +[![](https://img.shields.io/badge/unicorn-approved-ff69b4.svg)](https://www.youtube.com/watch?v=9auOCbH5Ns4) [colors.js](https://github.com/Marak/colors.js) used to be the most popular string styling module, but it has serious deficiencies like extending `String.prototype` which causes all kinds of [problems](https://github.com/yeoman/yo/issues/68). Although there are other ones, they either do too much or not enough. From 5679ec0c047063f1d1b6ff4e3357c93d47c2b351 Mon Sep 17 00:00:00 2001 From: Steve Mao Date: Tue, 5 Jan 2016 20:43:55 +1100 Subject: [PATCH 009/235] bump deps No breaking changes to this modules. --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 441a2d9..36f8204 100644 --- a/package.json +++ b/package.json @@ -47,16 +47,16 @@ "dependencies": { "ansi-styles": "^2.1.0", "escape-string-regexp": "^1.0.2", - "supports-color": "^2.0.0" + "supports-color": "^3.1.2" }, "devDependencies": { "coveralls": "^2.11.2", "matcha": "^0.6.0", "mocha": "*", - "nyc": "^3.0.0", + "nyc": "^5.2.0", "require-uncached": "^1.0.2", - "resolve-from": "^1.0.0", - "semver": "^4.3.3", + "resolve-from": "^2.0.0", + "semver": "^5.1.0", "xo": "*" }, "xo": { From 337f9c748584a41442eb9795fcb652f120b4840b Mon Sep 17 00:00:00 2001 From: Steve Mao Date: Wed, 6 Jan 2016 18:54:01 +1100 Subject: [PATCH 010/235] add missing tests --- test.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test.js b/test.js index 998d93d..d753917 100644 --- a/test.js +++ b/test.js @@ -58,8 +58,15 @@ describe('chalk', function () { assert.equal(chalk.red(0), '\u001b[31m0\u001b[39m'); }); - it('don\'t output escape codes if the input is empty', function () { + it('shouldn\'t output escape codes if the input is empty', function () { assert.equal(chalk.red(), ''); + assert.equal(chalk.red.blue.black(), ''); + }); + + it('should keep Function.prototype methods', function () { + assert.equal(chalk.grey.apply(null, ['foo']), '\u001b[90mfoo\u001b[39m'); + assert.equal(chalk.reset(chalk.red.bgGreen.underline.bind(null)('foo') + 'foo'), '\u001b[0m\u001b[31m\u001b[42m\u001b[4mfoo\u001b[24m\u001b[49m\u001b[39mfoo\u001b[0m'); + assert.equal(chalk.red.blue.black.call(null), ''); }); }); From 8417f175abe6811e74add2878f2e7f01530a067c Mon Sep 17 00:00:00 2001 From: Steve Mao Date: Sat, 9 Jan 2016 16:20:22 +0100 Subject: [PATCH 011/235] Close #95 PR: tweak defining proto. --- index.js | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/index.js b/index.js index d2ec92d..f2377a2 100644 --- a/index.js +++ b/index.js @@ -15,21 +15,17 @@ if (isSimpleWindowsTerm) { ansiStyles.blue.open = '\u001b[94m'; } -var styles = (function () { - var ret = {}; +var styles = {}; - Object.keys(ansiStyles).forEach(function (key) { - ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); +Object.keys(ansiStyles).forEach(function (key) { + ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); - ret[key] = { - get: function () { - return build.call(this, this._styles.concat(key)); - } - }; - }); - - return ret; -})(); + styles[key] = { + get: function () { + return build.call(this, this._styles ? this._styles.concat(key) : [key]); + } + }; +}); var proto = defineProps(function chalk() {}, styles); @@ -91,21 +87,7 @@ function applyStyle() { return str; } -function init() { - var ret = {}; - - Object.keys(styles).forEach(function (name) { - ret[name] = { - get: function () { - return build.call(this, [name]); - } - }; - }); - - return ret; -} - -defineProps(Chalk.prototype, init()); +defineProps(Chalk.prototype, styles); module.exports = new Chalk(); module.exports.styles = ansiStyles; From 51b8f329e896d049e8713376edef464cd7743988 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Mon, 11 Jan 2016 03:48:13 -0700 Subject: [PATCH 012/235] =?UTF-8?q?6700=20dependents!=20=F0=9F=94=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index c6f4433..088a53e 100644 --- a/readme.md +++ b/readme.md @@ -30,7 +30,7 @@ - Clean and focused - Auto-detects color support - Actively maintained -- [Used by ~5000 modules](https://www.npmjs.com/browse/depended/chalk) as of August 23, 2015 +- [Used by ~6700 modules](https://www.npmjs.com/browse/depended/chalk) as of January 11, 2016 ## Install From 139f8b68cccfa42269f92c33cdd0068251a5e854 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 15 Jan 2016 00:06:24 +0100 Subject: [PATCH 013/235] add Code of Conduct --- code-of-conduct.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++ contributing.md | 3 +++ 2 files changed, 53 insertions(+) create mode 100644 code-of-conduct.md create mode 100644 contributing.md diff --git a/code-of-conduct.md b/code-of-conduct.md new file mode 100644 index 0000000..be26cfd --- /dev/null +++ b/code-of-conduct.md @@ -0,0 +1,50 @@ +# Contributor Code of Conduct + +As contributors and maintainers of this project, and in the interest of +fostering an open and welcoming community, we pledge to respect all people who +contribute through reporting issues, posting feature requests, updating +documentation, submitting pull requests or patches, and other activities. + +We are committed to making participation in this project a harassment-free +experience for everyone, regardless of level of experience, gender, gender +identity and expression, sexual orientation, disability, personal appearance, +body size, race, ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery +* Personal attacks +* Trolling or insulting/derogatory comments +* Public or private harassment +* Publishing other's private information, such as physical or electronic + addresses, without explicit permission +* Other unethical or unprofessional conduct + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +By adopting this Code of Conduct, project maintainers commit themselves to +fairly and consistently applying these principles to every aspect of managing +this project. Project maintainers who do not follow or enforce the Code of +Conduct may be permanently removed from the project team. + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting a project maintainer at sindresorhus@gmail.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. Maintainers are +obligated to maintain confidentiality with regard to the reporter of an +incident. + + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 1.3.0, available at +[http://contributor-covenant.org/version/1/3/0/][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/3/0/ diff --git a/contributing.md b/contributing.md new file mode 100644 index 0000000..28bfd4b --- /dev/null +++ b/contributing.md @@ -0,0 +1,3 @@ +# Contributing to Chalk + +Please note that this project is released with a [Contributor Code of Conduct](code-of-conduct.md). By participating in this project you agree to abide by its terms. From 05f87e25e108726ee469aa56cc88fcc160a911ed Mon Sep 17 00:00:00 2001 From: Martin Heidegger Date: Sun, 17 Jan 2016 12:35:27 +0100 Subject: [PATCH 014/235] Close #92 PR: Closing before and reopening the style after a line break. --- index.js | 5 +++++ test.js | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/index.js b/index.js index f2377a2..b7e3b10 100644 --- a/index.js +++ b/index.js @@ -79,6 +79,11 @@ function applyStyle() { // otherwise only the part of the string until said closing code // will be colored, and the rest will simply be 'plain'. str = code.open + str.replace(code.closeRe, code.open) + code.close; + + // Close the coloring before a line break and reopening after next line + // To fix a bleed issue on macs + // see https://github.com/chalk/chalk/pull/92 + str = str.replace(/\n/gm, code.close + '\n' + code.open); } // Reset the original 'dim' if we changed it to work around the Windows dimmed gray issue. diff --git a/test.js b/test.js index d753917..9dddc2f 100644 --- a/test.js +++ b/test.js @@ -68,6 +68,10 @@ describe('chalk', function () { assert.equal(chalk.reset(chalk.red.bgGreen.underline.bind(null)('foo') + 'foo'), '\u001b[0m\u001b[31m\u001b[42m\u001b[4mfoo\u001b[24m\u001b[49m\u001b[39mfoo\u001b[0m'); assert.equal(chalk.red.blue.black.call(null), ''); }); + + it('line breaks should open and close colors', function () { + assert.equal(chalk.grey('hello\nworld'), '\u001b[90mhello\u001b[39m\n\u001b[90mworld\u001b[39m'); + }); }); describe('chalk on windows', function () { From 18c64ad7ba85bae41dd6226207fff8a329554826 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 17 Jan 2016 12:38:10 +0100 Subject: [PATCH 015/235] cleanup #92 --- index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index b7e3b10..c043357 100644 --- a/index.js +++ b/index.js @@ -80,10 +80,10 @@ function applyStyle() { // will be colored, and the rest will simply be 'plain'. str = code.open + str.replace(code.closeRe, code.open) + code.close; - // Close the coloring before a line break and reopening after next line - // To fix a bleed issue on macs - // see https://github.com/chalk/chalk/pull/92 - str = str.replace(/\n/gm, code.close + '\n' + code.open); + // Close the styling before a linebreak and reopen + // after next line to fix a bleed issue on OS X + // https://github.com/chalk/chalk/pull/92 + str = str.replace(/\r?\n/g, code.close + '$&' + code.open); } // Reset the original 'dim' if we changed it to work around the Windows dimmed gray issue. From 308f6b6a1eb4bb217fe873ee81a56237c1231b06 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 17 Jan 2016 12:44:51 +0100 Subject: [PATCH 016/235] minor tweaks --- .editorconfig | 3 --- .travis.yml | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.editorconfig b/.editorconfig index 8f9d77e..98a761d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,6 +10,3 @@ insert_final_newline = true [{package.json,*.yml}] indent_style = space indent_size = 2 - -[*.md] -trim_trailing_whitespace = false diff --git a/.travis.yml b/.travis.yml index 3da5271..4e2a815 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ sudo: false language: node_js node_js: - - 'iojs' + - '5' + - '4' - '0.12' - '0.10' after_success: npm run coveralls From 9001b3933afbba51ed4361f3d0edd719c0a1d2ab Mon Sep 17 00:00:00 2001 From: Joshua Boy Nicolai Appelman Date: Sun, 21 Feb 2016 13:10:57 +0100 Subject: [PATCH 017/235] Updates maintainer email. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 36f8204..27292a5 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "repository": "chalk/chalk", "maintainers": [ "Sindre Sorhus (sindresorhus.com)", - "Joshua Appelman (jbnicolai.com)", + "Joshua Boy Nicolai Appelman (jbna.nl)", "JD Ballard (github.com/qix-)" ], "engines": { From 426fc485bd5f038de52ecc8d170c9c9092ed77e2 Mon Sep 17 00:00:00 2001 From: Popey Gilbert Date: Tue, 15 Mar 2016 20:18:41 +0000 Subject: [PATCH 018/235] 7,700 Dependent Modules Yet another 1,000 modules in only two months. That's almost a project an hour now using Chalk! --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 088a53e..4ca519d 100644 --- a/readme.md +++ b/readme.md @@ -30,7 +30,7 @@ - Clean and focused - Auto-detects color support - Actively maintained -- [Used by ~6700 modules](https://www.npmjs.com/browse/depended/chalk) as of January 11, 2016 +- [Used by ~7700 modules](https://www.npmjs.com/browse/depended/chalk) as of March 15, 2016 ## Install From 2653218312383882256dd2b9217b74bfc4a5dd01 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 6 Apr 2016 23:05:21 +0700 Subject: [PATCH 019/235] meta tweaks --- package.json | 9 ++++----- readme.md | 11 ++++------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 27292a5..8baa69a 100644 --- a/package.json +++ b/package.json @@ -13,10 +13,9 @@ "node": ">=0.10.0" }, "scripts": { - "test": "xo && mocha", + "test": "xo && nyc mocha", "bench": "matcha benchmark.js", - "coverage": "nyc npm test && nyc report", - "coveralls": "nyc npm test && nyc report --reporter=text-lcov | coveralls" + "coveralls": "nyc report --reporter=text-lcov | coveralls" }, "files": [ "index.js" @@ -51,9 +50,9 @@ }, "devDependencies": { "coveralls": "^2.11.2", - "matcha": "^0.6.0", + "matcha": "^0.7.0", "mocha": "*", - "nyc": "^5.2.0", + "nyc": "^6.1.1", "require-uncached": "^1.0.2", "resolve-from": "^2.0.0", "semver": "^5.1.0", diff --git a/readme.md b/readme.md index 4ca519d..da9e86c 100644 --- a/readme.md +++ b/readme.md @@ -9,10 +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/chalk/chalk/badge.svg?branch=master)](https://coveralls.io/r/chalk/chalk?branch=master) -[![](https://img.shields.io/badge/unicorn-approved-ff69b4.svg)](https://www.youtube.com/watch?v=9auOCbH5Ns4) - +[![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) [![](https://img.shields.io/badge/unicorn-approved-ff69b4.svg)](https://www.youtube.com/watch?v=9auOCbH5Ns4) [colors.js](https://github.com/Marak/colors.js) used to be the most popular string styling module, but it has serious deficiencies like extending `String.prototype` which causes all kinds of [problems](https://github.com/yeoman/yo/issues/68). Although there are other ones, they either do too much or not enough. @@ -191,8 +188,8 @@ If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) i ## Related - [chalk-cli](https://github.com/chalk/chalk-cli) - CLI for this module -- [ansi-styles](https://github.com/chalk/ansi-styles/) - ANSI escape codes for styling strings in the terminal -- [supports-color](https://github.com/chalk/supports-color/) - Detect whether a terminal supports color +- [ansi-styles](https://github.com/chalk/ansi-styles) - ANSI escape codes for styling strings in the terminal +- [supports-color](https://github.com/chalk/supports-color) - Detect whether a terminal supports color - [strip-ansi](https://github.com/chalk/strip-ansi) - Strip ANSI escape codes - [has-ansi](https://github.com/chalk/has-ansi) - Check if a string has ANSI escape codes - [ansi-regex](https://github.com/chalk/ansi-regex) - Regular expression for matching ANSI escape codes @@ -202,4 +199,4 @@ If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) i ## License -MIT © [Sindre Sorhus](http://sindresorhus.com) +MIT © [Sindre Sorhus](https://sindresorhus.com) From fe2e4b093e446b2e7e037476919c113873aba394 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 2 May 2016 15:36:24 +0700 Subject: [PATCH 020/235] update code of conduct --- code-of-conduct.md | 80 ++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/code-of-conduct.md b/code-of-conduct.md index be26cfd..a7c7db8 100644 --- a/code-of-conduct.md +++ b/code-of-conduct.md @@ -1,24 +1,41 @@ -# Contributor Code of Conduct +# Contributor Covenant Code of Conduct -As contributors and maintainers of this project, and in the interest of -fostering an open and welcoming community, we pledge to respect all people who -contribute through reporting issues, posting feature requests, updating -documentation, submitting pull requests or patches, and other activities. +## Our Pledge -We are committed to making participation in this project a harassment-free -experience for everyone, regardless of level of experience, gender, gender -identity and expression, sexual orientation, disability, personal appearance, -body size, race, ethnicity, age, religion, or nationality. +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery -* Personal attacks -* Trolling or insulting/derogatory comments +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment -* Publishing other's private information, such as physical or electronic - addresses, without explicit permission -* Other unethical or unprofessional conduct +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions @@ -26,25 +43,32 @@ that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. -By adopting this Code of Conduct, project maintainers commit themselves to -fairly and consistently applying these principles to every aspect of managing -this project. Project maintainers who do not follow or enforce the Code of -Conduct may be permanently removed from the project team. +## Scope This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting a project maintainer at sindresorhus@gmail.com. All +reported by contacting the project team at sindresorhus@gmail.com. All complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. Maintainers are -obligated to maintain confidentiality with regard to the reporter of an -incident. +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 1.3.0, available at -[http://contributor-covenant.org/version/1/3/0/][version] +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/3/0/ +[version]: http://contributor-covenant.org/version/1/4/ From 6c3e57351bb8b3db20a400745b0ad249e66c3927 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 2 May 2016 15:36:40 +0700 Subject: [PATCH 021/235] test on Node.js 6 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4e2a815..ed76b65 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ sudo: false language: node_js node_js: - - '5' + - '6' - '4' - '0.12' - '0.10' From a125eb0e726f51a3ad6499831f6edcabcc5411db Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 14 Jun 2016 18:20:49 +0200 Subject: [PATCH 022/235] =?UTF-8?q?OS=20X=20=E2=86=92=20macOS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index c043357..19057f4 100644 --- a/index.js +++ b/index.js @@ -81,7 +81,7 @@ function applyStyle() { str = code.open + str.replace(code.closeRe, code.open) + code.close; // Close the styling before a linebreak and reopen - // after next line to fix a bleed issue on OS X + // after next line to fix a bleed issue on macOS // https://github.com/chalk/chalk/pull/92 str = str.replace(/\r?\n/g, code.close + '$&' + code.open); } From d939a3f9bc70b9f6d265934047e4a191078180b4 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 16 Jun 2016 14:36:05 +0200 Subject: [PATCH 023/235] fix XO lint issue --- index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/index.js b/index.js index 19057f4..e419174 100644 --- a/index.js +++ b/index.js @@ -2,6 +2,7 @@ var escapeStringRegexp = require('escape-string-regexp'); var ansiStyles = require('ansi-styles'); var supportsColor = require('supports-color'); + var defineProps = Object.defineProperties; var isSimpleWindowsTerm = process.platform === 'win32' && !/^xterm/i.test(process.env.TERM); From 74c087db82e56837a69aa3c2c636ed268b3c75a6 Mon Sep 17 00:00:00 2001 From: Sakthipriyan Vairamani Date: Wed, 27 Jul 2016 11:43:15 +0530 Subject: [PATCH 024/235] minor doc improvements (#120) * minor doc improvements * address review comments --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index da9e86c..8cb9166 100644 --- a/readme.md +++ b/readme.md @@ -32,7 +32,7 @@ ## Install -``` +```console $ npm install --save chalk ``` @@ -157,7 +157,7 @@ console.log(chalk.styles.red.open + 'Hello' + chalk.styles.red.close); - `red` - `green` - `yellow` -- `blue` *(on Windows the bright version is used as normal blue is illegible)* +- `blue` *(on Windows the bright version is used since normal blue is illegible)* - `magenta` - `cyan` - `white` From 835ca3d9503fa987725bde711b97ca4be2386221 Mon Sep 17 00:00:00 2001 From: Popey Gilbert Date: Wed, 3 Aug 2016 21:35:16 +0100 Subject: [PATCH 025/235] You've just reached 10,000 dependent modules. (#122) * You've just reached 10,000 dependent modules. * Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 8cb9166..f0fbf2e 100644 --- a/readme.md +++ b/readme.md @@ -27,7 +27,7 @@ - Clean and focused - Auto-detects color support - Actively maintained -- [Used by ~7700 modules](https://www.npmjs.com/browse/depended/chalk) as of March 15, 2016 +- [Used by ~10,000 modules](https://www.npmjs.com/browse/depended/chalk) as of August 2nd, 2016 ## Install From 7c02cf45f80d9c16c1d53496b28c4caeb382a36c Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Thu, 8 Sep 2016 03:12:05 -0700 Subject: [PATCH 026/235] Add log statement to chalk examples (#129) * Add log statement to chalk examples Added what are essentially `console.log()` calls to the chalk examples. Closes #128. * Update readme.md --- readme.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/readme.md b/readme.md index f0fbf2e..6e324be 100644 --- a/readme.md +++ b/readme.md @@ -47,36 +47,35 @@ 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. -Here without `console.log` for purity. - ```js const chalk = require('chalk'); +const log = console.log; // combine styled and normal strings -chalk.blue('Hello') + 'World' + chalk.red('!'); +log(chalk.blue('Hello') + 'World' + chalk.red('!')); // compose multiple styles using the chainable API -chalk.blue.bgRed.bold('Hello world!'); +log(chalk.blue.bgRed.bold('Hello world!')); // pass in multiple arguments -chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz'); +log(chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz')); // nest styles -chalk.red('Hello', chalk.underline.bgBlue('world') + '!'); +log(chalk.red('Hello', chalk.underline.bgBlue('world') + '!')); // nest styles of the same type even (color, underline, background) -chalk.green( +log(chalk.green( 'I am a green line ' + chalk.blue.underline.bold('with a blue substring') + ' that becomes green again!' -); +)); // ES2015 template literal -const systemStats = ` +log(` CPU: ${chalk.red('90%')} RAM: ${chalk.green('40%')} DISK: ${chalk.yellow('70%')} -`; +`); ``` Easily define your own themes. From 4ce73b632b8203227e8966a603f90f7fca7c53a8 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 14 Oct 2016 16:32:39 +0700 Subject: [PATCH 027/235] make XO happy --- index.js | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index e419174..00bd366 100644 --- a/index.js +++ b/index.js @@ -28,6 +28,7 @@ Object.keys(ansiStyles).forEach(function (key) { }; }); +// eslint-disable-next-line func-names var proto = defineProps(function chalk() {}, styles); function build(_styles) { diff --git a/package.json b/package.json index 8baa69a..70bac94 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "require-uncached": "^1.0.2", "resolve-from": "^2.0.0", "semver": "^5.1.0", - "xo": "*" + "xo": "^0.16.0" }, "xo": { "envs": [ From 492f11fb597094199c2e1926a73c64b94c759f06 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 26 Oct 2016 12:58:01 +0700 Subject: [PATCH 028/235] add example file --- example.js | 17 +++++++++++++++++ package.json | 3 +++ 2 files changed, 20 insertions(+) create mode 100644 example.js diff --git a/example.js b/example.js new file mode 100644 index 0000000..3b23690 --- /dev/null +++ b/example.js @@ -0,0 +1,17 @@ +'use strict'; +const chalk = require('./'); + +// generates screenshot +for (const key of Object.keys(chalk.styles)) { + let ret = key; + + if (key === 'reset' || key === 'hidden' || key === 'grey') { + continue; + } + + if (/^bg[^B]/.test(key)) { + ret = chalk.black(ret); + } + + process.stdout.write(chalk[key](ret) + ' '); +} diff --git a/package.json b/package.json index 70bac94..49b9ec5 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,9 @@ "envs": [ "node", "mocha" + ], + "ignores": [ + "example.js" ] } } From 5a6947614290da16f513780c56217e925cfab533 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 26 Oct 2016 20:13:45 +0700 Subject: [PATCH 029/235] add XO badge --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 6e324be..c80946b 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) [![](https://img.shields.io/badge/unicorn-approved-ff69b4.svg)](https://www.youtube.com/watch?v=9auOCbH5Ns4) +[![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) [![](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/sindresorhus/xo) [colors.js](https://github.com/Marak/colors.js) used to be the most popular string styling module, but it has serious deficiencies like extending `String.prototype` which causes all kinds of [problems](https://github.com/yeoman/yo/issues/68). Although there are other ones, they either do too much or not enough. From 0d2144904b9b5769076106aa67583273e160f801 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 30 Jan 2017 04:10:02 -0500 Subject: [PATCH 030/235] check parent builder object for enabled status (#142) --- index.js | 14 +++++++++++++- test.js | 22 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 00bd366..ab458f7 100644 --- a/index.js +++ b/index.js @@ -36,8 +36,20 @@ function build(_styles) { return applyStyle.apply(builder, arguments); }; + var self = this; + builder._styles = _styles; - builder.enabled = this.enabled; + + Object.defineProperty(builder, 'enabled', { + enumerable: true, + get: function () { + return self.enabled; + }, + set: function (v) { + self.enabled = v; + } + }); + // __proto__ is used because we must return a function, but there is // no way to create a function with a different prototype. /* eslint-disable no-proto */ diff --git a/test.js b/test.js index 9dddc2f..9805f95 100644 --- a/test.js +++ b/test.js @@ -138,6 +138,28 @@ describe('chalk.enabled', function () { assert.equal(chalk.red('foo'), 'foo'); chalk.enabled = true; }); + + it('should enable/disable colors based on overall chalk enabled property, not individual instances', function () { + chalk.enabled = true; + var red = chalk.red; + assert.equal(red.enabled, true); + chalk.enabled = false; + assert.equal(red.enabled, chalk.enabled); + chalk.enabled = true; + }); + + it('should propagate enable/disable changes from child colors', function () { + chalk.enabled = true; + var red = chalk.red; + assert.equal(red.enabled, true); + assert.equal(chalk.enabled, true); + red.enabled = false; + assert.equal(red.enabled, false); + assert.equal(chalk.enabled, false); + chalk.enabled = true; + assert.equal(red.enabled, true); + assert.equal(chalk.enabled, true); + }); }); describe('chalk.constructor', function () { From 9b60021fa605a6ebf62fbfd42d02c45597b10e6e Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 21 May 2017 23:28:38 +0700 Subject: [PATCH 031/235] Drop support for Node.js 0.10 and 0.12 --- .editorconfig | 2 +- .gitattributes | 1 + .travis.yml | 2 -- example.js | 4 ++-- package.json | 8 ++++---- test.js | 14 +++++++------- 6 files changed, 15 insertions(+), 16 deletions(-) diff --git a/.editorconfig b/.editorconfig index 98a761d..1c6314a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,6 +7,6 @@ charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -[{package.json,*.yml}] +[*.yml] indent_style = space indent_size = 2 diff --git a/.gitattributes b/.gitattributes index 176a458..391f0a4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ * text=auto +*.js text eol=lf diff --git a/.travis.yml b/.travis.yml index ed76b65..f3a8e90 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,4 @@ language: node_js node_js: - '6' - '4' - - '0.12' - - '0.10' after_success: npm run coveralls diff --git a/example.js b/example.js index 3b23690..e2bf751 100644 --- a/example.js +++ b/example.js @@ -1,7 +1,7 @@ 'use strict'; -const chalk = require('./'); +const chalk = require('.'); -// generates screenshot +// Generates screenshot for (const key of Object.keys(chalk.styles)) { let ret = key; diff --git a/package.json b/package.json index 49b9ec5..7008e0f 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "JD Ballard (github.com/qix-)" ], "engines": { - "node": ">=0.10.0" + "node": ">=4" }, "scripts": { "test": "xo && nyc mocha", @@ -50,11 +50,11 @@ }, "devDependencies": { "coveralls": "^2.11.2", + "import-fresh": "^2.0.0", "matcha": "^0.7.0", "mocha": "*", - "nyc": "^6.1.1", - "require-uncached": "^1.0.2", - "resolve-from": "^2.0.0", + "nyc": "^10.3.2", + "resolve-from": "^3.0.0", "semver": "^5.1.0", "xo": "^0.16.0" }, diff --git a/test.js b/test.js index 9805f95..b802684 100644 --- a/test.js +++ b/test.js @@ -1,9 +1,9 @@ 'use strict'; var assert = require('assert'); -var requireUncached = require('require-uncached'); +var importFresh = require('import-fresh'); var resolveFrom = require('resolve-from'); var semver = require('semver'); -var chalk = require('./'); +var chalk = require('.'); describe('chalk', function () { it('should style string', function () { @@ -103,31 +103,31 @@ describe('chalk on windows', function () { it('should replace blue foreground color in cmd.exe', function () { process.env.TERM = 'dumb'; - var chalkCtx = requireUncached('./'); + var chalkCtx = importFresh('.'); assert.equal(chalkCtx.blue('foo'), '\u001b[94mfoo\u001b[39m'); }); it('shouldn\'t replace blue foreground color in xterm based terminals', function () { process.env.TERM = 'xterm-256color'; - var chalkCtx = requireUncached('./'); + var chalkCtx = importFresh('.'); assert.equal(chalkCtx.blue('foo'), '\u001b[34mfoo\u001b[39m'); }); it('should not apply dimmed styling on gray strings, see https://github.com/chalk/chalk/issues/58', function () { process.env.TERM = 'dumb'; - var chalkCtx = requireUncached('./'); + var chalkCtx = importFresh('.'); assert.equal(chalkCtx.gray.dim('foo'), '\u001b[90mfoo\u001b[22m\u001b[39m'); }); it('should apply dimmed styling on xterm compatible terminals', function () { process.env.TERM = 'xterm'; - var chalkCtx = requireUncached('./'); + var chalkCtx = importFresh('.'); assert.equal(chalkCtx.gray.dim('foo'), '\u001b[90m\u001b[2mfoo\u001b[22m\u001b[39m'); }); it('should apply dimmed styling on strings of other colors', function () { process.env.TERM = 'dumb'; - var chalkCtx = requireUncached('./'); + var chalkCtx = importFresh('.'); assert.equal(chalkCtx.blue.dim('foo'), '\u001b[94m\u001b[2mfoo\u001b[22m\u001b[39m'); }); }); From dbae68d623270e86300b9e066bf960b42961b820 Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Wed, 31 May 2017 11:55:22 +0200 Subject: [PATCH 032/235] Update dependent package count in the readme (#154) --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index c80946b..3785043 100644 --- a/readme.md +++ b/readme.md @@ -27,7 +27,7 @@ - Clean and focused - Auto-detects color support - Actively maintained -- [Used by ~10,000 modules](https://www.npmjs.com/browse/depended/chalk) as of August 2nd, 2016 +- [Used by ~16,000 modules](https://www.npmjs.com/browse/depended/chalk) as of May 31st, 2017 ## Install From cb3f2308e17cd2878d2722db7762bdc725e9ff48 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Tue, 20 Jun 2017 10:02:09 -0700 Subject: [PATCH 033/235] Add RGB (256/Truecolor) support (#140) --- index.js | 68 +++++++++++++++++++++++++++++++++++++++++++--------- package.json | 4 ++-- readme.md | 59 +++++++++++++++++++++++++++++++++++++++++---- test.js | 60 ++++++++++++++++++++++++++++++++-------------- 4 files changed, 155 insertions(+), 36 deletions(-) diff --git a/index.js b/index.js index ab458f7..351253f 100644 --- a/index.js +++ b/index.js @@ -6,9 +6,14 @@ var supportsColor = require('supports-color'); var defineProps = Object.defineProperties; var isSimpleWindowsTerm = process.platform === 'win32' && !/^xterm/i.test(process.env.TERM); +// supportsColor.level -> ansiStyles.color[name] mapping +var levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; +// color-convert models to exclude from the Chalk API due to conflicts and such. +var skipModels = ['gray']; + function Chalk(options) { - // detect mode if not set manually - this.enabled = !options || options.enabled === undefined ? supportsColor : options.enabled; + // detect level if not set manually + this.level = !options || options.level === undefined ? supportsColor.level : options.level; } // use bright blue on Windows as the normal blue color is illegible @@ -23,7 +28,45 @@ Object.keys(ansiStyles).forEach(function (key) { styles[key] = { get: function () { - return build.call(this, this._styles ? this._styles.concat(key) : [key]); + var codes = ansiStyles[key]; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], key); + } + }; +}); + +ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); +Object.keys(ansiStyles.color.ansi).forEach(function (model) { + if (skipModels.indexOf(model) !== -1) { + return; + } + + styles[model] = { + get: function () { + var level = this.level; + return function () { + var open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments); + var codes = {open: open, close: ansiStyles.color.close, closeRe: ansiStyles.color.closeRe}; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], model); + }; + } + }; +}); + +ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); +Object.keys(ansiStyles.bgColor.ansi).forEach(function (model) { + if (skipModels.indexOf(model) !== -1) { + return; + } + + var bgModel = 'bg' + model.charAt(0).toUpperCase() + model.substring(1); + styles[bgModel] = { + get: function () { + var level = this.level; + return function () { + var open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments); + var codes = {open: open, close: ansiStyles.bgColor.close, closeRe: ansiStyles.bgColor.closeRe}; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], model); + }; } }; }); @@ -31,7 +74,7 @@ Object.keys(ansiStyles).forEach(function (key) { // eslint-disable-next-line func-names var proto = defineProps(function chalk() {}, styles); -function build(_styles) { +function build(_styles, key) { var builder = function () { return applyStyle.apply(builder, arguments); }; @@ -40,16 +83,19 @@ function build(_styles) { builder._styles = _styles; - Object.defineProperty(builder, 'enabled', { + Object.defineProperty(builder, 'level', { enumerable: true, get: function () { - return self.enabled; + return self.level; }, - set: function (v) { - self.enabled = v; + set: function (level) { + self.level = level; } }); + // see below for fix regarding invisible grey/dim combination on windows. + builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; + // __proto__ is used because we must return a function, but there is // no way to create a function with a different prototype. /* eslint-disable no-proto */ @@ -71,7 +117,7 @@ function applyStyle() { } } - if (!this.enabled || !str) { + if (!this.level || !str) { return str; } @@ -82,12 +128,12 @@ function applyStyle() { // see https://github.com/chalk/chalk/issues/58 // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop. var originalDim = ansiStyles.dim.open; - if (isSimpleWindowsTerm && (nestedStyles.indexOf('gray') !== -1 || nestedStyles.indexOf('grey') !== -1)) { + if (isSimpleWindowsTerm && this.hasGrey) { ansiStyles.dim.open = ''; } while (i--) { - var code = ansiStyles[nestedStyles[i]]; + var code = nestedStyles[i]; // Replace any instances already present with a re-opening code // otherwise only the part of the string until said closing code diff --git a/package.json b/package.json index 7008e0f..f8d2344 100644 --- a/package.json +++ b/package.json @@ -44,9 +44,9 @@ "text" ], "dependencies": { - "ansi-styles": "^2.1.0", + "ansi-styles": "^3.0.0", "escape-string-regexp": "^1.0.2", - "supports-color": "^3.1.2" + "supports-color": "^3.2.3" }, "devDependencies": { "coveralls": "^2.11.2", diff --git a/readme.md b/readme.md index 3785043..a6d5544 100644 --- a/readme.md +++ b/readme.md @@ -76,14 +76,23 @@ CPU: ${chalk.red('90%')} RAM: ${chalk.green('40%')} DISK: ${chalk.yellow('70%')} `); + +// 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!')); ``` Easily define your own themes. ```js const chalk = require('chalk'); + const error = chalk.bold.red; +const warning = chalk.keyword('orange'); + console.log(error('Error!')); +console.log(warning('Warning!')); ``` Take advantage of console.log [string substitution](http://nodejs.org/docs/latest/api/console.html#console_console_log_data). @@ -105,16 +114,23 @@ Chain [styles](#styles) and call the last one as a method with a string argument Multiple arguments will be separated by space. -### chalk.enabled +### chalk.level -Color support is automatically detected, but you can override it by setting the `enabled` property. You should however only do this in your own code as it applies globally to all chalk consumers. +Color support is automatically detected, but you can override it by setting the `level` property. You should however only do this in your own code as it applies globally to all chalk consumers. If you need to change this in a reusable module create a new instance: ```js -const ctx = new chalk.constructor({enabled: false}); +const ctx = new chalk.constructor({level: 0}); ``` +Levels are as follows: + +0. All colors disabled +1. Basic color support (16 colors) +2. 256 color support +3. RGB/Truecolor support (16 million colors) + ### chalk.supportsColor Detect whether the terminal [supports color](https://github.com/chalk/supports-color). Used internally and handled for you, but exposed for convenience. @@ -174,10 +190,42 @@ console.log(chalk.styles.red.open + 'Hello' + chalk.styles.red.close); - `bgWhite` -## 256-colors +## 256/16 million (Truecolor) color support -Chalk does not support anything other than the base eight colors, which guarantees it will work on all terminals and systems. Some terminals, specifically `xterm` compliant ones, will support the full range of 8-bit colors. For this the lower level [ansi-256-colors](https://github.com/jbnicolai/ansi-256-colors) package can be used. +Chalk supports 256 colors and, when manually specified, [Truecolor (16 million colors)](https://gist.github.com/XVilka/8346728) on all supported terminal emulators. +Colors are downsampled from 16 million RGB values to an ANSI color format that is supported by the terminal emulator (or by specifying {level: n} as a chalk option). For example, Chalk configured to run at level 1 (basic color support) will downsample an RGB value of #FF0000 (red) to 31 (ANSI escape for red). + +Some 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). + +- `chalk.bgHex('#DEADED').underline('Hello, world!')` +- `chalk.bgKeyword('orange')('Some orange text')` +- `chalk.bgRgb(15, 100, 204).inverse('Hello!')` + +As of this writing, these are the supported color models that are exposed in Chalk: + +- `rgb` - e.g. `chalk.rgb(255, 136, 0).bold('Orange!')` +- `hex` - e.g. `chalk.hex('#ff8800').bold('Orange!')` +- `keyword` (CSS keywords) - e.g. `chalk.keyword('orange').bold('Orange!')` +- `hsl` - e.g. `chalk.hsl(32, 100, 50).bold('Orange!')` +- `hsv` +- `hwb` +- `cmyk` +- `xyz` +- `lab` +- `lch` +- `ansi16` +- `ansi256` +- `hcg` +- `apple` (see [qix-/color-convert#30](https://github.com/Qix-/color-convert/issues/30)) + +For a complete list of color models, see [`color-convert`'s list of conversions](https://github.com/Qix-/color-convert/blob/master/conversions.js). ## Windows @@ -194,6 +242,7 @@ If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) i - [ansi-regex](https://github.com/chalk/ansi-regex) - Regular expression for matching ANSI escape codes - [wrap-ansi](https://github.com/chalk/wrap-ansi) - Wordwrap a string with ANSI escape codes - [slice-ansi](https://github.com/chalk/slice-ansi) - Slice a string with ANSI escape codes +- [color-convert](https://github.com/qix-/color-convert) - Converts colors between different models ## License diff --git a/test.js b/test.js index b802684..144efaf 100644 --- a/test.js +++ b/test.js @@ -72,6 +72,26 @@ describe('chalk', function () { it('line breaks should open and close colors', function () { assert.equal(chalk.grey('hello\nworld'), '\u001b[90mhello\u001b[39m\n\u001b[90mworld\u001b[39m'); }); + + it('should properly convert RGB to 16 colors on basic color terminals', function () { + assert.equal(new chalk.constructor({level: 1}).hex('#FF0000')('hello'), '\u001b[91mhello\u001b[39m'); + assert.equal(new chalk.constructor({level: 1}).bgHex('#FF0000')('hello'), '\u001b[101mhello\u001b[49m'); + }); + + it('should properly convert RGB to 256 colors on basic color terminals', function () { + assert.equal(new chalk.constructor({level: 2}).hex('#FF0000')('hello'), '\u001b[38;5;196mhello\u001b[39m'); + assert.equal(new chalk.constructor({level: 2}).bgHex('#FF0000')('hello'), '\u001b[48;5;196mhello\u001b[49m'); + }); + + it('should properly convert RGB to 256 colors on basic color terminals', function () { + assert.equal(new chalk.constructor({level: 3}).hex('#FF0000')('hello'), '\u001b[38;2;255;0;0mhello\u001b[39m'); + assert.equal(new chalk.constructor({level: 3}).bgHex('#FF0000')('hello'), '\u001b[48;2;255;0;0mhello\u001b[49m'); + }); + + it('should not emit RGB codes if level is 0', function () { + assert.equal(new chalk.constructor({level: 0}).hex('#FF0000')('hello'), 'hello'); + assert.equal(new chalk.constructor({level: 0}).bgHex('#FF0000')('hello'), 'hello'); + }); }); describe('chalk on windows', function () { @@ -132,39 +152,43 @@ describe('chalk on windows', function () { }); }); -describe('chalk.enabled', function () { +describe('chalk.level', function () { it('should not output colors when manually disabled', function () { - chalk.enabled = false; + var oldLevel = chalk.level; + chalk.level = 0; assert.equal(chalk.red('foo'), 'foo'); - chalk.enabled = true; + chalk.level = oldLevel; }); it('should enable/disable colors based on overall chalk enabled property, not individual instances', function () { - chalk.enabled = true; + var oldLevel = chalk.level; + chalk.level = 1; var red = chalk.red; - assert.equal(red.enabled, true); - chalk.enabled = false; - assert.equal(red.enabled, chalk.enabled); - chalk.enabled = true; + assert.equal(red.level, 1); + chalk.level = 0; + assert.equal(red.level, chalk.level); + chalk.level = oldLevel; }); it('should propagate enable/disable changes from child colors', function () { - chalk.enabled = true; + var oldLevel = chalk.level; + chalk.level = 1; var red = chalk.red; - assert.equal(red.enabled, true); - assert.equal(chalk.enabled, true); - red.enabled = false; - assert.equal(red.enabled, false); - assert.equal(chalk.enabled, false); - chalk.enabled = true; - assert.equal(red.enabled, true); - assert.equal(chalk.enabled, true); + assert.equal(red.level, 1); + assert.equal(chalk.level, 1); + red.level = 0; + assert.equal(red.level, 0); + assert.equal(chalk.level, 0); + chalk.level = 1; + assert.equal(red.level, 1); + assert.equal(chalk.level, 1); + chalk.level = oldLevel; }); }); describe('chalk.constructor', function () { it('should create a isolated context where colors can be disabled', function () { - var ctx = new chalk.constructor({enabled: false}); + var ctx = new chalk.constructor({level: 0}); assert.equal(ctx.red('foo'), 'foo'); assert.equal(chalk.red('foo'), '\u001b[31mfoo\u001b[39m'); }); From 249b9ac7e75077de5fc9d8063df35918745e8471 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 20 Jun 2017 19:18:21 +0200 Subject: [PATCH 034/235] ES2015ify the codebase --- .travis.yml | 2 +- benchmark.js | 14 ++--- index.js | 114 +++++++++++++++++---------------- license | 20 ++---- package.json | 127 +++++++++++++++++-------------------- readme.md | 9 ++- test.js | 174 +++++++++++++++++++++++++-------------------------- 7 files changed, 223 insertions(+), 237 deletions(-) diff --git a/.travis.yml b/.travis.yml index f3a8e90..ea5900d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ -sudo: false language: node_js node_js: + - '8' - '6' - '4' after_success: npm run coveralls diff --git a/benchmark.js b/benchmark.js index 5c26a87..af90c06 100644 --- a/benchmark.js +++ b/benchmark.js @@ -1,24 +1,24 @@ /* globals set bench */ 'use strict'; -var chalk = require('./'); +const chalk = require('.'); -suite('chalk', function () { +suite('chalk', () => { set('iterations', 100000); - bench('single style', function () { + bench('single style', () => { chalk.red('the fox jumps over the lazy dog'); }); - bench('several styles', function () { + bench('several styles', () => { chalk.blue.bgRed.bold('the fox jumps over the lazy dog'); }); - var cached = chalk.blue.bgRed.bold; - bench('cached styles', function () { + const cached = chalk.blue.bgRed.bold; + bench('cached styles', () => { cached('the fox jumps over the lazy dog'); }); - bench('nested styles', function () { + bench('nested styles', () => { chalk.red('the fox jumps', chalk.underline.bgBlue('over the lazy dog') + '!'); }); }); diff --git a/index.js b/index.js index 351253f..9abe28b 100644 --- a/index.js +++ b/index.js @@ -1,118 +1,124 @@ 'use strict'; -var escapeStringRegexp = require('escape-string-regexp'); -var ansiStyles = require('ansi-styles'); -var supportsColor = require('supports-color'); +const escapeStringRegexp = require('escape-string-regexp'); +const ansiStyles = require('ansi-styles'); +const supportsColor = require('supports-color'); -var defineProps = Object.defineProperties; -var isSimpleWindowsTerm = process.platform === 'win32' && !/^xterm/i.test(process.env.TERM); +const defineProps = Object.defineProperties; +const isSimpleWindowsTerm = process.platform === 'win32' && !process.env.TERM.toLowerCase().startsWith('xterm'); -// supportsColor.level -> ansiStyles.color[name] mapping -var levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; -// color-convert models to exclude from the Chalk API due to conflicts and such. -var skipModels = ['gray']; +// `supportsColor.level` → `ansiStyles.color[name]` mapping +const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; +// `color-convert` models to exclude from the Chalk API due to conflicts and such +const skipModels = ['gray']; function Chalk(options) { - // detect level if not set manually + // Detect level if not set manually this.level = !options || options.level === undefined ? supportsColor.level : options.level; } -// use bright blue on Windows as the normal blue color is illegible +// Use bright blue on Windows as the normal blue color is illegible if (isSimpleWindowsTerm) { - ansiStyles.blue.open = '\u001b[94m'; + ansiStyles.blue.open = '\u001B[94m'; } -var styles = {}; +const styles = Object.create(null); -Object.keys(ansiStyles).forEach(function (key) { +for (const key of Object.keys(ansiStyles)) { ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); styles[key] = { - get: function () { - var codes = ansiStyles[key]; + get() { + const codes = ansiStyles[key]; return build.call(this, this._styles ? this._styles.concat(codes) : [codes], key); } }; -}); +} ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); -Object.keys(ansiStyles.color.ansi).forEach(function (model) { +for (const model of Object.keys(ansiStyles.color.ansi)) { if (skipModels.indexOf(model) !== -1) { - return; + continue; } styles[model] = { - get: function () { - var level = this.level; + get() { + const level = this.level; return function () { - var open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments); - var codes = {open: open, close: ansiStyles.color.close, closeRe: ansiStyles.color.closeRe}; + const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments); + const codes = { + open, + close: ansiStyles.color.close, + closeRe: ansiStyles.color.closeRe + }; return build.call(this, this._styles ? this._styles.concat(codes) : [codes], model); }; } }; -}); +} ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); -Object.keys(ansiStyles.bgColor.ansi).forEach(function (model) { +for (const model of Object.keys(ansiStyles.bgColor.ansi)) { if (skipModels.indexOf(model) !== -1) { - return; + continue; } - var bgModel = 'bg' + model.charAt(0).toUpperCase() + model.substring(1); + const bgModel = 'bg' + model.charAt(0).toUpperCase() + model.slice(1); styles[bgModel] = { - get: function () { - var level = this.level; + get() { + const level = this.level; return function () { - var open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments); - var codes = {open: open, close: ansiStyles.bgColor.close, closeRe: ansiStyles.bgColor.closeRe}; + const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments); + const codes = { + open, + close: ansiStyles.bgColor.close, + closeRe: ansiStyles.bgColor.closeRe + }; return build.call(this, this._styles ? this._styles.concat(codes) : [codes], model); }; } }; -}); +} // eslint-disable-next-line func-names -var proto = defineProps(function chalk() {}, styles); +const proto = defineProps(() => {}, styles); function build(_styles, key) { - var builder = function () { + const builder = function () { return applyStyle.apply(builder, arguments); }; - var self = this; - builder._styles = _styles; + const self = this; Object.defineProperty(builder, 'level', { enumerable: true, - get: function () { + get() { return self.level; }, - set: function (level) { + set(level) { self.level = level; } }); - // see below for fix regarding invisible grey/dim combination on windows. + // See below for fix regarding invisible grey/dim combination on Windows builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; - // __proto__ is used because we must return a function, but there is + // `__proto__` is used because we must return a function, but there is // no way to create a function with a different prototype. - /* eslint-disable no-proto */ - builder.__proto__ = proto; + builder.__proto__ = proto; // eslint-disable-line no-proto return builder; } function applyStyle() { - // support varags, but simply cast to string in case there's only one arg - var args = arguments; - var argsLen = args.length; - var str = argsLen !== 0 && String(arguments[0]); + // Support varags, but simply cast to string in case there's only one arg + const args = arguments; + const argsLen = args.length; + let str = argsLen !== 0 && String(arguments[0]); if (argsLen > 1) { - // don't slice `arguments`, it prevents v8 optimizations - for (var a = 1; a < argsLen; a++) { + // Don't slice `arguments`, it prevents V8 optimizations + for (let a = 1; a < argsLen; a++) { str += ' ' + args[a]; } } @@ -121,19 +127,19 @@ function applyStyle() { return str; } - var nestedStyles = this._styles; - var i = nestedStyles.length; + const nestedStyles = this._styles; + let i = nestedStyles.length; // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, // see https://github.com/chalk/chalk/issues/58 // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop. - var originalDim = ansiStyles.dim.open; + const originalDim = ansiStyles.dim.open; if (isSimpleWindowsTerm && this.hasGrey) { ansiStyles.dim.open = ''; } while (i--) { - var code = nestedStyles[i]; + const code = nestedStyles[i]; // Replace any instances already present with a re-opening code // otherwise only the part of the string until said closing code @@ -143,10 +149,10 @@ function applyStyle() { // Close the styling before a linebreak and reopen // after next line to fix a bleed issue on macOS // https://github.com/chalk/chalk/pull/92 - str = str.replace(/\r?\n/g, code.close + '$&' + code.open); + str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`); } - // Reset the original 'dim' if we changed it to work around the Windows dimmed gray issue. + // Reset the original 'dim' if we changed it to work around the Windows dimmed gray issue ansiStyles.dim.open = originalDim; return str; diff --git a/license b/license index 654d0bf..e7af2f7 100644 --- a/license +++ b/license @@ -1,21 +1,9 @@ -The MIT License (MIT) +MIT License Copyright (c) Sindre Sorhus (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: +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: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/package.json b/package.json index f8d2344..ce879be 100644 --- a/package.json +++ b/package.json @@ -1,70 +1,61 @@ { - "name": "chalk", - "version": "1.1.1", - "description": "Terminal string styling done right. Much color.", - "license": "MIT", - "repository": "chalk/chalk", - "maintainers": [ - "Sindre Sorhus (sindresorhus.com)", - "Joshua Boy Nicolai Appelman (jbna.nl)", - "JD Ballard (github.com/qix-)" - ], - "engines": { - "node": ">=4" - }, - "scripts": { - "test": "xo && nyc mocha", - "bench": "matcha benchmark.js", - "coveralls": "nyc report --reporter=text-lcov | coveralls" - }, - "files": [ - "index.js" - ], - "keywords": [ - "color", - "colour", - "colors", - "terminal", - "console", - "cli", - "string", - "str", - "ansi", - "style", - "styles", - "tty", - "formatting", - "rgb", - "256", - "shell", - "xterm", - "log", - "logging", - "command-line", - "text" - ], - "dependencies": { - "ansi-styles": "^3.0.0", - "escape-string-regexp": "^1.0.2", - "supports-color": "^3.2.3" - }, - "devDependencies": { - "coveralls": "^2.11.2", - "import-fresh": "^2.0.0", - "matcha": "^0.7.0", - "mocha": "*", - "nyc": "^10.3.2", - "resolve-from": "^3.0.0", - "semver": "^5.1.0", - "xo": "^0.16.0" - }, - "xo": { - "envs": [ - "node", - "mocha" - ], - "ignores": [ - "example.js" - ] - } + "name": "chalk", + "version": "1.1.1", + "description": "Terminal string styling done right. Much color", + "license": "MIT", + "repository": "chalk/chalk", + "engines": { + "node": ">=4" + }, + "scripts": { + "test": "xo && nyc mocha", + "bench": "matcha benchmark.js", + "coveralls": "nyc report --reporter=text-lcov | coveralls" + }, + "files": [ + "index.js" + ], + "keywords": [ + "color", + "colour", + "colors", + "terminal", + "console", + "cli", + "string", + "str", + "ansi", + "style", + "styles", + "tty", + "formatting", + "rgb", + "256", + "shell", + "xterm", + "log", + "logging", + "command-line", + "text" + ], + "dependencies": { + "ansi-styles": "^3.0.0", + "escape-string-regexp": "^1.0.2", + "supports-color": "^3.2.3" + }, + "devDependencies": { + "coveralls": "^2.11.2", + "import-fresh": "^2.0.0", + "matcha": "^0.7.0", + "mocha": "*", + "nyc": "^11.0.2", + "resolve-from": "^3.0.0", + "xo": "*" + }, + "xo": { + "envs": [ + "node", + "mocha" + ] + } } diff --git a/readme.md b/readme.md index a6d5544..d06e842 100644 --- a/readme.md +++ b/readme.md @@ -227,6 +227,7 @@ As of this writing, these are the supported color models that are exposed in Cha For a complete list of color models, see [`color-convert`'s list of conversions](https://github.com/Qix-/color-convert/blob/master/conversions.js). + ## Windows If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) instead of `cmd.exe`. @@ -245,6 +246,12 @@ If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) i - [color-convert](https://github.com/qix-/color-convert) - Converts colors between different models +## Maintainers + +- [Sindre Sorhus](https://github.com/sindresorhus) +- [Josh Junon](https://github.com/qix-) + + ## License -MIT © [Sindre Sorhus](https://sindresorhus.com) +MIT diff --git a/test.js b/test.js index 144efaf..e4df628 100644 --- a/test.js +++ b/test.js @@ -1,179 +1,173 @@ 'use strict'; -var assert = require('assert'); -var importFresh = require('import-fresh'); -var resolveFrom = require('resolve-from'); -var semver = require('semver'); -var chalk = require('.'); +const assert = require('assert'); +const importFresh = require('import-fresh'); +const resolveFrom = require('resolve-from'); +const chalk = require('.'); -describe('chalk', function () { - it('should style string', function () { - assert.equal(chalk.underline('foo'), '\u001b[4mfoo\u001b[24m'); - assert.equal(chalk.red('foo'), '\u001b[31mfoo\u001b[39m'); - assert.equal(chalk.bgRed('foo'), '\u001b[41mfoo\u001b[49m'); +describe('chalk', () => { + it('should style string', () => { + assert.equal(chalk.underline('foo'), '\u001B[4mfoo\u001B[24m'); + assert.equal(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); + assert.equal(chalk.bgRed('foo'), '\u001B[41mfoo\u001B[49m'); }); - it('should support applying multiple styles at once', function () { - assert.equal(chalk.red.bgGreen.underline('foo'), '\u001b[31m\u001b[42m\u001b[4mfoo\u001b[24m\u001b[49m\u001b[39m'); - assert.equal(chalk.underline.red.bgGreen('foo'), '\u001b[4m\u001b[31m\u001b[42mfoo\u001b[49m\u001b[39m\u001b[24m'); + it('should support applying multiple styles at once', () => { + assert.equal(chalk.red.bgGreen.underline('foo'), '\u001B[31m\u001B[42m\u001B[4mfoo\u001B[24m\u001B[49m\u001B[39m'); + assert.equal(chalk.underline.red.bgGreen('foo'), '\u001B[4m\u001B[31m\u001B[42mfoo\u001B[49m\u001B[39m\u001B[24m'); }); - it('should support nesting styles', function () { + it('should support nesting styles', () => { assert.equal( chalk.red('foo' + chalk.underline.bgBlue('bar') + '!'), - '\u001b[31mfoo\u001b[4m\u001b[44mbar\u001b[49m\u001b[24m!\u001b[39m' + '\u001B[31mfoo\u001B[4m\u001B[44mbar\u001B[49m\u001B[24m!\u001B[39m' ); }); - it('should support nesting styles of the same type (color, underline, bg)', function () { + it('should support nesting styles of the same type (color, underline, bg)', () => { assert.equal( chalk.red('a' + chalk.yellow('b' + chalk.green('c') + 'b') + 'c'), - '\u001b[31ma\u001b[33mb\u001b[32mc\u001b[33mb\u001b[31mc\u001b[39m' + '\u001B[31ma\u001B[33mb\u001B[32mc\u001B[33mb\u001B[31mc\u001B[39m' ); }); - it('should reset all styles with `.reset()`', function () { - assert.equal(chalk.reset(chalk.red.bgGreen.underline('foo') + 'foo'), '\u001b[0m\u001b[31m\u001b[42m\u001b[4mfoo\u001b[24m\u001b[49m\u001b[39mfoo\u001b[0m'); + it('should reset all styles with `.reset()`', () => { + assert.equal(chalk.reset(chalk.red.bgGreen.underline('foo') + 'foo'), '\u001B[0m\u001B[31m\u001B[42m\u001B[4mfoo\u001B[24m\u001B[49m\u001B[39mfoo\u001B[0m'); }); - it('should be able to cache multiple styles', function () { - var red = chalk.red; - var green = chalk.green; - var redBold = red.bold; - var greenBold = green.bold; + it('should be able to cache multiple styles', () => { + const red = chalk.red; + const green = chalk.green; + const redBold = red.bold; + const greenBold = green.bold; assert.notEqual(red('foo'), green('foo')); assert.notEqual(redBold('bar'), greenBold('bar')); assert.notEqual(green('baz'), greenBold('baz')); }); - it('should alias gray to grey', function () { - assert.equal(chalk.grey('foo'), '\u001b[90mfoo\u001b[39m'); + it('should alias gray to grey', () => { + assert.equal(chalk.grey('foo'), '\u001B[90mfoo\u001B[39m'); }); - it('should support variable number of arguments', function () { - assert.equal(chalk.red('foo', 'bar'), '\u001b[31mfoo bar\u001b[39m'); + it('should support variable number of arguments', () => { + assert.equal(chalk.red('foo', 'bar'), '\u001B[31mfoo bar\u001B[39m'); }); - it('should support falsy values', function () { - assert.equal(chalk.red(0), '\u001b[31m0\u001b[39m'); + it('should support falsy values', () => { + assert.equal(chalk.red(0), '\u001B[31m0\u001B[39m'); }); - it('shouldn\'t output escape codes if the input is empty', function () { + it('shouldn\'t output escape codes if the input is empty', () => { assert.equal(chalk.red(), ''); assert.equal(chalk.red.blue.black(), ''); }); - it('should keep Function.prototype methods', function () { - assert.equal(chalk.grey.apply(null, ['foo']), '\u001b[90mfoo\u001b[39m'); - assert.equal(chalk.reset(chalk.red.bgGreen.underline.bind(null)('foo') + 'foo'), '\u001b[0m\u001b[31m\u001b[42m\u001b[4mfoo\u001b[24m\u001b[49m\u001b[39mfoo\u001b[0m'); + it('should keep Function.prototype methods', () => { + assert.equal(chalk.grey.apply(null, ['foo']), '\u001B[90mfoo\u001B[39m'); + assert.equal(chalk.reset(chalk.red.bgGreen.underline.bind(null)('foo') + 'foo'), '\u001B[0m\u001B[31m\u001B[42m\u001B[4mfoo\u001B[24m\u001B[49m\u001B[39mfoo\u001B[0m'); assert.equal(chalk.red.blue.black.call(null), ''); }); - it('line breaks should open and close colors', function () { - assert.equal(chalk.grey('hello\nworld'), '\u001b[90mhello\u001b[39m\n\u001b[90mworld\u001b[39m'); + it('line breaks should open and close colors', () => { + assert.equal(chalk.grey('hello\nworld'), '\u001B[90mhello\u001B[39m\n\u001B[90mworld\u001B[39m'); }); - it('should properly convert RGB to 16 colors on basic color terminals', function () { - assert.equal(new chalk.constructor({level: 1}).hex('#FF0000')('hello'), '\u001b[91mhello\u001b[39m'); - assert.equal(new chalk.constructor({level: 1}).bgHex('#FF0000')('hello'), '\u001b[101mhello\u001b[49m'); + it('should properly convert RGB to 16 colors on basic color terminals', () => { + assert.equal(new chalk.constructor({level: 1}).hex('#FF0000')('hello'), '\u001B[91mhello\u001B[39m'); + assert.equal(new chalk.constructor({level: 1}).bgHex('#FF0000')('hello'), '\u001B[101mhello\u001B[49m'); }); - it('should properly convert RGB to 256 colors on basic color terminals', function () { - assert.equal(new chalk.constructor({level: 2}).hex('#FF0000')('hello'), '\u001b[38;5;196mhello\u001b[39m'); - assert.equal(new chalk.constructor({level: 2}).bgHex('#FF0000')('hello'), '\u001b[48;5;196mhello\u001b[49m'); + it('should properly convert RGB to 256 colors on basic color terminals', () => { + assert.equal(new chalk.constructor({level: 2}).hex('#FF0000')('hello'), '\u001B[38;5;196mhello\u001B[39m'); + assert.equal(new chalk.constructor({level: 2}).bgHex('#FF0000')('hello'), '\u001B[48;5;196mhello\u001B[49m'); }); - it('should properly convert RGB to 256 colors on basic color terminals', function () { - assert.equal(new chalk.constructor({level: 3}).hex('#FF0000')('hello'), '\u001b[38;2;255;0;0mhello\u001b[39m'); - assert.equal(new chalk.constructor({level: 3}).bgHex('#FF0000')('hello'), '\u001b[48;2;255;0;0mhello\u001b[49m'); + it('should properly convert RGB to 256 colors on basic color terminals', () => { + assert.equal(new chalk.constructor({level: 3}).hex('#FF0000')('hello'), '\u001B[38;2;255;0;0mhello\u001B[39m'); + assert.equal(new chalk.constructor({level: 3}).bgHex('#FF0000')('hello'), '\u001B[48;2;255;0;0mhello\u001B[49m'); }); - it('should not emit RGB codes if level is 0', function () { + it('should not emit RGB codes if level is 0', () => { assert.equal(new chalk.constructor({level: 0}).hex('#FF0000')('hello'), 'hello'); assert.equal(new chalk.constructor({level: 0}).bgHex('#FF0000')('hello'), 'hello'); }); }); -describe('chalk on windows', function () { - var originalEnv; - var originalPlatform; +describe('chalk on windows', () => { + let originalEnv; + let originalPlatform; - // in node versions older than 0.12.x process.platform cannot be overridden - if (semver.lt(process.version, '0.12.0')) { - return; - } - - before(function () { + before(() => { originalEnv = process.env; originalPlatform = process.platform; }); - after(function () { + after(() => { process.env = originalEnv; Object.defineProperty(process, 'platform', {value: originalPlatform}); }); - beforeEach(function () { + beforeEach(() => { process.env = {}; Object.defineProperty(process, 'platform', {value: 'win32'}); - // since chalk internally modifies ansiStyles.blue.open, ansi-styles needs - // to be removed from the require cache for require-uncached to work + // Since chalk internally modifies `ansiStyles.blue.open`, `ansi-styles` needs + // to be removed from the require cache for `require-uncached` to work delete require.cache[resolveFrom(__dirname, 'ansi-styles')]; }); - it('should replace blue foreground color in cmd.exe', function () { + it('should replace blue foreground color in cmd.exe', () => { process.env.TERM = 'dumb'; - var chalkCtx = importFresh('.'); - assert.equal(chalkCtx.blue('foo'), '\u001b[94mfoo\u001b[39m'); + const chalkCtx = importFresh('.'); + assert.equal(chalkCtx.blue('foo'), '\u001B[94mfoo\u001B[39m'); }); - it('shouldn\'t replace blue foreground color in xterm based terminals', function () { + it('shouldn\'t replace blue foreground color in xterm based terminals', () => { process.env.TERM = 'xterm-256color'; - var chalkCtx = importFresh('.'); - assert.equal(chalkCtx.blue('foo'), '\u001b[34mfoo\u001b[39m'); + const chalkCtx = importFresh('.'); + assert.equal(chalkCtx.blue('foo'), '\u001B[34mfoo\u001B[39m'); }); - it('should not apply dimmed styling on gray strings, see https://github.com/chalk/chalk/issues/58', function () { + it('should not apply dimmed styling on gray strings, see https://github.com/chalk/chalk/issues/58', () => { process.env.TERM = 'dumb'; - var chalkCtx = importFresh('.'); - assert.equal(chalkCtx.gray.dim('foo'), '\u001b[90mfoo\u001b[22m\u001b[39m'); + const chalkCtx = importFresh('.'); + assert.equal(chalkCtx.gray.dim('foo'), '\u001B[90mfoo\u001B[22m\u001B[39m'); }); - it('should apply dimmed styling on xterm compatible terminals', function () { + it('should apply dimmed styling on xterm compatible terminals', () => { process.env.TERM = 'xterm'; - var chalkCtx = importFresh('.'); - assert.equal(chalkCtx.gray.dim('foo'), '\u001b[90m\u001b[2mfoo\u001b[22m\u001b[39m'); + const chalkCtx = importFresh('.'); + assert.equal(chalkCtx.gray.dim('foo'), '\u001B[90m\u001B[2mfoo\u001B[22m\u001B[39m'); }); - it('should apply dimmed styling on strings of other colors', function () { + it('should apply dimmed styling on strings of other colors', () => { process.env.TERM = 'dumb'; - var chalkCtx = importFresh('.'); - assert.equal(chalkCtx.blue.dim('foo'), '\u001b[94m\u001b[2mfoo\u001b[22m\u001b[39m'); + const chalkCtx = importFresh('.'); + assert.equal(chalkCtx.blue.dim('foo'), '\u001B[94m\u001B[2mfoo\u001B[22m\u001B[39m'); }); }); -describe('chalk.level', function () { - it('should not output colors when manually disabled', function () { - var oldLevel = chalk.level; +describe('chalk.level', () => { + it('should not output colors when manually disabled', () => { + const oldLevel = chalk.level; chalk.level = 0; assert.equal(chalk.red('foo'), 'foo'); chalk.level = oldLevel; }); - it('should enable/disable colors based on overall chalk enabled property, not individual instances', function () { - var oldLevel = chalk.level; + it('should enable/disable colors based on overall chalk enabled property, not individual instances', () => { + const oldLevel = chalk.level; chalk.level = 1; - var red = chalk.red; + const red = chalk.red; assert.equal(red.level, 1); chalk.level = 0; assert.equal(red.level, chalk.level); chalk.level = oldLevel; }); - it('should propagate enable/disable changes from child colors', function () { - var oldLevel = chalk.level; + it('should propagate enable/disable changes from child colors', () => { + const oldLevel = chalk.level; chalk.level = 1; - var red = chalk.red; + const red = chalk.red; assert.equal(red.level, 1); assert.equal(chalk.level, 1); red.level = 0; @@ -186,16 +180,16 @@ describe('chalk.level', function () { }); }); -describe('chalk.constructor', function () { - it('should create a isolated context where colors can be disabled', function () { - var ctx = new chalk.constructor({level: 0}); +describe('chalk.constructor', () => { + it('should create a isolated context where colors can be disabled', () => { + const ctx = new chalk.constructor({level: 0}); assert.equal(ctx.red('foo'), 'foo'); - assert.equal(chalk.red('foo'), '\u001b[31mfoo\u001b[39m'); + assert.equal(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); }); }); -describe('chalk.styles', function () { - it('should expose the styles as ANSI escape codes', function () { - assert.equal(chalk.styles.red.open, '\u001b[31m'); +describe('chalk.styles', () => { + it('should expose the styles as ANSI escape codes', () => { + assert.equal(chalk.styles.red.open, '\u001B[31m'); }); }); From 0412cdf07be9869fcb165d90f1949a805292d41b Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 20 Jun 2017 21:17:16 +0200 Subject: [PATCH 035/235] Minor code improvements --- index.js | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/index.js b/index.js index 9abe28b..50f0831 100644 --- a/index.js +++ b/index.js @@ -3,13 +3,13 @@ const escapeStringRegexp = require('escape-string-regexp'); const ansiStyles = require('ansi-styles'); const supportsColor = require('supports-color'); -const defineProps = Object.defineProperties; const isSimpleWindowsTerm = process.platform === 'win32' && !process.env.TERM.toLowerCase().startsWith('xterm'); // `supportsColor.level` → `ansiStyles.color[name]` mapping const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; + // `color-convert` models to exclude from the Chalk API due to conflicts and such -const skipModels = ['gray']; +const skipModels = new Set(['gray']); function Chalk(options) { // Detect level if not set manually @@ -36,7 +36,7 @@ for (const key of Object.keys(ansiStyles)) { ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); for (const model of Object.keys(ansiStyles.color.ansi)) { - if (skipModels.indexOf(model) !== -1) { + if (skipModels.has(model)) { continue; } @@ -58,11 +58,11 @@ for (const model of Object.keys(ansiStyles.color.ansi)) { ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); for (const model of Object.keys(ansiStyles.bgColor.ansi)) { - if (skipModels.indexOf(model) !== -1) { + if (skipModels.has(model)) { continue; } - const bgModel = 'bg' + model.charAt(0).toUpperCase() + model.slice(1); + const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); styles[bgModel] = { get() { const level = this.level; @@ -79,8 +79,7 @@ for (const model of Object.keys(ansiStyles.bgColor.ansi)) { }; } -// eslint-disable-next-line func-names -const proto = defineProps(() => {}, styles); +const proto = Object.defineProperties(() => {}, styles); function build(_styles, key) { const builder = function () { @@ -127,9 +126,6 @@ function applyStyle() { return str; } - const nestedStyles = this._styles; - let i = nestedStyles.length; - // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, // see https://github.com/chalk/chalk/issues/58 // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop. @@ -138,9 +134,7 @@ function applyStyle() { ansiStyles.dim.open = ''; } - while (i--) { - const code = nestedStyles[i]; - + for (const code of this._styles.slice().reverse()) { // Replace any instances already present with a re-opening code // otherwise only the part of the string until said closing code // will be colored, and the rest will simply be 'plain'. @@ -152,13 +146,13 @@ function applyStyle() { str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`); } - // Reset the original 'dim' if we changed it to work around the Windows dimmed gray issue + // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue ansiStyles.dim.open = originalDim; return str; } -defineProps(Chalk.prototype, styles); +Object.defineProperties(Chalk.prototype, styles); module.exports = new Chalk(); module.exports.styles = ansiStyles; From 870249689acc6b04e81e96d2c09c39b76c640a94 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 20 Jun 2017 21:37:29 +0200 Subject: [PATCH 036/235] Remove `chalk.styles` Very few consumers use this. Those who need it can just use the `ansi-styles` package directly. --- index.js | 1 - readme.md | 15 --------------- test.js | 6 ------ 3 files changed, 22 deletions(-) diff --git a/index.js b/index.js index 50f0831..48df977 100644 --- a/index.js +++ b/index.js @@ -155,5 +155,4 @@ function applyStyle() { Object.defineProperties(Chalk.prototype, styles); module.exports = new Chalk(); -module.exports.styles = ansiStyles; module.exports.supportsColor = supportsColor; diff --git a/readme.md b/readme.md index d06e842..5ef196d 100644 --- a/readme.md +++ b/readme.md @@ -137,21 +137,6 @@ Detect whether the terminal [supports color](https://github.com/chalk/supports-c Can be overridden by the user with the flags `--color` and `--no-color`. For situations where using `--color` is not possible, add an environment variable `FORCE_COLOR` with any value to force color. Trumps `--no-color`. -### chalk.styles - -Exposes the styles as [ANSI escape codes](https://github.com/chalk/ansi-styles). - -Generally not useful, but you might need just the `.open` or `.close` escape code if you're mixing externally styled strings with your own. - -```js -const chalk = require('chalk'); - -console.log(chalk.styles.red); -//=> {open: '\u001b[31m', close: '\u001b[39m'} - -console.log(chalk.styles.red.open + 'Hello' + chalk.styles.red.close); -``` - ## Styles diff --git a/test.js b/test.js index e4df628..074c1cd 100644 --- a/test.js +++ b/test.js @@ -187,9 +187,3 @@ describe('chalk.constructor', () => { assert.equal(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); }); }); - -describe('chalk.styles', () => { - it('should expose the styles as ANSI escape codes', () => { - assert.equal(chalk.styles.red.open, '\u001B[31m'); - }); -}); From 6f4d6b30fba5d207b45e3ee0aff318e08380f1cb Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 20 Jun 2017 21:38:49 +0200 Subject: [PATCH 037/235] Bump dependencies --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index ce879be..11ca559 100644 --- a/package.json +++ b/package.json @@ -39,9 +39,9 @@ "text" ], "dependencies": { - "ansi-styles": "^3.0.0", - "escape-string-regexp": "^1.0.2", - "supports-color": "^3.2.3" + "ansi-styles": "^3.1.0", + "escape-string-regexp": "^1.0.5", + "supports-color": "^4.0.0" }, "devDependencies": { "coveralls": "^2.11.2", From 1d73b211116d95bb4706b66523b59299952e83e5 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 20 Jun 2017 22:08:24 +0200 Subject: [PATCH 038/235] Improve readme --- readme.md | 91 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 40 deletions(-) diff --git a/readme.md b/readme.md index 5ef196d..6bb46e1 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,7 @@



- chalk + chalk


@@ -18,22 +18,23 @@ ![](https://github.com/chalk/ansi-styles/raw/master/screenshot.png) -## Why +## Highlights -- Highly performant -- Doesn't extend `String.prototype` - Expressive API +- Highly performant - Ability to nest styles -- Clean and focused +- [256/Truecolor color support](#256-and-truecolor-color-support) - Auto-detects color support +- Doesn't extend `String.prototype` +- Clean and focused - Actively maintained -- [Used by ~16,000 modules](https://www.npmjs.com/browse/depended/chalk) as of May 31st, 2017 +- [Used by ~17,000 packages](https://www.npmjs.com/browse/depended/chalk) as of June 20th, 2017 ## Install ```console -$ npm install --save chalk +$ npm install chalk ``` @@ -51,19 +52,19 @@ Chalk comes with an easy to use composable API where you just chain and nest the const chalk = require('chalk'); const log = console.log; -// combine styled and normal strings +// Combine styled and normal strings log(chalk.blue('Hello') + 'World' + chalk.red('!')); -// compose multiple styles using the chainable API +// Compose multiple styles using the chainable API log(chalk.blue.bgRed.bold('Hello world!')); -// pass in multiple arguments +// Pass in multiple arguments log(chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz')); -// nest styles +// Nest styles log(chalk.red('Hello', chalk.underline.bgBlue('world') + '!')); -// nest styles of the same type even (color, underline, background) +// Nest styles of the same type even (color, underline, background) log(chalk.green( 'I am a green line ' + chalk.blue.underline.bold('with a blue substring') + @@ -83,7 +84,7 @@ log(chalk.rgb(123, 45, 67).underline('Underlined reddish color')); log(chalk.hex('#DEADED').bold('Bold gray!')); ``` -Easily define your own themes. +Easily define your own themes: ```js const chalk = require('chalk'); @@ -95,7 +96,7 @@ console.log(error('Error!')); console.log(warning('Warning!')); ``` -Take advantage of console.log [string substitution](http://nodejs.org/docs/latest/api/console.html#console_console_log_data). +Take advantage of console.log [string substitution](https://nodejs.org/docs/latest/api/console.html#console_console_log_data_args): ```js const name = 'Sindre'; @@ -110,13 +111,13 @@ console.log(chalk.green('Hello %s'), name); Example: `chalk.red.bold.underline('Hello', 'world');` -Chain [styles](#styles) and 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`. +Chain [styles](#styles) and 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`. Multiple arguments will be separated by space. ### chalk.level -Color support is automatically detected, but you can override it by setting the `level` property. You should however only do this in your own code as it applies globally to all chalk consumers. +Color support is automatically detected, but you can override it by setting the `level` property. You should however only do this in your own code as it applies globally to all Chalk consumers. If you need to change this in a reusable module create a new instance: @@ -129,13 +130,15 @@ Levels are as follows: 0. All colors disabled 1. Basic color support (16 colors) 2. 256 color support -3. RGB/Truecolor support (16 million colors) +3. Truecolor support (16 million colors) ### chalk.supportsColor Detect whether the terminal [supports color](https://github.com/chalk/supports-color). Used internally and handled for you, but exposed for convenience. -Can be overridden by the user with the flags `--color` and `--no-color`. For situations where using `--color` is not possible, add an environment variable `FORCE_COLOR` with any value to force color. Trumps `--no-color`. +Can be overridden by the user with the flags `--color` and `--no-color`. For situations where using `--color` is not possible, add the environment variable `FORCE_COLOR=1` to forcefully enable color or `FORCE_COLOR=0` to forcefully disable. The use of `FORCE_COLOR` overrides all other color support checks. + +Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color=16m` flags, respectively. ## Styles @@ -145,11 +148,11 @@ Can be overridden by the user with the flags `--color` and `--no-color`. For sit - `reset` - `bold` - `dim` -- `italic` *(not widely supported)* +- `italic` *(Not widely supported)* - `underline` - `inverse` - `hidden` -- `strikethrough` *(not widely supported)* +- `strikethrough` *(Not widely supported)* ### Colors @@ -157,11 +160,19 @@ Can be overridden by the user with the flags `--color` and `--no-color`. For sit - `red` - `green` - `yellow` -- `blue` *(on Windows the bright version is used since normal blue is illegible)* +- `blue` *(On Windows the bright version is used since normal blue is illegible)* - `magenta` - `cyan` - `white` - `gray` +- `blackBright` +- `redBright` +- `greenBright` +- `yellowBright` +- `blueBright` +- `magentaBright` +- `cyanBright` +- `whiteBright` ### Background colors @@ -173,15 +184,23 @@ Can be overridden by the user with the flags `--color` and `--no-color`. For sit - `bgMagenta` - `bgCyan` - `bgWhite` +- `bgBlackBright` +- `bgRedBright` +- `bgGreenBright` +- `bgYellowBright` +- `bgBlueBright` +- `bgMagentaBright` +- `bgCyanBright` +- `bgWhiteBright` -## 256/16 million (Truecolor) color support +## 256 and Truecolor color support -Chalk supports 256 colors and, when manually specified, [Truecolor (16 million colors)](https://gist.github.com/XVilka/8346728) on all supported terminal emulators. +Chalk supports 256 colors and [Truecolor](https://gist.github.com/XVilka/8346728) (16 million colors) on supported terminal apps. -Colors are downsampled from 16 million RGB values to an ANSI color format that is supported by the terminal emulator (or by specifying {level: n} as a chalk option). For example, Chalk configured to run at level 1 (basic color support) will downsample an RGB value of #FF0000 (red) to 31 (ANSI escape for red). +Colors are downsampled from 16 million RGB values to an ANSI color format that is supported by the terminal emulator (or by specifying `{level: n}` as a Chalk option). For example, Chalk configured to run at level 1 (basic color support) will downsample an RGB value of #FF0000 (red) to 31 (ANSI escape for red). -Some examples: +Examples: - `chalk.hex('#DEADED').underline('Hello, world!')` - `chalk.keyword('orange')('Some orange text')` @@ -193,24 +212,16 @@ Background versions of these models are prefixed with `bg` and the first level o - `chalk.bgKeyword('orange')('Some orange text')` - `chalk.bgRgb(15, 100, 204).inverse('Hello!')` -As of this writing, these are the supported color models that are exposed in Chalk: +The following color models can be used: -- `rgb` - e.g. `chalk.rgb(255, 136, 0).bold('Orange!')` -- `hex` - e.g. `chalk.hex('#ff8800').bold('Orange!')` -- `keyword` (CSS keywords) - e.g. `chalk.keyword('orange').bold('Orange!')` -- `hsl` - e.g. `chalk.hsl(32, 100, 50).bold('Orange!')` -- `hsv` -- `hwb` -- `cmyk` -- `xyz` -- `lab` -- `lch` +- [`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.hsl(32, 1, 1).bold('Orange!')` +- [`hwb`](https://en.wikipedia.org/wiki/HWB_color_model) - Example: `chalk.hsl(32, 0, 50).bold('Orange!')` - `ansi16` - `ansi256` -- `hcg` -- `apple` (see [qix-/color-convert#30](https://github.com/Qix-/color-convert/issues/30)) - -For a complete list of color models, see [`color-convert`'s list of conversions](https://github.com/Qix-/color-convert/blob/master/conversions.js). ## Windows From 54975fb20d54eba20d7c4053fc6be8c475c26852 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Wed, 28 Jun 2017 23:42:38 -0700 Subject: [PATCH 039/235] TEMPORARY: emergency travis CI fix (see comments) --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index ea5900d..d4543b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,3 +4,8 @@ node_js: - '6' - '4' after_success: npm run coveralls + +# TODO temporary fix - please see links below +# https://blog.travis-ci.com/2017-06-21-trusty-updates-2017-Q2-launch +# https://github.com/travis-ci/travis-ci/issues/7991 +group: deprecated-2017Q2 From 523b998e64cbf1398d6a34138be23f53651597c1 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Thu, 29 Jun 2017 00:01:19 -0700 Subject: [PATCH 040/235] Revert "TEMPORARY: emergency travis CI fix (see comments)" This reverts commit 54975fb20d54eba20d7c4053fc6be8c475c26852. --- .travis.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index d4543b6..ea5900d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,3 @@ node_js: - '6' - '4' after_success: npm run coveralls - -# TODO temporary fix - please see links below -# https://blog.travis-ci.com/2017-06-21-trusty-updates-2017-Q2-launch -# https://github.com/travis-ci/travis-ci/issues/7991 -group: deprecated-2017Q2 From 18f2e7c122690070ea148fbbe846e839fa6a8962 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Wed, 28 Jun 2017 23:53:09 -0700 Subject: [PATCH 041/235] add host information output --- test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test.js b/test.js index 074c1cd..611a22e 100644 --- a/test.js +++ b/test.js @@ -4,6 +4,10 @@ const importFresh = require('import-fresh'); const resolveFrom = require('resolve-from'); const chalk = require('.'); +console.log('host TERM=', process.env.TERM || '[none]'); +console.log('host platform=', process.platform || '[unknown]'); +console.log('host support=', chalk.supportsColor); + describe('chalk', () => { it('should style string', () => { assert.equal(chalk.underline('foo'), '\u001B[4mfoo\u001B[24m'); From 608242a4fc05bf187d4bfb33052e94e011d4b30e Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Wed, 28 Jun 2017 23:58:47 -0700 Subject: [PATCH 042/235] spoof supports-color --- test.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test.js b/test.js index 611a22e..0fa6dd6 100644 --- a/test.js +++ b/test.js @@ -2,11 +2,21 @@ const assert = require('assert'); const importFresh = require('import-fresh'); const resolveFrom = require('resolve-from'); + +// Spoof supports-color +require.cache[resolveFrom(__dirname, 'supports-color')] = { + exports: { + level: 3, + hasBasic: true, + has256: true, + has16m: true + } +}; + const chalk = require('.'); console.log('host TERM=', process.env.TERM || '[none]'); console.log('host platform=', process.platform || '[unknown]'); -console.log('host support=', chalk.supportsColor); describe('chalk', () => { it('should style string', () => { From 09fb2d86060e6c46e57a696c5bf682be0245b47b Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Thu, 29 Jun 2017 13:34:00 -0700 Subject: [PATCH 043/235] Re-implement `chalk.enabled` (#160) --- index.js | 16 ++++++++++++++-- readme.md | 14 +++++++++++++- test.js | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index 48df977..2f6c71e 100644 --- a/index.js +++ b/index.js @@ -13,7 +13,8 @@ const skipModels = new Set(['gray']); function Chalk(options) { // Detect level if not set manually - this.level = !options || options.level === undefined ? supportsColor.level : options.level; + this.level = Number(!options || options.level === undefined ? supportsColor.level : options.level); + this.enabled = options && 'enabled' in options ? options.enabled : this.level > 0; } // Use bright blue on Windows as the normal blue color is illegible @@ -89,6 +90,7 @@ function build(_styles, key) { builder._styles = _styles; const self = this; + Object.defineProperty(builder, 'level', { enumerable: true, get() { @@ -99,6 +101,16 @@ function build(_styles, key) { } }); + Object.defineProperty(builder, 'enabled', { + enumerable: true, + get() { + return self.enabled; + }, + set(enabled) { + self.enabled = enabled; + } + }); + // See below for fix regarding invisible grey/dim combination on Windows builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; @@ -122,7 +134,7 @@ function applyStyle() { } } - if (!this.level || !str) { + if (!this.enabled || this.level <= 0 || !str) { return str; } diff --git a/readme.md b/readme.md index 6bb46e1..5ef6ed4 100644 --- a/readme.md +++ b/readme.md @@ -115,11 +115,23 @@ Chain [styles](#styles) and call the last one as a method with a string argument Multiple arguments will be separated by space. +### chalk.enabled + +Color support is automatically detected, as is the level (see `chalk.level`). However, if you'd like to simply enable/disable Chalk, you can do so via the `.enabled` property. + +Chalk is enabled by default unless expicitly disabled via the constructor or `chalk.level` is `0`. + +If you need to change this in a reusable module, create a new instance: + +```js +const ctx = new chalk.constructor({enabled: false}); +``` + ### chalk.level Color support is automatically detected, but you can override it by setting the `level` property. You should however only do this in your own code as it applies globally to all Chalk consumers. -If you need to change this in a reusable module create a new instance: +If you need to change this in a reusable module, create a new instance: ```js const ctx = new chalk.constructor({level: 0}); diff --git a/test.js b/test.js index 0fa6dd6..4c36a88 100644 --- a/test.js +++ b/test.js @@ -194,10 +194,51 @@ describe('chalk.level', () => { }); }); -describe('chalk.constructor', () => { - it('should create a isolated context where colors can be disabled', () => { - const ctx = new chalk.constructor({level: 0}); - assert.equal(ctx.red('foo'), 'foo'); - assert.equal(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); +describe('chalk.enabled', () => { + it('should not output colors when manually disabled', () => { + chalk.enabled = false; + assert.equal(chalk.red('foo'), 'foo'); + chalk.enabled = true; + }); + + it('should enable/disable colors based on overall chalk enabled property, not individual instances', () => { + chalk.enabled = false; + const red = chalk.red; + assert.equal(red.enabled, false); + chalk.enabled = true; + assert.equal(red.enabled, true); + chalk.enabled = true; + }); + + it('should propagate enable/disable changes from child colors', () => { + chalk.enabled = false; + const red = chalk.red; + assert.equal(red.enabled, false); + assert.equal(chalk.enabled, false); + red.enabled = true; + assert.equal(red.enabled, true); + assert.equal(chalk.enabled, true); + chalk.enabled = false; + assert.equal(red.enabled, false); + assert.equal(chalk.enabled, false); + chalk.enabled = true; + }); +}); + +describe('chalk.constructor', () => { + it('should create an isolated context where colors can be disabled (by level)', () => { + const ctx = new chalk.constructor({level: 0, enabled: true}); + assert.equal(ctx.red('foo'), 'foo'); + assert.equal(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); + ctx.level = 2; + assert.equal(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); + }); + + it('should create an isolated context where colors can be disabled (by enabled flag)', () => { + const ctx = new chalk.constructor({enabled: false}); + assert.equal(ctx.red('foo'), 'foo'); + assert.equal(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); + ctx.enabled = true; + assert.equal(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); }); }); From c0155688cf57edb6bee5b97dcc3548f47454e645 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Thu, 29 Jun 2017 16:00:51 -0700 Subject: [PATCH 044/235] add rainbow example --- examples/rainbow.js | 39 ++++++++++++++++++++++++++++ example.js => examples/screenshot.js | 5 ++-- 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 examples/rainbow.js rename example.js => examples/screenshot.js (68%) diff --git a/examples/rainbow.js b/examples/rainbow.js new file mode 100644 index 0000000..c4ed456 --- /dev/null +++ b/examples/rainbow.js @@ -0,0 +1,39 @@ +const chalk = require('..'); + +const ignoreChars = /[^!-~]/; + +function rainbow(str, offset) { + if (!str || str.length === 0) { + return str; + } + + const hueStep = 360 / str.replace(ignoreChars, '').length; + + let hue = offset % 360; + const chars = []; + for (const c of str) { + if (c.match(ignoreChars)) { + chars.push(c); + } else { + chars.push(chalk.hsl(hue, 100, 50)(c)); + hue = (hue + hueStep) % 360; + } + } + + return chars.join(''); +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +async function animateString(str) { + console.log(); + for (let i = 0; i < 360*5; i++) { + console.log('\x1b[1F\x1b[G ', rainbow(str, i)); + await sleep(2); + } +} + +console.log(); +animateString('We hope you enjoy the new version of Chalk 2! <3').then(() => console.log()); diff --git a/example.js b/examples/screenshot.js similarity index 68% rename from example.js rename to examples/screenshot.js index e2bf751..7d195a6 100644 --- a/example.js +++ b/examples/screenshot.js @@ -1,8 +1,9 @@ 'use strict'; -const chalk = require('.'); +const chalk = require('..'); +const styles = require('ansi-styles'); // Generates screenshot -for (const key of Object.keys(chalk.styles)) { +for (const key of Object.keys(styles)) { let ret = key; if (key === 'reset' || key === 'hidden' || key === 'grey') { From 23ef1c7ca2f64f905f0c17edc1b78ebf9def82cd Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Thu, 29 Jun 2017 16:05:28 -0700 Subject: [PATCH 045/235] fix linter errors --- examples/rainbow.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rainbow.js b/examples/rainbow.js index c4ed456..3da1e11 100644 --- a/examples/rainbow.js +++ b/examples/rainbow.js @@ -29,9 +29,9 @@ function sleep(ms) { async function animateString(str) { console.log(); - for (let i = 0; i < 360*5; i++) { + for (let i = 0; i < 360 * 5; i++) { console.log('\x1b[1F\x1b[G ', rainbow(str, i)); - await sleep(2); + await sleep(50); // eslint-disable-line no-await-in-loop } } From f66271e01a901470a3d5afcb3feae552848ccf0c Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Thu, 29 Jun 2017 16:46:19 -0700 Subject: [PATCH 046/235] Add tagged template literal (#163) --- index.js | 56 +++++++++++++++-- package.json | 3 +- readme.md | 37 +++++++++++ templates.js | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++ test.js | 95 ++++++++++++++++++++++++++++ 5 files changed, 359 insertions(+), 7 deletions(-) create mode 100644 templates.js diff --git a/index.js b/index.js index 2f6c71e..e6e0d6e 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,8 @@ const escapeStringRegexp = require('escape-string-regexp'); const ansiStyles = require('ansi-styles'); const supportsColor = require('supports-color'); +const template = require('./templates.js'); + const isSimpleWindowsTerm = process.platform === 'win32' && !process.env.TERM.toLowerCase().startsWith('xterm'); // `supportsColor.level` → `ansiStyles.color[name]` mapping @@ -11,10 +13,37 @@ const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; // `color-convert` models to exclude from the Chalk API due to conflicts and such const skipModels = new Set(['gray']); -function Chalk(options) { +const styles = Object.create(null); + +function applyOptions(obj, options) { + options = options || {}; + // Detect level if not set manually - this.level = Number(!options || options.level === undefined ? supportsColor.level : options.level); - this.enabled = options && 'enabled' in options ? options.enabled : this.level > 0; + obj.level = options.level === undefined ? supportsColor.level : options.level; + obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; +} + +function Chalk(options) { + // We check for this.template here since calling chalk.constructor() + // by itself will have a `this` of a previously constructed chalk object. + if (!this || !(this instanceof Chalk) || this.template) { + const chalk = {}; + applyOptions(chalk, options); + + chalk.template = function () { + const args = [].slice.call(arguments); + return chalkTag.apply(null, [chalk.template].concat(args)); + }; + + Object.setPrototypeOf(chalk, Chalk.prototype); + Object.setPrototypeOf(chalk.template, chalk); + + chalk.template.constructor = Chalk; + + return chalk.template; + } + + applyOptions(this, options); } // Use bright blue on Windows as the normal blue color is illegible @@ -22,8 +51,6 @@ if (isSimpleWindowsTerm) { ansiStyles.blue.open = '\u001B[94m'; } -const styles = Object.create(null); - for (const key of Object.keys(ansiStyles)) { ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); @@ -164,7 +191,24 @@ function applyStyle() { return str; } +function chalkTag(chalk, strings) { + const args = [].slice.call(arguments, 2); + + if (!Array.isArray(strings)) { + return strings.toString(); + } + + const parts = [strings.raw[0]]; + + for (let i = 1; i < strings.length; i++) { + parts.push(args[i - 1].toString().replace(/[{}]/g, '\\$&')); + parts.push(strings.raw[i]); + } + + return template(chalk, parts.join('')); +} + Object.defineProperties(Chalk.prototype, styles); -module.exports = new Chalk(); +module.exports = Chalk(); // eslint-disable-line new-cap module.exports.supportsColor = supportsColor; diff --git a/package.json b/package.json index 11ca559..a040744 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "coveralls": "nyc report --reporter=text-lcov | coveralls" }, "files": [ - "index.js" + "index.js", + "templates.js" ], "keywords": [ "color", diff --git a/readme.md b/readme.md index 5ef6ed4..18590bd 100644 --- a/readme.md +++ b/readme.md @@ -78,6 +78,13 @@ RAM: ${chalk.green('40%')} DISK: ${chalk.yellow('70%')} `); +// ES2015 tagged template literal +log(chalk` +CPU: {red ${cpu.totalPercent}%} +RAM: {green ${ram.used / ram.total * 100}%} +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')); @@ -206,6 +213,36 @@ Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color= - `bgWhiteBright` +## Tagged template literal + +Chalk can be used as a [tagged template literal](http://exploringjs.com/es6/ch_template-literals.html#_tagged-template-literals). + +```js +const chalk = require('chalk'); + +const miles = 18; +const calculateFeet = miles => miles * 5280; + +console.log(chalk` + There are {bold 5280 feet} in a mile. + In {bold ${miles} miles}, there are {green.bold ${calculateFeet(miles)} feet}. +`); +``` + +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: + +```js +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. + +All interpolated values (`` chalk`${foo}` ``) are converted to strings via the `.toString()` method. All curly braces (`{` and `}`) in interpolated value strings are escaped. + + ## 256 and Truecolor color support Chalk supports 256 colors and [Truecolor](https://gist.github.com/XVilka/8346728) (16 million colors) on supported terminal apps. diff --git a/templates.js b/templates.js new file mode 100644 index 0000000..afc6696 --- /dev/null +++ b/templates.js @@ -0,0 +1,175 @@ +'use strict'; + +function data(parent) { + return { + styles: [], + parent, + contents: [] + }; +} + +const zeroBound = n => n < 0 ? 0 : n; +const lastIndex = a => zeroBound(a.length - 1); + +const last = a => a[lastIndex(a)]; + +const takeWhileReverse = (array, predicate, start) => { + const out = []; + + for (let i = start; i >= 0 && i <= start; i--) { + if (predicate(array[i])) { + out.unshift(array[i]); + } else { + break; + } + } + + return out; +}; + +/** + * Checks if the character at position i in string is a normal character a.k.a a non control character. + * */ +const isNormalCharacter = (string, i) => { + const char = string[i]; + const backslash = '\\'; + + if (!(char === backslash || char === '{' || char === '}')) { + return true; + } + + const n = i === 0 ? 0 : takeWhileReverse(string, x => x === '\\', zeroBound(i - 1)).length; + + return n % 2 === 1; +}; + +const collectStyles = data => data ? collectStyles(data.parent).concat(data.styles) : ['reset']; + +/** + * Computes the style for a given data based on it's style and the style of it's parent. Also accounts for !style styles + * which remove a style from the list if present. + * */ +const sumStyles = data => { + const negateRegex = /^~.+/; + let out = []; + + for (const style of collectStyles(data)) { + if (negateRegex.test(style)) { + const exclude = style.slice(1); + out = out.filter(x => x !== exclude); + } else { + out.push(style); + } + } + + return out; +}; + +/** + * Takes a string and parses it into a tree of data objects which inherit styles from their parent. + * */ +function parse(string) { + const root = data(null); + let pushingStyle = false; + + let current = root; + + for (let i = 0; i < string.length; i++) { + const char = string[i]; + + const addNormalCharacter = () => { + const lastChunk = last(current.contents); + + if (typeof lastChunk === 'string') { + current.contents[lastIndex(current.contents)] = lastChunk + char; + } else { + current.contents.push(char); + } + }; + + if (pushingStyle) { + if (' \t'.indexOf(char) > -1) { + pushingStyle = false; + } else if (char === '\n') { + pushingStyle = false; + addNormalCharacter(); + } else if (char === '.') { + current.styles.push(''); + } else { + current.styles[lastIndex(current.styles)] = (last(current.styles) || '') + char; + } + } else if (isNormalCharacter(string, i)) { + addNormalCharacter(); + } else if (char === '{') { + pushingStyle = true; + const nCurrent = data(current); + current.contents.push(nCurrent); + current = nCurrent; + } else if (char === '}') { + current = current.parent; + } + } + + if (current !== root) { + throw new Error('literal template has an unclosed block'); + } + + return root; +} + +/** + * Takes a tree of data objects and flattens it to a list of data objects with the inherited and negations styles + * accounted for. + * */ +function flatten(data) { + let flat = []; + + for (const content of data.contents) { + if (typeof content === 'string') { + flat.push({ + styles: sumStyles(data), + content + }); + } else { + flat = flat.concat(flatten(content)); + } + } + + return flat; +} + +function assertStyle(chalk, style) { + if (!chalk[style]) { + throw new Error(`invalid Chalk style: ${style}`); + } +} + +/** + * Checks if a given style is valid and parses style functions. + * */ +function parseStyle(chalk, style) { + const fnMatch = style.match(/^\s*(\w+)\s*\(\s*([^)]*)\s*\)\s*/); + if (!fnMatch) { + assertStyle(chalk, style); + return chalk[style]; + } + + const name = fnMatch[1].trim(); + const args = fnMatch[2].split(/,/g).map(s => s.trim()); + + assertStyle(chalk, name); + + return chalk[name].apply(chalk, args); +} + +/** + * Performs the actual styling of the string, essentially lifted from cli.js. + * */ +function style(chalk, flat) { + return flat.map(data => { + const fn = data.styles.reduce(parseStyle, chalk); + return fn(data.content.replace(/\n$/, '')); + }).join(''); +} + +module.exports = (chalk, string) => style(chalk, flatten(parse(string))); diff --git a/test.js b/test.js index 4c36a88..a7a4a6b 100644 --- a/test.js +++ b/test.js @@ -19,6 +19,10 @@ console.log('host TERM=', process.env.TERM || '[none]'); console.log('host platform=', process.platform || '[unknown]'); describe('chalk', () => { + it('should not add any styling when called as the base function', () => { + assert.equal(chalk('foo'), 'foo'); + }); + it('should style string', () => { assert.equal(chalk.underline('foo'), '\u001B[4mfoo\u001B[24m'); assert.equal(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); @@ -242,3 +246,94 @@ describe('chalk.constructor', () => { assert.equal(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); }); }); + +describe('tagged template literal', () => { + it('should return an empty string for an empty literal', () => { + const ctx = chalk.constructor(); + assert.equal(ctx``, ''); + }); + + it('should return a regular string for a literal with no templates', () => { + const ctx = chalk.constructor({level: 0}); + assert.equal(ctx`hello`, 'hello'); + }); + + it('should correctly perform template parsing', () => { + const ctx = chalk.constructor({level: 0}); + assert.equal(ctx`{bold Hello, {cyan World!} This is a} test. {green Woo!}`, + ctx.bold('Hello,', ctx.cyan('World!'), 'This is a') + ' test. ' + ctx.green('Woo!')); + }); + + it('should correctly perform template substitutions', () => { + const ctx = chalk.constructor({level: 0}); + const name = 'Sindre'; + const exclamation = 'Neat'; + assert.equal(ctx`{bold Hello, {cyan.inverse ${name}!} This is a} test. {green ${exclamation}!}`, + ctx.bold('Hello,', ctx.cyan.inverse(name + '!'), 'This is a') + ' test. ' + ctx.green(exclamation + '!')); + }); + + it('should correctly parse and evaluate color-convert functions', () => { + const ctx = chalk.constructor({level: 3}); + assert.equal(ctx`{bold.rgb(144,10,178).inverse Hello, {~inverse there!}}`, + '\u001B[0m\u001B[1m\u001B[38;2;144;10;178m\u001B[7mHello, ' + + '\u001B[27m\u001B[39m\u001B[22m\u001B[0m\u001B[0m\u001B[1m' + + '\u001B[38;2;144;10;178mthere!\u001B[39m\u001B[22m\u001B[0m'); + + assert.equal(ctx`{bold.bgRgb(144,10,178).inverse Hello, {~inverse there!}}`, + '\u001B[0m\u001B[1m\u001B[48;2;144;10;178m\u001B[7mHello, ' + + '\u001B[27m\u001B[49m\u001B[22m\u001B[0m\u001B[0m\u001B[1m' + + '\u001B[48;2;144;10;178mthere!\u001B[49m\u001B[22m\u001B[0m'); + }); + + it('should properly handle escapes', () => { + const ctx = chalk.constructor({level: 3}); + assert.equal(ctx`{bold hello \{in brackets\}}`, + '\u001B[0m\u001B[1mhello {in brackets}\u001B[22m\u001B[0m'); + }); + + it('should throw if there is an unclosed block', () => { + const ctx = chalk.constructor({level: 3}); + try { + console.log(ctx`{bold this shouldn't appear ever\}`); + assert.fail(); + } catch (err) { + assert.equal(err.message, 'literal template has an unclosed block'); + } + }); + + it('should throw if there is an invalid style', () => { + const ctx = chalk.constructor({level: 3}); + try { + console.log(ctx`{abadstylethatdoesntexist this shouldn't appear ever}`); + assert.fail(); + } catch (err) { + assert.equal(err.message, 'invalid Chalk style: abadstylethatdoesntexist'); + } + }); + + it('should properly style multiline color blocks', () => { + const ctx = chalk.constructor({level: 3}); + assert.equal( + ctx`{bold + Hello! This is a + ${'multiline'} block! + :) + } {underline + I hope you enjoy + }`, + '\u001B[0m\u001B[1m\u001B[22m\u001B[0m\n' + + '\u001B[0m\u001B[1m\t\t\t\tHello! This is a\u001B[22m\u001B[0m\n' + + '\u001B[0m\u001B[1m\t\t\t\tmultiline block!\u001B[22m\u001B[0m\n' + + '\u001B[0m\u001B[1m\t\t\t\t:)\u001B[22m\u001B[0m\n' + + '\u001B[0m\u001B[1m\t\t\t\u001B[22m\u001B[0m\u001B[0m \u001B[0m\u001B[0m\u001B[4m\u001B[24m\u001B[0m\n' + + '\u001B[0m\u001B[4m\t\t\t\tI hope you enjoy\u001B[24m\u001B[0m\n' + + '\u001B[0m\u001B[4m\t\t\t\u001B[24m\u001B[0m' + ); + }); + + it('should escape interpolated values', () => { + const ctx = chalk.constructor({level: 0}); + assert.equal(ctx`Hello {bold hi}`, 'Hello hi'); + assert.equal(ctx`Hello ${'{bold hi}'}`, 'Hello {bold hi}'); + }); +}); From 3fca6150e23439e783409f5c8f948f767c2ddc5a Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 30 Jun 2017 01:49:18 +0200 Subject: [PATCH 047/235] 2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a040744..b99d34f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "1.1.1", + "version": "2.0.0", "description": "Terminal string styling done right. Much color", "license": "MIT", "repository": "chalk/chalk", From caeb7d8dca24cc09ade47ea48f762693a4926ed6 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Thu, 29 Jun 2017 20:11:09 -0700 Subject: [PATCH 048/235] fix missing TERM cases --- index.js | 2 +- test.js | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index e6e0d6e..7553089 100644 --- a/index.js +++ b/index.js @@ -5,7 +5,7 @@ const supportsColor = require('supports-color'); const template = require('./templates.js'); -const isSimpleWindowsTerm = process.platform === 'win32' && !process.env.TERM.toLowerCase().startsWith('xterm'); +const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); // `supportsColor.level` → `ansiStyles.color[name]` mapping const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; diff --git a/test.js b/test.js index a7a4a6b..237e3f3 100644 --- a/test.js +++ b/test.js @@ -133,6 +133,12 @@ describe('chalk on windows', () => { delete require.cache[resolveFrom(__dirname, 'ansi-styles')]; }); + it('should detect a simple term if TERM isn\'t set', () => { + delete process.env.TERM; + const chalkCtx = importFresh('.'); + assert.equal(chalkCtx.blue('foo'), '\u001B[94mfoo\u001B[39m'); + }); + it('should replace blue foreground color in cmd.exe', () => { process.env.TERM = 'dumb'; const chalkCtx = importFresh('.'); From 5827081719944a2f903b52a88baeec1ec8581f82 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Thu, 29 Jun 2017 20:26:07 -0700 Subject: [PATCH 049/235] 2.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b99d34f..e1b51ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "2.0.0", + "version": "2.0.1", "description": "Terminal string styling done right. Much color", "license": "MIT", "repository": "chalk/chalk", From 3d10f8fad76737fd9443219997d83a24e88dffb0 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 30 Jun 2017 12:42:24 +0200 Subject: [PATCH 050/235] Code style tweaks --- .gitignore | 1 + .npmrc | 1 + examples/rainbow.js | 9 ++++----- index.js | 6 +++--- templates.js | 35 +++++++++++------------------------ test.js | 4 ++-- 6 files changed, 22 insertions(+), 34 deletions(-) create mode 100644 .npmrc diff --git a/.gitignore b/.gitignore index 1fd04da..6bff314 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules +yarn.lock coverage .nyc_output diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..43c97e7 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/examples/rainbow.js b/examples/rainbow.js index 3da1e11..a4a2e0a 100644 --- a/examples/rainbow.js +++ b/examples/rainbow.js @@ -1,3 +1,4 @@ +'use strict'; const chalk = require('..'); const ignoreChars = /[^!-~]/; @@ -23,15 +24,13 @@ function rainbow(str, offset) { return chars.join(''); } -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} +const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); async function animateString(str) { console.log(); for (let i = 0; i < 360 * 5; i++) { - console.log('\x1b[1F\x1b[G ', rainbow(str, i)); - await sleep(50); // eslint-disable-line no-await-in-loop + console.log('\u001B[1F\u001B[G ', rainbow(str, i)); + await sleep(2); // eslint-disable-line no-await-in-loop } } diff --git a/index.js b/index.js index 7553089..f98f65a 100644 --- a/index.js +++ b/index.js @@ -24,8 +24,8 @@ function applyOptions(obj, options) { } function Chalk(options) { - // We check for this.template here since calling chalk.constructor() - // by itself will have a `this` of a previously constructed chalk object. + // We check for this.template here since calling `chalk.constructor()` + // by itself will have a `this` of a previously constructed chalk object if (!this || !(this instanceof Chalk) || this.template) { const chalk = {}; applyOptions(chalk, options); @@ -142,7 +142,7 @@ function build(_styles, key) { builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; // `__proto__` is used because we must return a function, but there is - // no way to create a function with a different prototype. + // no way to create a function with a different prototype builder.__proto__ = proto; // eslint-disable-line no-proto return builder; diff --git a/templates.js b/templates.js index afc6696..6c0a912 100644 --- a/templates.js +++ b/templates.js @@ -27,9 +27,7 @@ const takeWhileReverse = (array, predicate, start) => { return out; }; -/** - * Checks if the character at position i in string is a normal character a.k.a a non control character. - * */ +// Check if the character at position `i` in string is a normal character (non-control character) const isNormalCharacter = (string, i) => { const char = string[i]; const backslash = '\\'; @@ -45,10 +43,8 @@ const isNormalCharacter = (string, i) => { const collectStyles = data => data ? collectStyles(data.parent).concat(data.styles) : ['reset']; -/** - * Computes the style for a given data based on it's style and the style of it's parent. Also accounts for !style styles - * which remove a style from the list if present. - * */ +// Compute the style for a given data based on its style and the style of its parent. +// Also accounts for `!style` styles which remove a style from the list if present. const sumStyles = data => { const negateRegex = /^~.+/; let out = []; @@ -65,13 +61,10 @@ const sumStyles = data => { return out; }; -/** - * Takes a string and parses it into a tree of data objects which inherit styles from their parent. - * */ +// Take a string and parse it into a tree of data objects which inherit styles from their parent function parse(string) { const root = data(null); let pushingStyle = false; - let current = root; for (let i = 0; i < string.length; i++) { @@ -88,7 +81,7 @@ function parse(string) { }; if (pushingStyle) { - if (' \t'.indexOf(char) > -1) { + if (' \t'.includes(char)) { pushingStyle = false; } else if (char === '\n') { pushingStyle = false; @@ -111,16 +104,14 @@ function parse(string) { } if (current !== root) { - throw new Error('literal template has an unclosed block'); + throw new Error('Template literal has an unclosed block'); } return root; } -/** - * Takes a tree of data objects and flattens it to a list of data objects with the inherited and negations styles - * accounted for. - * */ +// Take a tree of data objects and flatten it to a list of data +// objects with the inherited and negations styles accounted for function flatten(data) { let flat = []; @@ -140,13 +131,11 @@ function flatten(data) { function assertStyle(chalk, style) { if (!chalk[style]) { - throw new Error(`invalid Chalk style: ${style}`); + throw new Error(`Invalid Chalk style: ${style}`); } } -/** - * Checks if a given style is valid and parses style functions. - * */ +// Check if a given style is valid and parse style functions function parseStyle(chalk, style) { const fnMatch = style.match(/^\s*(\w+)\s*\(\s*([^)]*)\s*\)\s*/); if (!fnMatch) { @@ -162,9 +151,7 @@ function parseStyle(chalk, style) { return chalk[name].apply(chalk, args); } -/** - * Performs the actual styling of the string, essentially lifted from cli.js. - * */ +// Perform the actual styling of the string function style(chalk, flat) { return flat.map(data => { const fn = data.styles.reduce(parseStyle, chalk); diff --git a/test.js b/test.js index 237e3f3..325950b 100644 --- a/test.js +++ b/test.js @@ -303,7 +303,7 @@ describe('tagged template literal', () => { console.log(ctx`{bold this shouldn't appear ever\}`); assert.fail(); } catch (err) { - assert.equal(err.message, 'literal template has an unclosed block'); + assert.equal(err.message, 'Template literal has an unclosed block'); } }); @@ -313,7 +313,7 @@ describe('tagged template literal', () => { console.log(ctx`{abadstylethatdoesntexist this shouldn't appear ever}`); assert.fail(); } catch (err) { - assert.equal(err.message, 'invalid Chalk style: abadstylethatdoesntexist'); + assert.equal(err.message, 'Invalid Chalk style: abadstylethatdoesntexist'); } }); From 5ec90cb35460008ef7d3adb506ba3ce2cd46672d Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 30 Jun 2017 12:53:46 +0200 Subject: [PATCH 051/235] Link to v2 release notes --- readme.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 18590bd..dde68ab 100644 --- a/readme.md +++ b/readme.md @@ -11,9 +11,7 @@ [![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) [![](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/sindresorhus/xo) -[colors.js](https://github.com/Marak/colors.js) used to be the most popular string styling module, but it has serious deficiencies like extending `String.prototype` which causes all kinds of [problems](https://github.com/yeoman/yo/issues/68). Although there are other ones, they either do too much or not enough. - -**Chalk is a clean and focused alternative.** +### [See what's new in Chalk 2](https://github.com/chalk/chalk/releases/tag/v2.0.0) ![](https://github.com/chalk/ansi-styles/raw/master/screenshot.png) @@ -278,6 +276,11 @@ The following color models can be used: If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) instead of `cmd.exe`. +## Origin story + +[colors.js](https://github.com/Marak/colors.js) used to be the most popular string styling module, but it has serious deficiencies like extending `String.prototype` which causes all kinds of [problems](https://github.com/yeoman/yo/issues/68) and the package is unmaintained. Although there are other packages, they either do too much or not enough. Chalk is a clean and focused alternative. + + ## Related - [chalk-cli](https://github.com/chalk/chalk-cli) - CLI for this module From 8d26c1401cac1b1123e6b82f20f866e1d8756986 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 30 Jun 2017 17:19:57 +0200 Subject: [PATCH 052/235] Minor meta tweaks --- package.json | 2 +- test.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e1b51ab..ac1f9b2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "chalk", "version": "2.0.1", - "description": "Terminal string styling done right. Much color", + "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk", "engines": { diff --git a/test.js b/test.js index 325950b..47cbf15 100644 --- a/test.js +++ b/test.js @@ -15,8 +15,8 @@ require.cache[resolveFrom(__dirname, 'supports-color')] = { const chalk = require('.'); -console.log('host TERM=', process.env.TERM || '[none]'); -console.log('host platform=', process.platform || '[unknown]'); +console.log('TERM:', process.env.TERM || '[none]'); +console.log('platform:', process.platform || '[unknown]'); describe('chalk', () => { it('should not add any styling when called as the base function', () => { @@ -111,7 +111,7 @@ describe('chalk', () => { }); }); -describe('chalk on windows', () => { +describe('chalk on Windows', () => { let originalEnv; let originalPlatform; @@ -235,7 +235,7 @@ describe('chalk.enabled', () => { }); }); -describe('chalk.constructor', () => { +describe('chalk.constructor()', () => { it('should create an isolated context where colors can be disabled (by level)', () => { const ctx = new chalk.constructor({level: 0, enabled: true}); assert.equal(ctx.red('foo'), 'foo'); From 23092eefd2401f1a41d9fb931ce9091ec2f624c5 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Fri, 7 Jul 2017 16:03:36 -0700 Subject: [PATCH 053/235] add note about brightBlack (ref chalk/ansi-styles#33) --- readme.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/readme.md b/readme.md index dde68ab..3065910 100644 --- a/readme.md +++ b/readme.md @@ -181,8 +181,7 @@ Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color= - `magenta` - `cyan` - `white` -- `gray` -- `blackBright` +- `gray` ("bright black") - `redBright` - `greenBright` - `yellowBright` From 5cdd9eddf8d1e53c03b3bb122004786fb90706bf Mon Sep 17 00:00:00 2001 From: Vadim Demedes Date: Sat, 22 Jul 2017 01:03:49 +0300 Subject: [PATCH 054/235] Demonstrate crash when using Truecolor methods and color is unsupported (#174) --- fixture.js | 4 ++++ package.json | 1 + test.js | 8 ++++++++ 3 files changed, 13 insertions(+) create mode 100644 fixture.js diff --git a/fixture.js b/fixture.js new file mode 100644 index 0000000..a57f562 --- /dev/null +++ b/fixture.js @@ -0,0 +1,4 @@ +'use strict'; +const chalk = require('.'); + +console.log(chalk.hex('#ff6159')('test')); diff --git a/package.json b/package.json index ac1f9b2..2501c72 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ }, "devDependencies": { "coveralls": "^2.11.2", + "execa": "^0.7.0", "import-fresh": "^2.0.0", "matcha": "^0.7.0", "mocha": "*", diff --git a/test.js b/test.js index 47cbf15..fe7a14e 100644 --- a/test.js +++ b/test.js @@ -2,6 +2,7 @@ const assert = require('assert'); const importFresh = require('import-fresh'); const resolveFrom = require('resolve-from'); +const execa = require('execa'); // Spoof supports-color require.cache[resolveFrom(__dirname, 'supports-color')] = { @@ -202,6 +203,13 @@ describe('chalk.level', () => { assert.equal(chalk.level, 1); chalk.level = oldLevel; }); + + it('should disable colors if they are not supported', () => { + return execa('node', ['fixture']) + .then(result => { + assert.equal(result.stdout, 'test'); + }); + }); }); describe('chalk.enabled', () => { From e8d28f3041251c650ee05b4cdd34a3ff95754d02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20M=C3=A5rtensson?= Date: Sun, 23 Jul 2017 22:13:55 +0200 Subject: [PATCH 055/235] Return empty `string` when there are no arguments (#183) --- index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index f98f65a..87300fc 100644 --- a/index.js +++ b/index.js @@ -152,7 +152,11 @@ function applyStyle() { // Support varags, but simply cast to string in case there's only one arg const args = arguments; const argsLen = args.length; - let str = argsLen !== 0 && String(arguments[0]); + let str = String(arguments[0]); + + if (argsLen === 0) { + return ''; + } if (argsLen > 1) { // Don't slice `arguments`, it prevents V8 optimizations From 4c4eb1fd0aa9efea2b469f130ed01d6891670ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20M=C3=A5rtensson?= Date: Sun, 23 Jul 2017 22:17:33 +0200 Subject: [PATCH 056/235] Move testing to `ava` (#182) --- package.json | 4 +- test.js | 353 --------------------------------- fixture.js => test/_fixture.js | 2 +- test/_supports-color.js | 13 ++ test/chalk.js | 96 +++++++++ test/constructor.js | 22 ++ test/enabled.js | 35 ++++ test/level.js | 44 ++++ test/template-literal.js | 95 +++++++++ test/windows.js | 63 ++++++ 10 files changed, 371 insertions(+), 356 deletions(-) delete mode 100644 test.js rename fixture.js => test/_fixture.js (66%) create mode 100644 test/_supports-color.js create mode 100644 test/chalk.js create mode 100644 test/constructor.js create mode 100644 test/enabled.js create mode 100644 test/level.js create mode 100644 test/template-literal.js create mode 100644 test/windows.js diff --git a/package.json b/package.json index 2501c72..07ed8ed 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "node": ">=4" }, "scripts": { - "test": "xo && nyc mocha", + "test": "xo && nyc ava", "bench": "matcha benchmark.js", "coveralls": "nyc report --reporter=text-lcov | coveralls" }, @@ -45,11 +45,11 @@ "supports-color": "^4.0.0" }, "devDependencies": { + "ava": "*", "coveralls": "^2.11.2", "execa": "^0.7.0", "import-fresh": "^2.0.0", "matcha": "^0.7.0", - "mocha": "*", "nyc": "^11.0.2", "resolve-from": "^3.0.0", "xo": "*" diff --git a/test.js b/test.js deleted file mode 100644 index fe7a14e..0000000 --- a/test.js +++ /dev/null @@ -1,353 +0,0 @@ -'use strict'; -const assert = require('assert'); -const importFresh = require('import-fresh'); -const resolveFrom = require('resolve-from'); -const execa = require('execa'); - -// Spoof supports-color -require.cache[resolveFrom(__dirname, 'supports-color')] = { - exports: { - level: 3, - hasBasic: true, - has256: true, - has16m: true - } -}; - -const chalk = require('.'); - -console.log('TERM:', process.env.TERM || '[none]'); -console.log('platform:', process.platform || '[unknown]'); - -describe('chalk', () => { - it('should not add any styling when called as the base function', () => { - assert.equal(chalk('foo'), 'foo'); - }); - - it('should style string', () => { - assert.equal(chalk.underline('foo'), '\u001B[4mfoo\u001B[24m'); - assert.equal(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); - assert.equal(chalk.bgRed('foo'), '\u001B[41mfoo\u001B[49m'); - }); - - it('should support applying multiple styles at once', () => { - assert.equal(chalk.red.bgGreen.underline('foo'), '\u001B[31m\u001B[42m\u001B[4mfoo\u001B[24m\u001B[49m\u001B[39m'); - assert.equal(chalk.underline.red.bgGreen('foo'), '\u001B[4m\u001B[31m\u001B[42mfoo\u001B[49m\u001B[39m\u001B[24m'); - }); - - it('should support nesting styles', () => { - assert.equal( - chalk.red('foo' + chalk.underline.bgBlue('bar') + '!'), - '\u001B[31mfoo\u001B[4m\u001B[44mbar\u001B[49m\u001B[24m!\u001B[39m' - ); - }); - - it('should support nesting styles of the same type (color, underline, bg)', () => { - assert.equal( - chalk.red('a' + chalk.yellow('b' + chalk.green('c') + 'b') + 'c'), - '\u001B[31ma\u001B[33mb\u001B[32mc\u001B[33mb\u001B[31mc\u001B[39m' - ); - }); - - it('should reset all styles with `.reset()`', () => { - assert.equal(chalk.reset(chalk.red.bgGreen.underline('foo') + 'foo'), '\u001B[0m\u001B[31m\u001B[42m\u001B[4mfoo\u001B[24m\u001B[49m\u001B[39mfoo\u001B[0m'); - }); - - it('should be able to cache multiple styles', () => { - const red = chalk.red; - const green = chalk.green; - const redBold = red.bold; - const greenBold = green.bold; - - assert.notEqual(red('foo'), green('foo')); - assert.notEqual(redBold('bar'), greenBold('bar')); - assert.notEqual(green('baz'), greenBold('baz')); - }); - - it('should alias gray to grey', () => { - assert.equal(chalk.grey('foo'), '\u001B[90mfoo\u001B[39m'); - }); - - it('should support variable number of arguments', () => { - assert.equal(chalk.red('foo', 'bar'), '\u001B[31mfoo bar\u001B[39m'); - }); - - it('should support falsy values', () => { - assert.equal(chalk.red(0), '\u001B[31m0\u001B[39m'); - }); - - it('shouldn\'t output escape codes if the input is empty', () => { - assert.equal(chalk.red(), ''); - assert.equal(chalk.red.blue.black(), ''); - }); - - it('should keep Function.prototype methods', () => { - assert.equal(chalk.grey.apply(null, ['foo']), '\u001B[90mfoo\u001B[39m'); - assert.equal(chalk.reset(chalk.red.bgGreen.underline.bind(null)('foo') + 'foo'), '\u001B[0m\u001B[31m\u001B[42m\u001B[4mfoo\u001B[24m\u001B[49m\u001B[39mfoo\u001B[0m'); - assert.equal(chalk.red.blue.black.call(null), ''); - }); - - it('line breaks should open and close colors', () => { - assert.equal(chalk.grey('hello\nworld'), '\u001B[90mhello\u001B[39m\n\u001B[90mworld\u001B[39m'); - }); - - it('should properly convert RGB to 16 colors on basic color terminals', () => { - assert.equal(new chalk.constructor({level: 1}).hex('#FF0000')('hello'), '\u001B[91mhello\u001B[39m'); - assert.equal(new chalk.constructor({level: 1}).bgHex('#FF0000')('hello'), '\u001B[101mhello\u001B[49m'); - }); - - it('should properly convert RGB to 256 colors on basic color terminals', () => { - assert.equal(new chalk.constructor({level: 2}).hex('#FF0000')('hello'), '\u001B[38;5;196mhello\u001B[39m'); - assert.equal(new chalk.constructor({level: 2}).bgHex('#FF0000')('hello'), '\u001B[48;5;196mhello\u001B[49m'); - }); - - it('should properly convert RGB to 256 colors on basic color terminals', () => { - assert.equal(new chalk.constructor({level: 3}).hex('#FF0000')('hello'), '\u001B[38;2;255;0;0mhello\u001B[39m'); - assert.equal(new chalk.constructor({level: 3}).bgHex('#FF0000')('hello'), '\u001B[48;2;255;0;0mhello\u001B[49m'); - }); - - it('should not emit RGB codes if level is 0', () => { - assert.equal(new chalk.constructor({level: 0}).hex('#FF0000')('hello'), 'hello'); - assert.equal(new chalk.constructor({level: 0}).bgHex('#FF0000')('hello'), 'hello'); - }); -}); - -describe('chalk on Windows', () => { - let originalEnv; - let originalPlatform; - - before(() => { - originalEnv = process.env; - originalPlatform = process.platform; - }); - - after(() => { - process.env = originalEnv; - Object.defineProperty(process, 'platform', {value: originalPlatform}); - }); - - beforeEach(() => { - process.env = {}; - Object.defineProperty(process, 'platform', {value: 'win32'}); - // Since chalk internally modifies `ansiStyles.blue.open`, `ansi-styles` needs - // to be removed from the require cache for `require-uncached` to work - delete require.cache[resolveFrom(__dirname, 'ansi-styles')]; - }); - - it('should detect a simple term if TERM isn\'t set', () => { - delete process.env.TERM; - const chalkCtx = importFresh('.'); - assert.equal(chalkCtx.blue('foo'), '\u001B[94mfoo\u001B[39m'); - }); - - it('should replace blue foreground color in cmd.exe', () => { - process.env.TERM = 'dumb'; - const chalkCtx = importFresh('.'); - assert.equal(chalkCtx.blue('foo'), '\u001B[94mfoo\u001B[39m'); - }); - - it('shouldn\'t replace blue foreground color in xterm based terminals', () => { - process.env.TERM = 'xterm-256color'; - const chalkCtx = importFresh('.'); - assert.equal(chalkCtx.blue('foo'), '\u001B[34mfoo\u001B[39m'); - }); - - it('should not apply dimmed styling on gray strings, see https://github.com/chalk/chalk/issues/58', () => { - process.env.TERM = 'dumb'; - const chalkCtx = importFresh('.'); - assert.equal(chalkCtx.gray.dim('foo'), '\u001B[90mfoo\u001B[22m\u001B[39m'); - }); - - it('should apply dimmed styling on xterm compatible terminals', () => { - process.env.TERM = 'xterm'; - const chalkCtx = importFresh('.'); - assert.equal(chalkCtx.gray.dim('foo'), '\u001B[90m\u001B[2mfoo\u001B[22m\u001B[39m'); - }); - - it('should apply dimmed styling on strings of other colors', () => { - process.env.TERM = 'dumb'; - const chalkCtx = importFresh('.'); - assert.equal(chalkCtx.blue.dim('foo'), '\u001B[94m\u001B[2mfoo\u001B[22m\u001B[39m'); - }); -}); - -describe('chalk.level', () => { - it('should not output colors when manually disabled', () => { - const oldLevel = chalk.level; - chalk.level = 0; - assert.equal(chalk.red('foo'), 'foo'); - chalk.level = oldLevel; - }); - - it('should enable/disable colors based on overall chalk enabled property, not individual instances', () => { - const oldLevel = chalk.level; - chalk.level = 1; - const red = chalk.red; - assert.equal(red.level, 1); - chalk.level = 0; - assert.equal(red.level, chalk.level); - chalk.level = oldLevel; - }); - - it('should propagate enable/disable changes from child colors', () => { - const oldLevel = chalk.level; - chalk.level = 1; - const red = chalk.red; - assert.equal(red.level, 1); - assert.equal(chalk.level, 1); - red.level = 0; - assert.equal(red.level, 0); - assert.equal(chalk.level, 0); - chalk.level = 1; - assert.equal(red.level, 1); - assert.equal(chalk.level, 1); - chalk.level = oldLevel; - }); - - it('should disable colors if they are not supported', () => { - return execa('node', ['fixture']) - .then(result => { - assert.equal(result.stdout, 'test'); - }); - }); -}); - -describe('chalk.enabled', () => { - it('should not output colors when manually disabled', () => { - chalk.enabled = false; - assert.equal(chalk.red('foo'), 'foo'); - chalk.enabled = true; - }); - - it('should enable/disable colors based on overall chalk enabled property, not individual instances', () => { - chalk.enabled = false; - const red = chalk.red; - assert.equal(red.enabled, false); - chalk.enabled = true; - assert.equal(red.enabled, true); - chalk.enabled = true; - }); - - it('should propagate enable/disable changes from child colors', () => { - chalk.enabled = false; - const red = chalk.red; - assert.equal(red.enabled, false); - assert.equal(chalk.enabled, false); - red.enabled = true; - assert.equal(red.enabled, true); - assert.equal(chalk.enabled, true); - chalk.enabled = false; - assert.equal(red.enabled, false); - assert.equal(chalk.enabled, false); - chalk.enabled = true; - }); -}); - -describe('chalk.constructor()', () => { - it('should create an isolated context where colors can be disabled (by level)', () => { - const ctx = new chalk.constructor({level: 0, enabled: true}); - assert.equal(ctx.red('foo'), 'foo'); - assert.equal(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); - ctx.level = 2; - assert.equal(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); - }); - - it('should create an isolated context where colors can be disabled (by enabled flag)', () => { - const ctx = new chalk.constructor({enabled: false}); - assert.equal(ctx.red('foo'), 'foo'); - assert.equal(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); - ctx.enabled = true; - assert.equal(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); - }); -}); - -describe('tagged template literal', () => { - it('should return an empty string for an empty literal', () => { - const ctx = chalk.constructor(); - assert.equal(ctx``, ''); - }); - - it('should return a regular string for a literal with no templates', () => { - const ctx = chalk.constructor({level: 0}); - assert.equal(ctx`hello`, 'hello'); - }); - - it('should correctly perform template parsing', () => { - const ctx = chalk.constructor({level: 0}); - assert.equal(ctx`{bold Hello, {cyan World!} This is a} test. {green Woo!}`, - ctx.bold('Hello,', ctx.cyan('World!'), 'This is a') + ' test. ' + ctx.green('Woo!')); - }); - - it('should correctly perform template substitutions', () => { - const ctx = chalk.constructor({level: 0}); - const name = 'Sindre'; - const exclamation = 'Neat'; - assert.equal(ctx`{bold Hello, {cyan.inverse ${name}!} This is a} test. {green ${exclamation}!}`, - ctx.bold('Hello,', ctx.cyan.inverse(name + '!'), 'This is a') + ' test. ' + ctx.green(exclamation + '!')); - }); - - it('should correctly parse and evaluate color-convert functions', () => { - const ctx = chalk.constructor({level: 3}); - assert.equal(ctx`{bold.rgb(144,10,178).inverse Hello, {~inverse there!}}`, - '\u001B[0m\u001B[1m\u001B[38;2;144;10;178m\u001B[7mHello, ' + - '\u001B[27m\u001B[39m\u001B[22m\u001B[0m\u001B[0m\u001B[1m' + - '\u001B[38;2;144;10;178mthere!\u001B[39m\u001B[22m\u001B[0m'); - - assert.equal(ctx`{bold.bgRgb(144,10,178).inverse Hello, {~inverse there!}}`, - '\u001B[0m\u001B[1m\u001B[48;2;144;10;178m\u001B[7mHello, ' + - '\u001B[27m\u001B[49m\u001B[22m\u001B[0m\u001B[0m\u001B[1m' + - '\u001B[48;2;144;10;178mthere!\u001B[49m\u001B[22m\u001B[0m'); - }); - - it('should properly handle escapes', () => { - const ctx = chalk.constructor({level: 3}); - assert.equal(ctx`{bold hello \{in brackets\}}`, - '\u001B[0m\u001B[1mhello {in brackets}\u001B[22m\u001B[0m'); - }); - - it('should throw if there is an unclosed block', () => { - const ctx = chalk.constructor({level: 3}); - try { - console.log(ctx`{bold this shouldn't appear ever\}`); - assert.fail(); - } catch (err) { - assert.equal(err.message, 'Template literal has an unclosed block'); - } - }); - - it('should throw if there is an invalid style', () => { - const ctx = chalk.constructor({level: 3}); - try { - console.log(ctx`{abadstylethatdoesntexist this shouldn't appear ever}`); - assert.fail(); - } catch (err) { - assert.equal(err.message, 'Invalid Chalk style: abadstylethatdoesntexist'); - } - }); - - it('should properly style multiline color blocks', () => { - const ctx = chalk.constructor({level: 3}); - assert.equal( - ctx`{bold - Hello! This is a - ${'multiline'} block! - :) - } {underline - I hope you enjoy - }`, - '\u001B[0m\u001B[1m\u001B[22m\u001B[0m\n' + - '\u001B[0m\u001B[1m\t\t\t\tHello! This is a\u001B[22m\u001B[0m\n' + - '\u001B[0m\u001B[1m\t\t\t\tmultiline block!\u001B[22m\u001B[0m\n' + - '\u001B[0m\u001B[1m\t\t\t\t:)\u001B[22m\u001B[0m\n' + - '\u001B[0m\u001B[1m\t\t\t\u001B[22m\u001B[0m\u001B[0m \u001B[0m\u001B[0m\u001B[4m\u001B[24m\u001B[0m\n' + - '\u001B[0m\u001B[4m\t\t\t\tI hope you enjoy\u001B[24m\u001B[0m\n' + - '\u001B[0m\u001B[4m\t\t\t\u001B[24m\u001B[0m' - ); - }); - - it('should escape interpolated values', () => { - const ctx = chalk.constructor({level: 0}); - assert.equal(ctx`Hello {bold hi}`, 'Hello hi'); - assert.equal(ctx`Hello ${'{bold hi}'}`, 'Hello {bold hi}'); - }); -}); diff --git a/fixture.js b/test/_fixture.js similarity index 66% rename from fixture.js rename to test/_fixture.js index a57f562..5f1771d 100644 --- a/fixture.js +++ b/test/_fixture.js @@ -1,4 +1,4 @@ 'use strict'; -const chalk = require('.'); +const chalk = require('..'); console.log(chalk.hex('#ff6159')('test')); diff --git a/test/_supports-color.js b/test/_supports-color.js new file mode 100644 index 0000000..d6e82bb --- /dev/null +++ b/test/_supports-color.js @@ -0,0 +1,13 @@ +'use strict'; +const resolveFrom = require('resolve-from'); + +module.exports = dir => { + require.cache[resolveFrom(dir, 'supports-color')] = { + exports: { + level: 3, + hasBasic: true, + has256: true, + has16m: true + } + }; +}; diff --git a/test/chalk.js b/test/chalk.js new file mode 100644 index 0000000..46060d4 --- /dev/null +++ b/test/chalk.js @@ -0,0 +1,96 @@ +import test from 'ava'; + +// Spoof supports-color +require('./_supports-color')(__dirname); + +const m = require('..'); + +console.log('TERM:', process.env.TERM || '[none]'); +console.log('platform:', process.platform || '[unknown]'); + +test('don\'t add any styling when called as the base function', t => { + t.is(m('foo'), 'foo'); +}); + +test('style string', t => { + t.is(m.underline('foo'), '\u001B[4mfoo\u001B[24m'); + t.is(m.red('foo'), '\u001B[31mfoo\u001B[39m'); + t.is(m.bgRed('foo'), '\u001B[41mfoo\u001B[49m'); +}); + +test('support applying multiple styles at once', t => { + t.is(m.red.bgGreen.underline('foo'), '\u001B[31m\u001B[42m\u001B[4mfoo\u001B[24m\u001B[49m\u001B[39m'); + t.is(m.underline.red.bgGreen('foo'), '\u001B[4m\u001B[31m\u001B[42mfoo\u001B[49m\u001B[39m\u001B[24m'); +}); + +test('support nesting styles', t => { + t.is( + m.red('foo' + m.underline.bgBlue('bar') + '!'), + '\u001B[31mfoo\u001B[4m\u001B[44mbar\u001B[49m\u001B[24m!\u001B[39m' + ); +}); + +test('support nesting styles of the same type (color, underline, bg)', t => { + t.is( + m.red('a' + m.yellow('b' + m.green('c') + 'b') + 'c'), + '\u001B[31ma\u001B[33mb\u001B[32mc\u001B[33mb\u001B[31mc\u001B[39m' + ); +}); + +test('reset all styles with `.reset()`', t => { + t.is(m.reset(m.red.bgGreen.underline('foo') + 'foo'), '\u001B[0m\u001B[31m\u001B[42m\u001B[4mfoo\u001B[24m\u001B[49m\u001B[39mfoo\u001B[0m'); +}); + +test('support caching multiple styles', t => { + const red = m.red; + const green = m.green; + const redBold = red.bold; + const greenBold = green.bold; + + t.not(red('foo'), green('foo')); + t.not(redBold('bar'), greenBold('bar')); + t.not(green('baz'), greenBold('baz')); +}); + +test('alias gray to grey', t => { + t.is(m.grey('foo'), '\u001B[90mfoo\u001B[39m'); +}); + +test('support variable number of arguments', t => { + t.is(m.red('foo', 'bar'), '\u001B[31mfoo bar\u001B[39m'); +}); + +test('support falsy values', t => { + t.is(m.red(0), '\u001B[31m0\u001B[39m'); +}); + +test('don\'t output escape codes if the input is empty', t => { + t.is(m.red(), ''); + t.is(m.red.blue.black(), ''); +}); + +test('keep Function.prototype methods', t => { + t.is(m.grey.apply(null, ['foo']), '\u001B[90mfoo\u001B[39m'); + t.is(m.reset(m.red.bgGreen.underline.bind(null)('foo') + 'foo'), '\u001B[0m\u001B[31m\u001B[42m\u001B[4mfoo\u001B[24m\u001B[49m\u001B[39mfoo\u001B[0m'); + t.is(m.red.blue.black.call(null), ''); +}); + +test('line breaks should open and close colors', t => { + t.is(m.grey('hello\nworld'), '\u001B[90mhello\u001B[39m\n\u001B[90mworld\u001B[39m'); +}); + +test('properly convert RGB to 16 colors on basic color terminals', t => { + t.is(new m.constructor({level: 1}).hex('#FF0000')('hello'), '\u001B[91mhello\u001B[39m'); + t.is(new m.constructor({level: 1}).bgHex('#FF0000')('hello'), '\u001B[101mhello\u001B[49m'); +}); + +test('properly convert RGB to 256 colors on basic color terminals', t => { + t.is(new m.constructor({level: 2}).hex('#FF0000')('hello'), '\u001B[38;5;196mhello\u001B[39m'); + t.is(new m.constructor({level: 2}).bgHex('#FF0000')('hello'), '\u001B[48;5;196mhello\u001B[49m'); + t.is(new m.constructor({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 m.constructor({level: 0}).hex('#FF0000')('hello'), 'hello'); + t.is(new m.constructor({level: 0}).bgHex('#FF0000')('hello'), 'hello'); +}); diff --git a/test/constructor.js b/test/constructor.js new file mode 100644 index 0000000..d592e82 --- /dev/null +++ b/test/constructor.js @@ -0,0 +1,22 @@ +import test from 'ava'; + +// Spoof supports-color +require('./_supports-color')(__dirname); + +const m = require('..'); + +test('create an isolated context where colors can be disabled (by level)', t => { + const ctx = new m.constructor({level: 0, enabled: true}); + t.is(ctx.red('foo'), 'foo'); + t.is(m.red('foo'), '\u001B[31mfoo\u001B[39m'); + ctx.level = 2; + t.is(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); +}); + +test('create an isolated context where colors can be disabled (by enabled flag)', t => { + const ctx = new m.constructor({enabled: false}); + t.is(ctx.red('foo'), 'foo'); + t.is(m.red('foo'), '\u001B[31mfoo\u001B[39m'); + ctx.enabled = true; + t.is(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); +}); diff --git a/test/enabled.js b/test/enabled.js new file mode 100644 index 0000000..3270e54 --- /dev/null +++ b/test/enabled.js @@ -0,0 +1,35 @@ +import test from 'ava'; + +// Spoof supports-color +require('./_supports-color')(__dirname); + +const m = require('..'); + +test('don\'t output colors when manually disabled', t => { + m.enabled = false; + t.is(m.red('foo'), 'foo'); + m.enabled = true; +}); + +test('enable/disable colors based on overall chalk enabled property, not individual instances', t => { + m.enabled = false; + const red = m.red; + t.false(red.enabled); + m.enabled = true; + t.true(red.enabled); + m.enabled = true; +}); + +test('propagate enable/disable changes from child colors', t => { + m.enabled = false; + const red = m.red; + t.false(red.enabled); + t.false(m.enabled); + red.enabled = true; + t.true(red.enabled); + t.true(m.enabled); + m.enabled = false; + t.false(red.enabled); + t.false(m.enabled); + m.enabled = true; +}); diff --git a/test/level.js b/test/level.js new file mode 100644 index 0000000..9caf6c4 --- /dev/null +++ b/test/level.js @@ -0,0 +1,44 @@ +import path from 'path'; +import test from 'ava'; +import execa from 'execa'; + +// Spoof supports-color +require('./_supports-color')(__dirname); + +const m = require('..'); + +test('don\'t output colors when manually disabled', t => { + const oldLevel = m.level; + m.level = 0; + t.is(m.red('foo'), 'foo'); + m.level = oldLevel; +}); + +test('enable/disable colors based on overall chalk enabled property, not individual instances', t => { + const oldLevel = m.level; + m.level = 1; + const red = m.red; + t.is(red.level, 1); + m.level = 0; + t.is(red.level, m.level); + m.level = oldLevel; +}); + +test('propagate enable/disable changes from child colors', t => { + const oldLevel = m.level; + m.level = 1; + const red = m.red; + t.is(red.level, 1); + t.is(m.level, 1); + red.level = 0; + t.is(red.level, 0); + t.is(m.level, 0); + m.level = 1; + t.is(red.level, 1); + t.is(m.level, 1); + m.level = oldLevel; +}); + +test.failing('disable colors if they are not supported', async t => { + t.is(await execa.stdout('node', [path.join(__dirname, '_fixture')]), 'test'); +}); diff --git a/test/template-literal.js b/test/template-literal.js new file mode 100644 index 0000000..0b969ba --- /dev/null +++ b/test/template-literal.js @@ -0,0 +1,95 @@ +import test from 'ava'; + +// Spoof supports-color +require('./_supports-color')(__dirname); + +const m = require('..'); + +test('return an empty string for an empty literal', t => { + const ctx = m.constructor(); + t.is(ctx``, ''); +}); + +test('return a regular string for a literal with no templates', t => { + const ctx = m.constructor({level: 0}); + t.is(ctx`hello`, 'hello'); +}); + +test('correctly perform template parsing', t => { + const ctx = m.constructor({level: 0}); + t.is(ctx`{bold Hello, {cyan World!} This is a} test. {green Woo!}`, + ctx.bold('Hello,', ctx.cyan('World!'), 'This is a') + ' test. ' + ctx.green('Woo!')); +}); + +test('correctly perform template substitutions', t => { + const ctx = m.constructor({level: 0}); + const name = 'Sindre'; + const exclamation = 'Neat'; + t.is(ctx`{bold Hello, {cyan.inverse ${name}!} This is a} test. {green ${exclamation}!}`, + ctx.bold('Hello,', ctx.cyan.inverse(name + '!'), 'This is a') + ' test. ' + ctx.green(exclamation + '!')); +}); + +test('correctly parse and evaluate color-convert functions', t => { + const ctx = m.constructor({level: 3}); + t.is(ctx`{bold.rgb(144,10,178).inverse Hello, {~inverse there!}}`, + '\u001B[0m\u001B[1m\u001B[38;2;144;10;178m\u001B[7mHello, ' + + '\u001B[27m\u001B[39m\u001B[22m\u001B[0m\u001B[0m\u001B[1m' + + '\u001B[38;2;144;10;178mthere!\u001B[39m\u001B[22m\u001B[0m'); + + t.is(ctx`{bold.bgRgb(144,10,178).inverse Hello, {~inverse there!}}`, + '\u001B[0m\u001B[1m\u001B[48;2;144;10;178m\u001B[7mHello, ' + + '\u001B[27m\u001B[49m\u001B[22m\u001B[0m\u001B[0m\u001B[1m' + + '\u001B[48;2;144;10;178mthere!\u001B[49m\u001B[22m\u001B[0m'); +}); + +test('properly handle escapes', t => { + const ctx = m.constructor({level: 3}); + t.is(ctx`{bold hello \{in brackets\}}`, + '\u001B[0m\u001B[1mhello {in brackets}\u001B[22m\u001B[0m'); +}); + +test('throw if there is an unclosed block', t => { + const ctx = m.constructor({level: 3}); + try { + console.log(ctx`{bold this shouldn't appear ever\}`); + t.fail(); + } catch (err) { + t.is(err.message, 'Template literal has an unclosed block'); + } +}); + +test('throw if there is an invalid style', t => { + const ctx = m.constructor({level: 3}); + try { + console.log(ctx`{abadstylethatdoesntexist this shouldn't appear ever}`); + t.fail(); + } catch (err) { + t.is(err.message, 'Invalid Chalk style: abadstylethatdoesntexist'); + } +}); + +test('properly style multiline color blocks', t => { + const ctx = m.constructor({level: 3}); + t.is( + ctx`{bold + Hello! This is a + ${'multiline'} block! + :) + } {underline + I hope you enjoy + }`, + '\u001B[0m\u001B[1m\u001B[22m\u001B[0m\n' + + '\u001B[0m\u001B[1m\t\t\t\tHello! This is a\u001B[22m\u001B[0m\n' + + '\u001B[0m\u001B[1m\t\t\t\tmultiline block!\u001B[22m\u001B[0m\n' + + '\u001B[0m\u001B[1m\t\t\t\t:)\u001B[22m\u001B[0m\n' + + '\u001B[0m\u001B[1m\t\t\t\u001B[22m\u001B[0m\u001B[0m \u001B[0m\u001B[0m\u001B[4m\u001B[24m\u001B[0m\n' + + '\u001B[0m\u001B[4m\t\t\t\tI hope you enjoy\u001B[24m\u001B[0m\n' + + '\u001B[0m\u001B[4m\t\t\t\u001B[24m\u001B[0m' + ); +}); + +test('escape interpolated values', t => { + const ctx = m.constructor({level: 0}); + t.is(ctx`Hello {bold hi}`, 'Hello hi'); + t.is(ctx`Hello ${'{bold hi}'}`, 'Hello {bold hi}'); +}); diff --git a/test/windows.js b/test/windows.js new file mode 100644 index 0000000..2f2815e --- /dev/null +++ b/test/windows.js @@ -0,0 +1,63 @@ +import test from 'ava'; +import importFresh from 'import-fresh'; +import resolveFrom from 'resolve-from'; + +// Spoof supports-color +require('./_supports-color')(__dirname); + +let originalEnv; +let originalPlatform; + +test.before(() => { + originalEnv = process.env; + originalPlatform = process.platform; +}); + +test.after(() => { + process.env = originalEnv; + Object.defineProperty(process, 'platform', {value: originalPlatform}); +}); + +test.beforeEach(() => { + process.env = {}; + Object.defineProperty(process, 'platform', {value: 'win32'}); + // Since chalk internally modifies `ansiStyles.blue.open`, `ansi-styles` needs + // to be removed from the require cache for `require-uncached` to work + delete require.cache[resolveFrom(__dirname, 'ansi-styles')]; +}); + +test('detect a simple term if TERM isn\'t set', t => { + delete process.env.TERM; + const m = importFresh('..'); + t.is(m.blue('foo'), '\u001B[94mfoo\u001B[39m'); +}); + +test('replace blue foreground color in cmd.exe', t => { + process.env.TERM = 'dumb'; + const m = importFresh('..'); + t.is(m.blue('foo'), '\u001B[94mfoo\u001B[39m'); +}); + +test('don\'t replace blue foreground color in xterm based terminals', t => { + process.env.TERM = 'xterm-256color'; + const m = importFresh('..'); + t.is(m.blue('foo'), '\u001B[34mfoo\u001B[39m'); +}); + +test('don\'t apply dimmed styling on gray strings, see https://github.com/chalk/chalk/issues/58', t => { + process.env.TERM = 'dumb'; + const m = importFresh('..'); + t.is(m.gray.dim('foo'), '\u001B[90mfoo\u001B[22m\u001B[39m'); +}); + +test('apply dimmed styling on xterm compatible terminals', t => { + process.env.TERM = 'xterm'; + const m = importFresh('..'); + t.is(m.gray.dim('foo'), '\u001B[90m\u001B[2mfoo\u001B[22m\u001B[39m'); +}); + +test('apply dimmed styling on strings of other colors', t => { + process.env.TERM = 'dumb'; + const m = importFresh('..'); + t.is(m.blue.dim('foo'), '\u001B[94m\u001B[2mfoo\u001B[22m\u001B[39m'); +}); From 4c4ba2df3d7630fd16f0c49c4b7c923109338807 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 23 Jul 2017 22:24:56 +0200 Subject: [PATCH 057/235] Fix template literal test --- test/template-literal.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/template-literal.js b/test/template-literal.js index 0b969ba..7b37ff7 100644 --- a/test/template-literal.js +++ b/test/template-literal.js @@ -79,12 +79,12 @@ test('properly style multiline color blocks', t => { I hope you enjoy }`, '\u001B[0m\u001B[1m\u001B[22m\u001B[0m\n' + - '\u001B[0m\u001B[1m\t\t\t\tHello! This is a\u001B[22m\u001B[0m\n' + - '\u001B[0m\u001B[1m\t\t\t\tmultiline block!\u001B[22m\u001B[0m\n' + - '\u001B[0m\u001B[1m\t\t\t\t:)\u001B[22m\u001B[0m\n' + - '\u001B[0m\u001B[1m\t\t\t\u001B[22m\u001B[0m\u001B[0m \u001B[0m\u001B[0m\u001B[4m\u001B[24m\u001B[0m\n' + - '\u001B[0m\u001B[4m\t\t\t\tI hope you enjoy\u001B[24m\u001B[0m\n' + - '\u001B[0m\u001B[4m\t\t\t\u001B[24m\u001B[0m' + '\u001B[0m\u001B[1m\t\t\tHello! This is a\u001B[22m\u001B[0m\n' + + '\u001B[0m\u001B[1m\t\t\tmultiline block!\u001B[22m\u001B[0m\n' + + '\u001B[0m\u001B[1m\t\t\t:)\u001B[22m\u001B[0m\n' + + '\u001B[0m\u001B[1m\t\t\u001B[22m\u001B[0m\u001B[0m \u001B[0m\u001B[0m\u001B[4m\u001B[24m\u001B[0m\n' + + '\u001B[0m\u001B[4m\t\t\tI hope you enjoy\u001B[24m\u001B[0m\n' + + '\u001B[0m\u001B[4m\t\t\u001B[24m\u001B[0m' ); }); From 7dbd8c3993e3b2ccfa0ac0864b8266e43799461b Mon Sep 17 00:00:00 2001 From: Boris K Date: Wed, 2 Aug 2017 01:41:35 +0200 Subject: [PATCH 058/235] Add related packages in the readme (#193) Added chalk-animation as suggested by @sindresorhus Added gradient-string because it also uses chalk and provides new features. --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 3065910..dfcfdf2 100644 --- a/readme.md +++ b/readme.md @@ -291,6 +291,8 @@ If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) i - [wrap-ansi](https://github.com/chalk/wrap-ansi) - Wordwrap a string with ANSI escape codes - [slice-ansi](https://github.com/chalk/slice-ansi) - Slice a string with ANSI escape codes - [color-convert](https://github.com/qix-/color-convert) - Converts colors between different models +- [chalk-animation](https://github.com/bokub/chalk-animation) - Animate strings in the terminal +- [gradient-string](https://github.com/bokub/gradient-string) - Apply color gradients to strings ## Maintainers From 7a75399b7263bd68e3bfcded88f6624890aea01f Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Sun, 30 Jul 2017 22:41:15 -0700 Subject: [PATCH 059/235] Add failing template tests --- test/template-literal.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/template-literal.js b/test/template-literal.js index 7b37ff7..bd36109 100644 --- a/test/template-literal.js +++ b/test/template-literal.js @@ -93,3 +93,26 @@ test('escape interpolated values', t => { t.is(ctx`Hello {bold hi}`, 'Hello hi'); t.is(ctx`Hello ${'{bold hi}'}`, 'Hello {bold hi}'); }); + +test('allow custom colors (themes) on custom contexts', t => { + const ctx = m.constructor({level: 3}); + ctx.rose = ctx.hex('#F6D9D9'); + t.is(ctx`Hello, {rose Rose}.`, '\u001b[0mHello, \u001b[38;2;246;217;217mRose\u001b[38m.\u001b[0m'); +}); + +test('correctly parse newline literals (bug #184)', t => { + const ctx = m.constructor({level: 0}); + t.is(ctx`Hello +{red there}`, 'Hello\nthere'); +}); + +test('correctly parse newline escapes (bug #177)', t => { + const ctx = m.constructor({level: 0}); + t.is(ctx`Hello\nthere!`, `Hello\nthere!`); +}); + +test('correctly parse escape in parameters (bug #177 comment 318622809)', t => { + const ctx = m.constructor({level: 0}); + const str = '\\'; + t.is(ctx`{blue ${str}}`, '\\'); +}); From fbd17e7a699e7a7a1d3ebbb0ce4961b5ea172449 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Sun, 30 Jul 2017 22:41:47 -0700 Subject: [PATCH 060/235] Escape backslashes in template arguments (fixes #177) --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 87300fc..204889c 100644 --- a/index.js +++ b/index.js @@ -205,7 +205,7 @@ function chalkTag(chalk, strings) { const parts = [strings.raw[0]]; for (let i = 1; i < strings.length; i++) { - parts.push(args[i - 1].toString().replace(/[{}]/g, '\\$&')); + parts.push(args[i - 1].toString().replace(/[{}\\]/g, '\\$&')); parts.push(strings.raw[i]); } From 0827d3b6327dfd5e132589b1308703c9b4e127ef Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Sun, 30 Jul 2017 19:52:59 -0700 Subject: [PATCH 061/235] Fix level when supportsColor returns falsey (fixes #176, #175) --- index.js | 3 ++- test/level.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 204889c..94c1ae5 100644 --- a/index.js +++ b/index.js @@ -19,7 +19,8 @@ function applyOptions(obj, options) { options = options || {}; // Detect level if not set manually - obj.level = options.level === undefined ? supportsColor.level : options.level; + const scLevel = supportsColor ? supportsColor.level : 0; + obj.level = options.level === undefined ? scLevel : options.level; obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; } diff --git a/test/level.js b/test/level.js index 9caf6c4..85624ea 100644 --- a/test/level.js +++ b/test/level.js @@ -39,6 +39,6 @@ test('propagate enable/disable changes from child colors', t => { m.level = oldLevel; }); -test.failing('disable colors if they are not supported', async t => { +test('disable colors if they are not supported', async t => { t.is(await execa.stdout('node', [path.join(__dirname, '_fixture')]), 'test'); }); From f0c0178d12c4e0b2b3a3e92afb15dbabb2882b9b Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Sun, 30 Jul 2017 22:28:44 -0700 Subject: [PATCH 062/235] Allow multiple arguments in base chalk object (fixes #187) --- index.js | 7 ++++--- test/chalk.js | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 94c1ae5..ab3831c 100644 --- a/index.js +++ b/index.js @@ -197,12 +197,13 @@ function applyStyle() { } function chalkTag(chalk, strings) { - const args = [].slice.call(arguments, 2); - if (!Array.isArray(strings)) { - return strings.toString(); + // If chalk() was called by itself or with a string, + // return the string itself as a string. + return [].slice.call(arguments, 1).join(' '); } + const args = [].slice.call(arguments, 2); const parts = [strings.raw[0]]; for (let i = 1; i < strings.length; i++) { diff --git a/test/chalk.js b/test/chalk.js index 46060d4..8480dad 100644 --- a/test/chalk.js +++ b/test/chalk.js @@ -12,6 +12,10 @@ test('don\'t add any styling when called as the base function', t => { t.is(m('foo'), 'foo'); }); +test('support multiple arguments in base function', t => { + t.is(m('hello', 'there'), 'hello there'); +}); + test('style string', t => { t.is(m.underline('foo'), '\u001B[4mfoo\u001B[24m'); t.is(m.red('foo'), '\u001B[31mfoo\u001B[39m'); From 106f086aaf00467b7161f8cec4b6cd255c30169f Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Sun, 30 Jul 2017 22:36:59 -0700 Subject: [PATCH 063/235] Rewrite templating system (closes #186, fixes #184) --- templates.js | 222 +++++++++++++++++---------------------- test/template-literal.js | 79 +++++++++++--- 2 files changed, 156 insertions(+), 145 deletions(-) diff --git a/templates.js b/templates.js index 6c0a912..1015515 100644 --- a/templates.js +++ b/templates.js @@ -1,162 +1,128 @@ 'use strict'; +const TEMPLATE_REGEX = /(?:\\(u[a-f0-9]{4}|x[a-f0-9]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; +const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; +const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; +const ESCAPE_REGEX = /\\(u[0-9a-f]{4}|x[0-9a-f]{2}|.)|([^\\])/gi; -function data(parent) { - return { - styles: [], - parent, - contents: [] - }; +const ESCAPES = { + n: '\n', + r: '\r', + t: '\t', + b: '\b', + f: '\f', + v: '\v', + 0: '\0', + '\\': '\\', + e: '\u001b', + a: '\u0007' +}; + +function unescape(c) { + if ((c[0] === 'u' && c.length === 5) || (c[0] === 'x' && c.length === 3)) { + return String.fromCharCode(parseInt(c.slice(1), 16)); + } + + return ESCAPES[c] || c; } -const zeroBound = n => n < 0 ? 0 : n; -const lastIndex = a => zeroBound(a.length - 1); +function parseArguments(name, args) { + const results = []; + const chunks = args.trim().split(/\s*,\s*/g); + let matches; -const last = a => a[lastIndex(a)]; - -const takeWhileReverse = (array, predicate, start) => { - const out = []; - - for (let i = start; i >= 0 && i <= start; i--) { - if (predicate(array[i])) { - out.unshift(array[i]); + for (const chunk of chunks) { + if (!isNaN(chunk)) { + results.push(Number(chunk)); + } else if ((matches = chunk.match(STRING_REGEX))) { + results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, chr) => escape ? unescape(escape) : chr)); } else { - break; + throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); } } - return out; -}; + return results; +} -// Check if the character at position `i` in string is a normal character (non-control character) -const isNormalCharacter = (string, i) => { - const char = string[i]; - const backslash = '\\'; +function parseStyle(style) { + STYLE_REGEX.lastIndex = 0; - if (!(char === backslash || char === '{' || char === '}')) { - return true; - } + const results = []; + let matches; - const n = i === 0 ? 0 : takeWhileReverse(string, x => x === '\\', zeroBound(i - 1)).length; + while ((matches = STYLE_REGEX.exec(style)) !== null) { + const name = matches[1]; - return n % 2 === 1; -}; - -const collectStyles = data => data ? collectStyles(data.parent).concat(data.styles) : ['reset']; - -// Compute the style for a given data based on its style and the style of its parent. -// Also accounts for `!style` styles which remove a style from the list if present. -const sumStyles = data => { - const negateRegex = /^~.+/; - let out = []; - - for (const style of collectStyles(data)) { - if (negateRegex.test(style)) { - const exclude = style.slice(1); - out = out.filter(x => x !== exclude); + if (matches[2]) { + const args = parseArguments(name, matches[2]); + results.push([name].concat(args)); } else { - out.push(style); + results.push([name]); } } - return out; -}; + return results; +} -// Take a string and parse it into a tree of data objects which inherit styles from their parent -function parse(string) { - const root = data(null); - let pushingStyle = false; - let current = root; +function buildStyle(chalk, styles) { + const enabled = {}; - for (let i = 0; i < string.length; i++) { - const char = string[i]; + for (const layer of styles) { + for (const style of layer.styles) { + enabled[style[0]] = layer.inverse ? null : style.slice(1); + } + } - const addNormalCharacter = () => { - const lastChunk = last(current.contents); - - if (typeof lastChunk === 'string') { - current.contents[lastIndex(current.contents)] = lastChunk + char; - } else { - current.contents.push(char); + let current = chalk; + for (const styleName of Object.keys(enabled)) { + if (Array.isArray(enabled[styleName])) { + if (!(styleName in current)) { + throw new Error(`Unknown Chalk style: ${styleName}`); } - }; - if (pushingStyle) { - if (' \t'.includes(char)) { - pushingStyle = false; - } else if (char === '\n') { - pushingStyle = false; - addNormalCharacter(); - } else if (char === '.') { - current.styles.push(''); + if (enabled[styleName].length > 0) { + current = current[styleName].apply(current, enabled[styleName]); } else { - current.styles[lastIndex(current.styles)] = (last(current.styles) || '') + char; + current = current[styleName]; } - } else if (isNormalCharacter(string, i)) { - addNormalCharacter(); - } else if (char === '{') { - pushingStyle = true; - const nCurrent = data(current); - current.contents.push(nCurrent); - current = nCurrent; - } else if (char === '}') { - current = current.parent; } } - if (current !== root) { - throw new Error('Template literal has an unclosed block'); - } - - return root; + return current; } -// Take a tree of data objects and flatten it to a list of data -// objects with the inherited and negations styles accounted for -function flatten(data) { - let flat = []; +module.exports = (chalk, tmp) => { + const styles = []; + const chunks = []; + let chunk = []; - for (const content of data.contents) { - if (typeof content === 'string') { - flat.push({ - styles: sumStyles(data), - content - }); + // eslint-disable-next-line max-params + tmp.replace(TEMPLATE_REGEX, (m, escapeChar, inverse, style, close, chr) => { + if (escapeChar) { + chunk.push(unescape(escapeChar)); + } else if (style) { + const str = chunk.join(''); + chunk = []; + chunks.push(styles.length === 0 ? str : buildStyle(chalk, styles)(str)); + styles.push({inverse, styles: parseStyle(style)}); + } else if (close) { + if (styles.length === 0) { + throw new Error('Found extraneous } in Chalk template literal'); + } + + chunks.push(buildStyle(chalk, styles)(chunk.join(''))); + chunk = []; + styles.pop(); } else { - flat = flat.concat(flatten(content)); + chunk.push(chr); } + }); + + chunks.push(chunk.join('')); + + if (styles.length > 0) { + const errMsg = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`; + throw new Error(errMsg); } - return flat; -} - -function assertStyle(chalk, style) { - if (!chalk[style]) { - throw new Error(`Invalid Chalk style: ${style}`); - } -} - -// Check if a given style is valid and parse style functions -function parseStyle(chalk, style) { - const fnMatch = style.match(/^\s*(\w+)\s*\(\s*([^)]*)\s*\)\s*/); - if (!fnMatch) { - assertStyle(chalk, style); - return chalk[style]; - } - - const name = fnMatch[1].trim(); - const args = fnMatch[2].split(/,/g).map(s => s.trim()); - - assertStyle(chalk, name); - - return chalk[name].apply(chalk, args); -} - -// Perform the actual styling of the string -function style(chalk, flat) { - return flat.map(data => { - const fn = data.styles.reduce(parseStyle, chalk); - return fn(data.content.replace(/\n$/, '')); - }).join(''); -} - -module.exports = (chalk, string) => style(chalk, flatten(parse(string))); + return chunks.join(''); +}; diff --git a/test/template-literal.js b/test/template-literal.js index bd36109..6ab17a6 100644 --- a/test/template-literal.js +++ b/test/template-literal.js @@ -32,20 +32,20 @@ test('correctly perform template substitutions', t => { test('correctly parse and evaluate color-convert functions', t => { const ctx = m.constructor({level: 3}); t.is(ctx`{bold.rgb(144,10,178).inverse Hello, {~inverse there!}}`, - '\u001B[0m\u001B[1m\u001B[38;2;144;10;178m\u001B[7mHello, ' + - '\u001B[27m\u001B[39m\u001B[22m\u001B[0m\u001B[0m\u001B[1m' + - '\u001B[38;2;144;10;178mthere!\u001B[39m\u001B[22m\u001B[0m'); + '\u001B[1m\u001B[38;2;144;10;178m\u001B[7mHello, ' + + '\u001B[27m\u001B[39m\u001B[22m\u001B[1m' + + '\u001B[38;2;144;10;178mthere!\u001B[39m\u001B[22m'); t.is(ctx`{bold.bgRgb(144,10,178).inverse Hello, {~inverse there!}}`, - '\u001B[0m\u001B[1m\u001B[48;2;144;10;178m\u001B[7mHello, ' + - '\u001B[27m\u001B[49m\u001B[22m\u001B[0m\u001B[0m\u001B[1m' + - '\u001B[48;2;144;10;178mthere!\u001B[49m\u001B[22m\u001B[0m'); + '\u001B[1m\u001B[48;2;144;10;178m\u001B[7mHello, ' + + '\u001B[27m\u001B[49m\u001B[22m\u001B[1m' + + '\u001B[48;2;144;10;178mthere!\u001B[49m\u001B[22m'); }); test('properly handle escapes', t => { const ctx = m.constructor({level: 3}); t.is(ctx`{bold hello \{in brackets\}}`, - '\u001B[0m\u001B[1mhello {in brackets}\u001B[22m\u001B[0m'); + '\u001B[1mhello {in brackets}\u001B[22m'); }); test('throw if there is an unclosed block', t => { @@ -54,7 +54,14 @@ test('throw if there is an unclosed block', t => { console.log(ctx`{bold this shouldn't appear ever\}`); t.fail(); } catch (err) { - t.is(err.message, 'Template literal has an unclosed block'); + t.is(err.message, 'Chalk template literal is missing 1 closing bracket (`}`)'); + } + + try { + console.log(ctx`{bold this shouldn't {inverse appear {underline ever\} :) \}`); + t.fail(); + } catch (err) { + t.is(err.message, 'Chalk template literal is missing 3 closing brackets (`}`)'); } }); @@ -64,7 +71,7 @@ test('throw if there is an invalid style', t => { console.log(ctx`{abadstylethatdoesntexist this shouldn't appear ever}`); t.fail(); } catch (err) { - t.is(err.message, 'Invalid Chalk style: abadstylethatdoesntexist'); + t.is(err.message, 'Unknown Chalk style: abadstylethatdoesntexist'); } }); @@ -78,13 +85,13 @@ test('properly style multiline color blocks', t => { } {underline I hope you enjoy }`, - '\u001B[0m\u001B[1m\u001B[22m\u001B[0m\n' + - '\u001B[0m\u001B[1m\t\t\tHello! This is a\u001B[22m\u001B[0m\n' + - '\u001B[0m\u001B[1m\t\t\tmultiline block!\u001B[22m\u001B[0m\n' + - '\u001B[0m\u001B[1m\t\t\t:)\u001B[22m\u001B[0m\n' + - '\u001B[0m\u001B[1m\t\t\u001B[22m\u001B[0m\u001B[0m \u001B[0m\u001B[0m\u001B[4m\u001B[24m\u001B[0m\n' + - '\u001B[0m\u001B[4m\t\t\tI hope you enjoy\u001B[24m\u001B[0m\n' + - '\u001B[0m\u001B[4m\t\t\u001B[24m\u001B[0m' + '\u001B[1m\u001B[22m\n' + + '\u001B[1m\t\t\tHello! This is a\u001B[22m\n' + + '\u001B[1m\t\t\tmultiline block!\u001B[22m\n' + + '\u001B[1m\t\t\t:)\u001B[22m\n' + + '\u001B[1m\t\t\u001B[22m \u001B[4m\u001B[24m\n' + + '\u001B[4m\t\t\tI hope you enjoy\u001B[24m\n' + + '\u001B[4m\t\t\u001B[24m' ); }); @@ -97,7 +104,7 @@ test('escape interpolated values', t => { test('allow custom colors (themes) on custom contexts', t => { const ctx = m.constructor({level: 3}); ctx.rose = ctx.hex('#F6D9D9'); - t.is(ctx`Hello, {rose Rose}.`, '\u001b[0mHello, \u001b[38;2;246;217;217mRose\u001b[38m.\u001b[0m'); + t.is(ctx`Hello, {rose Rose}.`, 'Hello, \u001B[38;2;246;217;217mRose\u001B[39m.'); }); test('correctly parse newline literals (bug #184)', t => { @@ -116,3 +123,41 @@ test('correctly parse escape in parameters (bug #177 comment 318622809)', t => { const str = '\\'; t.is(ctx`{blue ${str}}`, '\\'); }); + +test('correctly parses unicode/hex escapes', t => { + const ctx = m.constructor({level: 0}); + t.is(ctx`\u0078ylophones are fo\x78y! {magenta.inverse \u0078ylophones are fo\x78y!}`, + 'xylophones are foxy! xylophones are foxy!'); +}); + +test('correctly parses string arguments', t => { + const ctx = m.constructor({level: 3}); + t.is(ctx`{keyword('black').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); + t.is(ctx`{keyword('blac\x6B').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); + t.is(ctx`{keyword('blac\u006B').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 ctx = m.constructor({level: 3}); // Keep level at least 1 in case we optimize for disabled chalk instances + try { + console.log(ctx`{keyword(????) hi}`); + t.fail(); + } catch (err) { + t.is(err.message, 'Invalid Chalk template style argument: ???? (in style \'keyword\')'); + } +}); + +test('throws if an extra unescaped } is found', t => { + const ctx = m.constructor({level: 0}); + try { + console.log(ctx`{red hi!}}`); + t.fail(); + } catch (err) { + t.is(err.message, 'Found extraneous } in Chalk template literal'); + } +}); + +test('should not parse upper-case escapes', t => { + const ctx = m.constructor({level: 0}); + t.is(ctx`\N\n\T\t\X07\x07\U000A\u000A\U000a\u000a`, 'N\nT\tX07\x07U000A\u000AU000a\u000A'); +}); From 69ac663f29e92d309b0b221e117ccb6be4ed4ecd Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Tue, 1 Aug 2017 18:55:54 -0700 Subject: [PATCH 064/235] Fix undefined and null interpolated expressions (fixes #194) --- index.js | 4 ++-- test/template-literal.js | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index ab3831c..4c81d6d 100644 --- a/index.js +++ b/index.js @@ -207,8 +207,8 @@ function chalkTag(chalk, strings) { const parts = [strings.raw[0]]; for (let i = 1; i < strings.length; i++) { - parts.push(args[i - 1].toString().replace(/[{}\\]/g, '\\$&')); - parts.push(strings.raw[i]); + parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); + parts.push(String(strings.raw[i])); } return template(chalk, parts.join('')); diff --git a/test/template-literal.js b/test/template-literal.js index 6ab17a6..bfa346c 100644 --- a/test/template-literal.js +++ b/test/template-literal.js @@ -161,3 +161,9 @@ test('should not parse upper-case escapes', t => { const ctx = m.constructor({level: 0}); t.is(ctx`\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 ctx = m.constructor({level: 0}); + t.is(ctx`hello ${undefined}`, 'hello undefined'); + t.is(ctx`hello ${null}`, 'hello null'); +}); From 38f641a222d7ee0e607e4e5209d3931d2af1e409 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Sun, 6 Aug 2017 20:51:22 -0700 Subject: [PATCH 065/235] v2.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 07ed8ed..a257127 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "2.0.1", + "version": "2.1.0", "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk", From a9f0c771422b0bae65d3ff1ae4835de416350715 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 7 Aug 2017 17:41:16 +0200 Subject: [PATCH 066/235] Use a `Map` and some minor regex tweaks --- package.json | 2 +- templates.js | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index a257127..a3152ee 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "devDependencies": { "ava": "*", "coveralls": "^2.11.2", - "execa": "^0.7.0", + "execa": "^0.8.0", "import-fresh": "^2.0.0", "matcha": "^0.7.0", "nyc": "^11.0.2", diff --git a/templates.js b/templates.js index 1015515..dbdf9b2 100644 --- a/templates.js +++ b/templates.js @@ -1,28 +1,28 @@ 'use strict'; -const TEMPLATE_REGEX = /(?:\\(u[a-f0-9]{4}|x[a-f0-9]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; +const TEMPLATE_REGEX = /(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; -const ESCAPE_REGEX = /\\(u[0-9a-f]{4}|x[0-9a-f]{2}|.)|([^\\])/gi; +const ESCAPE_REGEX = /\\(u[a-f\d]{4}|x[a-f\d]{2}|.)|([^\\])/gi; -const ESCAPES = { - n: '\n', - r: '\r', - t: '\t', - b: '\b', - f: '\f', - v: '\v', - 0: '\0', - '\\': '\\', - e: '\u001b', - a: '\u0007' -}; +const ESCAPES = new Map([ + ['n', '\n'], + ['r', '\r'], + ['t', '\t'], + ['b', '\b'], + ['f', '\f'], + ['v', '\v'], + ['0', '\0'], + ['\\', '\\'], + ['e', '\u001B'], + ['a', '\u0007'] +]); function unescape(c) { if ((c[0] === 'u' && c.length === 5) || (c[0] === 'x' && c.length === 3)) { return String.fromCharCode(parseInt(c.slice(1), 16)); } - return ESCAPES[c] || c; + return ESCAPES.get(c) || c; } function parseArguments(name, args) { From 37db75e1fd6efaabda7e7ba7751d359a34ab75cd Mon Sep 17 00:00:00 2001 From: LitoMore Date: Thu, 24 Aug 2017 02:58:45 +0800 Subject: [PATCH 067/235] Add related package in the readme --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index dfcfdf2..8c9609c 100644 --- a/readme.md +++ b/readme.md @@ -293,6 +293,7 @@ If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) i - [color-convert](https://github.com/qix-/color-convert) - Converts colors between different models - [chalk-animation](https://github.com/bokub/chalk-animation) - Animate strings in the terminal - [gradient-string](https://github.com/bokub/gradient-string) - Apply color gradients to strings +- [chalk-pipe](https://github.com/LitoMore/chalk-pipe) - Create chalk scheme with a style pipe ## Maintainers From 7898eda561759850852fe63ba0895a49fe5b4b72 Mon Sep 17 00:00:00 2001 From: LitoMore Date: Thu, 24 Aug 2017 09:04:07 +0800 Subject: [PATCH 068/235] Update chalk-pipe description --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 8c9609c..ea7540a 100644 --- a/readme.md +++ b/readme.md @@ -293,7 +293,7 @@ If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) i - [color-convert](https://github.com/qix-/color-convert) - Converts colors between different models - [chalk-animation](https://github.com/bokub/chalk-animation) - Animate strings in the terminal - [gradient-string](https://github.com/bokub/gradient-string) - Apply color gradients to strings -- [chalk-pipe](https://github.com/LitoMore/chalk-pipe) - Create chalk scheme with a style pipe +- [chalk-pipe](https://github.com/LitoMore/chalk-pipe) - Create chalk style schemes with simpler style strings ## Maintainers From 5e6d5fda44aa08e24a6b279bc16caf148c28e2db Mon Sep 17 00:00:00 2001 From: Kevin Martensson Date: Wed, 20 Sep 2017 18:03:52 +0200 Subject: [PATCH 069/235] Add `strip-ansi-stream` to related modules --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index ea7540a..7158d5a 100644 --- a/readme.md +++ b/readme.md @@ -286,6 +286,7 @@ If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) i - [ansi-styles](https://github.com/chalk/ansi-styles) - ANSI escape codes for styling strings in the terminal - [supports-color](https://github.com/chalk/supports-color) - Detect whether a terminal supports color - [strip-ansi](https://github.com/chalk/strip-ansi) - Strip ANSI escape codes +- [strip-ansi-stream](https://github.com/chalk/strip-ansi-stream) - Strip ANSI escape codes from a stream - [has-ansi](https://github.com/chalk/has-ansi) - Check if a string has ANSI escape codes - [ansi-regex](https://github.com/chalk/ansi-regex) - Regular expression for matching ANSI escape codes - [wrap-ansi](https://github.com/chalk/wrap-ansi) - Wordwrap a string with ANSI escape codes From f653b061d6fbdb1c7224f7d80476391202c47877 Mon Sep 17 00:00:00 2001 From: calebboyd Date: Tue, 17 Oct 2017 22:10:43 -0500 Subject: [PATCH 070/235] Add TypeScript definitions (#207) --- index.js | 1 + package.json | 7 +++- types/index.d.ts | 90 +++++++++++++++++++++++++++++++++++++++++++++ types/test.ts | 47 +++++++++++++++++++++++ types/tsconfig.json | 9 +++++ 5 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 types/index.d.ts create mode 100644 types/test.ts create mode 100644 types/tsconfig.json diff --git a/index.js b/index.js index 4c81d6d..de65bd4 100644 --- a/index.js +++ b/index.js @@ -218,3 +218,4 @@ Object.defineProperties(Chalk.prototype, styles); module.exports = Chalk(); // eslint-disable-line new-cap module.exports.supportsColor = supportsColor; +module.exports.default = module.exports; // For TypeScript diff --git a/package.json b/package.json index a3152ee..084aea6 100644 --- a/package.json +++ b/package.json @@ -8,13 +8,14 @@ "node": ">=4" }, "scripts": { - "test": "xo && nyc ava", + "test": "xo && tsc --project types && nyc ava", "bench": "matcha benchmark.js", "coveralls": "nyc report --reporter=text-lcov | coveralls" }, "files": [ "index.js", - "templates.js" + "templates.js", + "types/index.d.ts" ], "keywords": [ "color", @@ -52,8 +53,10 @@ "matcha": "^0.7.0", "nyc": "^11.0.2", "resolve-from": "^3.0.0", + "typescript": "^2.5.3", "xo": "*" }, + "types": "types/index.d.ts", "xo": { "envs": [ "node", diff --git a/types/index.d.ts b/types/index.d.ts new file mode 100644 index 0000000..7505746 --- /dev/null +++ b/types/index.d.ts @@ -0,0 +1,90 @@ +// Type definitions for Chalk +// Definitions by: Thomas Sauer + +export const enum Level { + None = 0, + Basic = 1, + Ansi256 = 2, + TrueColor = 3 +} + +export interface ChalkOptions { + enabled?: boolean; + level?: Level; +} + +export interface Chalk { + new (options?: ChalkOptions): Chalk; + (options?: ChalkOptions): Chalk; + (...text: string[]): string; + (text: TemplateStringsArray, ...placeholders: string[]): string; + constructor: Chalk; + enabled: boolean; + level: Level; + supportsColor: { + level: Level; + hasBasic: boolean; + has256: boolean; + has16m: boolean; + }; + rgb(r: number, g: number, b: number): Chalk; + hsl(h: number, s: number, l: number): Chalk; + hsv(h: number, s: number, v: number): Chalk; + hwb(h: number, w: number, b: number): Chalk; + bgHex(color: string): Chalk; + bgKeyword(color: string): Chalk; + bgRgb(r: number, g: number, b: number): Chalk; + bgHsl(h: number, s: number, l: number): Chalk; + bgHsv(h: number, s: number, v: number): Chalk; + bgHwb(h: number, w: number, b: number): Chalk; + hex(color: string): Chalk; + keyword(color: string): Chalk; + + reset: Chalk; + bold: Chalk; + dim: Chalk; + italic: Chalk; + underline: Chalk; + inverse: Chalk; + hidden: Chalk; + strikethrough: Chalk; + + black: Chalk; + red: Chalk; + green: Chalk; + yellow: Chalk; + blue: Chalk; + magenta: Chalk; + cyan: Chalk; + white: Chalk; + gray: Chalk; + grey: Chalk; + blackBright: Chalk; + redBright: Chalk; + greenBright: Chalk; + yellowBright: Chalk; + blueBright: Chalk; + magentaBright: Chalk; + cyanBright: Chalk; + whiteBright: Chalk; + + bgBlack: Chalk; + bgRed: Chalk; + bgGreen: Chalk; + bgYellow: Chalk; + bgBlue: Chalk; + bgMagenta: Chalk; + bgCyan: Chalk; + bgWhite: Chalk; + bgBlackBright: Chalk; + bgRedBright: Chalk; + bgGreenBright: Chalk; + bgYellowBright: Chalk; + bgBlueBright: Chalk; + bgMagentaBright: Chalk; + bgCyanBright: Chalk; + bgWhiteBright: Chalk; +} + +declare function chalk (): any; +export default chalk as Chalk; diff --git a/types/test.ts b/types/test.ts new file mode 100644 index 0000000..01509fd --- /dev/null +++ b/types/test.ts @@ -0,0 +1,47 @@ +import chalk, {Level} from '..'; + +chalk.underline('foo'); +chalk.red('foo'); +chalk.bgRed('foo'); + +const name = 'Josh'; +chalk`Hello {bold.red ${name}}`; + +chalk.red`foo`; +chalk.underline`foo`; +chalk`foo`; + +chalk.red.bgGreen.underline('foo'); +chalk.underline.red.bgGreen('foo'); + +chalk.grey('foo'); + +chalk.constructor({level: 1}); +const ctx = chalk.constructor({level: Level.TrueColor }); +ctx('foo'); +ctx.red('foo'); +ctx`foo`; + +chalk.enabled = true; +chalk.level = 1; +chalk.level = Level.Ansi256; + +chalk.level === Level.Ansi256; + +let chalkInstance = new chalk(); +chalkInstance = new chalk.constructor(); +chalkInstance = chalk.constructor(); + +chalk.enabled; +chalk.level; +chalk.supportsColor.level; +chalk.supportsColor.has16m; +chalk.supportsColor.has256; +chalk.supportsColor.hasBasic; + +chalk.keyword('orange').bgBlue('foo'); +chalk.hex('#123456').bgBlue('foo'); +chalk.rgb(1, 14, 9).bgBlue('foo'); +chalk.hsl(1, 14, 9).bgBlue('foo'); +chalk.hsv(1, 14, 9).bgBlue('foo'); +chalk.hwb(1, 14, 9).bgBlue('foo'); diff --git a/types/tsconfig.json b/types/tsconfig.json new file mode 100644 index 0000000..b73840f --- /dev/null +++ b/types/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "noImplicitAny": true, + "noEmit": true, + "allowJs": true + } +} From f0533f655d237f04ec1b8744e45de60c42a7bee2 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 18 Oct 2017 10:14:40 +0700 Subject: [PATCH 071/235] Bump dev dependencies --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 084aea6..2cd5a4e 100644 --- a/package.json +++ b/package.json @@ -47,12 +47,12 @@ }, "devDependencies": { "ava": "*", - "coveralls": "^2.11.2", + "coveralls": "^3.0.0", "execa": "^0.8.0", "import-fresh": "^2.0.0", "matcha": "^0.7.0", "nyc": "^11.0.2", - "resolve-from": "^3.0.0", + "resolve-from": "^4.0.0", "typescript": "^2.5.3", "xo": "*" }, From d86db88e778fa856f4d6f5f68c588750ca06b822 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 18 Oct 2017 10:15:39 +0700 Subject: [PATCH 072/235] 2.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2cd5a4e..426092f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "2.1.0", + "version": "2.2.0", "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk", From 4372d27f7eb887c4d33cdca1f9484f321ceab3dd Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 22 Oct 2017 15:20:23 +0700 Subject: [PATCH 073/235] Add Awesome mentioned badge --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 7158d5a..9423ebc 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) [![](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/sindresorhus/xo) +[![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) [![](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/sindresorhus/xo) [![Mentioned in Awesome Node.js](https://awesome.re/mentioned-badge.svg)](https://github.com/sindresorhus/awesome-nodejs) ### [See what's new in Chalk 2](https://github.com/chalk/chalk/releases/tag/v2.0.0) From dc092b4a5f5ca77dd1e22607cdf2fdd388803064 Mon Sep 17 00:00:00 2001 From: Danny Kirchmeier Date: Mon, 23 Oct 2017 20:39:21 -0500 Subject: [PATCH 074/235] Add .visible for emitting text only when enabled (fixes #192) --- index.js | 10 +++++++++- readme.md | 1 + test/visible.js | 24 ++++++++++++++++++++++++ types/index.d.ts | 2 ++ types/test.ts | 4 ++++ 5 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 test/visible.js diff --git a/index.js b/index.js index de65bd4..861908c 100644 --- a/index.js +++ b/index.js @@ -63,6 +63,13 @@ for (const key of Object.keys(ansiStyles)) { }; } +styles.visible = { + get() { + this._emptyIfNotVisible = true; + return build.call(this, this._styles ? this._styles : [], 'visible'); + } +}; + ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); for (const model of Object.keys(ansiStyles.color.ansi)) { if (skipModels.has(model)) { @@ -116,6 +123,7 @@ function build(_styles, key) { }; builder._styles = _styles; + builder._emptyIfNotVisible = this._emptyIfNotVisible; const self = this; @@ -167,7 +175,7 @@ function applyStyle() { } if (!this.enabled || this.level <= 0 || !str) { - return str; + return this._emptyIfNotVisible ? '' : str; } // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, diff --git a/readme.md b/readme.md index 9423ebc..9bb2e65 100644 --- a/readme.md +++ b/readme.md @@ -170,6 +170,7 @@ Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color= - `inverse` - `hidden` - `strikethrough` *(Not widely supported)* +- `visible` (Text is emitted only if enabled) ### Colors diff --git a/test/visible.js b/test/visible.js new file mode 100644 index 0000000..20f7ecb --- /dev/null +++ b/test/visible.js @@ -0,0 +1,24 @@ +import test from 'ava'; + +// Spoof supports-color +require('./_supports-color')(__dirname); + +const m = require('..'); + +test('visible: normal output when enabled', t => { + const ctx = new m.constructor({level: 3, enabled: true}); + t.is(ctx.visible.red('foo'), '\u001B[31mfoo\u001B[39m'); + t.is(ctx.red.visible('foo'), '\u001B[31mfoo\u001B[39m'); +}); + +test('visible: no output when disabled', t => { + const ctx = new m.constructor({level: 3, enabled: false}); + t.is(ctx.red.visible('foo'), ''); + t.is(ctx.visible.red('foo'), ''); +}); + +test('visible: no output when level is too low', t => { + const ctx = new m.constructor({level: 0, enabled: true}); + t.is(ctx.visible.red('foo'), ''); + t.is(ctx.red.visible('foo'), ''); +}); diff --git a/types/index.d.ts b/types/index.d.ts index 7505746..9312e2d 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -49,6 +49,8 @@ export interface Chalk { hidden: Chalk; strikethrough: Chalk; + visible: Chalk; + black: Chalk; red: Chalk; green: Chalk; diff --git a/types/test.ts b/types/test.ts index 01509fd..63ca1e9 100644 --- a/types/test.ts +++ b/types/test.ts @@ -45,3 +45,7 @@ chalk.rgb(1, 14, 9).bgBlue('foo'); chalk.hsl(1, 14, 9).bgBlue('foo'); chalk.hsv(1, 14, 9).bgBlue('foo'); chalk.hwb(1, 14, 9).bgBlue('foo'); + +chalk.visible('foo'); +chalk.red.visible('foo'); +chalk.visible.red('foo'); From 6adf5794a38552923ea474c4b60c372ef0582035 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Mon, 23 Oct 2017 19:46:10 -0700 Subject: [PATCH 075/235] 2.2.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 426092f..d4cfc50 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "2.2.0", + "version": "2.2.1", "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk", From ede310303b9893146bd7cc24261a50e3b47c633a Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Mon, 23 Oct 2017 19:53:26 -0700 Subject: [PATCH 076/235] add failing test for .visible bug --- test/visible.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/visible.js b/test/visible.js index 20f7ecb..5d53bce 100644 --- a/test/visible.js +++ b/test/visible.js @@ -22,3 +22,26 @@ test('visible: no output when level is too low', t => { t.is(ctx.visible.red('foo'), ''); t.is(ctx.red.visible('foo'), ''); }); + +test('test switching back and forth between enabled and disabled', t => { + const ctx = new m.constructor({level: 3, enabled: true}); + t.is(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); + t.is(ctx.visible.red('foo'), '\u001B[31mfoo\u001B[39m'); + t.is(ctx.red.visible('foo'), '\u001B[31mfoo\u001B[39m'); + t.is(ctx.visible('foo'), 'foo'); + t.is(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); + + ctx.enabled = false; + t.is(ctx.red('foo'), 'foo'); + t.is(ctx.visible('foo'), ''); + t.is(ctx.visible.red('foo'), ''); + t.is(ctx.red.visible('foo'), ''); + t.is(ctx.red('foo'), 'foo'); + + ctx.enabled = true; + t.is(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); + t.is(ctx.visible.red('foo'), '\u001B[31mfoo\u001B[39m'); + t.is(ctx.red.visible('foo'), '\u001B[31mfoo\u001B[39m'); + t.is(ctx.visible('foo'), 'foo'); + t.is(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); +}); From e2a4aa427568ff1c5d649739c4d1f8319cf0d072 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Mon, 23 Oct 2017 20:12:34 -0700 Subject: [PATCH 077/235] fix .visible when called after .enable is set to false --- index.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index 861908c..05e62b3 100644 --- a/index.js +++ b/index.js @@ -58,15 +58,14 @@ for (const key of Object.keys(ansiStyles)) { styles[key] = { get() { const codes = ansiStyles[key]; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], key); + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); } }; } styles.visible = { get() { - this._emptyIfNotVisible = true; - return build.call(this, this._styles ? this._styles : [], 'visible'); + return build.call(this, this._styles || [], true, 'visible'); } }; @@ -86,7 +85,7 @@ for (const model of Object.keys(ansiStyles.color.ansi)) { close: ansiStyles.color.close, closeRe: ansiStyles.color.closeRe }; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], model); + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); }; } }; @@ -109,7 +108,7 @@ for (const model of Object.keys(ansiStyles.bgColor.ansi)) { close: ansiStyles.bgColor.close, closeRe: ansiStyles.bgColor.closeRe }; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], model); + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); }; } }; @@ -117,13 +116,13 @@ for (const model of Object.keys(ansiStyles.bgColor.ansi)) { const proto = Object.defineProperties(() => {}, styles); -function build(_styles, key) { +function build(_styles, _empty, key) { const builder = function () { return applyStyle.apply(builder, arguments); }; builder._styles = _styles; - builder._emptyIfNotVisible = this._emptyIfNotVisible; + builder._empty = _empty; const self = this; @@ -175,7 +174,7 @@ function applyStyle() { } if (!this.enabled || this.level <= 0 || !str) { - return this._emptyIfNotVisible ? '' : str; + return this._empty ? '' : str; } // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, From e1177ec3628f6d0d37489c1e1accd2c389a376a8 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Mon, 23 Oct 2017 20:15:51 -0700 Subject: [PATCH 078/235] 2.2.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d4cfc50..7a9edde 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "2.2.1", + "version": "2.2.2", "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk", From 7be154c074026f77b99e7d854b3a4cdd5e4ae502 Mon Sep 17 00:00:00 2001 From: calebboyd Date: Mon, 23 Oct 2017 23:02:36 -0500 Subject: [PATCH 079/235] TypeScript fixes (#217) --- types/index.d.ts | 151 ++++++++++++++++++++++++----------------------- types/test.ts | 9 ++- 2 files changed, 85 insertions(+), 75 deletions(-) diff --git a/types/index.d.ts b/types/index.d.ts index 9312e2d..b4e4dc5 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -13,80 +13,85 @@ export interface ChalkOptions { level?: Level; } -export interface Chalk { +export interface ChalkConstructor { new (options?: ChalkOptions): Chalk; (options?: ChalkOptions): Chalk; - (...text: string[]): string; - (text: TemplateStringsArray, ...placeholders: string[]): string; - constructor: Chalk; - enabled: boolean; - level: Level; - supportsColor: { - level: Level; - hasBasic: boolean; - has256: boolean; - has16m: boolean; - }; - rgb(r: number, g: number, b: number): Chalk; - hsl(h: number, s: number, l: number): Chalk; - hsv(h: number, s: number, v: number): Chalk; - hwb(h: number, w: number, b: number): Chalk; - bgHex(color: string): Chalk; - bgKeyword(color: string): Chalk; - bgRgb(r: number, g: number, b: number): Chalk; - bgHsl(h: number, s: number, l: number): Chalk; - bgHsv(h: number, s: number, v: number): Chalk; - bgHwb(h: number, w: number, b: number): Chalk; - hex(color: string): Chalk; - keyword(color: string): Chalk; - - reset: Chalk; - bold: Chalk; - dim: Chalk; - italic: Chalk; - underline: Chalk; - inverse: Chalk; - hidden: Chalk; - strikethrough: Chalk; - - visible: Chalk; - - black: Chalk; - red: Chalk; - green: Chalk; - yellow: Chalk; - blue: Chalk; - magenta: Chalk; - cyan: Chalk; - white: Chalk; - gray: Chalk; - grey: Chalk; - blackBright: Chalk; - redBright: Chalk; - greenBright: Chalk; - yellowBright: Chalk; - blueBright: Chalk; - magentaBright: Chalk; - cyanBright: Chalk; - whiteBright: Chalk; - - bgBlack: Chalk; - bgRed: Chalk; - bgGreen: Chalk; - bgYellow: Chalk; - bgBlue: Chalk; - bgMagenta: Chalk; - bgCyan: Chalk; - bgWhite: Chalk; - bgBlackBright: Chalk; - bgRedBright: Chalk; - bgGreenBright: Chalk; - bgYellowBright: Chalk; - bgBlueBright: Chalk; - bgMagentaBright: Chalk; - bgCyanBright: Chalk; - bgWhiteBright: Chalk; } -declare function chalk (): any; -export default chalk as Chalk; +export interface ColorSupport { + level: Level; + hasBasic: boolean; + has256: boolean; + has16m: boolean; +} + +export interface Chalk { + (...text: string[]): string; + (text: TemplateStringsArray, ...placeholders: string[]): string; + constructor: ChalkConstructor; + enabled: boolean; + level: Level; + rgb(r: number, g: number, b: number): this; + hsl(h: number, s: number, l: number): this; + hsv(h: number, s: number, v: number): this; + hwb(h: number, w: number, b: number): this; + bgHex(color: string): this; + bgKeyword(color: string): this; + bgRgb(r: number, g: number, b: number): this; + bgHsl(h: number, s: number, l: number): this; + bgHsv(h: number, s: number, v: number): this; + bgHwb(h: number, w: number, b: number): this; + hex(color: string): this; + keyword(color: string): this; + + readonly reset: this; + readonly bold: this; + readonly dim: this; + readonly italic: this; + readonly underline: this; + readonly inverse: this; + readonly hidden: this; + readonly strikethrough: this; + + 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; + readonly gray: this; + 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; + readonly bgBlackBright: this; + readonly bgRedBright: this; + readonly bgGreenBright: this; + readonly bgYellowBright: this; + readonly bgBlueBright: this; + readonly bgMagentaBright: this; + readonly bgCyanBright: this; + readonly bgWhiteBright: this; +} + +declare const chalk: Chalk & { supportsColor: ColorSupport }; + +export default chalk diff --git a/types/test.ts b/types/test.ts index 63ca1e9..cedb39a 100644 --- a/types/test.ts +++ b/types/test.ts @@ -28,10 +28,15 @@ chalk.level = Level.Ansi256; chalk.level === Level.Ansi256; -let chalkInstance = new chalk(); -chalkInstance = new chalk.constructor(); +let chalkInstance = new chalk.constructor(); chalkInstance = chalk.constructor(); +chalkInstance.blue('foo'); +chalkInstance`foo`; + +let x = 'imastring'; +x = chalk(); + chalk.enabled; chalk.level; chalk.supportsColor.level; From 14e0aa97727019b22f0a003fdc631aeec5e2e24c Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 24 Oct 2017 11:12:53 +0700 Subject: [PATCH 080/235] 2.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7a9edde..69889f0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "2.2.2", + "version": "2.3.0", "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk", From 539231341426d4b3951b062e806123137b452bf7 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 25 Oct 2017 21:53:18 -0700 Subject: [PATCH 081/235] Correct HSV and HWB examples --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 9bb2e65..4536ac0 100644 --- a/readme.md +++ b/readme.md @@ -265,8 +265,8 @@ The following color models can be used: - [`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.hsl(32, 1, 1).bold('Orange!')` -- [`hwb`](https://en.wikipedia.org/wiki/HWB_color_model) - Example: `chalk.hsl(32, 0, 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!')` - `ansi16` - `ansi256` From a8c60e37fa5fd9024c727e296bd24c37f7d725d1 Mon Sep 17 00:00:00 2001 From: Brandon Smith Date: Sat, 9 Dec 2017 05:20:28 -0500 Subject: [PATCH 082/235] Fix spelling error in readme (#232) --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 4536ac0..6148004 100644 --- a/readme.md +++ b/readme.md @@ -124,7 +124,7 @@ Multiple arguments will be separated by space. Color support is automatically detected, as is the level (see `chalk.level`). However, if you'd like to simply enable/disable Chalk, you can do so via the `.enabled` property. -Chalk is enabled by default unless expicitly disabled via the constructor or `chalk.level` is `0`. +Chalk is enabled by default unless explicitly disabled via the constructor or `chalk.level` is `0`. If you need to change this in a reusable module, create a new instance: From bc3dd75329b43eeda3200ac9a161b6e5a9b9dfe3 Mon Sep 17 00:00:00 2001 From: Samarth Verma Date: Sun, 31 Dec 2017 20:50:49 +0530 Subject: [PATCH 083/235] Update usage stats in the readme (#242) --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 6148004..6955631 100644 --- a/readme.md +++ b/readme.md @@ -26,7 +26,7 @@ - Doesn't extend `String.prototype` - Clean and focused - Actively maintained -- [Used by ~17,000 packages](https://www.npmjs.com/browse/depended/chalk) as of June 20th, 2017 +- [Used by ~23,000 packages](https://www.npmjs.com/browse/depended/chalk) as of December 31, 2017 ## Install From 655403055099299cc8c5053af970366d0c4c32b7 Mon Sep 17 00:00:00 2001 From: Mario Nebl Date: Tue, 2 Jan 2018 08:53:34 +0100 Subject: [PATCH 084/235] Use svg screenshot --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 6955631..eb74603 100644 --- a/readme.md +++ b/readme.md @@ -13,7 +13,7 @@ ### [See what's new in Chalk 2](https://github.com/chalk/chalk/releases/tag/v2.0.0) -![](https://github.com/chalk/ansi-styles/raw/master/screenshot.png) + ## Highlights From 011dd0421e14b21a07392b8d9d28ba9e851397b4 Mon Sep 17 00:00:00 2001 From: Aman Pratap Singh Date: Sun, 11 Feb 2018 14:33:50 +0530 Subject: [PATCH 085/235] Fix usage example in the readme (#251) --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index eb74603..6a903c7 100644 --- a/readme.md +++ b/readme.md @@ -51,7 +51,7 @@ const chalk = require('chalk'); const log = console.log; // Combine styled and normal strings -log(chalk.blue('Hello') + 'World' + chalk.red('!')); +log(chalk.blue('Hello') + ' World' + chalk.red('!')); // Compose multiple styles using the chainable API log(chalk.blue.bgRed.bold('Hello world!')); From 678152cf1952f3afe1e523a306c0413ad57c34b3 Mon Sep 17 00:00:00 2001 From: Kayla Washburn Date: Sun, 11 Feb 2018 02:59:24 -0700 Subject: [PATCH 086/235] Update chalk to use the latest updates to supports-color (#247) --- index.js | 6 +++--- package.json | 2 +- test/_supports-color.js | 10 ++++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index 05e62b3..1cc5fa8 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,7 @@ 'use strict'; const escapeStringRegexp = require('escape-string-regexp'); const ansiStyles = require('ansi-styles'); -const supportsColor = require('supports-color'); +const stdoutColor = require('supports-color').stdout; const template = require('./templates.js'); @@ -19,7 +19,7 @@ function applyOptions(obj, options) { options = options || {}; // Detect level if not set manually - const scLevel = supportsColor ? supportsColor.level : 0; + const scLevel = stdoutColor ? stdoutColor.level : 0; obj.level = options.level === undefined ? scLevel : options.level; obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; } @@ -224,5 +224,5 @@ function chalkTag(chalk, strings) { Object.defineProperties(Chalk.prototype, styles); module.exports = Chalk(); // eslint-disable-line new-cap -module.exports.supportsColor = supportsColor; +module.exports.supportsColor = stdoutColor; module.exports.default = module.exports; // For TypeScript diff --git a/package.json b/package.json index 69889f0..d5db4f7 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "dependencies": { "ansi-styles": "^3.1.0", "escape-string-regexp": "^1.0.5", - "supports-color": "^4.0.0" + "supports-color": "^5.0.0" }, "devDependencies": { "ava": "*", diff --git a/test/_supports-color.js b/test/_supports-color.js index d6e82bb..cfca6cc 100644 --- a/test/_supports-color.js +++ b/test/_supports-color.js @@ -4,10 +4,12 @@ const resolveFrom = require('resolve-from'); module.exports = dir => { require.cache[resolveFrom(dir, 'supports-color')] = { exports: { - level: 3, - hasBasic: true, - has256: true, - has16m: true + stdout: { + level: 3, + hasBasic: true, + has256: true, + has16m: true + } } }; }; From b55dd79f8bbd37725de562ce7422cd3ba8c87c3e Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 11 Feb 2018 20:04:55 +0700 Subject: [PATCH 087/235] Force bump dependencies npm is buggy, so doing this just to be sure. --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index d5db4f7..f59fbb5 100644 --- a/package.json +++ b/package.json @@ -41,14 +41,14 @@ "text" ], "dependencies": { - "ansi-styles": "^3.1.0", + "ansi-styles": "^3.2.0", "escape-string-regexp": "^1.0.5", - "supports-color": "^5.0.0" + "supports-color": "^5.2.0" }, "devDependencies": { "ava": "*", "coveralls": "^3.0.0", - "execa": "^0.8.0", + "execa": "^0.9.0", "import-fresh": "^2.0.0", "matcha": "^0.7.0", "nyc": "^11.0.2", From ae8a03f2c5c49896adeb3dd4ec5350e4ab9449a2 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 11 Feb 2018 20:18:25 +0700 Subject: [PATCH 088/235] 2.3.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f59fbb5..a02207c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "2.3.0", + "version": "2.3.1", "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk", From 576d8d217179d2e913e29639586204c2c2a76dc3 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 15 Feb 2018 00:15:28 +0700 Subject: [PATCH 089/235] Update URL to XO --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 6a903c7..f96a964 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) [![](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/sindresorhus/xo) [![Mentioned in Awesome Node.js](https://awesome.re/mentioned-badge.svg)](https://github.com/sindresorhus/awesome-nodejs) +[![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) [![](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) [![Mentioned in Awesome Node.js](https://awesome.re/mentioned-badge.svg)](https://github.com/sindresorhus/awesome-nodejs) ### [See what's new in Chalk 2](https://github.com/chalk/chalk/releases/tag/v2.0.0) From 12d1276b36cc026ecea1bdfe1771198b242f7b1d Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 15 Feb 2018 00:41:45 +0700 Subject: [PATCH 090/235] Fix linting --- templates.js | 1 + test/template-literal.js | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/templates.js b/templates.js index dbdf9b2..b2a33a4 100644 --- a/templates.js +++ b/templates.js @@ -1,3 +1,4 @@ +/* eslint-disable unicorn/no-unsafe-regex */ 'use strict'; const TEMPLATE_REGEX = /(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; diff --git a/test/template-literal.js b/test/template-literal.js index bfa346c..117b596 100644 --- a/test/template-literal.js +++ b/test/template-literal.js @@ -126,14 +126,14 @@ test('correctly parse escape in parameters (bug #177 comment 318622809)', t => { test('correctly parses unicode/hex escapes', t => { const ctx = m.constructor({level: 0}); - t.is(ctx`\u0078ylophones are fo\x78y! {magenta.inverse \u0078ylophones are fo\x78y!}`, + t.is(ctx`\u0078ylophones are fo\u0078y! {magenta.inverse \u0078ylophones are fo\u0078y!}`, 'xylophones are foxy! xylophones are foxy!'); }); test('correctly parses string arguments', t => { const ctx = m.constructor({level: 3}); t.is(ctx`{keyword('black').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); - t.is(ctx`{keyword('blac\x6B').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); + t.is(ctx`{keyword('blac\u006B').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); t.is(ctx`{keyword('blac\u006B').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); }); @@ -159,7 +159,7 @@ test('throws if an extra unescaped } is found', t => { test('should not parse upper-case escapes', t => { const ctx = m.constructor({level: 0}); - t.is(ctx`\N\n\T\t\X07\x07\U000A\u000A\U000a\u000a`, 'N\nT\tX07\x07U000A\u000AU000a\u000A'); + t.is(ctx`\N\n\T\t\X07\u0007\U000A\u000A\U000a\u000a`, 'N\nT\tX07\u0007U000A\u000AU000a\u000A'); }); test('should properly handle undefined template interpolated values', t => { From 52823001a59ea2270c186cb41c36b0e3e0a6da37 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Wed, 14 Feb 2018 18:28:22 -0800 Subject: [PATCH 091/235] Revert "Fix linting" This reverts commit 12d1276b36cc026ecea1bdfe1771198b242f7b1d. --- templates.js | 1 - test/template-literal.js | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/templates.js b/templates.js index b2a33a4..dbdf9b2 100644 --- a/templates.js +++ b/templates.js @@ -1,4 +1,3 @@ -/* eslint-disable unicorn/no-unsafe-regex */ 'use strict'; const TEMPLATE_REGEX = /(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; diff --git a/test/template-literal.js b/test/template-literal.js index 117b596..bfa346c 100644 --- a/test/template-literal.js +++ b/test/template-literal.js @@ -126,14 +126,14 @@ test('correctly parse escape in parameters (bug #177 comment 318622809)', t => { test('correctly parses unicode/hex escapes', t => { const ctx = m.constructor({level: 0}); - t.is(ctx`\u0078ylophones are fo\u0078y! {magenta.inverse \u0078ylophones are fo\u0078y!}`, + t.is(ctx`\u0078ylophones are fo\x78y! {magenta.inverse \u0078ylophones are fo\x78y!}`, 'xylophones are foxy! xylophones are foxy!'); }); test('correctly parses string arguments', t => { const ctx = m.constructor({level: 3}); t.is(ctx`{keyword('black').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); - t.is(ctx`{keyword('blac\u006B').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); + t.is(ctx`{keyword('blac\x6B').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); t.is(ctx`{keyword('blac\u006B').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); }); @@ -159,7 +159,7 @@ test('throws if an extra unescaped } is found', t => { test('should not parse upper-case escapes', t => { const ctx = m.constructor({level: 0}); - t.is(ctx`\N\n\T\t\X07\u0007\U000A\u000A\U000a\u000a`, 'N\nT\tX07\u0007U000A\u000AU000a\u000A'); + t.is(ctx`\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 => { From 925397a0f5d7f17605eaabd6ee3bb26d77280d2d Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Wed, 14 Feb 2018 18:29:19 -0800 Subject: [PATCH 092/235] Disable unicorn/no-unsafe-regex for template parser --- templates.js | 1 + 1 file changed, 1 insertion(+) diff --git a/templates.js b/templates.js index dbdf9b2..b2a33a4 100644 --- a/templates.js +++ b/templates.js @@ -1,3 +1,4 @@ +/* eslint-disable unicorn/no-unsafe-regex */ 'use strict'; const TEMPLATE_REGEX = /(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; From e80f02e2ddae53b897fa2d9751d5d86fae493b45 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Wed, 14 Feb 2018 18:30:01 -0800 Subject: [PATCH 093/235] Disable unicorn/no-hex-escape for template tests --- test/template-literal.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/template-literal.js b/test/template-literal.js index bfa346c..71cc106 100644 --- a/test/template-literal.js +++ b/test/template-literal.js @@ -1,3 +1,4 @@ +/* eslint-disable unicorn/no-hex-escape */ import test from 'ava'; // Spoof supports-color From 245dfa5c6fc4200894fc812eaa4b4159d153e0bb Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 3 Mar 2018 00:38:17 +0700 Subject: [PATCH 094/235] Bump dependencies Closes #255 Fixes #254 Fixes #224 --- package.json | 4 ++-- templates.js | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index a02207c..b1cabb5 100644 --- a/package.json +++ b/package.json @@ -41,9 +41,9 @@ "text" ], "dependencies": { - "ansi-styles": "^3.2.0", + "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", - "supports-color": "^5.2.0" + "supports-color": "^5.3.0" }, "devDependencies": { "ava": "*", diff --git a/templates.js b/templates.js index b2a33a4..dbdf9b2 100644 --- a/templates.js +++ b/templates.js @@ -1,4 +1,3 @@ -/* eslint-disable unicorn/no-unsafe-regex */ 'use strict'; const TEMPLATE_REGEX = /(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; From 84f27d4bd86f7f482a32652ae536cd996ad204bd Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 3 Mar 2018 00:43:48 +0700 Subject: [PATCH 095/235] 2.3.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b1cabb5..3edc94a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "2.3.1", + "version": "2.3.2", "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk", From 0dae4c28e136513b96c3cc1b49de4d85a53b50a2 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 2 Apr 2018 14:35:53 +0700 Subject: [PATCH 096/235] Add Patreon badge --- readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.md b/readme.md index f96a964..2e9b1a3 100644 --- a/readme.md +++ b/readme.md @@ -35,6 +35,10 @@ $ npm install chalk ``` + + + + ## Usage From 58483b5ab110775eb0cfc4999f1cf7e971a00fda Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 5 Apr 2018 00:43:20 +0700 Subject: [PATCH 097/235] Add a related package to the readme --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 2e9b1a3..aac3a71 100644 --- a/readme.md +++ b/readme.md @@ -300,6 +300,7 @@ If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) i - [chalk-animation](https://github.com/bokub/chalk-animation) - Animate strings in the terminal - [gradient-string](https://github.com/bokub/gradient-string) - Apply color gradients to strings - [chalk-pipe](https://github.com/LitoMore/chalk-pipe) - Create chalk style schemes with simpler style strings +- [terminal-link](https://github.com/sindresorhus/terminal-link) - Create clickable links in the terminal ## Maintainers From 7c6f83f719b241b7a1a1cd54b256d123e53eab4a Mon Sep 17 00:00:00 2001 From: Saad Quadri Date: Tue, 17 Apr 2018 00:26:17 -0400 Subject: [PATCH 098/235] Add Flow type definitions (#260) --- .flowconfig | 5 +++ index.js.flow | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 9 +++-- test/_flow.js | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 .flowconfig create mode 100644 index.js.flow create mode 100644 test/_flow.js diff --git a/.flowconfig b/.flowconfig new file mode 100644 index 0000000..2318f0d --- /dev/null +++ b/.flowconfig @@ -0,0 +1,5 @@ +[ignore] +.*/node_modules/.* + +[options] +suppress_comment= \\(.\\|\n\\)*\\$ExpectError diff --git a/index.js.flow b/index.js.flow new file mode 100644 index 0000000..a55cf1d --- /dev/null +++ b/index.js.flow @@ -0,0 +1,95 @@ +// @flow + +type TemplateStringsArray = $ReadOnlyArray; + +export type Level = $Values<{ + None: 0, + Basic: 1, + Ansi256: 2, + TrueColor: 3 +}>; + +export type ChalkOptions = {| + enabled?: boolean, + level?: Level +|}; + +export type ColorSupport = {| + level: Level, + hasBasic: boolean, + has256: boolean, + has16m: boolean +|}; + +export interface Chalk { + (...text: string[]): string, + (text: TemplateStringsArray, ...placeholders: string[]): string, + constructor(options?: ChalkOptions): Chalk, + enabled: boolean, + level: Level, + rgb(r: number, g: number, b: number): Chalk, + hsl(h: number, s: number, l: number): Chalk, + hsv(h: number, s: number, v: number): Chalk, + hwb(h: number, w: number, b: number): Chalk, + bgHex(color: string): Chalk, + bgKeyword(color: string): Chalk, + bgRgb(r: number, g: number, b: number): Chalk, + bgHsl(h: number, s: number, l: number): Chalk, + bgHsv(h: number, s: number, v: number): Chalk, + bgHwb(h: number, w: number, b: number): Chalk, + hex(color: string): Chalk, + keyword(color: string): Chalk, + + +reset: Chalk, + +bold: Chalk, + +dim: Chalk, + +italic: Chalk, + +underline: Chalk, + +inverse: Chalk, + +hidden: Chalk, + +strikethrough: Chalk, + + +visible: Chalk, + + +black: Chalk, + +red: Chalk, + +green: Chalk, + +yellow: Chalk, + +blue: Chalk, + +magenta: Chalk, + +cyan: Chalk, + +white: Chalk, + +gray: Chalk, + +grey: Chalk, + +blackBright: Chalk, + +redBright: Chalk, + +greenBright: Chalk, + +yellowBright: Chalk, + +blueBright: Chalk, + +magentaBright: Chalk, + +cyanBright: Chalk, + +whiteBright: Chalk, + + +bgBlack: Chalk, + +bgRed: Chalk, + +bgGreen: Chalk, + +bgYellow: Chalk, + +bgBlue: Chalk, + +bgMagenta: Chalk, + +bgCyan: Chalk, + +bgWhite: Chalk, + +bgBlackBright: Chalk, + +bgRedBright: Chalk, + +bgGreenBright: Chalk, + +bgYellowBright: Chalk, + +bgBlueBright: Chalk, + +bgMagentaBright: Chalk, + +bgCyanBright: Chalk, + +bgWhiteBrigh: Chalk, + + supportsColor: ColorSupport +}; + +declare var chalk: Chalk; + +export default chalk; diff --git a/package.json b/package.json index 3edc94a..05ab3df 100644 --- a/package.json +++ b/package.json @@ -8,14 +8,15 @@ "node": ">=4" }, "scripts": { - "test": "xo && tsc --project types && nyc ava", + "test": "xo && tsc --project types && flow --max-warnings=0 && nyc ava", "bench": "matcha benchmark.js", "coveralls": "nyc report --reporter=text-lcov | coveralls" }, "files": [ "index.js", "templates.js", - "types/index.d.ts" + "types/index.d.ts", + "index.js.flow" ], "keywords": [ "color", @@ -49,6 +50,7 @@ "ava": "*", "coveralls": "^3.0.0", "execa": "^0.9.0", + "flow-bin": "^0.68.0", "import-fresh": "^2.0.0", "matcha": "^0.7.0", "nyc": "^11.0.2", @@ -61,6 +63,9 @@ "envs": [ "node", "mocha" + ], + "ignores": [ + "test/_flow.js" ] } } diff --git a/test/_flow.js b/test/_flow.js new file mode 100644 index 0000000..2cf3cf2 --- /dev/null +++ b/test/_flow.js @@ -0,0 +1,94 @@ +// @flow +import chalk from '..'; + +// $ExpectError (Can't have typo in option name) +chalk.constructor({levl: 1}); +chalk.constructor({level: 1}); + +// $ExpectError (Option must have proper type) +new chalk.constructor({enabled: 'true'}); +new chalk.constructor({enabled: true}); + +// $ExpectError (Can't pass in null) +chalk.underline(null); +chalk.underline('foo'); + +// $ExpectError (Can't have typo in chalk method) +chalk.rd('foo'); +chalk.red('foo'); + +// $ExpectError (Can't have typo in chalk method) +chalk.gren`foo`; +chalk.green`foo`; + +// $ExpectError (Can't have typo in chalk method) +chalk.red.bgBlu.underline('foo'); +chalk.red.bgBlue.underline('foo'); + +// $ExpectError (Level must be 0, 1, 2, or 3) +const badCtx = chalk.constructor({level: 4}); +const ctx = chalk.constructor({level: 3}); + +// $ExpectError (Can't pass in null) +ctx(null); +ctx('foo'); + +// $ExpectError (Can't have typo in method name) +ctx.gry('foo'); +ctx.grey('foo'); + +// $ExpectError (Can't have typo in method name) +ctx`foo`.value(); +ctx`foo`.valueOf(); + +// $ExpectError (Can't have typo in property name) +chalk.abled = true; +chalk.enabled = true; + +// $ExpectError (Can't use invalid Level for property setter) +chalk.level = 10; +chalk.level = 1; + +const chalkInstance = new chalk.constructor(); + +// $ExpectError (Can't have typo in method name) +chalkInstance.blu('foo'); +chalkInstance.blue('foo'); +chalkInstance`foo`; + +// $ExpectError (Can't have typo in method name) +chalk.keywrd('orange').bgBlue('foo'); +chalk.keyword('orange').bgBlue('foo'); + +// $ExpectError (rgb should take in 3 numbers) +chalk.rgb(1, 14).bgBlue('foo'); +chalk.rgb(1, 14, 9).bgBlue('foo'); + +// $ExpectError (hsl should take in 3 numbers) +chalk.hsl(1, 14, '9').bgBlue('foo'); +chalk.hsl(1, 14, 9).bgBlue('foo'); + +// $ExpectError (hsv should take in 3 numbers) +chalk.hsv(1, 14).bgBlue('foo'); +chalk.hsv(1, 14, 9).bgBlue('foo'); + +// $ExpectError (hwb should take in 3 numbers) +chalk.hwb(1, 14).bgBlue('foo'); +chalk.hwb(1, 14, 9).bgBlue('foo'); + +// $ExpectError (Can't have typo in method name) +chalk.visibl('foo'); +chalk.visible('foo'); + +// $ExpectError (Can't have typo in method name) +chalk.red.visibl('foo'); +chalk.red.visible('foo'); +chalk.visible.red('foo'); + +// $ExpectError (Can't write to readonly property) +chalk.black = 'foo'; +chalk.black; + +// $ExpectError (Can't write to readonly property) +chalk.reset = 'foo'; +console.log(chalk.reset); From af8b3657e96a0a6ca5190fb0d0a1345797148320 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 17 Apr 2018 11:28:35 +0700 Subject: [PATCH 099/235] 2.4.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 05ab3df..1ba18c7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "2.3.2", + "version": "2.4.0", "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk", From fc9a7e369b83eb91d27e0880b06b4d0a7e204a69 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 20 Apr 2018 13:42:21 +0700 Subject: [PATCH 100/235] GitHub now natively supports SVG --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index aac3a71..d298e2c 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,7 @@



- chalk + Chalk


From 01cfb5c888481d044b90fcfebddb73defee602d7 Mon Sep 17 00:00:00 2001 From: Jamie Date: Wed, 25 Apr 2018 22:14:22 -0700 Subject: [PATCH 101/235] Improve Flow type definition for CommonJS interop (#268) --- index.js.flow | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/index.js.flow b/index.js.flow index a55cf1d..872a156 100644 --- a/index.js.flow +++ b/index.js.flow @@ -90,6 +90,4 @@ export interface Chalk { supportsColor: ColorSupport }; -declare var chalk: Chalk; - -export default chalk; +declare module.exports: Chalk; From 48ba5b0b9beadcabd9fc406ac4d9337d8fa6b36d Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 26 Apr 2018 12:15:49 +0700 Subject: [PATCH 102/235] 2.4.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1ba18c7..0893783 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "2.4.0", + "version": "2.4.1", "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk", From a6ad9454525c0af602931049155cc51eccc72bb4 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 28 May 2018 09:16:44 +0700 Subject: [PATCH 103/235] Fix XO linting and update some dev dependencies Fixes #275 --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 0893783..4a213f9 100644 --- a/package.json +++ b/package.json @@ -47,16 +47,16 @@ "supports-color": "^5.3.0" }, "devDependencies": { - "ava": "*", + "ava": "0.25.0", "coveralls": "^3.0.0", - "execa": "^0.9.0", - "flow-bin": "^0.68.0", + "execa": "^0.10.0", + "flow-bin": "^0.73.0", "import-fresh": "^2.0.0", "matcha": "^0.7.0", "nyc": "^11.0.2", "resolve-from": "^4.0.0", "typescript": "^2.5.3", - "xo": "*" + "xo": "0.20.3" }, "types": "types/index.d.ts", "xo": { From a2b5fa22dca4cf0949d978826d3c05478ea2ecf2 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 6 Aug 2018 15:53:00 +0700 Subject: [PATCH 104/235] Add some badges to the readme --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index d298e2c..e16f679 100644 --- a/readme.md +++ b/readme.md @@ -9,11 +9,11 @@ > 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) [![](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) [![Mentioned in Awesome Node.js](https://awesome.re/mentioned-badge.svg)](https://github.com/sindresorhus/awesome-nodejs) +[![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) [![Mentioned in Awesome Node.js](https://awesome.re/mentioned-badge.svg)](https://github.com/sindresorhus/awesome-nodejs) ### [See what's new in Chalk 2](https://github.com/chalk/chalk/releases/tag/v2.0.0) - + ## Highlights @@ -26,7 +26,7 @@ - Doesn't extend `String.prototype` - Clean and focused - Actively maintained -- [Used by ~23,000 packages](https://www.npmjs.com/browse/depended/chalk) as of December 31, 2017 +- [Used by ~30,000 packages](https://www.npmjs.com/browse/depended/chalk) as of August 6, 2018 ## Install From 70f22d87ba4348637f236686bd17318922107a44 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 1 Sep 2018 02:50:53 +0700 Subject: [PATCH 105/235] Tiny travis.yml tweak --- .travis.yml | 3 ++- package.json | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index ea5900d..2126ad4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,5 @@ node_js: - '8' - '6' - '4' -after_success: npm run coveralls +after_success: + - './node_modules/.bin/nyc report --reporter=text-lcov | ./node_modules/.bin/coveralls' diff --git a/package.json b/package.json index 4a213f9..514c53d 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,8 @@ "node": ">=4" }, "scripts": { - "test": "xo && tsc --project types && flow --max-warnings=0 && nyc ava", - "bench": "matcha benchmark.js", - "coveralls": "nyc report --reporter=text-lcov | coveralls" + "test": "xo && nyc ava && tsc --project types && flow --max-warnings=0", + "bench": "matcha benchmark.js" }, "files": [ "index.js", From 0307f263cb29dace28e7cf0648b13a3f527697af Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 18 Sep 2018 14:05:08 +0700 Subject: [PATCH 106/235] Require Node.js 6 --- .gitattributes | 3 +- .travis.yml | 1 - benchmark.js | 2 +- index.js | 43 +++++++------- package.json | 22 +++---- templates.js | 2 +- test/chalk.js | 57 +++++++++---------- test/constructor.js | 22 +++---- test/enabled.js | 30 +++++----- test/level.js | 38 ++++++------- test/template-literal.js | 120 +++++++++++++++++++-------------------- test/visible.js | 56 +++++++++--------- test/windows.js | 24 ++++---- 13 files changed, 204 insertions(+), 216 deletions(-) diff --git a/.gitattributes b/.gitattributes index 391f0a4..6313b56 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1 @@ -* text=auto -*.js text eol=lf +* text=auto eol=lf diff --git a/.travis.yml b/.travis.yml index 2126ad4..60e38d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,5 @@ language: node_js node_js: - '8' - '6' - - '4' after_success: - './node_modules/.bin/nyc report --reporter=text-lcov | ./node_modules/.bin/coveralls' diff --git a/benchmark.js b/benchmark.js index af90c06..f4e9cf3 100644 --- a/benchmark.js +++ b/benchmark.js @@ -1,4 +1,4 @@ -/* globals set bench */ +/* globals suite, set, bench */ 'use strict'; const chalk = require('.'); diff --git a/index.js b/index.js index 1cc5fa8..333c836 100644 --- a/index.js +++ b/index.js @@ -31,10 +31,7 @@ function Chalk(options) { const chalk = {}; applyOptions(chalk, options); - chalk.template = function () { - const args = [].slice.call(arguments); - return chalkTag.apply(null, [chalk.template].concat(args)); - }; + chalk.template = (...args) => chalkTag(...[chalk.template].concat(args)); Object.setPrototypeOf(chalk, Chalk.prototype); Object.setPrototypeOf(chalk.template, chalk); @@ -77,9 +74,9 @@ for (const model of Object.keys(ansiStyles.color.ansi)) { styles[model] = { get() { - const level = this.level; - return function () { - const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments); + const {level} = this; + return function (...args) { + const open = ansiStyles.color[levelMapping[level]][model](...args); const codes = { open, close: ansiStyles.color.close, @@ -100,9 +97,9 @@ for (const model of Object.keys(ansiStyles.bgColor.ansi)) { const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); styles[bgModel] = { get() { - const level = this.level; - return function () { - const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments); + const {level} = this; + return function (...args) { + const open = ansiStyles.bgColor[levelMapping[level]][model](...args); const codes = { open, close: ansiStyles.bgColor.close, @@ -117,10 +114,7 @@ for (const model of Object.keys(ansiStyles.bgColor.ansi)) { const proto = Object.defineProperties(() => {}, styles); function build(_styles, _empty, key) { - const builder = function () { - return applyStyle.apply(builder, arguments); - }; - + const builder = (...args) => applyStyle.call(builder, ...args); builder._styles = _styles; builder._empty = _empty; @@ -156,11 +150,10 @@ function build(_styles, _empty, key) { return builder; } -function applyStyle() { +function applyStyle(...args) { // Support varags, but simply cast to string in case there's only one arg - const args = arguments; const argsLen = args.length; - let str = String(arguments[0]); + let str = String(args[0]); if (argsLen === 0) { return ''; @@ -203,19 +196,21 @@ function applyStyle() { return str; } -function chalkTag(chalk, strings) { - if (!Array.isArray(strings)) { +function chalkTag(chalk, ...strings) { + const firstString = strings[0]; + + if (!Array.isArray(firstString)) { // If chalk() was called by itself or with a string, // return the string itself as a string. - return [].slice.call(arguments, 1).join(' '); + return strings.join(' '); } - const args = [].slice.call(arguments, 2); - const parts = [strings.raw[0]]; + const args = strings.slice(1); + const parts = [firstString.raw[0]]; - for (let i = 1; i < strings.length; i++) { + for (let i = 1; i < firstString.length; i++) { parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); - parts.push(String(strings.raw[i])); + parts.push(String(firstString.raw[i])); } return template(chalk, parts.join('')); diff --git a/package.json b/package.json index 514c53d..32c6f73 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "license": "MIT", "repository": "chalk/chalk", "engines": { - "node": ">=4" + "node": ">=6" }, "scripts": { "test": "xo && nyc ava && tsc --project types && flow --max-warnings=0", @@ -43,26 +43,22 @@ "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "supports-color": "^5.5.0" }, "devDependencies": { - "ava": "0.25.0", - "coveralls": "^3.0.0", - "execa": "^0.10.0", - "flow-bin": "^0.73.0", + "ava": "^0.25.0", + "coveralls": "^3.0.2", + "execa": "^1.0.0", + "flow-bin": "^0.81.0", "import-fresh": "^2.0.0", "matcha": "^0.7.0", - "nyc": "^11.0.2", + "nyc": "^13.0.1", "resolve-from": "^4.0.0", - "typescript": "^2.5.3", - "xo": "0.20.3" + "typescript": "^3.0.3", + "xo": "^0.23.0" }, "types": "types/index.d.ts", "xo": { - "envs": [ - "node", - "mocha" - ], "ignores": [ "test/_flow.js" ] diff --git a/templates.js b/templates.js index dbdf9b2..8ce33fe 100644 --- a/templates.js +++ b/templates.js @@ -80,7 +80,7 @@ function buildStyle(chalk, styles) { } if (enabled[styleName].length > 0) { - current = current[styleName].apply(current, enabled[styleName]); + current = current[styleName](...enabled[styleName]); } else { current = current[styleName]; } diff --git a/test/chalk.js b/test/chalk.js index 8480dad..a53b6f5 100644 --- a/test/chalk.js +++ b/test/chalk.js @@ -3,51 +3,50 @@ import test from 'ava'; // Spoof supports-color require('./_supports-color')(__dirname); -const m = require('..'); +const chalk = require('..'); console.log('TERM:', process.env.TERM || '[none]'); console.log('platform:', process.platform || '[unknown]'); test('don\'t add any styling when called as the base function', t => { - t.is(m('foo'), 'foo'); + t.is(chalk('foo'), 'foo'); }); test('support multiple arguments in base function', t => { - t.is(m('hello', 'there'), 'hello there'); + t.is(chalk('hello', 'there'), 'hello there'); }); test('style string', t => { - t.is(m.underline('foo'), '\u001B[4mfoo\u001B[24m'); - t.is(m.red('foo'), '\u001B[31mfoo\u001B[39m'); - t.is(m.bgRed('foo'), '\u001B[41mfoo\u001B[49m'); + t.is(chalk.underline('foo'), '\u001B[4mfoo\u001B[24m'); + t.is(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); + t.is(chalk.bgRed('foo'), '\u001B[41mfoo\u001B[49m'); }); test('support applying multiple styles at once', t => { - t.is(m.red.bgGreen.underline('foo'), '\u001B[31m\u001B[42m\u001B[4mfoo\u001B[24m\u001B[49m\u001B[39m'); - t.is(m.underline.red.bgGreen('foo'), '\u001B[4m\u001B[31m\u001B[42mfoo\u001B[49m\u001B[39m\u001B[24m'); + t.is(chalk.red.bgGreen.underline('foo'), '\u001B[31m\u001B[42m\u001B[4mfoo\u001B[24m\u001B[49m\u001B[39m'); + t.is(chalk.underline.red.bgGreen('foo'), '\u001B[4m\u001B[31m\u001B[42mfoo\u001B[49m\u001B[39m\u001B[24m'); }); test('support nesting styles', t => { t.is( - m.red('foo' + m.underline.bgBlue('bar') + '!'), + chalk.red('foo' + chalk.underline.bgBlue('bar') + '!'), '\u001B[31mfoo\u001B[4m\u001B[44mbar\u001B[49m\u001B[24m!\u001B[39m' ); }); test('support nesting styles of the same type (color, underline, bg)', t => { t.is( - m.red('a' + m.yellow('b' + m.green('c') + 'b') + 'c'), + chalk.red('a' + chalk.yellow('b' + chalk.green('c') + 'b') + 'c'), '\u001B[31ma\u001B[33mb\u001B[32mc\u001B[33mb\u001B[31mc\u001B[39m' ); }); test('reset all styles with `.reset()`', t => { - t.is(m.reset(m.red.bgGreen.underline('foo') + 'foo'), '\u001B[0m\u001B[31m\u001B[42m\u001B[4mfoo\u001B[24m\u001B[49m\u001B[39mfoo\u001B[0m'); + t.is(chalk.reset(chalk.red.bgGreen.underline('foo') + 'foo'), '\u001B[0m\u001B[31m\u001B[42m\u001B[4mfoo\u001B[24m\u001B[49m\u001B[39mfoo\u001B[0m'); }); test('support caching multiple styles', t => { - const red = m.red; - const green = m.green; + const {red, green} = chalk.red; const redBold = red.bold; const greenBold = green.bold; @@ -57,44 +56,44 @@ test('support caching multiple styles', t => { }); test('alias gray to grey', t => { - t.is(m.grey('foo'), '\u001B[90mfoo\u001B[39m'); + t.is(chalk.grey('foo'), '\u001B[90mfoo\u001B[39m'); }); test('support variable number of arguments', t => { - t.is(m.red('foo', 'bar'), '\u001B[31mfoo bar\u001B[39m'); + t.is(chalk.red('foo', 'bar'), '\u001B[31mfoo bar\u001B[39m'); }); test('support falsy values', t => { - t.is(m.red(0), '\u001B[31m0\u001B[39m'); + t.is(chalk.red(0), '\u001B[31m0\u001B[39m'); }); test('don\'t output escape codes if the input is empty', t => { - t.is(m.red(), ''); - t.is(m.red.blue.black(), ''); + t.is(chalk.red(), ''); + t.is(chalk.red.blue.black(), ''); }); test('keep Function.prototype methods', t => { - t.is(m.grey.apply(null, ['foo']), '\u001B[90mfoo\u001B[39m'); - t.is(m.reset(m.red.bgGreen.underline.bind(null)('foo') + 'foo'), '\u001B[0m\u001B[31m\u001B[42m\u001B[4mfoo\u001B[24m\u001B[49m\u001B[39mfoo\u001B[0m'); - t.is(m.red.blue.black.call(null), ''); + t.is(chalk.grey.apply(null, ['foo']), '\u001B[90mfoo\u001B[39m'); + t.is(chalk.reset(chalk.red.bgGreen.underline.bind(null)('foo') + 'foo'), '\u001B[0m\u001B[31m\u001B[42m\u001B[4mfoo\u001B[24m\u001B[49m\u001B[39mfoo\u001B[0m'); + t.is(chalk.red.blue.black.call(null), ''); }); test('line breaks should open and close colors', t => { - t.is(m.grey('hello\nworld'), '\u001B[90mhello\u001B[39m\n\u001B[90mworld\u001B[39m'); + t.is(chalk.grey('hello\nworld'), '\u001B[90mhello\u001B[39m\n\u001B[90mworld\u001B[39m'); }); test('properly convert RGB to 16 colors on basic color terminals', t => { - t.is(new m.constructor({level: 1}).hex('#FF0000')('hello'), '\u001B[91mhello\u001B[39m'); - t.is(new m.constructor({level: 1}).bgHex('#FF0000')('hello'), '\u001B[101mhello\u001B[49m'); + t.is(new chalk.constructor({level: 1}).hex('#FF0000')('hello'), '\u001B[91mhello\u001B[39m'); + t.is(new chalk.constructor({level: 1}).bgHex('#FF0000')('hello'), '\u001B[101mhello\u001B[49m'); }); test('properly convert RGB to 256 colors on basic color terminals', t => { - t.is(new m.constructor({level: 2}).hex('#FF0000')('hello'), '\u001B[38;5;196mhello\u001B[39m'); - t.is(new m.constructor({level: 2}).bgHex('#FF0000')('hello'), '\u001B[48;5;196mhello\u001B[49m'); - t.is(new m.constructor({level: 3}).bgHex('#FF0000')('hello'), '\u001B[48;2;255;0;0mhello\u001B[49m'); + t.is(new chalk.constructor({level: 2}).hex('#FF0000')('hello'), '\u001B[38;5;196mhello\u001B[39m'); + t.is(new chalk.constructor({level: 2}).bgHex('#FF0000')('hello'), '\u001B[48;5;196mhello\u001B[49m'); + t.is(new chalk.constructor({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 m.constructor({level: 0}).hex('#FF0000')('hello'), 'hello'); - t.is(new m.constructor({level: 0}).bgHex('#FF0000')('hello'), 'hello'); + t.is(new chalk.constructor({level: 0}).hex('#FF0000')('hello'), 'hello'); + t.is(new chalk.constructor({level: 0}).bgHex('#FF0000')('hello'), 'hello'); }); diff --git a/test/constructor.js b/test/constructor.js index d592e82..510f1a0 100644 --- a/test/constructor.js +++ b/test/constructor.js @@ -3,20 +3,20 @@ import test from 'ava'; // Spoof supports-color require('./_supports-color')(__dirname); -const m = require('..'); +const chalk = require('..'); test('create an isolated context where colors can be disabled (by level)', t => { - const ctx = new m.constructor({level: 0, enabled: true}); - t.is(ctx.red('foo'), 'foo'); - t.is(m.red('foo'), '\u001B[31mfoo\u001B[39m'); - ctx.level = 2; - t.is(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); + const instance = new chalk.constructor({level: 0, enabled: true}); + t.is(instance.red('foo'), 'foo'); + t.is(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); + instance.level = 2; + t.is(instance.red('foo'), '\u001B[31mfoo\u001B[39m'); }); test('create an isolated context where colors can be disabled (by enabled flag)', t => { - const ctx = new m.constructor({enabled: false}); - t.is(ctx.red('foo'), 'foo'); - t.is(m.red('foo'), '\u001B[31mfoo\u001B[39m'); - ctx.enabled = true; - t.is(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); + const instance = new chalk.constructor({enabled: false}); + t.is(instance.red('foo'), 'foo'); + t.is(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); + instance.enabled = true; + t.is(instance.red('foo'), '\u001B[31mfoo\u001B[39m'); }); diff --git a/test/enabled.js b/test/enabled.js index 3270e54..e596621 100644 --- a/test/enabled.js +++ b/test/enabled.js @@ -3,33 +3,33 @@ import test from 'ava'; // Spoof supports-color require('./_supports-color')(__dirname); -const m = require('..'); +const chalk = require('..'); test('don\'t output colors when manually disabled', t => { - m.enabled = false; - t.is(m.red('foo'), 'foo'); - m.enabled = true; + chalk.enabled = false; + t.is(chalk.red('foo'), 'foo'); + chalk.enabled = true; }); test('enable/disable colors based on overall chalk enabled property, not individual instances', t => { - m.enabled = false; - const red = m.red; + chalk.enabled = false; + const {red} = chalk; t.false(red.enabled); - m.enabled = true; + chalk.enabled = true; t.true(red.enabled); - m.enabled = true; + chalk.enabled = true; }); test('propagate enable/disable changes from child colors', t => { - m.enabled = false; - const red = m.red; + chalk.enabled = false; + const {red} = chalk; t.false(red.enabled); - t.false(m.enabled); + t.false(chalk.enabled); red.enabled = true; t.true(red.enabled); - t.true(m.enabled); - m.enabled = false; + t.true(chalk.enabled); + chalk.enabled = false; t.false(red.enabled); - t.false(m.enabled); - m.enabled = true; + t.false(chalk.enabled); + chalk.enabled = true; }); diff --git a/test/level.js b/test/level.js index 85624ea..06fdb59 100644 --- a/test/level.js +++ b/test/level.js @@ -5,38 +5,38 @@ import execa from 'execa'; // Spoof supports-color require('./_supports-color')(__dirname); -const m = require('..'); +const chalk = require('..'); test('don\'t output colors when manually disabled', t => { - const oldLevel = m.level; - m.level = 0; - t.is(m.red('foo'), 'foo'); - m.level = oldLevel; + const oldLevel = chalk.level; + chalk.level = 0; + t.is(chalk.red('foo'), 'foo'); + chalk.level = oldLevel; }); test('enable/disable colors based on overall chalk enabled property, not individual instances', t => { - const oldLevel = m.level; - m.level = 1; - const red = m.red; + const oldLevel = chalk.level; + chalk.level = 1; + const {red} = chalk; t.is(red.level, 1); - m.level = 0; - t.is(red.level, m.level); - m.level = oldLevel; + chalk.level = 0; + t.is(red.level, chalk.level); + chalk.level = oldLevel; }); test('propagate enable/disable changes from child colors', t => { - const oldLevel = m.level; - m.level = 1; - const red = m.red; + const oldLevel = chalk.level; + chalk.level = 1; + const {red} = chalk; t.is(red.level, 1); - t.is(m.level, 1); + t.is(chalk.level, 1); red.level = 0; t.is(red.level, 0); - t.is(m.level, 0); - m.level = 1; + t.is(chalk.level, 0); + chalk.level = 1; t.is(red.level, 1); - t.is(m.level, 1); - m.level = oldLevel; + t.is(chalk.level, 1); + chalk.level = oldLevel; }); test('disable colors if they are not supported', async t => { diff --git a/test/template-literal.js b/test/template-literal.js index 71cc106..34588d2 100644 --- a/test/template-literal.js +++ b/test/template-literal.js @@ -4,82 +4,82 @@ import test from 'ava'; // Spoof supports-color require('./_supports-color')(__dirname); -const m = require('..'); +const chalk = require('..'); test('return an empty string for an empty literal', t => { - const ctx = m.constructor(); - t.is(ctx``, ''); + const instance = chalk.constructor(); + t.is(instance``, ''); }); test('return a regular string for a literal with no templates', t => { - const ctx = m.constructor({level: 0}); - t.is(ctx`hello`, 'hello'); + const instance = chalk.constructor({level: 0}); + t.is(instance`hello`, 'hello'); }); test('correctly perform template parsing', t => { - const ctx = m.constructor({level: 0}); - t.is(ctx`{bold Hello, {cyan World!} This is a} test. {green Woo!}`, - ctx.bold('Hello,', ctx.cyan('World!'), 'This is a') + ' test. ' + ctx.green('Woo!')); + const instance = chalk.constructor({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 ctx = m.constructor({level: 0}); + const instance = chalk.constructor({level: 0}); const name = 'Sindre'; const exclamation = 'Neat'; - t.is(ctx`{bold Hello, {cyan.inverse ${name}!} This is a} test. {green ${exclamation}!}`, - ctx.bold('Hello,', ctx.cyan.inverse(name + '!'), 'This is a') + ' test. ' + ctx.green(exclamation + '!')); + t.is(instance`{bold Hello, {cyan.inverse ${name}!} This is a} test. {green ${exclamation}!}`, + instance.bold('Hello,', instance.cyan.inverse(name + '!'), 'This is a') + ' test. ' + instance.green(exclamation + '!')); }); test('correctly parse and evaluate color-convert functions', t => { - const ctx = m.constructor({level: 3}); - t.is(ctx`{bold.rgb(144,10,178).inverse Hello, {~inverse there!}}`, + const instance = chalk.constructor({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' + '\u001B[38;2;144;10;178mthere!\u001B[39m\u001B[22m'); - t.is(ctx`{bold.bgRgb(144,10,178).inverse Hello, {~inverse there!}}`, + t.is(instance`{bold.bgRgb(144,10,178).inverse Hello, {~inverse there!}}`, '\u001B[1m\u001B[48;2;144;10;178m\u001B[7mHello, ' + '\u001B[27m\u001B[49m\u001B[22m\u001B[1m' + '\u001B[48;2;144;10;178mthere!\u001B[49m\u001B[22m'); }); test('properly handle escapes', t => { - const ctx = m.constructor({level: 3}); - t.is(ctx`{bold hello \{in brackets\}}`, + const instance = chalk.constructor({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 ctx = m.constructor({level: 3}); + const instance = chalk.constructor({level: 3}); try { - console.log(ctx`{bold this shouldn't appear ever\}`); + console.log(instance`{bold this shouldn't appear ever\}`); t.fail(); - } catch (err) { - t.is(err.message, 'Chalk template literal is missing 1 closing bracket (`}`)'); + } catch (error) { + t.is(error.message, 'Chalk template literal is missing 1 closing bracket (`}`)'); } try { - console.log(ctx`{bold this shouldn't {inverse appear {underline ever\} :) \}`); + console.log(instance`{bold this shouldn't {inverse appear {underline ever\} :) \}`); t.fail(); - } catch (err) { - t.is(err.message, 'Chalk template literal is missing 3 closing brackets (`}`)'); + } catch (error) { + t.is(error.message, 'Chalk template literal is missing 3 closing brackets (`}`)'); } }); test('throw if there is an invalid style', t => { - const ctx = m.constructor({level: 3}); + const instance = chalk.constructor({level: 3}); try { - console.log(ctx`{abadstylethatdoesntexist this shouldn't appear ever}`); + console.log(instance`{abadstylethatdoesntexist this shouldn't appear ever}`); t.fail(); - } catch (err) { - t.is(err.message, 'Unknown Chalk style: abadstylethatdoesntexist'); + } catch (error) { + t.is(error.message, 'Unknown Chalk style: abadstylethatdoesntexist'); } }); test('properly style multiline color blocks', t => { - const ctx = m.constructor({level: 3}); + const instance = chalk.constructor({level: 3}); t.is( - ctx`{bold + instance`{bold Hello! This is a ${'multiline'} block! :) @@ -97,74 +97,74 @@ test('properly style multiline color blocks', t => { }); test('escape interpolated values', t => { - const ctx = m.constructor({level: 0}); - t.is(ctx`Hello {bold hi}`, 'Hello hi'); - t.is(ctx`Hello ${'{bold hi}'}`, 'Hello {bold hi}'); + const instance = chalk.constructor({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 ctx = m.constructor({level: 3}); - ctx.rose = ctx.hex('#F6D9D9'); - t.is(ctx`Hello, {rose Rose}.`, 'Hello, \u001B[38;2;246;217;217mRose\u001B[39m.'); + const instance = chalk.constructor({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 ctx = m.constructor({level: 0}); - t.is(ctx`Hello + const instance = chalk.constructor({level: 0}); + t.is(instance`Hello {red there}`, 'Hello\nthere'); }); test('correctly parse newline escapes (bug #177)', t => { - const ctx = m.constructor({level: 0}); - t.is(ctx`Hello\nthere!`, `Hello\nthere!`); + const instance = chalk.constructor({level: 0}); + t.is(instance`Hello\nthere!`, 'Hello\nthere!'); }); test('correctly parse escape in parameters (bug #177 comment 318622809)', t => { - const ctx = m.constructor({level: 0}); + const instance = chalk.constructor({level: 0}); const str = '\\'; - t.is(ctx`{blue ${str}}`, '\\'); + t.is(instance`{blue ${str}}`, '\\'); }); test('correctly parses unicode/hex escapes', t => { - const ctx = m.constructor({level: 0}); - t.is(ctx`\u0078ylophones are fo\x78y! {magenta.inverse \u0078ylophones are fo\x78y!}`, + const instance = chalk.constructor({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 ctx = m.constructor({level: 3}); - t.is(ctx`{keyword('black').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); - t.is(ctx`{keyword('blac\x6B').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); - t.is(ctx`{keyword('blac\u006B').bold can haz cheezburger}`, '\u001B[38;2;0;0;0m\u001B[1mcan haz cheezburger\u001B[22m\u001B[39m'); + const instance = chalk.constructor({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'); }); test('throws if a bad argument is encountered', t => { - const ctx = m.constructor({level: 3}); // Keep level at least 1 in case we optimize for disabled chalk instances + const instance = chalk.constructor({level: 3}); // Keep level at least 1 in case we optimize for disabled chalk instances try { - console.log(ctx`{keyword(????) hi}`); + console.log(instance`{keyword(????) hi}`); t.fail(); - } catch (err) { - t.is(err.message, 'Invalid Chalk template style argument: ???? (in style \'keyword\')'); + } catch (error) { + t.is(error.message, 'Invalid Chalk template style argument: ???? (in style \'keyword\')'); } }); test('throws if an extra unescaped } is found', t => { - const ctx = m.constructor({level: 0}); + const instance = chalk.constructor({level: 0}); try { - console.log(ctx`{red hi!}}`); + console.log(instance`{red hi!}}`); t.fail(); - } catch (err) { - t.is(err.message, 'Found extraneous } in Chalk template literal'); + } catch (error) { + t.is(error.message, 'Found extraneous } in Chalk template literal'); } }); test('should not parse upper-case escapes', t => { - const ctx = m.constructor({level: 0}); - t.is(ctx`\N\n\T\t\X07\x07\U000A\u000A\U000a\u000a`, 'N\nT\tX07\x07U000A\u000AU000a\u000A'); + const instance = chalk.constructor({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 ctx = m.constructor({level: 0}); - t.is(ctx`hello ${undefined}`, 'hello undefined'); - t.is(ctx`hello ${null}`, 'hello null'); + const instance = chalk.constructor({level: 0}); + t.is(instance`hello ${undefined}`, 'hello undefined'); + t.is(instance`hello ${null}`, 'hello null'); }); diff --git a/test/visible.js b/test/visible.js index 5d53bce..3266295 100644 --- a/test/visible.js +++ b/test/visible.js @@ -3,45 +3,45 @@ import test from 'ava'; // Spoof supports-color require('./_supports-color')(__dirname); -const m = require('..'); +const chalk = require('..'); test('visible: normal output when enabled', t => { - const ctx = new m.constructor({level: 3, enabled: true}); - t.is(ctx.visible.red('foo'), '\u001B[31mfoo\u001B[39m'); - t.is(ctx.red.visible('foo'), '\u001B[31mfoo\u001B[39m'); + const instance = new chalk.constructor({level: 3, enabled: true}); + 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 disabled', t => { - const ctx = new m.constructor({level: 3, enabled: false}); - t.is(ctx.red.visible('foo'), ''); - t.is(ctx.visible.red('foo'), ''); + const instance = new chalk.constructor({level: 3, enabled: false}); + t.is(instance.red.visible('foo'), ''); + t.is(instance.visible.red('foo'), ''); }); test('visible: no output when level is too low', t => { - const ctx = new m.constructor({level: 0, enabled: true}); - t.is(ctx.visible.red('foo'), ''); - t.is(ctx.red.visible('foo'), ''); + const instance = new chalk.constructor({level: 0, enabled: true}); + t.is(instance.visible.red('foo'), ''); + t.is(instance.red.visible('foo'), ''); }); test('test switching back and forth between enabled and disabled', t => { - const ctx = new m.constructor({level: 3, enabled: true}); - t.is(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); - t.is(ctx.visible.red('foo'), '\u001B[31mfoo\u001B[39m'); - t.is(ctx.red.visible('foo'), '\u001B[31mfoo\u001B[39m'); - t.is(ctx.visible('foo'), 'foo'); - t.is(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); + const instance = new chalk.constructor({level: 3, enabled: true}); + 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'); + t.is(instance.visible('foo'), 'foo'); + t.is(instance.red('foo'), '\u001B[31mfoo\u001B[39m'); - ctx.enabled = false; - t.is(ctx.red('foo'), 'foo'); - t.is(ctx.visible('foo'), ''); - t.is(ctx.visible.red('foo'), ''); - t.is(ctx.red.visible('foo'), ''); - t.is(ctx.red('foo'), 'foo'); + instance.enabled = false; + t.is(instance.red('foo'), 'foo'); + t.is(instance.visible('foo'), ''); + t.is(instance.visible.red('foo'), ''); + t.is(instance.red.visible('foo'), ''); + t.is(instance.red('foo'), 'foo'); - ctx.enabled = true; - t.is(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); - t.is(ctx.visible.red('foo'), '\u001B[31mfoo\u001B[39m'); - t.is(ctx.red.visible('foo'), '\u001B[31mfoo\u001B[39m'); - t.is(ctx.visible('foo'), 'foo'); - t.is(ctx.red('foo'), '\u001B[31mfoo\u001B[39m'); + instance.enabled = true; + 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'); + t.is(instance.visible('foo'), 'foo'); + t.is(instance.red('foo'), '\u001B[31mfoo\u001B[39m'); }); diff --git a/test/windows.js b/test/windows.js index 2f2815e..3ede386 100644 --- a/test/windows.js +++ b/test/windows.js @@ -28,36 +28,36 @@ test.beforeEach(() => { test('detect a simple term if TERM isn\'t set', t => { delete process.env.TERM; - const m = importFresh('..'); - t.is(m.blue('foo'), '\u001B[94mfoo\u001B[39m'); + const chalk = importFresh('..'); + t.is(chalk.blue('foo'), '\u001B[94mfoo\u001B[39m'); }); test('replace blue foreground color in cmd.exe', t => { process.env.TERM = 'dumb'; - const m = importFresh('..'); - t.is(m.blue('foo'), '\u001B[94mfoo\u001B[39m'); + const chalk = importFresh('..'); + t.is(chalk.blue('foo'), '\u001B[94mfoo\u001B[39m'); }); test('don\'t replace blue foreground color in xterm based terminals', t => { process.env.TERM = 'xterm-256color'; - const m = importFresh('..'); - t.is(m.blue('foo'), '\u001B[34mfoo\u001B[39m'); + const chalk = importFresh('..'); + t.is(chalk.blue('foo'), '\u001B[34mfoo\u001B[39m'); }); test('don\'t apply dimmed styling on gray strings, see https://github.com/chalk/chalk/issues/58', t => { process.env.TERM = 'dumb'; - const m = importFresh('..'); - t.is(m.gray.dim('foo'), '\u001B[90mfoo\u001B[22m\u001B[39m'); + const chalk = importFresh('..'); + t.is(chalk.gray.dim('foo'), '\u001B[90mfoo\u001B[22m\u001B[39m'); }); test('apply dimmed styling on xterm compatible terminals', t => { process.env.TERM = 'xterm'; - const m = importFresh('..'); - t.is(m.gray.dim('foo'), '\u001B[90m\u001B[2mfoo\u001B[22m\u001B[39m'); + const chalk = importFresh('..'); + t.is(chalk.gray.dim('foo'), '\u001B[90m\u001B[2mfoo\u001B[22m\u001B[39m'); }); test('apply dimmed styling on strings of other colors', t => { process.env.TERM = 'dumb'; - const m = importFresh('..'); - t.is(m.blue.dim('foo'), '\u001B[94m\u001B[2mfoo\u001B[22m\u001B[39m'); + const chalk = importFresh('..'); + t.is(chalk.blue.dim('foo'), '\u001B[94m\u001B[2mfoo\u001B[22m\u001B[39m'); }); From 2a678789b1ecdb6ad2ad0c918a7ee70df7abb464 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 18 Sep 2018 15:33:20 +0700 Subject: [PATCH 107/235] Validate the `level` option Fixes #248 --- index.js | 6 ++++-- test/constructor.js | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 333c836..917c45f 100644 --- a/index.js +++ b/index.js @@ -15,8 +15,10 @@ const skipModels = new Set(['gray']); const styles = Object.create(null); -function applyOptions(obj, options) { - options = options || {}; +function applyOptions(obj, options = {}) { + if (options.level > 3 || options.level < 0) { + throw new Error('The `level` option should be an integer from 0 to 3'); + } // Detect level if not set manually const scLevel = stdoutColor ? stdoutColor.level : 0; diff --git a/test/constructor.js b/test/constructor.js index 510f1a0..bda0137 100644 --- a/test/constructor.js +++ b/test/constructor.js @@ -20,3 +20,15 @@ test('create an isolated context where colors can be disabled (by enabled flag)' instance.enabled = true; t.is(instance.red('foo'), '\u001B[31mfoo\u001B[39m'); }); + +test('the `level` option should be a number from 0 to 3', t => { + /* eslint-disable no-new */ + t.throws(() => { + new chalk.constructor({level: 10}); + }, /should be an integer from 0 to 3/); + + t.throws(() => { + new chalk.constructor({level: -1}); + }, /should be an integer from 0 to 3/); + /* eslint-enable no-new */ +}); From 6a14c58e54809f15889830eddee1ea8a6acb1b2e Mon Sep 17 00:00:00 2001 From: Chris Harwood Date: Tue, 18 Sep 2018 04:48:47 -0400 Subject: [PATCH 108/235] Add failing test for #234 (#235) --- test/_supports-color.js | 22 +++++++++++----------- test/no-color-support.js | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 11 deletions(-) create mode 100644 test/no-color-support.js diff --git a/test/_supports-color.js b/test/_supports-color.js index cfca6cc..490c323 100644 --- a/test/_supports-color.js +++ b/test/_supports-color.js @@ -1,15 +1,15 @@ 'use strict'; const resolveFrom = require('resolve-from'); -module.exports = dir => { - require.cache[resolveFrom(dir, 'supports-color')] = { - exports: { - stdout: { - level: 3, - hasBasic: true, - has256: true, - has16m: true - } - } - }; +const DEFAULT = { + stdout: { + 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/no-color-support.js b/test/no-color-support.js new file mode 100644 index 0000000..90d934d --- /dev/null +++ b/test/no-color-support.js @@ -0,0 +1,16 @@ +import test from 'ava'; + +// Spoof supports-color +require('./_supports-color')(__dirname, { + level: 0, + hasBasic: false, + has256: false, + has16m: false +}); + +const chalk = require('..'); + +test.failing('colors can be forced by using chalk.enabled', t => { + chalk.enabled = true; + t.is(chalk.green('hello'), '\u001B[32mhello\u001B[39m'); +}); From b9c95dbfd27371a428e642dd3b8d0f2159d642ac Mon Sep 17 00:00:00 2001 From: Paul Melnikow Date: Tue, 18 Sep 2018 15:20:53 -0400 Subject: [PATCH 109/235] Add type definitions badge (#286) --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index e16f679..99556d8 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) [![Mentioned in Awesome Node.js](https://awesome.re/mentioned-badge.svg)](https://github.com/sindresorhus/awesome-nodejs) +[![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- and Flow-ready](https://img.shields.io/npm/types/chalk.svg) ### [See what's new in Chalk 2](https://github.com/chalk/chalk/releases/tag/v2.0.0) From 8a090d788513a96c4c5e5cc74017c8006d1ba236 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 30 Sep 2018 01:41:55 +0700 Subject: [PATCH 110/235] Add Tidelift mention in the readme --- readme.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 99556d8..2454dd2 100644 --- a/readme.md +++ b/readme.md @@ -11,10 +11,22 @@ [![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- and Flow-ready](https://img.shields.io/npm/types/chalk.svg) -### [See what's new in Chalk 2](https://github.com/chalk/chalk/releases/tag/v2.0.0) - +--- + +
+ + Get professional support for Chalk with a Tidelift subscription + +
+ + Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies. +
+
+ +--- + ## Highlights From 1542c85f1b31867f387a322be7396ce069adfe26 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 13 Oct 2018 12:32:09 +0700 Subject: [PATCH 111/235] Replace RawGit URL Fixes #305 --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 2454dd2..53a7e7e 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ [![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- and Flow-ready](https://img.shields.io/npm/types/chalk.svg) - + --- From b827cb081792c04212284c93bb07bd5c758bab05 Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Sat, 27 Oct 2018 16:09:54 +0200 Subject: [PATCH 112/235] Fix ignore chars regex flags in rainbow example (#306) Use global matches rather than stopping after the first match. --- examples/rainbow.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rainbow.js b/examples/rainbow.js index a4a2e0a..fc086fa 100644 --- a/examples/rainbow.js +++ b/examples/rainbow.js @@ -1,7 +1,7 @@ 'use strict'; const chalk = require('..'); -const ignoreChars = /[^!-~]/; +const ignoreChars = /[^!-~]/g; function rainbow(str, offset) { if (!str || str.length === 0) { From 70bb378e8e99385acfff28141b08249c5985b351 Mon Sep 17 00:00:00 2001 From: Timothy Yung Date: Thu, 29 Nov 2018 20:34:09 -0800 Subject: [PATCH 113/235] Strict mode in Flow definition (#309) --- index.js.flow | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js.flow b/index.js.flow index 872a156..622caaa 100644 --- a/index.js.flow +++ b/index.js.flow @@ -1,4 +1,4 @@ -// @flow +// @flow strict type TemplateStringsArray = $ReadOnlyArray; From f590a65489d8fc36c21a2f5f8d82d91d438ab05d Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 25 Dec 2018 14:45:17 +0100 Subject: [PATCH 114/235] Add security section --- readme.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/readme.md b/readme.md index 53a7e7e..604fc4e 100644 --- a/readme.md +++ b/readme.md @@ -297,6 +297,11 @@ If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) i [colors.js](https://github.com/Marak/colors.js) used to be the most popular string styling module, but it has serious deficiencies like extending `String.prototype` which causes all kinds of [problems](https://github.com/yeoman/yo/issues/68) and the package is unmaintained. Although there are other packages, they either do too much or not enough. Chalk is a clean and focused alternative. +## Security + +To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. + + ## Related - [chalk-cli](https://github.com/chalk/chalk-cli) - CLI for this module From 90c7a92ff126233a6e0350fdc163b5045935b09c Mon Sep 17 00:00:00 2001 From: George Gkasdrogkas Date: Wed, 26 Dec 2018 03:06:00 +0200 Subject: [PATCH 115/235] Add docs comments and tests for TypeScript definitions (#299) Fixes #293 --- index.d.ts | 282 +++++++++++++++++++++++++++ index.js | 2 +- index.test-d.ts | 139 +++++++++++++ package.json | 11 +- readme.md | 18 +- templates.js | 2 +- types/tsconfig.json => tsconfig.json | 0 types/index.d.ts | 97 --------- types/test.ts | 56 ------ 9 files changed, 438 insertions(+), 169 deletions(-) create mode 100644 index.d.ts create mode 100644 index.test-d.ts rename types/tsconfig.json => tsconfig.json (100%) delete mode 100644 types/index.d.ts delete mode 100644 types/test.ts diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..f08f46d --- /dev/null +++ b/index.d.ts @@ -0,0 +1,282 @@ +export const enum Level { + /** + * All colors disabled. + */ + None = 0, + + /** + * Basic 16 colors support. + */ + Basic = 1, + + /** + * ANSI 256 colors support. + */ + Ansi256 = 2, + + /** + * Truecolor 16 million colors support. + */ + TrueColor = 3 +} + +export interface Options { + /** + * Enable or disable Chalk. + * + * @default true + */ + enabled?: boolean; + + /** + * Specify the color support for Chalk. By default, + * color support is automatically detected based on + * the environment. + */ + level?: Level; +} + +export interface Constructor { + /** + * Return a new Chalk instance. + */ + new (options?: Options): Chalk; + + /** + * Return a new Chalk instance. + */ + (options?: Options): Chalk; +} + +/** + * Detect whether the terminal supports color. + */ +export 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; +} + +export interface Chalk { + (...text: string[]): string; + + (text: TemplateStringsArray, ...placeholders: string[]): string; + + /** + * Return a new Chalk instance. + */ + constructor: Constructor; + + /** + * Enable or disable Chalk. + * + * @default true + */ + enabled: boolean; + + /** + * The color support for Chalk. By default, color + * support is automatically detected based on the + * environment. + */ + level: Level; + + /** + * 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 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 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 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; + + /** + * Modifier: Resets the current color chain. + */ + readonly reset: this; + + /** + * Modifier: Make text bold. + */ + readonly bold: this; + + /** + * Modifier: Emitting only a small amount of light. + */ + readonly dim: this; + + /** + * Modifier: Make text italic. (Not widely supported) + */ + readonly italic: this; + + /** + * Modifier: Make text underline. (Not widely supported) + */ + readonly underline: 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 is enabled. 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; + readonly gray: this; + 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; + 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 & { supportsColor: ColorSupport }; + +export default chalk; diff --git a/index.js b/index.js index 917c45f..b77dfbb 100644 --- a/index.js +++ b/index.js @@ -199,7 +199,7 @@ function applyStyle(...args) { } function chalkTag(chalk, ...strings) { - const firstString = strings[0]; + const [firstString] = strings; if (!Array.isArray(firstString)) { // If chalk() was called by itself or with a string, diff --git a/index.test-d.ts b/index.test-d.ts new file mode 100644 index 0000000..a91003b --- /dev/null +++ b/index.test-d.ts @@ -0,0 +1,139 @@ +import {expectType} from 'tsd-check'; +import chalk, {Level, Chalk, ColorSupport} from '.'; + +// - Helpers - +type colorReturn = Chalk & {supportsColor: ColorSupport}; + +// - Level - +expectType(Level.None); +expectType(Level.Basic); +expectType(Level.Ansi256); +expectType(Level.TrueColor); + +// - supportsColor - +expectType(chalk.supportsColor.hasBasic); +expectType(chalk.supportsColor.has256); +expectType(chalk.supportsColor.has16m); + +// - Chalk - +// -- Constructor -- +expectType(chalk.constructor()); +expectType(chalk.constructor()); +expectType(new chalk.constructor({level: 1})); + +// -- Properties -- +expectType(chalk.enabled); +expectType(chalk.level); + +// -- Template literal -- +expectType(chalk``); +const name = 'John'; +expectType(chalk`Hello {bold.red ${name}}`); + +// -- Color methods -- +expectType(chalk.hex('#DEADED')); +expectType(chalk.keyword('orange')); +expectType(chalk.rgb(0, 0, 0)); +expectType(chalk.hsl(0, 0, 0)); +expectType(chalk.hsv(0, 0, 0)); +expectType(chalk.hwb(0, 0, 0)); +expectType(chalk.bgHex('#DEADED')); +expectType(chalk.bgKeyword('orange')); +expectType(chalk.bgRgb(0, 0, 0)); +expectType(chalk.bgHsl(0, 0, 0)); +expectType(chalk.bgHsv(0, 0, 0)); +expectType(chalk.bgHwb(0, 0, 0)); + +// -- Modifiers -- +expectType(chalk.reset('foo')); +expectType(chalk.bold('foo')); +expectType(chalk.dim('foo')); +expectType(chalk.italic('foo')); +expectType(chalk.underline('foo')); +expectType(chalk.inverse('foo')); +expectType(chalk.hidden('foo')); +expectType(chalk.strikethrough('foo')); +expectType(chalk.visible('foo')); +expectType(chalk.reset`foo`); +expectType(chalk.bold`foo`); +expectType(chalk.dim`foo`); +expectType(chalk.italic`foo`); +expectType(chalk.underline`foo`); +expectType(chalk.inverse`foo`); +expectType(chalk.hidden`foo`); +expectType(chalk.strikethrough`foo`); +expectType(chalk.visible`foo`); + +// -- Colors -- +expectType(chalk.black('foo')); +expectType(chalk.red('foo')); +expectType(chalk.green('foo')); +expectType(chalk.yellow('foo')); +expectType(chalk.blue('foo')); +expectType(chalk.magenta('foo')); +expectType(chalk.cyan('foo')); +expectType(chalk.white('foo')); +expectType(chalk.gray('foo')); +expectType(chalk.grey('foo')); +expectType(chalk.blackBright('foo')); +expectType(chalk.redBright('foo')); +expectType(chalk.greenBright('foo')); +expectType(chalk.yellowBright('foo')); +expectType(chalk.blueBright('foo')); +expectType(chalk.magentaBright('foo')); +expectType(chalk.cyanBright('foo')); +expectType(chalk.whiteBright('foo')); +expectType(chalk.bgBlack('foo')); +expectType(chalk.bgRed('foo')); +expectType(chalk.bgGreen('foo')); +expectType(chalk.bgYellow('foo')); +expectType(chalk.bgBlue('foo')); +expectType(chalk.bgMagenta('foo')); +expectType(chalk.bgCyan('foo')); +expectType(chalk.bgWhite('foo')); +expectType(chalk.bgBlackBright('foo')); +expectType(chalk.bgRedBright('foo')); +expectType(chalk.bgGreenBright('foo')); +expectType(chalk.bgYellowBright('foo')); +expectType(chalk.bgBlueBright('foo')); +expectType(chalk.bgMagentaBright('foo')); +expectType(chalk.bgCyanBright('foo')); +expectType(chalk.bgWhiteBright('foo')); +expectType(chalk.black`foo`); +expectType(chalk.red`foo`); +expectType(chalk.green`foo`); +expectType(chalk.yellow`foo`); +expectType(chalk.blue`foo`); +expectType(chalk.magenta`foo`); +expectType(chalk.cyan`foo`); +expectType(chalk.white`foo`); +expectType(chalk.gray`foo`); +expectType(chalk.grey`foo`); +expectType(chalk.blackBright`foo`); +expectType(chalk.redBright`foo`); +expectType(chalk.greenBright`foo`); +expectType(chalk.yellowBright`foo`); +expectType(chalk.blueBright`foo`); +expectType(chalk.magentaBright`foo`); +expectType(chalk.cyanBright`foo`); +expectType(chalk.whiteBright`foo`); +expectType(chalk.bgBlack`foo`); +expectType(chalk.bgRed`foo`); +expectType(chalk.bgGreen`foo`); +expectType(chalk.bgYellow`foo`); +expectType(chalk.bgBlue`foo`); +expectType(chalk.bgMagenta`foo`); +expectType(chalk.bgCyan`foo`); +expectType(chalk.bgWhite`foo`); +expectType(chalk.bgBlackBright`foo`); +expectType(chalk.bgRedBright`foo`); +expectType(chalk.bgGreenBright`foo`); +expectType(chalk.bgYellowBright`foo`); +expectType(chalk.bgBlueBright`foo`); +expectType(chalk.bgMagentaBright`foo`); +expectType(chalk.bgCyanBright`foo`); +expectType(chalk.bgWhiteBright`foo`); + +// -- Complex -- +expectType(chalk.red.bgGreen.underline('foo')); +expectType(chalk.underline.red.bgGreen('foo')); diff --git a/package.json b/package.json index 32c6f73..44a2ba3 100644 --- a/package.json +++ b/package.json @@ -8,13 +8,13 @@ "node": ">=6" }, "scripts": { - "test": "xo && nyc ava && tsc --project types && flow --max-warnings=0", + "test": "xo && nyc ava && tsd-check && flow --max-warnings=0", "bench": "matcha benchmark.js" }, "files": [ "index.js", "templates.js", - "types/index.d.ts", + "index.d.ts", "index.js.flow" ], "keywords": [ @@ -54,10 +54,11 @@ "matcha": "^0.7.0", "nyc": "^13.0.1", "resolve-from": "^4.0.0", - "typescript": "^3.0.3", - "xo": "^0.23.0" + "tsd-check": "^0.2.1", + "typescript": "^2.5.3", + "xo": "0.20.3" }, - "types": "types/index.d.ts", + "types": "index.d.ts", "xo": { "ignores": [ "test/_flow.js" diff --git a/readme.md b/readme.md index 604fc4e..7134b2b 100644 --- a/readme.md +++ b/readme.md @@ -178,15 +178,15 @@ Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color= ### Modifiers -- `reset` -- `bold` -- `dim` -- `italic` *(Not widely supported)* -- `underline` -- `inverse` -- `hidden` -- `strikethrough` *(Not widely supported)* -- `visible` (Text is emitted only if enabled) +- `reset` - Resets the current color chain. +- `bold` - Make text bold. +- `dim` - Emitting only a small amount of light. +- `italic` - Make text italic. *(Not widely supported)* +- `underline` - Make text underline. *(Not widely supported)* +- `inverse`- Inverse background and foreground colors. +- `hidden` - Prints the text, but makes it invisible. +- `strikethrough` - Puts a horizontal line through the center of the text. *(Not widely supported)* +- `visible`- Prints the text only when Chalk is enabled. Can be useful for things that are purely cosmetic. ### Colors diff --git a/templates.js b/templates.js index 8ce33fe..1f6c035 100644 --- a/templates.js +++ b/templates.js @@ -50,7 +50,7 @@ function parseStyle(style) { let matches; while ((matches = STYLE_REGEX.exec(style)) !== null) { - const name = matches[1]; + const name = matches[1]; // eslint-disable-line prefer-destructuring if (matches[2]) { const args = parseArguments(name, matches[2]); diff --git a/types/tsconfig.json b/tsconfig.json similarity index 100% rename from types/tsconfig.json rename to tsconfig.json diff --git a/types/index.d.ts b/types/index.d.ts deleted file mode 100644 index b4e4dc5..0000000 --- a/types/index.d.ts +++ /dev/null @@ -1,97 +0,0 @@ -// Type definitions for Chalk -// Definitions by: Thomas Sauer - -export const enum Level { - None = 0, - Basic = 1, - Ansi256 = 2, - TrueColor = 3 -} - -export interface ChalkOptions { - enabled?: boolean; - level?: Level; -} - -export interface ChalkConstructor { - new (options?: ChalkOptions): Chalk; - (options?: ChalkOptions): Chalk; -} - -export interface ColorSupport { - level: Level; - hasBasic: boolean; - has256: boolean; - has16m: boolean; -} - -export interface Chalk { - (...text: string[]): string; - (text: TemplateStringsArray, ...placeholders: string[]): string; - constructor: ChalkConstructor; - enabled: boolean; - level: Level; - rgb(r: number, g: number, b: number): this; - hsl(h: number, s: number, l: number): this; - hsv(h: number, s: number, v: number): this; - hwb(h: number, w: number, b: number): this; - bgHex(color: string): this; - bgKeyword(color: string): this; - bgRgb(r: number, g: number, b: number): this; - bgHsl(h: number, s: number, l: number): this; - bgHsv(h: number, s: number, v: number): this; - bgHwb(h: number, w: number, b: number): this; - hex(color: string): this; - keyword(color: string): this; - - readonly reset: this; - readonly bold: this; - readonly dim: this; - readonly italic: this; - readonly underline: this; - readonly inverse: this; - readonly hidden: this; - readonly strikethrough: this; - - 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; - readonly gray: this; - 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; - readonly bgBlackBright: this; - readonly bgRedBright: this; - readonly bgGreenBright: this; - readonly bgYellowBright: this; - readonly bgBlueBright: this; - readonly bgMagentaBright: this; - readonly bgCyanBright: this; - readonly bgWhiteBright: this; -} - -declare const chalk: Chalk & { supportsColor: ColorSupport }; - -export default chalk diff --git a/types/test.ts b/types/test.ts deleted file mode 100644 index cedb39a..0000000 --- a/types/test.ts +++ /dev/null @@ -1,56 +0,0 @@ -import chalk, {Level} from '..'; - -chalk.underline('foo'); -chalk.red('foo'); -chalk.bgRed('foo'); - -const name = 'Josh'; -chalk`Hello {bold.red ${name}}`; - -chalk.red`foo`; -chalk.underline`foo`; -chalk`foo`; - -chalk.red.bgGreen.underline('foo'); -chalk.underline.red.bgGreen('foo'); - -chalk.grey('foo'); - -chalk.constructor({level: 1}); -const ctx = chalk.constructor({level: Level.TrueColor }); -ctx('foo'); -ctx.red('foo'); -ctx`foo`; - -chalk.enabled = true; -chalk.level = 1; -chalk.level = Level.Ansi256; - -chalk.level === Level.Ansi256; - -let chalkInstance = new chalk.constructor(); -chalkInstance = chalk.constructor(); - -chalkInstance.blue('foo'); -chalkInstance`foo`; - -let x = 'imastring'; -x = chalk(); - -chalk.enabled; -chalk.level; -chalk.supportsColor.level; -chalk.supportsColor.has16m; -chalk.supportsColor.has256; -chalk.supportsColor.hasBasic; - -chalk.keyword('orange').bgBlue('foo'); -chalk.hex('#123456').bgBlue('foo'); -chalk.rgb(1, 14, 9).bgBlue('foo'); -chalk.hsl(1, 14, 9).bgBlue('foo'); -chalk.hsv(1, 14, 9).bgBlue('foo'); -chalk.hwb(1, 14, 9).bgBlue('foo'); - -chalk.visible('foo'); -chalk.red.visible('foo'); -chalk.visible.red('foo'); From 4726b1bfda3046ed02387ed587c8e9e8be1728b5 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 26 Dec 2018 02:18:40 +0100 Subject: [PATCH 116/235] Update dependencies and meta tweaks --- .flowconfig | 1 + .travis.yml | 1 + package.json | 18 +++++++++--------- tsconfig.json | 4 +--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.flowconfig b/.flowconfig index 2318f0d..48ee960 100644 --- a/.flowconfig +++ b/.flowconfig @@ -3,3 +3,4 @@ [options] suppress_comment= \\(.\\|\n\\)*\\$ExpectError +include_warnings=true diff --git a/.travis.yml b/.travis.yml index 60e38d8..c89aee6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: node_js node_js: + - '10' - '8' - '6' after_success: diff --git a/package.json b/package.json index 44a2ba3..35fb7d0 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "node": ">=6" }, "scripts": { - "test": "xo && nyc ava && tsd-check && flow --max-warnings=0", + "test": "xo && nyc ava && tsd-check && flow", "bench": "matcha benchmark.js" }, "files": [ @@ -43,20 +43,20 @@ "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", - "supports-color": "^5.5.0" + "supports-color": "^6.0.0" }, "devDependencies": { - "ava": "^0.25.0", + "@sindresorhus/tsconfig": "^0.1.1", + "ava": "^1.0.1", "coveralls": "^3.0.2", "execa": "^1.0.0", - "flow-bin": "^0.81.0", - "import-fresh": "^2.0.0", + "flow-bin": "^0.89.0", + "import-fresh": "^3.0.0", "matcha": "^0.7.0", - "nyc": "^13.0.1", + "nyc": "^13.1.0", "resolve-from": "^4.0.0", - "tsd-check": "^0.2.1", - "typescript": "^2.5.3", - "xo": "0.20.3" + "tsd-check": "^0.3.0", + "xo": "^0.23.0" }, "types": "index.d.ts", "xo": { diff --git a/tsconfig.json b/tsconfig.json index b73840f..3d73ee9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,6 @@ { + "extends": "@sindresorhus/tsconfig", "compilerOptions": { - "module": "commonjs", - "target": "es6", - "noImplicitAny": true, "noEmit": true, "allowJs": true } From cf6615647a55d5f0b8ff1c36f06faee6b22e3221 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 26 Dec 2018 02:25:23 +0100 Subject: [PATCH 117/235] Type definition improvements --- index.d.ts | 13 ++++++------- index.js.flow | 22 +++++++++++----------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/index.d.ts b/index.d.ts index f08f46d..f2a1149 100644 --- a/index.d.ts +++ b/index.d.ts @@ -29,9 +29,8 @@ export interface Options { enabled?: boolean; /** - * Specify the color support for Chalk. By default, - * color support is automatically detected based on - * the environment. + * Specify the color support for Chalk. + * By default, color support is automatically detected based on the environment. */ level?: Level; } @@ -91,9 +90,8 @@ export interface Chalk { enabled: boolean; /** - * The color support for Chalk. By default, color - * support is automatically detected based on the - * environment. + * The color support for Chalk. + * By default, color support is automatically detected based on the environment. */ level: Level; @@ -230,7 +228,8 @@ export interface Chalk { readonly strikethrough: this; /** - * Modifier: Prints the text only when Chalk is enabled. Can be useful for things that are purely cosmetic. + * Modifier: Prints the text only when Chalk is enabled. + * Can be useful for things that are purely cosmetic. */ readonly visible: this; diff --git a/index.js.flow b/index.js.flow index 622caaa..aac750e 100644 --- a/index.js.flow +++ b/index.js.flow @@ -9,7 +9,7 @@ export type Level = $Values<{ TrueColor: 3 }>; -export type ChalkOptions = {| +export type Options = {| enabled?: boolean, level?: Level |}; @@ -24,19 +24,19 @@ export type ColorSupport = {| export interface Chalk { (...text: string[]): string, (text: TemplateStringsArray, ...placeholders: string[]): string, - constructor(options?: ChalkOptions): Chalk, + constructor(options?: Options): Chalk, enabled: boolean, level: Level, - rgb(r: number, g: number, b: number): Chalk, - hsl(h: number, s: number, l: number): Chalk, - hsv(h: number, s: number, v: number): Chalk, - hwb(h: number, w: number, b: number): Chalk, + rgb(red: number, green: number, blue: number): Chalk, + hsl(hue: number, saturation: number, lightness: number): Chalk, + hsv(hue: number, saturation: number, value: number): Chalk, + hwb(hue: number, whiteness: number, blackness: number): Chalk, bgHex(color: string): Chalk, bgKeyword(color: string): Chalk, - bgRgb(r: number, g: number, b: number): Chalk, - bgHsl(h: number, s: number, l: number): Chalk, - bgHsv(h: number, s: number, v: number): Chalk, - bgHwb(h: number, w: number, b: number): Chalk, + bgRgb(red: number, green: number, blue: number): Chalk, + bgHsl(hue: number, saturation: number, lightness: number): Chalk, + bgHsv(hue: number, saturation: number, value: number): Chalk, + bgHwb(hue: number, whiteness: number, blackness: number): Chalk, hex(color: string): Chalk, keyword(color: string): Chalk, @@ -85,7 +85,7 @@ export interface Chalk { +bgBlueBright: Chalk, +bgMagentaBright: Chalk, +bgCyanBright: Chalk, - +bgWhiteBrigh: Chalk, + +bgWhiteBright: Chalk, supportsColor: ColorSupport }; From 1284415013c24c5c51c1ee339bf85c7c8b7cbd7c Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 26 Dec 2018 02:27:57 +0100 Subject: [PATCH 118/235] Enforce `chalk.constructor` to be called with `new` in TypeScript --- index.d.ts | 5 ----- index.test-d.ts | 2 -- 2 files changed, 7 deletions(-) diff --git a/index.d.ts b/index.d.ts index f2a1149..b42e4c0 100644 --- a/index.d.ts +++ b/index.d.ts @@ -40,11 +40,6 @@ export interface Constructor { * Return a new Chalk instance. */ new (options?: Options): Chalk; - - /** - * Return a new Chalk instance. - */ - (options?: Options): Chalk; } /** diff --git a/index.test-d.ts b/index.test-d.ts index a91003b..6cda4da 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -17,8 +17,6 @@ expectType(chalk.supportsColor.has16m); // - Chalk - // -- Constructor -- -expectType(chalk.constructor()); -expectType(chalk.constructor()); expectType(new chalk.constructor({level: 1})); // -- Properties -- From 076f0c9eb6d6575db745f2753832918eaefe627d Mon Sep 17 00:00:00 2001 From: Chris Harwood Date: Tue, 25 Dec 2018 20:29:32 -0500 Subject: [PATCH 119/235] Add extra level/enabled property info in the readme (#308) --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 7134b2b..d8ca070 100644 --- a/readme.md +++ b/readme.md @@ -138,7 +138,7 @@ Multiple arguments will be separated by space. ### chalk.enabled -Color support is automatically detected, as is the level (see `chalk.level`). However, if you'd like to simply enable/disable Chalk, you can do so via the `.enabled` property. +Color support is automatically detected, as is the level (see `chalk.level`). However, if you'd like to simply enable/disable Chalk, you can do so via the `.enabled` property. When `chalk.enabled` is `true`, `chalk.level` must *also* be greater than `0` for colored output to be produced. Chalk is enabled by default unless explicitly disabled via the constructor or `chalk.level` is `0`. @@ -150,7 +150,7 @@ const ctx = new chalk.constructor({enabled: false}); ### chalk.level -Color support is automatically detected, but you can override it by setting the `level` property. You should however only do this in your own code as it applies globally to all Chalk consumers. +Color support is automatically detected, but you can override it by setting the `level` property. You should however only do this in your own code as it applies globally to all Chalk consumers. When `chalk.level` is greater than `0`, `chalk.enabled` must *also* be `true` for colored output to be produced. If you need to change this in a reusable module, create a new instance: From 587a5fbcbb61f83270fc102da47615b8ff64351c Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 26 Dec 2018 02:37:03 +0100 Subject: [PATCH 120/235] Code style tweaks --- index.js | 50 +++++++++++++++++++------------------------------- templates.js | 40 ++++++++++++++++++++++------------------ 2 files changed, 41 insertions(+), 49 deletions(-) diff --git a/index.js b/index.js index b77dfbb..73598be 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,7 @@ 'use strict'; const escapeStringRegexp = require('escape-string-regexp'); const ansiStyles = require('ansi-styles'); -const stdoutColor = require('supports-color').stdout; - +const {stdout: stdoutColor} = require('supports-color'); const template = require('./templates.js'); const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); @@ -15,15 +14,15 @@ const skipModels = new Set(['gray']); const styles = Object.create(null); -function applyOptions(obj, options = {}) { +function applyOptions(object, options = {}) { if (options.level > 3 || options.level < 0) { throw new Error('The `level` option should be an integer from 0 to 3'); } // Detect level if not set manually - const scLevel = stdoutColor ? stdoutColor.level : 0; - obj.level = options.level === undefined ? scLevel : options.level; - obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; + const colorLevel = stdoutColor ? stdoutColor.level : 0; + object.level = options.level === undefined ? colorLevel : options.level; + object.enabled = 'enabled' in options ? options.enabled : object.level > 0; } function Chalk(options) { @@ -33,7 +32,7 @@ function Chalk(options) { const chalk = {}; applyOptions(chalk, options); - chalk.template = (...args) => chalkTag(...[chalk.template].concat(args)); + chalk.template = (...args) => chalkTag(chalk.template, ...args); Object.setPrototypeOf(chalk, Chalk.prototype); Object.setPrototypeOf(chalk.template, chalk); @@ -57,7 +56,7 @@ for (const key of Object.keys(ansiStyles)) { styles[key] = { get() { const codes = ansiStyles[key]; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); + return build.call(this, [...(this._styles || []), codes], this._empty, key); } }; } @@ -84,7 +83,7 @@ for (const model of Object.keys(ansiStyles.color.ansi)) { close: ansiStyles.color.close, closeRe: ansiStyles.color.closeRe }; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); + return build.call(this, [...(this._styles || []), codes], this._empty, model); }; } }; @@ -107,7 +106,7 @@ for (const model of Object.keys(ansiStyles.bgColor.ansi)) { close: ansiStyles.bgColor.close, closeRe: ansiStyles.bgColor.closeRe }; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); + return build.call(this, [...(this._styles || []), codes], this._empty, model); }; } }; @@ -153,23 +152,10 @@ function build(_styles, _empty, key) { } function applyStyle(...args) { - // Support varags, but simply cast to string in case there's only one arg - const argsLen = args.length; - let str = String(args[0]); + let string = args.join(' '); - if (argsLen === 0) { - return ''; - } - - if (argsLen > 1) { - // Don't slice `arguments`, it prevents V8 optimizations - for (let a = 1; a < argsLen; a++) { - str += ' ' + args[a]; - } - } - - if (!this.enabled || this.level <= 0 || !str) { - return this._empty ? '' : str; + if (!this.enabled || this.level <= 0 || !string) { + return this._empty ? '' : string; } // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, @@ -184,18 +170,18 @@ function applyStyle(...args) { // Replace any instances already present with a re-opening code // otherwise only the part of the string until said closing code // will be colored, and the rest will simply be 'plain'. - str = code.open + str.replace(code.closeRe, code.open) + code.close; + string = code.open + string.replace(code.closeRe, code.open) + code.close; // Close the styling before a linebreak and reopen // after next line to fix a bleed issue on macOS // https://github.com/chalk/chalk/pull/92 - str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`); + string = string.replace(/\r?\n/g, `${code.close}$&${code.open}`); } // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue ansiStyles.dim.open = originalDim; - return str; + return string; } function chalkTag(chalk, ...strings) { @@ -211,8 +197,10 @@ function chalkTag(chalk, ...strings) { const parts = [firstString.raw[0]]; for (let i = 1; i < firstString.length; i++) { - parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); - parts.push(String(firstString.raw[i])); + parts.push( + String(args[i - 1]).replace(/[{}\\]/g, '\\$&'), + String(firstString.raw[i]) + ); } return template(chalk, parts.join('')); diff --git a/templates.js b/templates.js index 1f6c035..bbc614d 100644 --- a/templates.js +++ b/templates.js @@ -31,10 +31,11 @@ function parseArguments(name, args) { let matches; for (const chunk of chunks) { - if (!isNaN(chunk)) { - results.push(Number(chunk)); + const number = Number(chunk); + if (!Number.isNaN(number)) { + results.push(number); } else if ((matches = chunk.match(STRING_REGEX))) { - results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, chr) => escape ? unescape(escape) : chr)); + results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, character) => escape ? unescape(escape) : character)); } else { throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); } @@ -73,17 +74,20 @@ function buildStyle(chalk, styles) { } let current = chalk; + // TODO: Use `Object.entries` when targeting Node.js 8 for (const styleName of Object.keys(enabled)) { - if (Array.isArray(enabled[styleName])) { - if (!(styleName in current)) { - throw new Error(`Unknown Chalk style: ${styleName}`); - } + if (!Array.isArray(enabled[styleName])) { + continue; + } - if (enabled[styleName].length > 0) { - current = current[styleName](...enabled[styleName]); - } else { - current = current[styleName]; - } + if (!(styleName in current)) { + throw new Error(`Unknown Chalk style: ${styleName}`); + } + + if (enabled[styleName].length > 0) { + current = current[styleName](...enabled[styleName]); + } else { + current = current[styleName]; } } @@ -96,13 +100,13 @@ module.exports = (chalk, tmp) => { let chunk = []; // eslint-disable-next-line max-params - tmp.replace(TEMPLATE_REGEX, (m, escapeChar, inverse, style, close, chr) => { - if (escapeChar) { - chunk.push(unescape(escapeChar)); + tmp.replace(TEMPLATE_REGEX, (m, escapeCharacter, inverse, style, close, character) => { + if (escapeCharacter) { + chunk.push(unescape(escapeCharacter)); } else if (style) { - const str = chunk.join(''); + const string = chunk.join(''); chunk = []; - chunks.push(styles.length === 0 ? str : buildStyle(chalk, styles)(str)); + chunks.push(styles.length === 0 ? string : buildStyle(chalk, styles)(string)); styles.push({inverse, styles: parseStyle(style)}); } else if (close) { if (styles.length === 0) { @@ -113,7 +117,7 @@ module.exports = (chalk, tmp) => { chunk = []; styles.pop(); } else { - chunk.push(chr); + chunk.push(character); } }); From 7f6e5630b0097774d6961e9c0921697a300fbd0f Mon Sep 17 00:00:00 2001 From: Jonathan Van Buren Date: Fri, 28 Dec 2018 19:13:56 +0800 Subject: [PATCH 121/235] Change tagged template literal argument type to accept `unknown` instead of just `string` (#316) --- index.d.ts | 4 ++-- index.js.flow | 2 +- index.test-d.ts | 1 + test/_flow.js | 8 -------- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/index.d.ts b/index.d.ts index b42e4c0..b2c7213 100644 --- a/index.d.ts +++ b/index.d.ts @@ -68,9 +68,9 @@ export interface ColorSupport { } export interface Chalk { - (...text: string[]): string; + (...text: unknown[]): string; - (text: TemplateStringsArray, ...placeholders: string[]): string; + (text: TemplateStringsArray, ...placeholders: unknown[]): string; /** * Return a new Chalk instance. diff --git a/index.js.flow b/index.js.flow index aac750e..1a3099d 100644 --- a/index.js.flow +++ b/index.js.flow @@ -23,7 +23,7 @@ export type ColorSupport = {| export interface Chalk { (...text: string[]): string, - (text: TemplateStringsArray, ...placeholders: string[]): string, + (text: TemplateStringsArray, ...placeholders: mixed[]): string, constructor(options?: Options): Chalk, enabled: boolean, level: Level, diff --git a/index.test-d.ts b/index.test-d.ts index 6cda4da..5920526 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -27,6 +27,7 @@ expectType(chalk.level); expectType(chalk``); const name = 'John'; expectType(chalk`Hello {bold.red ${name}}`); +expectType(chalk`Works with numbers {bold.red ${1}}`); // -- Color methods -- expectType(chalk.hex('#DEADED')); diff --git a/test/_flow.js b/test/_flow.js index 2cf3cf2..ac76e85 100644 --- a/test/_flow.js +++ b/test/_flow.js @@ -9,10 +9,6 @@ chalk.constructor({level: 1}); new chalk.constructor({enabled: 'true'}); new chalk.constructor({enabled: true}); -// $ExpectError (Can't pass in null) -chalk.underline(null); -chalk.underline('foo'); - // $ExpectError (Can't have typo in chalk method) chalk.rd('foo'); chalk.red('foo'); @@ -29,10 +25,6 @@ chalk.red.bgBlue.underline('foo'); const badCtx = chalk.constructor({level: 4}); const ctx = chalk.constructor({level: 3}); -// $ExpectError (Can't pass in null) -ctx(null); -ctx('foo'); - // $ExpectError (Can't have typo in method name) ctx.gry('foo'); ctx.grey('foo'); From 60959e05cfe7086a38927eae5b5e04c459ce4182 Mon Sep 17 00:00:00 2001 From: Richie Bendall Date: Fri, 1 Mar 2019 19:14:20 +1300 Subject: [PATCH 122/235] Update depended packages count --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index d8ca070..1a511d4 100644 --- a/readme.md +++ b/readme.md @@ -38,7 +38,7 @@ - Doesn't extend `String.prototype` - Clean and focused - Actively maintained -- [Used by ~30,000 packages](https://www.npmjs.com/browse/depended/chalk) as of August 6, 2018 +- [Used by ~40,000 packages](https://www.npmjs.com/browse/depended/chalk) as of March 1, 2019 ## Install From de2f4cd6063b40834096c7dc874562006bb1283c Mon Sep 17 00:00:00 2001 From: Tom Sherman Date: Tue, 12 Mar 2019 12:53:03 +0000 Subject: [PATCH 123/235] Deprecate `chalk.constructor()` in favor of `new chalk.Instance()` (#322) --- index.d.ts | 4 ++-- index.js | 39 +++++++++++++++++++++++---------------- index.js.flow | 2 +- index.test-d.ts | 4 ++-- readme.md | 6 +++--- test/_flow.js | 14 +++++++------- test/chalk.js | 14 +++++++------- test/constructor.js | 33 +++++++-------------------------- test/instance.js | 34 ++++++++++++++++++++++++++++++++++ test/template-literal.js | 40 ++++++++++++++++++++-------------------- test/visible.js | 8 ++++---- 11 files changed, 110 insertions(+), 88 deletions(-) create mode 100644 test/instance.js diff --git a/index.d.ts b/index.d.ts index b2c7213..189e1a3 100644 --- a/index.d.ts +++ b/index.d.ts @@ -35,7 +35,7 @@ export interface Options { level?: Level; } -export interface Constructor { +export interface Instance { /** * Return a new Chalk instance. */ @@ -75,7 +75,7 @@ export interface Chalk { /** * Return a new Chalk instance. */ - constructor: Constructor; + Instance: Instance; /** * Enable or disable Chalk. diff --git a/index.js b/index.js index 73598be..d04ce95 100644 --- a/index.js +++ b/index.js @@ -25,24 +25,31 @@ function applyOptions(object, options = {}) { object.enabled = 'enabled' in options ? options.enabled : object.level > 0; } -function Chalk(options) { - // We check for this.template here since calling `chalk.constructor()` - // by itself will have a `this` of a previously constructed chalk object - if (!this || !(this instanceof Chalk) || this.template) { - const chalk = {}; - applyOptions(chalk, options); - - chalk.template = (...args) => chalkTag(chalk.template, ...args); - - Object.setPrototypeOf(chalk, Chalk.prototype); - Object.setPrototypeOf(chalk.template, chalk); - - chalk.template.constructor = Chalk; - - return chalk.template; +class ChalkClass { + constructor(options) { + return chalkFactory(options); } +} - applyOptions(this, options); +function chalkFactory(options) { + const chalk = {}; + applyOptions(chalk, options); + + chalk.template = (...args) => chalkTag(chalk.template, ...args); + + Object.setPrototypeOf(chalk, Chalk.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; + + return chalk.template; +} + +function Chalk(options) { + return chalkFactory(options); } // Use bright blue on Windows as the normal blue color is illegible diff --git a/index.js.flow b/index.js.flow index 1a3099d..f7e4abc 100644 --- a/index.js.flow +++ b/index.js.flow @@ -24,7 +24,7 @@ export type ColorSupport = {| export interface Chalk { (...text: string[]): string, (text: TemplateStringsArray, ...placeholders: mixed[]): string, - constructor(options?: Options): Chalk, + Instance(options?: Options): Chalk, enabled: boolean, level: Level, rgb(red: number, green: number, blue: number): Chalk, diff --git a/index.test-d.ts b/index.test-d.ts index 5920526..0b26e9c 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -16,8 +16,8 @@ expectType(chalk.supportsColor.has256); expectType(chalk.supportsColor.has16m); // - Chalk - -// -- Constructor -- -expectType(new chalk.constructor({level: 1})); +// -- Instance -- +expectType(new chalk.Instance({level: 1})); // -- Properties -- expectType(chalk.enabled); diff --git a/readme.md b/readme.md index 1a511d4..1e3b9bb 100644 --- a/readme.md +++ b/readme.md @@ -140,12 +140,12 @@ Multiple arguments will be separated by space. Color support is automatically detected, as is the level (see `chalk.level`). However, if you'd like to simply enable/disable Chalk, you can do so via the `.enabled` property. When `chalk.enabled` is `true`, `chalk.level` must *also* be greater than `0` for colored output to be produced. -Chalk is enabled by default unless explicitly disabled via the constructor or `chalk.level` is `0`. +Chalk is enabled by default unless explicitly disabled via `new chalk.Instance()` or `chalk.level` is `0`. If you need to change this in a reusable module, create a new instance: ```js -const ctx = new chalk.constructor({enabled: false}); +const ctx = new chalk.Instance({enabled: false}); ``` ### chalk.level @@ -155,7 +155,7 @@ 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.constructor({level: 0}); +const ctx = new chalk.Instance({level: 0}); ``` Levels are as follows: diff --git a/test/_flow.js b/test/_flow.js index ac76e85..dbb6dd0 100644 --- a/test/_flow.js +++ b/test/_flow.js @@ -2,12 +2,12 @@ import chalk from '..'; // $ExpectError (Can't have typo in option name) -chalk.constructor({levl: 1}); -chalk.constructor({level: 1}); +new chalk.Instance({levl: 1}); +new chalk.Instance({level: 1}); // $ExpectError (Option must have proper type) -new chalk.constructor({enabled: 'true'}); -new chalk.constructor({enabled: true}); +new chalk.Instance({enabled: 'true'}); +new chalk.Instance({enabled: true}); // $ExpectError (Can't have typo in chalk method) chalk.rd('foo'); @@ -22,8 +22,8 @@ chalk.red.bgBlu.underline('foo'); chalk.red.bgBlue.underline('foo'); // $ExpectError (Level must be 0, 1, 2, or 3) -const badCtx = chalk.constructor({level: 4}); -const ctx = chalk.constructor({level: 3}); +const badCtx = chalk.Instance({level: 4}); +const ctx = chalk.Instance({level: 3}); // $ExpectError (Can't have typo in method name) ctx.gry('foo'); @@ -41,7 +41,7 @@ chalk.enabled = true; chalk.level = 10; chalk.level = 1; -const chalkInstance = new chalk.constructor(); +const chalkInstance = new chalk.Instance(); // $ExpectError (Can't have typo in method name) chalkInstance.blu('foo'); diff --git a/test/chalk.js b/test/chalk.js index a53b6f5..240f0f9 100644 --- a/test/chalk.js +++ b/test/chalk.js @@ -83,17 +83,17 @@ test('line breaks should open and close colors', t => { }); test('properly convert RGB to 16 colors on basic color terminals', t => { - t.is(new chalk.constructor({level: 1}).hex('#FF0000')('hello'), '\u001B[91mhello\u001B[39m'); - t.is(new chalk.constructor({level: 1}).bgHex('#FF0000')('hello'), '\u001B[101mhello\u001B[49m'); + 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'); }); test('properly convert RGB to 256 colors on basic color terminals', t => { - t.is(new chalk.constructor({level: 2}).hex('#FF0000')('hello'), '\u001B[38;5;196mhello\u001B[39m'); - t.is(new chalk.constructor({level: 2}).bgHex('#FF0000')('hello'), '\u001B[48;5;196mhello\u001B[49m'); - t.is(new chalk.constructor({level: 3}).bgHex('#FF0000')('hello'), '\u001B[48;2;255;0;0mhello\u001B[49m'); + 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'); }); test('don\'t emit RGB codes if level is 0', t => { - t.is(new chalk.constructor({level: 0}).hex('#FF0000')('hello'), 'hello'); - t.is(new chalk.constructor({level: 0}).bgHex('#FF0000')('hello'), 'hello'); + t.is(new chalk.Instance({level: 0}).hex('#FF0000')('hello'), 'hello'); + t.is(new chalk.Instance({level: 0}).bgHex('#FF0000')('hello'), 'hello'); }); diff --git a/test/constructor.js b/test/constructor.js index bda0137..188001a 100644 --- a/test/constructor.js +++ b/test/constructor.js @@ -1,34 +1,15 @@ import test from 'ava'; -// Spoof supports-color -require('./_supports-color')(__dirname); - const chalk = require('..'); -test('create an isolated context where colors can be disabled (by level)', t => { - const instance = new chalk.constructor({level: 0, enabled: true}); - t.is(instance.red('foo'), 'foo'); - t.is(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); - instance.level = 2; - t.is(instance.red('foo'), '\u001B[31mfoo\u001B[39m'); -}); +test('Chalk.constructor should throw an expected error', t => { + const expectedError = t.throws(() => { + chalk.constructor(); + }); -test('create an isolated context where colors can be disabled (by enabled flag)', t => { - const instance = new chalk.constructor({enabled: false}); - t.is(instance.red('foo'), 'foo'); - t.is(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); - instance.enabled = true; - t.is(instance.red('foo'), '\u001B[31mfoo\u001B[39m'); -}); - -test('the `level` option should be a number from 0 to 3', t => { - /* eslint-disable no-new */ - t.throws(() => { - new chalk.constructor({level: 10}); - }, /should be an integer from 0 to 3/); + t.is(expectedError.message, '`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.'); t.throws(() => { - new chalk.constructor({level: -1}); - }, /should be an integer from 0 to 3/); - /* eslint-enable no-new */ + new chalk.constructor(); // eslint-disable-line no-new + }); }); diff --git a/test/instance.js b/test/instance.js new file mode 100644 index 0000000..e34bea7 --- /dev/null +++ b/test/instance.js @@ -0,0 +1,34 @@ +import test from 'ava'; + +// Spoof supports-color +require('./_supports-color')(__dirname); + +const chalk = require('..'); + +test('create an isolated context where colors can be disabled (by level)', t => { + const instance = new chalk.Instance({level: 0, enabled: true}); + t.is(instance.red('foo'), 'foo'); + t.is(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); + instance.level = 2; + t.is(instance.red('foo'), '\u001B[31mfoo\u001B[39m'); +}); + +test('create an isolated context where colors can be disabled (by enabled flag)', t => { + const instance = new chalk.Instance({enabled: false}); + t.is(instance.red('foo'), 'foo'); + t.is(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); + instance.enabled = true; + t.is(instance.red('foo'), '\u001B[31mfoo\u001B[39m'); +}); + +test('the `level` option should be a number from 0 to 3', t => { + /* eslint-disable no-new */ + t.throws(() => { + new chalk.Instance({level: 10}); + }, /should be an integer from 0 to 3/); + + t.throws(() => { + new chalk.Instance({level: -1}); + }, /should be an integer from 0 to 3/); + /* eslint-enable no-new */ +}); diff --git a/test/template-literal.js b/test/template-literal.js index 34588d2..1f388c8 100644 --- a/test/template-literal.js +++ b/test/template-literal.js @@ -7,23 +7,23 @@ require('./_supports-color')(__dirname); const chalk = require('..'); test('return an empty string for an empty literal', t => { - const instance = chalk.constructor(); + const instance = new chalk.Instance(); t.is(instance``, ''); }); test('return a regular string for a literal with no templates', t => { - const instance = chalk.constructor({level: 0}); + const instance = new chalk.Instance({level: 0}); t.is(instance`hello`, 'hello'); }); test('correctly perform template parsing', t => { - const instance = chalk.constructor({level: 0}); + const instance = new chalk.Instance({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 = chalk.constructor({level: 0}); + 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. {green ${exclamation}!}`, @@ -31,7 +31,7 @@ test('correctly perform template substitutions', t => { }); test('correctly parse and evaluate color-convert functions', t => { - const instance = chalk.constructor({level: 3}); + const instance = new chalk.Instance({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' + @@ -44,13 +44,13 @@ test('correctly parse and evaluate color-convert functions', t => { }); test('properly handle escapes', t => { - const instance = chalk.constructor({level: 3}); + const instance = new chalk.Instance({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 = chalk.constructor({level: 3}); + const instance = new chalk.Instance({level: 3}); try { console.log(instance`{bold this shouldn't appear ever\}`); t.fail(); @@ -67,7 +67,7 @@ test('throw if there is an unclosed block', t => { }); test('throw if there is an invalid style', t => { - const instance = chalk.constructor({level: 3}); + const instance = new chalk.Instance({level: 3}); try { console.log(instance`{abadstylethatdoesntexist this shouldn't appear ever}`); t.fail(); @@ -77,7 +77,7 @@ test('throw if there is an invalid style', t => { }); test('properly style multiline color blocks', t => { - const instance = chalk.constructor({level: 3}); + const instance = new chalk.Instance({level: 3}); t.is( instance`{bold Hello! This is a @@ -97,49 +97,49 @@ test('properly style multiline color blocks', t => { }); test('escape interpolated values', t => { - const instance = chalk.constructor({level: 0}); + const instance = new chalk.Instance({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 = chalk.constructor({level: 3}); + const instance = new chalk.Instance({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 = chalk.constructor({level: 0}); + const instance = new chalk.Instance({level: 0}); t.is(instance`Hello {red there}`, 'Hello\nthere'); }); test('correctly parse newline escapes (bug #177)', t => { - const instance = chalk.constructor({level: 0}); + const instance = new chalk.Instance({level: 0}); t.is(instance`Hello\nthere!`, 'Hello\nthere!'); }); test('correctly parse escape in parameters (bug #177 comment 318622809)', t => { - const instance = chalk.constructor({level: 0}); + const instance = new chalk.Instance({level: 0}); const str = '\\'; t.is(instance`{blue ${str}}`, '\\'); }); test('correctly parses unicode/hex escapes', t => { - const instance = chalk.constructor({level: 0}); + const instance = new chalk.Instance({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 = chalk.constructor({level: 3}); + 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'); }); test('throws if a bad argument is encountered', t => { - const instance = chalk.constructor({level: 3}); // Keep level at least 1 in case we optimize for disabled chalk instances + const instance = new chalk.Instance({level: 3}); // Keep level at least 1 in case we optimize for disabled chalk instances try { console.log(instance`{keyword(????) hi}`); t.fail(); @@ -149,7 +149,7 @@ test('throws if a bad argument is encountered', t => { }); test('throws if an extra unescaped } is found', t => { - const instance = chalk.constructor({level: 0}); + const instance = new chalk.Instance({level: 0}); try { console.log(instance`{red hi!}}`); t.fail(); @@ -159,12 +159,12 @@ test('throws if an extra unescaped } is found', t => { }); test('should not parse upper-case escapes', t => { - const instance = chalk.constructor({level: 0}); + const instance = new chalk.Instance({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 = chalk.constructor({level: 0}); + const instance = new chalk.Instance({level: 0}); t.is(instance`hello ${undefined}`, 'hello undefined'); t.is(instance`hello ${null}`, 'hello null'); }); diff --git a/test/visible.js b/test/visible.js index 3266295..01eb087 100644 --- a/test/visible.js +++ b/test/visible.js @@ -6,25 +6,25 @@ require('./_supports-color')(__dirname); const chalk = require('..'); test('visible: normal output when enabled', t => { - const instance = new chalk.constructor({level: 3, enabled: true}); + const instance = new chalk.Instance({level: 3, enabled: true}); 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 disabled', t => { - const instance = new chalk.constructor({level: 3, enabled: false}); + const instance = new chalk.Instance({level: 3, enabled: false}); t.is(instance.red.visible('foo'), ''); t.is(instance.visible.red('foo'), ''); }); test('visible: no output when level is too low', t => { - const instance = new chalk.constructor({level: 0, enabled: true}); + const instance = new chalk.Instance({level: 0, enabled: true}); t.is(instance.visible.red('foo'), ''); t.is(instance.red.visible('foo'), ''); }); test('test switching back and forth between enabled and disabled', t => { - const instance = new chalk.constructor({level: 3, enabled: true}); + const instance = new chalk.Instance({level: 3, enabled: true}); 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'); From 3ef170b457dd9a318f74080dbaeb935c86ed026b Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 12 Mar 2019 20:11:31 +0700 Subject: [PATCH 124/235] Require Node.js 8 --- .travis.yml | 1 - examples/rainbow.js | 37 ++++++++++++++++++++----------------- index.d.ts | 2 +- index.js | 33 +++++++++++++++++++-------------- package.json | 16 ++++++++-------- templates.js | 21 ++++++++------------- 6 files changed, 56 insertions(+), 54 deletions(-) diff --git a/.travis.yml b/.travis.yml index c89aee6..5e3bcf3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,5 @@ language: node_js node_js: - '10' - '8' - - '6' after_success: - './node_modules/.bin/nyc report --reporter=text-lcov | ./node_modules/.bin/coveralls' diff --git a/examples/rainbow.js b/examples/rainbow.js index fc086fa..813e026 100644 --- a/examples/rainbow.js +++ b/examples/rainbow.js @@ -3,36 +3,39 @@ const chalk = require('..'); const ignoreChars = /[^!-~]/g; -function rainbow(str, offset) { - if (!str || str.length === 0) { - return str; +const delay = milliseconds => new Promise(resolve => setTimeout(resolve, milliseconds)); + +function rainbow(string, offset) { + if (!string || string.length === 0) { + return string; } - const hueStep = 360 / str.replace(ignoreChars, '').length; + const hueStep = 360 / string.replace(ignoreChars, '').length; let hue = offset % 360; - const chars = []; - for (const c of str) { - if (c.match(ignoreChars)) { - chars.push(c); + const characters = []; + for (const character of string) { + if (character.match(ignoreChars)) { + characters.push(character); } else { - chars.push(chalk.hsl(hue, 100, 50)(c)); + characters.push(chalk.hsl(hue, 100, 50)(character)); hue = (hue + hueStep) % 360; } } - return chars.join(''); + return characters.join(''); } -const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); - -async function animateString(str) { +async function animateString(string) { console.log(); for (let i = 0; i < 360 * 5; i++) { - console.log('\u001B[1F\u001B[G ', rainbow(str, i)); - await sleep(2); // eslint-disable-line no-await-in-loop + console.log('\u001B[1F\u001B[G', rainbow(string, i)); + await delay(2); // eslint-disable-line no-await-in-loop } } -console.log(); -animateString('We hope you enjoy the new version of Chalk 2! <3').then(() => console.log()); +(async () => { + console.log(); + await animateString('We hope you enjoy Chalk! <3'); + console.log(); +})(); diff --git a/index.d.ts b/index.d.ts index 189e1a3..6256ce3 100644 --- a/index.d.ts +++ b/index.d.ts @@ -271,6 +271,6 @@ export interface Chalk { * 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 & { supportsColor: ColorSupport }; +declare const chalk: Chalk & {supportsColor: ColorSupport}; export default chalk; diff --git a/index.js b/index.js index d04ce95..50e7591 100644 --- a/index.js +++ b/index.js @@ -7,7 +7,12 @@ const template = require('./templates.js'); const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); // `supportsColor.level` → `ansiStyles.color[name]` mapping -const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; +const levelMapping = [ + 'ansi', + 'ansi', + 'ansi256', + 'ansi16m' +]; // `color-convert` models to exclude from the Chalk API due to conflicts and such const skipModels = new Set(['gray']); @@ -35,7 +40,7 @@ function chalkFactory(options) { const chalk = {}; applyOptions(chalk, options); - chalk.template = (...args) => chalkTag(chalk.template, ...args); + chalk.template = (...arguments_) => chalkTag(chalk.template, ...arguments_); Object.setPrototypeOf(chalk, Chalk.prototype); Object.setPrototypeOf(chalk.template, chalk); @@ -43,6 +48,7 @@ function chalkFactory(options) { chalk.template.constructor = () => { throw new Error('`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.'); }; + chalk.template.Instance = ChalkClass; return chalk.template; @@ -57,13 +63,12 @@ if (isSimpleWindowsTerm) { ansiStyles.blue.open = '\u001B[94m'; } -for (const key of Object.keys(ansiStyles)) { - ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); +for (const [styleName, style] of Object.entries(ansiStyles)) { + style.closeRe = new RegExp(escapeStringRegexp(style.close), 'g'); - styles[key] = { + styles[styleName] = { get() { - const codes = ansiStyles[key]; - return build.call(this, [...(this._styles || []), codes], this._empty, key); + return build.call(this, [...(this._styles || []), style], this._empty, styleName); } }; } @@ -106,8 +111,8 @@ for (const model of Object.keys(ansiStyles.bgColor.ansi)) { styles[bgModel] = { get() { const {level} = this; - return function (...args) { - const open = ansiStyles.bgColor[levelMapping[level]][model](...args); + return function (...arguments_) { + const open = ansiStyles.bgColor[levelMapping[level]][model](...arguments_); const codes = { open, close: ansiStyles.bgColor.close, @@ -122,7 +127,7 @@ for (const model of Object.keys(ansiStyles.bgColor.ansi)) { const proto = Object.defineProperties(() => {}, styles); function build(_styles, _empty, key) { - const builder = (...args) => applyStyle.call(builder, ...args); + const builder = (...arguments_) => applyStyle.call(builder, ...arguments_); builder._styles = _styles; builder._empty = _empty; @@ -158,8 +163,8 @@ function build(_styles, _empty, key) { return builder; } -function applyStyle(...args) { - let string = args.join(' '); +function applyStyle(...arguments_) { + let string = arguments_.join(' '); if (!this.enabled || this.level <= 0 || !string) { return this._empty ? '' : string; @@ -200,12 +205,12 @@ function chalkTag(chalk, ...strings) { return strings.join(' '); } - const args = strings.slice(1); + const arguments_ = strings.slice(1); const parts = [firstString.raw[0]]; for (let i = 1; i < firstString.length; i++) { parts.push( - String(args[i - 1]).replace(/[{}\\]/g, '\\$&'), + String(arguments_[i - 1]).replace(/[{}\\]/g, '\\$&'), String(firstString.raw[i]) ); } diff --git a/package.json b/package.json index 35fb7d0..bbc1634 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "license": "MIT", "repository": "chalk/chalk", "engines": { - "node": ">=6" + "node": ">=8" }, "scripts": { "test": "xo && nyc ava && tsd-check && flow", @@ -43,20 +43,20 @@ "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", - "supports-color": "^6.0.0" + "supports-color": "^6.1.0" }, "devDependencies": { - "@sindresorhus/tsconfig": "^0.1.1", - "ava": "^1.0.1", - "coveralls": "^3.0.2", + "@sindresorhus/tsconfig": "^0.2.1", + "ava": "^1.3.1", + "coveralls": "^3.0.3", "execa": "^1.0.0", - "flow-bin": "^0.89.0", + "flow-bin": "^0.94.0", "import-fresh": "^3.0.0", "matcha": "^0.7.0", - "nyc": "^13.1.0", + "nyc": "^13.3.0", "resolve-from": "^4.0.0", "tsd-check": "^0.3.0", - "xo": "^0.23.0" + "xo": "^0.24.0" }, "types": "index.d.ts", "xo": { diff --git a/templates.js b/templates.js index bbc614d..6cdddea 100644 --- a/templates.js +++ b/templates.js @@ -25,9 +25,9 @@ function unescape(c) { return ESCAPES.get(c) || c; } -function parseArguments(name, args) { +function parseArguments(name, arguments_) { const results = []; - const chunks = args.trim().split(/\s*,\s*/g); + const chunks = arguments_.trim().split(/\s*,\s*/g); let matches; for (const chunk of chunks) { @@ -51,7 +51,7 @@ function parseStyle(style) { let matches; while ((matches = STYLE_REGEX.exec(style)) !== null) { - const name = matches[1]; // eslint-disable-line prefer-destructuring + const name = matches[1]; if (matches[2]) { const args = parseArguments(name, matches[2]); @@ -74,9 +74,8 @@ function buildStyle(chalk, styles) { } let current = chalk; - // TODO: Use `Object.entries` when targeting Node.js 8 - for (const styleName of Object.keys(enabled)) { - if (!Array.isArray(enabled[styleName])) { + for (const [styleName, styles] of Object.entries(enabled)) { + if (!Array.isArray(styles)) { continue; } @@ -84,23 +83,19 @@ function buildStyle(chalk, styles) { throw new Error(`Unknown Chalk style: ${styleName}`); } - if (enabled[styleName].length > 0) { - current = current[styleName](...enabled[styleName]); - } else { - current = current[styleName]; - } + current = styles.length > 0 ? current[styleName](...styles) : current[styleName]; } return current; } -module.exports = (chalk, tmp) => { +module.exports = (chalk, temporary) => { const styles = []; const chunks = []; let chunk = []; // eslint-disable-next-line max-params - tmp.replace(TEMPLATE_REGEX, (m, escapeCharacter, inverse, style, close, character) => { + temporary.replace(TEMPLATE_REGEX, (m, escapeCharacter, inverse, style, close, character) => { if (escapeCharacter) { chunk.push(unescape(escapeCharacter)); } else if (style) { From 2ca015c4c537896dd378b94ecbbdec935a7b1b52 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 12 Mar 2019 20:31:33 +0700 Subject: [PATCH 125/235] Remove the blue color workaround for Windows (#330) The illegible blue color has been fixed in Windows 10 build 16257: https://blogs.msdn.microsoft.com/commandline/2017/08/02/updating-the-windows-console-colors/ The workaround causes all kinds of problems, so better to remove it than adding conditionals for older Windows versions. Fixes #329 --- index.js | 5 ----- test/windows.js | 14 +------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/index.js b/index.js index 50e7591..80d9e3d 100644 --- a/index.js +++ b/index.js @@ -58,11 +58,6 @@ function Chalk(options) { return chalkFactory(options); } -// Use bright blue on Windows as the normal blue color is illegible -if (isSimpleWindowsTerm) { - ansiStyles.blue.open = '\u001B[94m'; -} - for (const [styleName, style] of Object.entries(ansiStyles)) { style.closeRe = new RegExp(escapeStringRegexp(style.close), 'g'); diff --git a/test/windows.js b/test/windows.js index 3ede386..ca51a0a 100644 --- a/test/windows.js +++ b/test/windows.js @@ -29,18 +29,6 @@ test.beforeEach(() => { test('detect a simple term if TERM isn\'t set', t => { delete process.env.TERM; const chalk = importFresh('..'); - t.is(chalk.blue('foo'), '\u001B[94mfoo\u001B[39m'); -}); - -test('replace blue foreground color in cmd.exe', t => { - process.env.TERM = 'dumb'; - const chalk = importFresh('..'); - t.is(chalk.blue('foo'), '\u001B[94mfoo\u001B[39m'); -}); - -test('don\'t replace blue foreground color in xterm based terminals', t => { - process.env.TERM = 'xterm-256color'; - const chalk = importFresh('..'); t.is(chalk.blue('foo'), '\u001B[34mfoo\u001B[39m'); }); @@ -59,5 +47,5 @@ test('apply dimmed styling on xterm compatible terminals', t => { test('apply dimmed styling on strings of other colors', t => { process.env.TERM = 'dumb'; const chalk = importFresh('..'); - t.is(chalk.blue.dim('foo'), '\u001B[94m\u001B[2mfoo\u001B[22m\u001B[39m'); + t.is(chalk.blue.dim('foo'), '\u001B[34m\u001B[2mfoo\u001B[22m\u001B[39m'); }); From cd5de7a2f6a7a04fbad4c75c0364a3efc6048ade Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 13 Mar 2019 00:24:34 +0700 Subject: [PATCH 126/235] Remove dim style workaround for Windows (#331) See: https://github.com/chalk/chalk/pull/330/#issuecomment-471977551 The issue seems to have been fixed in newer Windows 10 builds. We're not interested in adding a conditional for older Windows versions as the fix severely complicates the codebase, and it also creates problems for consumers as it makes the output unpredictable. --- index.js | 26 +++++-------------------- test/windows.js | 51 ------------------------------------------------- 2 files changed, 5 insertions(+), 72 deletions(-) delete mode 100644 test/windows.js diff --git a/index.js b/index.js index 80d9e3d..a33dae0 100644 --- a/index.js +++ b/index.js @@ -4,8 +4,6 @@ const ansiStyles = require('ansi-styles'); const {stdout: stdoutColor} = require('supports-color'); const template = require('./templates.js'); -const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); - // `supportsColor.level` → `ansiStyles.color[name]` mapping const levelMapping = [ 'ansi', @@ -63,14 +61,14 @@ for (const [styleName, style] of Object.entries(ansiStyles)) { styles[styleName] = { get() { - return build.call(this, [...(this._styles || []), style], this._empty, styleName); + return build.call(this, [...(this._styles || []), style], this._empty); } }; } styles.visible = { get() { - return build.call(this, this._styles || [], true, 'visible'); + return build.call(this, this._styles || [], true); } }; @@ -90,7 +88,7 @@ for (const model of Object.keys(ansiStyles.color.ansi)) { close: ansiStyles.color.close, closeRe: ansiStyles.color.closeRe }; - return build.call(this, [...(this._styles || []), codes], this._empty, model); + return build.call(this, [...(this._styles || []), codes], this._empty); }; } }; @@ -113,7 +111,7 @@ for (const model of Object.keys(ansiStyles.bgColor.ansi)) { close: ansiStyles.bgColor.close, closeRe: ansiStyles.bgColor.closeRe }; - return build.call(this, [...(this._styles || []), codes], this._empty, model); + return build.call(this, [...(this._styles || []), codes], this._empty); }; } }; @@ -121,7 +119,7 @@ for (const model of Object.keys(ansiStyles.bgColor.ansi)) { const proto = Object.defineProperties(() => {}, styles); -function build(_styles, _empty, key) { +function build(_styles, _empty) { const builder = (...arguments_) => applyStyle.call(builder, ...arguments_); builder._styles = _styles; builder._empty = _empty; @@ -148,9 +146,6 @@ function build(_styles, _empty, key) { } }); - // See below for fix regarding invisible grey/dim combination on Windows - builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; - // `__proto__` is used because we must return a function, but there is // no way to create a function with a different prototype builder.__proto__ = proto; // eslint-disable-line no-proto @@ -165,14 +160,6 @@ function applyStyle(...arguments_) { return this._empty ? '' : string; } - // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, - // see https://github.com/chalk/chalk/issues/58 - // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop. - const originalDim = ansiStyles.dim.open; - if (isSimpleWindowsTerm && this.hasGrey) { - ansiStyles.dim.open = ''; - } - for (const code of this._styles.slice().reverse()) { // Replace any instances already present with a re-opening code // otherwise only the part of the string until said closing code @@ -185,9 +172,6 @@ function applyStyle(...arguments_) { string = string.replace(/\r?\n/g, `${code.close}$&${code.open}`); } - // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue - ansiStyles.dim.open = originalDim; - return string; } diff --git a/test/windows.js b/test/windows.js deleted file mode 100644 index ca51a0a..0000000 --- a/test/windows.js +++ /dev/null @@ -1,51 +0,0 @@ -import test from 'ava'; -import importFresh from 'import-fresh'; -import resolveFrom from 'resolve-from'; - -// Spoof supports-color -require('./_supports-color')(__dirname); - -let originalEnv; -let originalPlatform; - -test.before(() => { - originalEnv = process.env; - originalPlatform = process.platform; -}); - -test.after(() => { - process.env = originalEnv; - Object.defineProperty(process, 'platform', {value: originalPlatform}); -}); - -test.beforeEach(() => { - process.env = {}; - Object.defineProperty(process, 'platform', {value: 'win32'}); - // Since chalk internally modifies `ansiStyles.blue.open`, `ansi-styles` needs - // to be removed from the require cache for `require-uncached` to work - delete require.cache[resolveFrom(__dirname, 'ansi-styles')]; -}); - -test('detect a simple term if TERM isn\'t set', t => { - delete process.env.TERM; - const chalk = importFresh('..'); - t.is(chalk.blue('foo'), '\u001B[34mfoo\u001B[39m'); -}); - -test('don\'t apply dimmed styling on gray strings, see https://github.com/chalk/chalk/issues/58', t => { - process.env.TERM = 'dumb'; - const chalk = importFresh('..'); - t.is(chalk.gray.dim('foo'), '\u001B[90mfoo\u001B[22m\u001B[39m'); -}); - -test('apply dimmed styling on xterm compatible terminals', t => { - process.env.TERM = 'xterm'; - const chalk = importFresh('..'); - t.is(chalk.gray.dim('foo'), '\u001B[90m\u001B[2mfoo\u001B[22m\u001B[39m'); -}); - -test('apply dimmed styling on strings of other colors', t => { - process.env.TERM = 'dumb'; - const chalk = importFresh('..'); - t.is(chalk.blue.dim('foo'), '\u001B[34m\u001B[2mfoo\u001B[22m\u001B[39m'); -}); From 7b9211be501f0608ed89c1a6da88a144199b7a54 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 14 Mar 2019 23:53:22 +0700 Subject: [PATCH 127/235] Minor refactoring --- index.js | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/index.js b/index.js index a33dae0..7d00571 100644 --- a/index.js +++ b/index.js @@ -17,7 +17,7 @@ const skipModels = new Set(['gray']); const styles = Object.create(null); -function applyOptions(object, options = {}) { +const applyOptions = (object, options = {}) => { if (options.level > 3 || options.level < 0) { throw new Error('The `level` option should be an integer from 0 to 3'); } @@ -26,7 +26,7 @@ function applyOptions(object, options = {}) { const colorLevel = stdoutColor ? stdoutColor.level : 0; object.level = options.level === undefined ? colorLevel : options.level; object.enabled = 'enabled' in options ? options.enabled : object.level > 0; -} +}; class ChalkClass { constructor(options) { @@ -34,7 +34,7 @@ class ChalkClass { } } -function chalkFactory(options) { +const chalkFactory = options => { const chalk = {}; applyOptions(chalk, options); @@ -50,7 +50,7 @@ function chalkFactory(options) { chalk.template.Instance = ChalkClass; return chalk.template; -} +}; function Chalk(options) { return chalkFactory(options); @@ -61,14 +61,14 @@ for (const [styleName, style] of Object.entries(ansiStyles)) { styles[styleName] = { get() { - return build.call(this, [...(this._styles || []), style], this._empty); + return createBuilder(this, [...(this._styles || []), style], this._isEmpty); } }; } styles.visible = { get() { - return build.call(this, this._styles || [], true); + return createBuilder(this, this._styles || [], true); } }; @@ -81,14 +81,14 @@ for (const model of Object.keys(ansiStyles.color.ansi)) { styles[model] = { get() { const {level} = this; - return function (...args) { - const open = ansiStyles.color[levelMapping[level]][model](...args); + return function (...arguments_) { + const open = ansiStyles.color[levelMapping[level]][model](...arguments_); const codes = { open, close: ansiStyles.color.close, closeRe: ansiStyles.color.closeRe }; - return build.call(this, [...(this._styles || []), codes], this._empty); + return createBuilder(this, [...(this._styles || []), codes], this._isEmpty); }; } }; @@ -111,7 +111,7 @@ for (const model of Object.keys(ansiStyles.bgColor.ansi)) { close: ansiStyles.bgColor.close, closeRe: ansiStyles.bgColor.closeRe }; - return build.call(this, [...(this._styles || []), codes], this._empty); + return createBuilder(this, [...(this._styles || []), codes], this._isEmpty); }; } }; @@ -119,12 +119,10 @@ for (const model of Object.keys(ansiStyles.bgColor.ansi)) { const proto = Object.defineProperties(() => {}, styles); -function build(_styles, _empty) { - const builder = (...arguments_) => applyStyle.call(builder, ...arguments_); +const createBuilder = (self, _styles, _isEmpty) => { + const builder = (...arguments_) => applyStyle(builder, ...arguments_); builder._styles = _styles; - builder._empty = _empty; - - const self = this; + builder._isEmpty = _isEmpty; Object.defineProperty(builder, 'level', { enumerable: true, @@ -151,16 +149,16 @@ function build(_styles, _empty) { builder.__proto__ = proto; // eslint-disable-line no-proto return builder; -} +}; -function applyStyle(...arguments_) { +const applyStyle = (self, ...arguments_) => { let string = arguments_.join(' '); - if (!this.enabled || this.level <= 0 || !string) { - return this._empty ? '' : string; + if (!self.enabled || self.level <= 0 || !string) { + return self._isEmpty ? '' : string; } - for (const code of this._styles.slice().reverse()) { + for (const code of self._styles.slice().reverse()) { // Replace any instances already present with a re-opening code // otherwise only the part of the string until said closing code // will be colored, and the rest will simply be 'plain'. @@ -173,9 +171,9 @@ function applyStyle(...arguments_) { } return string; -} +}; -function chalkTag(chalk, ...strings) { +const chalkTag = (chalk, ...strings) => { const [firstString] = strings; if (!Array.isArray(firstString)) { @@ -195,7 +193,7 @@ function chalkTag(chalk, ...strings) { } return template(chalk, parts.join('')); -} +}; Object.defineProperties(Chalk.prototype, styles); From 98628d9f087a5c1771651fa7b867dcd2356c2123 Mon Sep 17 00:00:00 2001 From: Dimitri Benin Date: Sun, 28 Apr 2019 04:10:44 +0000 Subject: [PATCH 128/235] Use CommonJS-compatible export in TypeScript definition (#344) --- .travis.yml | 1 + index.d.ts | 523 ++++++++++++++++++++++++------------------------ index.js | 1 - index.test-d.ts | 18 +- package.json | 15 +- 5 files changed, 284 insertions(+), 274 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5e3bcf3..1492647 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: node_js node_js: + - '12' - '10' - '8' after_success: diff --git a/index.d.ts b/index.d.ts index 6256ce3..c7d4a54 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,276 +1,287 @@ -export const enum Level { +declare const enum LevelEnum { /** - * All colors disabled. - */ + All colors disabled. + */ None = 0, /** - * Basic 16 colors support. - */ + Basic 16 colors support. + */ Basic = 1, /** - * ANSI 256 colors support. - */ + ANSI 256 colors support. + */ Ansi256 = 2, /** - * Truecolor 16 million colors support. - */ + Truecolor 16 million colors support. + */ TrueColor = 3 } -export interface Options { - /** - * Enable or disable Chalk. - * - * @default true - */ - enabled?: boolean; +declare namespace chalk { + type Level = LevelEnum; + + interface Options { + /** + Enable or disable Chalk. + + @default true + */ + enabled?: boolean; + + /** + Specify the color support for Chalk. + By default, color support is automatically detected based on the environment. + */ + level?: Level; + } + + interface Instance { + /** + Return a new Chalk instance. + */ + new (options?: Options): Chalk; + } /** - * Specify the color support for Chalk. - * By default, color support is automatically detected based on the environment. - */ - level?: Level; -} + Detect whether the terminal supports color. + */ + interface ColorSupport { + /** + The color level used by Chalk. + */ + level: Level; -export interface Instance { - /** - * Return a new Chalk instance. - */ - new (options?: Options): Chalk; + /** + 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 Chalk { + (...text: unknown[]): string; + + (text: TemplateStringsArray, ...placeholders: unknown[]): string; + + /** + Return a new Chalk instance. + */ + Instance: Instance; + + /** + Enable or disable Chalk. + + @default true + */ + enabled: boolean; + + /** + The color support for Chalk. + By default, color support is automatically detected based on the environment. + */ + 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): this; + + /** + 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): 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 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): this; + + /** + 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): 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; + + /** + Modifier: Resets the current color chain. + */ + readonly reset: this; + + /** + Modifier: Make text bold. + */ + readonly bold: this; + + /** + Modifier: Emitting only a small amount of light. + */ + readonly dim: this; + + /** + Modifier: Make text italic. (Not widely supported) + */ + readonly italic: this; + + /** + Modifier: Make text underline. (Not widely supported) + */ + readonly underline: 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 is enabled. + 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; + readonly gray: this; + 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; + readonly bgBlackBright: this; + readonly bgRedBright: this; + readonly bgGreenBright: this; + readonly bgYellowBright: this; + readonly bgBlueBright: this; + readonly bgMagentaBright: this; + readonly bgCyanBright: this; + readonly bgWhiteBright: this; + } } /** - * Detect whether the terminal supports color. - */ -export interface ColorSupport { - /** - * The color level used by Chalk. - */ - level: Level; +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 & { + supportsColor: chalk.ColorSupport; + Level: typeof LevelEnum; +}; - /** - * 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; -} - -export interface Chalk { - (...text: unknown[]): string; - - (text: TemplateStringsArray, ...placeholders: unknown[]): string; - - /** - * Return a new Chalk instance. - */ - Instance: Instance; - - /** - * Enable or disable Chalk. - * - * @default true - */ - enabled: boolean; - - /** - * The color support for Chalk. - * By default, color support is automatically detected based on the environment. - */ - level: Level; - - /** - * 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 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 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 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; - - /** - * Modifier: Resets the current color chain. - */ - readonly reset: this; - - /** - * Modifier: Make text bold. - */ - readonly bold: this; - - /** - * Modifier: Emitting only a small amount of light. - */ - readonly dim: this; - - /** - * Modifier: Make text italic. (Not widely supported) - */ - readonly italic: this; - - /** - * Modifier: Make text underline. (Not widely supported) - */ - readonly underline: 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 is enabled. - * 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; - readonly gray: this; - 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; - 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 & {supportsColor: ColorSupport}; - -export default chalk; +export = chalk; diff --git a/index.js b/index.js index 7d00571..9f5575a 100644 --- a/index.js +++ b/index.js @@ -199,4 +199,3 @@ Object.defineProperties(Chalk.prototype, styles); module.exports = Chalk(); // eslint-disable-line new-cap module.exports.supportsColor = stdoutColor; -module.exports.default = module.exports; // For TypeScript diff --git a/index.test-d.ts b/index.test-d.ts index 0b26e9c..7a791a8 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1,14 +1,14 @@ -import {expectType} from 'tsd-check'; -import chalk, {Level, Chalk, ColorSupport} from '.'; +import {expectType} from 'tsd'; +import chalk = require('.'); // - Helpers - -type colorReturn = Chalk & {supportsColor: ColorSupport}; +type colorReturn = chalk.Chalk & {supportsColor: chalk.ColorSupport}; // - Level - -expectType(Level.None); -expectType(Level.Basic); -expectType(Level.Ansi256); -expectType(Level.TrueColor); +expectType(chalk.Level.None); +expectType(chalk.Level.Basic); +expectType(chalk.Level.Ansi256); +expectType(chalk.Level.TrueColor); // - supportsColor - expectType(chalk.supportsColor.hasBasic); @@ -17,11 +17,11 @@ expectType(chalk.supportsColor.has16m); // - Chalk - // -- Instance -- -expectType(new chalk.Instance({level: 1})); +expectType(new chalk.Instance({level: 1})); // -- Properties -- expectType(chalk.enabled); -expectType(chalk.level); +expectType(chalk.level); // -- Template literal -- expectType(chalk``); diff --git a/package.json b/package.json index bbc1634..39ec03d 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "node": ">=8" }, "scripts": { - "test": "xo && nyc ava && tsd-check && flow", + "test": "xo && nyc ava && tsd && flow", "bench": "matcha benchmark.js" }, "files": [ @@ -46,19 +46,18 @@ "supports-color": "^6.1.0" }, "devDependencies": { - "@sindresorhus/tsconfig": "^0.2.1", - "ava": "^1.3.1", + "@sindresorhus/tsconfig": "^0.3.0", + "ava": "^1.4.1", "coveralls": "^3.0.3", "execa": "^1.0.0", - "flow-bin": "^0.94.0", + "flow-bin": "^0.98.0", "import-fresh": "^3.0.0", "matcha": "^0.7.0", - "nyc": "^13.3.0", - "resolve-from": "^4.0.0", - "tsd-check": "^0.3.0", + "nyc": "^14.0.0", + "resolve-from": "^5.0.0", + "tsd": "^0.7.2", "xo": "^0.24.0" }, - "types": "index.d.ts", "xo": { "ignores": [ "test/_flow.js" From d3be9c65b11f505e0e8bd9d4796c4988bb634cf7 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 3 May 2019 15:03:53 +0700 Subject: [PATCH 129/235] Drop built-in Flow type definition I don't want to be responsible for maintaining it. Submit it to https://github.com/flow-typed/flow-typed if you need it. --- .flowconfig | 6 ---- index.js.flow | 93 --------------------------------------------------- package.json | 11 ++---- readme.md | 2 +- test/_flow.js | 86 ----------------------------------------------- 5 files changed, 3 insertions(+), 195 deletions(-) delete mode 100644 .flowconfig delete mode 100644 index.js.flow delete mode 100644 test/_flow.js diff --git a/.flowconfig b/.flowconfig deleted file mode 100644 index 48ee960..0000000 --- a/.flowconfig +++ /dev/null @@ -1,6 +0,0 @@ -[ignore] -.*/node_modules/.* - -[options] -suppress_comment= \\(.\\|\n\\)*\\$ExpectError -include_warnings=true diff --git a/index.js.flow b/index.js.flow deleted file mode 100644 index f7e4abc..0000000 --- a/index.js.flow +++ /dev/null @@ -1,93 +0,0 @@ -// @flow strict - -type TemplateStringsArray = $ReadOnlyArray; - -export type Level = $Values<{ - None: 0, - Basic: 1, - Ansi256: 2, - TrueColor: 3 -}>; - -export type Options = {| - enabled?: boolean, - level?: Level -|}; - -export type ColorSupport = {| - level: Level, - hasBasic: boolean, - has256: boolean, - has16m: boolean -|}; - -export interface Chalk { - (...text: string[]): string, - (text: TemplateStringsArray, ...placeholders: mixed[]): string, - Instance(options?: Options): Chalk, - enabled: boolean, - level: Level, - rgb(red: number, green: number, blue: number): Chalk, - hsl(hue: number, saturation: number, lightness: number): Chalk, - hsv(hue: number, saturation: number, value: number): Chalk, - hwb(hue: number, whiteness: number, blackness: number): Chalk, - bgHex(color: string): Chalk, - bgKeyword(color: string): Chalk, - bgRgb(red: number, green: number, blue: number): Chalk, - bgHsl(hue: number, saturation: number, lightness: number): Chalk, - bgHsv(hue: number, saturation: number, value: number): Chalk, - bgHwb(hue: number, whiteness: number, blackness: number): Chalk, - hex(color: string): Chalk, - keyword(color: string): Chalk, - - +reset: Chalk, - +bold: Chalk, - +dim: Chalk, - +italic: Chalk, - +underline: Chalk, - +inverse: Chalk, - +hidden: Chalk, - +strikethrough: Chalk, - - +visible: Chalk, - - +black: Chalk, - +red: Chalk, - +green: Chalk, - +yellow: Chalk, - +blue: Chalk, - +magenta: Chalk, - +cyan: Chalk, - +white: Chalk, - +gray: Chalk, - +grey: Chalk, - +blackBright: Chalk, - +redBright: Chalk, - +greenBright: Chalk, - +yellowBright: Chalk, - +blueBright: Chalk, - +magentaBright: Chalk, - +cyanBright: Chalk, - +whiteBright: Chalk, - - +bgBlack: Chalk, - +bgRed: Chalk, - +bgGreen: Chalk, - +bgYellow: Chalk, - +bgBlue: Chalk, - +bgMagenta: Chalk, - +bgCyan: Chalk, - +bgWhite: Chalk, - +bgBlackBright: Chalk, - +bgRedBright: Chalk, - +bgGreenBright: Chalk, - +bgYellowBright: Chalk, - +bgBlueBright: Chalk, - +bgMagentaBright: Chalk, - +bgCyanBright: Chalk, - +bgWhiteBright: Chalk, - - supportsColor: ColorSupport -}; - -declare module.exports: Chalk; diff --git a/package.json b/package.json index 39ec03d..b18d8a3 100644 --- a/package.json +++ b/package.json @@ -8,14 +8,13 @@ "node": ">=8" }, "scripts": { - "test": "xo && nyc ava && tsd && flow", + "test": "xo && nyc ava && tsd", "bench": "matcha benchmark.js" }, "files": [ "index.js", "templates.js", - "index.d.ts", - "index.js.flow" + "index.d.ts" ], "keywords": [ "color", @@ -50,17 +49,11 @@ "ava": "^1.4.1", "coveralls": "^3.0.3", "execa": "^1.0.0", - "flow-bin": "^0.98.0", "import-fresh": "^3.0.0", "matcha": "^0.7.0", "nyc": "^14.0.0", "resolve-from": "^5.0.0", "tsd": "^0.7.2", "xo": "^0.24.0" - }, - "xo": { - "ignores": [ - "test/_flow.js" - ] } } diff --git a/readme.md b/readme.md index 1e3b9bb..ed3cd1b 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- and Flow-ready](https://img.shields.io/npm/types/chalk.svg) +[![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) diff --git a/test/_flow.js b/test/_flow.js deleted file mode 100644 index dbb6dd0..0000000 --- a/test/_flow.js +++ /dev/null @@ -1,86 +0,0 @@ -// @flow -import chalk from '..'; - -// $ExpectError (Can't have typo in option name) -new chalk.Instance({levl: 1}); -new chalk.Instance({level: 1}); - -// $ExpectError (Option must have proper type) -new chalk.Instance({enabled: 'true'}); -new chalk.Instance({enabled: true}); - -// $ExpectError (Can't have typo in chalk method) -chalk.rd('foo'); -chalk.red('foo'); - -// $ExpectError (Can't have typo in chalk method) -chalk.gren`foo`; -chalk.green`foo`; - -// $ExpectError (Can't have typo in chalk method) -chalk.red.bgBlu.underline('foo'); -chalk.red.bgBlue.underline('foo'); - -// $ExpectError (Level must be 0, 1, 2, or 3) -const badCtx = chalk.Instance({level: 4}); -const ctx = chalk.Instance({level: 3}); - -// $ExpectError (Can't have typo in method name) -ctx.gry('foo'); -ctx.grey('foo'); - -// $ExpectError (Can't have typo in method name) -ctx`foo`.value(); -ctx`foo`.valueOf(); - -// $ExpectError (Can't have typo in property name) -chalk.abled = true; -chalk.enabled = true; - -// $ExpectError (Can't use invalid Level for property setter) -chalk.level = 10; -chalk.level = 1; - -const chalkInstance = new chalk.Instance(); - -// $ExpectError (Can't have typo in method name) -chalkInstance.blu('foo'); -chalkInstance.blue('foo'); -chalkInstance`foo`; - -// $ExpectError (Can't have typo in method name) -chalk.keywrd('orange').bgBlue('foo'); -chalk.keyword('orange').bgBlue('foo'); - -// $ExpectError (rgb should take in 3 numbers) -chalk.rgb(1, 14).bgBlue('foo'); -chalk.rgb(1, 14, 9).bgBlue('foo'); - -// $ExpectError (hsl should take in 3 numbers) -chalk.hsl(1, 14, '9').bgBlue('foo'); -chalk.hsl(1, 14, 9).bgBlue('foo'); - -// $ExpectError (hsv should take in 3 numbers) -chalk.hsv(1, 14).bgBlue('foo'); -chalk.hsv(1, 14, 9).bgBlue('foo'); - -// $ExpectError (hwb should take in 3 numbers) -chalk.hwb(1, 14).bgBlue('foo'); -chalk.hwb(1, 14, 9).bgBlue('foo'); - -// $ExpectError (Can't have typo in method name) -chalk.visibl('foo'); -chalk.visible('foo'); - -// $ExpectError (Can't have typo in method name) -chalk.red.visibl('foo'); -chalk.red.visible('foo'); -chalk.visible.red('foo'); - -// $ExpectError (Can't write to readonly property) -chalk.black = 'foo'; -chalk.black; - -// $ExpectError (Can't write to readonly property) -chalk.reset = 'foo'; -console.log(chalk.reset); From b3e9b91405c8fa93fa8b2b9343449a797baba0a0 Mon Sep 17 00:00:00 2001 From: ExE Boss <3889017+ExE-Boss@users.noreply.github.com> Date: Sat, 11 May 2019 10:04:20 +0200 Subject: [PATCH 130/235] =?UTF-8?q?Fix=20TypeScript=20types=20for=20`suppo?= =?UTF-8?q?rtsColor`=20which=20is=C2=A0top=E2=80=91level=20only=20(#342)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Dimitri Benin --- index.d.ts | 132 +++++++++++++++++++++++++++--------------------- index.test-d.ts | 7 ++- 2 files changed, 79 insertions(+), 60 deletions(-) diff --git a/index.d.ts b/index.d.ts index c7d4a54..eed72e0 100644 --- a/index.d.ts +++ b/index.d.ts @@ -70,11 +70,27 @@ declare namespace chalk { has16m: boolean; } - interface Chalk { - (...text: unknown[]): string; + 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 + ``` + log(chalk` + CPU: {red ${cpu.totalPercent}%} + RAM: {green ${ram.used / ram.total * 100}%} + DISK: {rgb(255,131,0) ${disk.used / disk.total * 100}%} + `); + ``` + */ (text: TemplateStringsArray, ...placeholders: unknown[]): string; + (...text: unknown[]): string; + } + + interface Chalk extends ChalkFunction { /** Return a new Chalk instance. */ @@ -105,7 +121,7 @@ declare namespace chalk { chalk.hex('#DEADED'); ``` */ - hex(color: string): this; + hex(color: string): Chalk; /** Use keyword color value to set text color. @@ -119,27 +135,27 @@ declare namespace chalk { chalk.keyword('orange'); ``` */ - keyword(color: string): this; + keyword(color: string): Chalk; /** Use RGB values to set text color. */ - rgb(red: number, green: number, blue: number): this; + rgb(red: number, green: number, blue: number): Chalk; /** Use HSL values to set text color. */ - hsl(hue: number, saturation: number, lightness: number): this; + hsl(hue: number, saturation: number, lightness: number): Chalk; /** Use HSV values to set text color. */ - hsv(hue: number, saturation: number, value: number): this; + hsv(hue: number, saturation: number, value: number): Chalk; /** Use HWB values to set text color. */ - hwb(hue: number, whiteness: number, blackness: number): this; + hwb(hue: number, whiteness: number, blackness: number): Chalk; /** Use HEX value to set background color. @@ -153,7 +169,7 @@ declare namespace chalk { chalk.bgHex('#DEADED'); ``` */ - bgHex(color: string): this; + bgHex(color: string): Chalk; /** Use keyword color value to set background color. @@ -167,109 +183,109 @@ declare namespace chalk { chalk.bgKeyword('orange'); ``` */ - bgKeyword(color: string): this; + bgKeyword(color: string): Chalk; /** Use RGB values to set background color. */ - bgRgb(red: number, green: number, blue: number): this; + bgRgb(red: number, green: number, blue: number): Chalk; /** Use HSL values to set background color. */ - bgHsl(hue: number, saturation: number, lightness: number): this; + bgHsl(hue: number, saturation: number, lightness: number): Chalk; /** Use HSV values to set background color. */ - bgHsv(hue: number, saturation: number, value: number): this; + bgHsv(hue: number, saturation: number, value: number): Chalk; /** Use HWB values to set background color. */ - bgHwb(hue: number, whiteness: number, blackness: number): this; + bgHwb(hue: number, whiteness: number, blackness: number): Chalk; /** Modifier: Resets the current color chain. */ - readonly reset: this; + readonly reset: Chalk; /** Modifier: Make text bold. */ - readonly bold: this; + readonly bold: Chalk; /** Modifier: Emitting only a small amount of light. */ - readonly dim: this; + readonly dim: Chalk; /** Modifier: Make text italic. (Not widely supported) */ - readonly italic: this; + readonly italic: Chalk; /** Modifier: Make text underline. (Not widely supported) */ - readonly underline: this; + readonly underline: Chalk; /** Modifier: Inverse background and foreground colors. */ - readonly inverse: this; + readonly inverse: Chalk; /** Modifier: Prints the text, but makes it invisible. */ - readonly hidden: this; + readonly hidden: Chalk; /** Modifier: Puts a horizontal line through the center of the text. (Not widely supported) */ - readonly strikethrough: this; + readonly strikethrough: Chalk; /** Modifier: Prints the text only when Chalk is enabled. Can be useful for things that are purely cosmetic. */ - readonly visible: this; + readonly visible: Chalk; - readonly black: this; - readonly red: this; - readonly green: this; - readonly yellow: this; - readonly blue: this; - readonly magenta: this; - readonly cyan: this; - readonly white: this; - readonly gray: this; - 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 black: Chalk; + readonly red: Chalk; + readonly green: Chalk; + readonly yellow: Chalk; + readonly blue: Chalk; + readonly magenta: Chalk; + readonly cyan: Chalk; + readonly white: Chalk; + readonly gray: Chalk; + 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: this; - readonly bgRed: this; - readonly bgGreen: this; - readonly bgYellow: this; - readonly bgBlue: this; - readonly bgMagenta: this; - readonly bgCyan: this; - readonly bgWhite: 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; + readonly bgBlack: Chalk; + readonly bgRed: Chalk; + readonly bgGreen: Chalk; + readonly bgYellow: Chalk; + readonly bgBlue: Chalk; + readonly bgMagenta: Chalk; + readonly bgCyan: Chalk; + readonly bgWhite: 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; } } @@ -279,7 +295,7 @@ 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 & { +declare const chalk: chalk.Chalk & chalk.ChalkFunction & { supportsColor: chalk.ColorSupport; Level: typeof LevelEnum; }; diff --git a/index.test-d.ts b/index.test-d.ts index 7a791a8..0a25ff7 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1,8 +1,8 @@ -import {expectType} from 'tsd'; +import {expectType, expectError} from 'tsd'; import chalk = require('.'); // - Helpers - -type colorReturn = chalk.Chalk & {supportsColor: chalk.ColorSupport}; +type colorReturn = chalk.Chalk & {supportsColor?: never}; // - Level - expectType(chalk.Level.None); @@ -15,6 +15,9 @@ expectType(chalk.supportsColor.hasBasic); expectType(chalk.supportsColor.has256); expectType(chalk.supportsColor.has16m); +// -- `supportsColor` is not a member of the Chalk interface -- +expectError(chalk.reset.supportsColor); + // - Chalk - // -- Instance -- expectType(new chalk.Instance({level: 1})); From 4990a3578affe1c14ad5d66923ff9849a4117ec3 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 23 May 2019 16:45:56 +0700 Subject: [PATCH 131/235] Add GitHub Sponsors button to the repo --- .github/funding.yml | 5 +++++ readme.md | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 .github/funding.yml diff --git a/.github/funding.yml b/.github/funding.yml new file mode 100644 index 0000000..baa12cf --- /dev/null +++ b/.github/funding.yml @@ -0,0 +1,5 @@ +github: sindresorhus +open_collective: sindresorhus +patreon: sindresorhus +tidelift: npm/chalk +custom: https://sindresorhus.com/donate diff --git a/readme.md b/readme.md index ed3cd1b..99693e4 100644 --- a/readme.md +++ b/readme.md @@ -47,10 +47,6 @@ $ npm install chalk ``` - - - - ## Usage From 4ab4665994689b1157be7d37148eb2547b0b446b Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 31 May 2019 14:53:04 +0700 Subject: [PATCH 132/235] Tidelift tasks --- .github/security.md | 3 +++ readme.md | 31 ++++++++++--------------------- 2 files changed, 13 insertions(+), 21 deletions(-) create mode 100644 .github/security.md diff --git a/.github/security.md b/.github/security.md new file mode 100644 index 0000000..5358dc5 --- /dev/null +++ b/.github/security.md @@ -0,0 +1,3 @@ +# Security Policy + +To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. diff --git a/readme.md b/readme.md index 99693e4..5e96212 100644 --- a/readme.md +++ b/readme.md @@ -13,20 +13,6 @@ ---- - -
- - Get professional support for Chalk with a Tidelift subscription - -
- - Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies. -
-
- ---- - ## Highlights @@ -293,11 +279,6 @@ If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) i [colors.js](https://github.com/Marak/colors.js) used to be the most popular string styling module, but it has serious deficiencies like extending `String.prototype` which causes all kinds of [problems](https://github.com/yeoman/yo/issues/68) and the package is unmaintained. Although there are other packages, they either do too much or not enough. Chalk is a clean and focused alternative. -## Security - -To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. - - ## Related - [chalk-cli](https://github.com/chalk/chalk-cli) - CLI for this module @@ -322,6 +303,14 @@ To report a security vulnerability, please use the [Tidelift security contact](h - [Josh Junon](https://github.com/qix-) -## License +--- -MIT +
+ + Get professional support for Chalk with a Tidelift subscription + +
+ + Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies. +
+
From d82b2a66389d26dab1a44c85ac273f894af4aaae Mon Sep 17 00:00:00 2001 From: Florian Reuschel Date: Mon, 10 Jun 2019 19:47:16 +0200 Subject: [PATCH 133/235] Add missing `false` type to chalk.supportsColor (#347) --- index.d.ts | 2 +- index.test-d.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/index.d.ts b/index.d.ts index eed72e0..0f5d885 100644 --- a/index.d.ts +++ b/index.d.ts @@ -296,7 +296,7 @@ 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; + supportsColor: chalk.ColorSupport | false; Level: typeof LevelEnum; }; diff --git a/index.test-d.ts b/index.test-d.ts index 0a25ff7..fd19d04 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -11,9 +11,10 @@ expectType(chalk.Level.Ansi256); expectType(chalk.Level.TrueColor); // - supportsColor - -expectType(chalk.supportsColor.hasBasic); -expectType(chalk.supportsColor.has256); -expectType(chalk.supportsColor.has16m); +expectType(chalk.supportsColor); +expectType((chalk.supportsColor as chalk.ColorSupport).hasBasic); +expectType((chalk.supportsColor as chalk.ColorSupport).has256); +expectType((chalk.supportsColor as chalk.ColorSupport).has16m); // -- `supportsColor` is not a member of the Chalk interface -- expectError(chalk.reset.supportsColor); From e2dd171597200df04aad3bf6e39329189a315153 Mon Sep 17 00:00:00 2001 From: Marcos Marado Date: Sun, 30 Jun 2019 17:11:52 +0100 Subject: [PATCH 134/235] Remove outdated info in the readme (#351) --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 5e96212..78af5ae 100644 --- a/readme.md +++ b/readme.md @@ -176,7 +176,7 @@ Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color= - `red` - `green` - `yellow` -- `blue` *(On Windows the bright version is used since normal blue is illegible)* +- `blue` - `magenta` - `cyan` - `white` From 983094883cfe42e79c60c6a6a05b21a0bcd00c35 Mon Sep 17 00:00:00 2001 From: Qix Date: Fri, 12 Jul 2019 08:35:11 +0200 Subject: [PATCH 135/235] Fix support for bracketed Unicode escapes in template literals (#350) --- templates.js | 13 ++++++++++--- test/template-literal.js | 7 +++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/templates.js b/templates.js index 6cdddea..fe94642 100644 --- a/templates.js +++ b/templates.js @@ -1,8 +1,8 @@ 'use strict'; -const TEMPLATE_REGEX = /(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; +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$/; -const ESCAPE_REGEX = /\\(u[a-f\d]{4}|x[a-f\d]{2}|.)|([^\\])/gi; +const ESCAPE_REGEX = /\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.)|([^\\])/gi; const ESCAPES = new Map([ ['n', '\n'], @@ -18,10 +18,17 @@ const ESCAPES = new Map([ ]); function unescape(c) { - if ((c[0] === 'u' && c.length === 5) || (c[0] === 'x' && c.length === 3)) { + const u = c[0] === 'u'; + const bracket = c[1] === '{'; + + if ((u && !bracket && c.length === 5) || (c[0] === 'x' && c.length === 3)) { return String.fromCharCode(parseInt(c.slice(1), 16)); } + if (u && bracket) { + return String.fromCodePoint(parseInt(c.slice(2, -1), 16)); + } + return ESCAPES.get(c) || c; } diff --git a/test/template-literal.js b/test/template-literal.js index 1f388c8..ae4a0bc 100644 --- a/test/template-literal.js +++ b/test/template-literal.js @@ -168,3 +168,10 @@ test('should properly handle undefined template interpolated values', t => { 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}); + 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'); +}); From c08417e88ca41f7133eb1a00e0b3fc8aefbb6cc9 Mon Sep 17 00:00:00 2001 From: Yanis Benson Date: Fri, 12 Jul 2019 09:40:23 +0300 Subject: [PATCH 136/235] Improve performance greatly (#337) --- benchmark.js | 42 ++++++++++--- examples/screenshot.js | 2 +- index.js | 133 +++++++++++++++++++++++++---------------- lib/util.js | 37 ++++++++++++ package.json | 1 - test/chalk.js | 4 ++ 6 files changed, 159 insertions(+), 60 deletions(-) create mode 100644 lib/util.js diff --git a/benchmark.js b/benchmark.js index f4e9cf3..dc24696 100644 --- a/benchmark.js +++ b/benchmark.js @@ -3,22 +3,48 @@ const chalk = require('.'); suite('chalk', () => { - set('iterations', 100000); + set('iterations', 1000000); - bench('single style', () => { + const chalkRed = chalk.red; + const chalkBgRed = chalk.bgRed; + const chalkBlueBgRed = chalk.blue.bgRed; + const chalkBlueBgRedBold = chalk.blue.bgRed.bold; + + const blueStyledString = 'the fox jumps' + chalk.blue('over the lazy dog') + '!'; + + bench('1 style', () => { chalk.red('the fox jumps over the lazy dog'); }); - bench('several styles', () => { + bench('2 styles', () => { + chalk.blue.bgRed('the fox jumps over the lazy dog'); + }); + + bench('3 styles', () => { chalk.blue.bgRed.bold('the fox jumps over the lazy dog'); }); - const cached = chalk.blue.bgRed.bold; - bench('cached styles', () => { - cached('the fox jumps over the lazy dog'); + bench('cached: 1 style', () => { + chalkRed('the fox jumps over the lazy dog'); }); - bench('nested styles', () => { - chalk.red('the fox jumps', chalk.underline.bgBlue('over the lazy dog') + '!'); + bench('cached: 2 styles', () => { + chalkBlueBgRed('the fox jumps over the lazy dog'); + }); + + bench('cached: 3 styles', () => { + chalkBlueBgRedBold('the fox jumps over the lazy dog'); + }); + + bench('cached: 1 style with newline', () => { + chalkRed('the fox jumps\nover the lazy dog'); + }); + + bench('cached: 1 style nested intersecting', () => { + chalkRed(blueStyledString); + }); + + bench('cached: 1 style nested non-intersecting', () => { + chalkBgRed(blueStyledString); }); }); diff --git a/examples/screenshot.js b/examples/screenshot.js index 7d195a6..37f5850 100644 --- a/examples/screenshot.js +++ b/examples/screenshot.js @@ -1,6 +1,6 @@ 'use strict'; -const chalk = require('..'); const styles = require('ansi-styles'); +const chalk = require('..'); // Generates screenshot for (const key of Object.keys(styles)) { diff --git a/index.js b/index.js index 9f5575a..21d3a83 100644 --- a/index.js +++ b/index.js @@ -1,9 +1,13 @@ 'use strict'; -const escapeStringRegexp = require('escape-string-regexp'); const ansiStyles = require('ansi-styles'); const {stdout: stdoutColor} = require('supports-color'); const template = require('./templates.js'); +const { + stringReplaceAll, + stringEncaseCRLFWithFirstIndex +} = require('./lib/util'); + // `supportsColor.level` → `ansiStyles.color[name]` mapping const levelMapping = [ 'ansi', @@ -57,22 +61,23 @@ function Chalk(options) { } for (const [styleName, style] of Object.entries(ansiStyles)) { - style.closeRe = new RegExp(escapeStringRegexp(style.close), 'g'); - styles[styleName] = { get() { - return createBuilder(this, [...(this._styles || []), style], this._isEmpty); + const builder = createBuilder(this, createStyler(style.open, style.close, this._styler), this._isEmpty); + Object.defineProperty(this, styleName, {value: builder}); + return builder; } }; } styles.visible = { get() { - return createBuilder(this, this._styles || [], true); + const builder = createBuilder(this, this._styler, true); + Object.defineProperty(this, 'visible', {value: builder}); + return builder; } }; -ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); for (const model of Object.keys(ansiStyles.color.ansi)) { if (skipModels.has(model)) { continue; @@ -82,19 +87,13 @@ for (const model of Object.keys(ansiStyles.color.ansi)) { get() { const {level} = this; return function (...arguments_) { - const open = ansiStyles.color[levelMapping[level]][model](...arguments_); - const codes = { - open, - close: ansiStyles.color.close, - closeRe: ansiStyles.color.closeRe - }; - return createBuilder(this, [...(this._styles || []), codes], this._isEmpty); + const styler = createStyler(ansiStyles.color[levelMapping[level]][model](...arguments_), ansiStyles.color.close, this._styler); + return createBuilder(this, styler, this._isEmpty); }; } }; } -ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); for (const model of Object.keys(ansiStyles.bgColor.ansi)) { if (skipModels.has(model)) { continue; @@ -105,72 +104,106 @@ for (const model of Object.keys(ansiStyles.bgColor.ansi)) { get() { const {level} = this; return function (...arguments_) { - const open = ansiStyles.bgColor[levelMapping[level]][model](...arguments_); - const codes = { - open, - close: ansiStyles.bgColor.close, - closeRe: ansiStyles.bgColor.closeRe - }; - return createBuilder(this, [...(this._styles || []), codes], this._isEmpty); + const styler = createStyler(ansiStyles.bgColor[levelMapping[level]][model](...arguments_), ansiStyles.bgColor.close, this._styler); + return createBuilder(this, styler, this._isEmpty); }; } }; } -const proto = Object.defineProperties(() => {}, styles); - -const createBuilder = (self, _styles, _isEmpty) => { - const builder = (...arguments_) => applyStyle(builder, ...arguments_); - builder._styles = _styles; - builder._isEmpty = _isEmpty; - - Object.defineProperty(builder, 'level', { +const proto = Object.defineProperties(() => {}, { + ...styles, + level: { enumerable: true, get() { - return self.level; + return this._generator.level; }, set(level) { - self.level = level; + this._generator.level = level; } - }); - - Object.defineProperty(builder, 'enabled', { + }, + enabled: { enumerable: true, get() { - return self.enabled; + return this._generator.enabled; }, set(enabled) { - self.enabled = enabled; + this._generator.enabled = enabled; } - }); + } +}); + +const createStyler = (open, close, parent) => { + let openAll; + let closeAll; + if (parent === undefined) { + openAll = open; + closeAll = close; + } else { + openAll = parent.openAll + open; + closeAll = close + parent.closeAll; + } + + return { + open, + close, + openAll, + closeAll, + parent + }; +}; + +const createBuilder = (self, _styler, _isEmpty) => { + const 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(' ')); + }; // `__proto__` is used because we must return a function, but there is // no way to create a function with a different prototype builder.__proto__ = proto; // eslint-disable-line no-proto + builder._generator = self; + builder._styler = _styler; + builder._isEmpty = _isEmpty; + return builder; }; -const applyStyle = (self, ...arguments_) => { - let string = arguments_.join(' '); - +const applyStyle = (self, string) => { if (!self.enabled || self.level <= 0 || !string) { return self._isEmpty ? '' : string; } - for (const code of self._styles.slice().reverse()) { - // Replace any instances already present with a re-opening code - // otherwise only the part of the string until said closing code - // will be colored, and the rest will simply be 'plain'. - string = code.open + string.replace(code.closeRe, code.open) + code.close; + let styler = self._styler; - // Close the styling before a linebreak and reopen - // after next line to fix a bleed issue on macOS - // https://github.com/chalk/chalk/pull/92 - string = string.replace(/\r?\n/g, `${code.close}$&${code.open}`); + if (styler === undefined) { + return string; } - return string; + const {openAll, closeAll} = styler; + if (string.indexOf('\u001B') !== -1) { + while (styler !== undefined) { + // Replace any instances already present with a re-opening code + // otherwise only the part of the string until said closing code + // will be colored, and the rest will simply be 'plain'. + string = stringReplaceAll(string, styler.close, styler.open); + + styler = styler.parent; + } + } + + // We can move both next actions out of loop, because remaining actions in loop won't have any/visible effect on parts we add here + // Close the styling before a linebreak and reopen + // after next line to fix a bleed issue on macOS + // https://github.com/chalk/chalk/pull/92 + const lfIndex = string.indexOf('\n'); + if (lfIndex !== -1) { + string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex); + } + + return openAll + string + closeAll; }; const chalkTag = (chalk, ...strings) => { diff --git a/lib/util.js b/lib/util.js new file mode 100644 index 0000000..8ce1166 --- /dev/null +++ b/lib/util.js @@ -0,0 +1,37 @@ +const stringReplaceAll = (string, substring, replacer) => { + let index = string.indexOf(substring); + if (index === -1) { + return string; + } + + const subLen = substring.length; + let end = 0; + let res = ''; + do { + res += string.substr(end, index - end) + replacer; + end = index + subLen; + index = string.indexOf(substring, end); + } while (index !== -1); + + res += string.substr(end); + return res; +}; + +const stringEncaseCRLFWithFirstIndex = (string, prefix, postfix, index) => { + let end = 0; + let res = ''; + do { + const gotCR = string[index - 1] === '\r'; + res += string.substr(end, (gotCR ? index - 1 : index) - end) + prefix + (gotCR ? '\r\n' : '\n') + postfix; + end = index + 1; + index = string.indexOf('\n', end); + } while (index !== -1); + + res += string.substr(end); + return res; +}; + +module.exports = { + stringReplaceAll, + stringEncaseCRLFWithFirstIndex +}; diff --git a/package.json b/package.json index b18d8a3..48712eb 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ ], "dependencies": { "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", "supports-color": "^6.1.0" }, "devDependencies": { diff --git a/test/chalk.js b/test/chalk.js index 240f0f9..3f90ba6 100644 --- a/test/chalk.js +++ b/test/chalk.js @@ -82,6 +82,10 @@ test('line breaks should open and close colors', t => { t.is(chalk.grey('hello\nworld'), '\u001B[90mhello\u001B[39m\n\u001B[90mworld\u001B[39m'); }); +test('line breaks should open and close colors with CRLF', t => { + t.is(chalk.grey('hello\r\nworld'), '\u001B[90mhello\u001B[39m\r\n\u001B[90mworld\u001B[39m'); +}); + 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'); From af4a0782458e212aa858a858c55f3878fcbbd75b Mon Sep 17 00:00:00 2001 From: Boris K Date: Fri, 12 Jul 2019 09:11:25 +0200 Subject: [PATCH 137/235] Update docs for `FORCE_COLOR` environment variable (#315) --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 78af5ae..d403085 100644 --- a/readme.md +++ b/readme.md @@ -151,7 +151,7 @@ Levels are as follows: Detect whether the terminal [supports color](https://github.com/chalk/supports-color). Used internally and handled for you, but exposed for convenience. -Can be overridden by the user with the flags `--color` and `--no-color`. For situations where using `--color` is not possible, add the environment variable `FORCE_COLOR=1` to forcefully enable color or `FORCE_COLOR=0` to forcefully disable. The use of `FORCE_COLOR` overrides all other color support checks. +Can be overridden by the user with the flags `--color` and `--no-color`. For situations where using `--color` is not possible, use the environment variable `FORCE_COLOR=1` (level 1), `FORCE_COLOR=2` (level 2), or `FORCE_COLOR=3` (level 3) to forcefully enable color, or `FORCE_COLOR=0` to forcefully disable. The use of `FORCE_COLOR` overrides all other color support checks. Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color=16m` flags, respectively. From 655653bb0c88fb05f839d5027f79751449771ec4 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 12 Jul 2019 13:51:07 +0700 Subject: [PATCH 138/235] Meta tweaks --- index.d.ts | 2 ++ package.json | 5 ++--- readme.md | 4 ++-- index.js => source/index.js | 5 ++--- templates.js => source/templates.js | 0 {lib => source}/util.js | 2 ++ test/_fixture.js | 2 +- test/chalk.js | 2 +- test/constructor.js | 2 +- test/enabled.js | 2 +- test/instance.js | 2 +- test/level.js | 2 +- test/no-color-support.js | 2 +- test/template-literal.js | 2 +- test/visible.js | 2 +- tsconfig.json | 7 ------- 16 files changed, 19 insertions(+), 24 deletions(-) rename index.js => source/index.js (98%) rename templates.js => source/templates.js (100%) rename {lib => source}/util.js (98%) delete mode 100644 tsconfig.json diff --git a/index.d.ts b/index.d.ts index 0f5d885..9ccc725 100644 --- a/index.d.ts +++ b/index.d.ts @@ -78,6 +78,8 @@ declare namespace chalk { @example ``` + import chalk = require('chalk'); + log(chalk` CPU: {red ${cpu.totalPercent}%} RAM: {green ${ram.used / ram.total * 100}%} diff --git a/package.json b/package.json index 48712eb..764bcbf 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk", + "main": "source", "engines": { "node": ">=8" }, @@ -12,8 +13,7 @@ "bench": "matcha benchmark.js" }, "files": [ - "index.js", - "templates.js", + "source", "index.d.ts" ], "keywords": [ @@ -44,7 +44,6 @@ "supports-color": "^6.1.0" }, "devDependencies": { - "@sindresorhus/tsconfig": "^0.3.0", "ava": "^1.4.1", "coveralls": "^3.0.3", "execa": "^1.0.0", diff --git a/readme.md b/readme.md index d403085..d99b712 100644 --- a/readme.md +++ b/readme.md @@ -220,8 +220,8 @@ const miles = 18; const calculateFeet = miles => miles * 5280; console.log(chalk` - There are {bold 5280 feet} in a mile. - In {bold ${miles} miles}, there are {green.bold ${calculateFeet(miles)} feet}. + There are {bold 5280 feet} in a mile. + In {bold ${miles} miles}, there are {green.bold ${calculateFeet(miles)} feet}. `); ``` diff --git a/index.js b/source/index.js similarity index 98% rename from index.js rename to source/index.js index 21d3a83..0519720 100644 --- a/index.js +++ b/source/index.js @@ -1,12 +1,11 @@ 'use strict'; const ansiStyles = require('ansi-styles'); const {stdout: stdoutColor} = require('supports-color'); -const template = require('./templates.js'); - +const template = require('./templates'); const { stringReplaceAll, stringEncaseCRLFWithFirstIndex -} = require('./lib/util'); +} = require('./util'); // `supportsColor.level` → `ansiStyles.color[name]` mapping const levelMapping = [ diff --git a/templates.js b/source/templates.js similarity index 100% rename from templates.js rename to source/templates.js diff --git a/lib/util.js b/source/util.js similarity index 98% rename from lib/util.js rename to source/util.js index 8ce1166..aaf3d79 100644 --- a/lib/util.js +++ b/source/util.js @@ -1,3 +1,5 @@ +'use strict'; + const stringReplaceAll = (string, substring, replacer) => { let index = string.indexOf(substring); if (index === -1) { diff --git a/test/_fixture.js b/test/_fixture.js index 5f1771d..214a86c 100644 --- a/test/_fixture.js +++ b/test/_fixture.js @@ -1,4 +1,4 @@ 'use strict'; -const chalk = require('..'); +const chalk = require('../source'); console.log(chalk.hex('#ff6159')('test')); diff --git a/test/chalk.js b/test/chalk.js index 3f90ba6..92091cb 100644 --- a/test/chalk.js +++ b/test/chalk.js @@ -3,7 +3,7 @@ import test from 'ava'; // Spoof supports-color require('./_supports-color')(__dirname); -const chalk = require('..'); +const chalk = require('../source'); console.log('TERM:', process.env.TERM || '[none]'); console.log('platform:', process.platform || '[unknown]'); diff --git a/test/constructor.js b/test/constructor.js index 188001a..f4e9ca1 100644 --- a/test/constructor.js +++ b/test/constructor.js @@ -1,6 +1,6 @@ import test from 'ava'; -const chalk = require('..'); +const chalk = require('../source'); test('Chalk.constructor should throw an expected error', t => { const expectedError = t.throws(() => { diff --git a/test/enabled.js b/test/enabled.js index e596621..3d9c55f 100644 --- a/test/enabled.js +++ b/test/enabled.js @@ -3,7 +3,7 @@ import test from 'ava'; // Spoof supports-color require('./_supports-color')(__dirname); -const chalk = require('..'); +const chalk = require('../source'); test('don\'t output colors when manually disabled', t => { chalk.enabled = false; diff --git a/test/instance.js b/test/instance.js index e34bea7..8d2c4e1 100644 --- a/test/instance.js +++ b/test/instance.js @@ -3,7 +3,7 @@ import test from 'ava'; // Spoof supports-color require('./_supports-color')(__dirname); -const chalk = require('..'); +const chalk = require('../source'); test('create an isolated context where colors can be disabled (by level)', t => { const instance = new chalk.Instance({level: 0, enabled: true}); diff --git a/test/level.js b/test/level.js index 06fdb59..36df016 100644 --- a/test/level.js +++ b/test/level.js @@ -5,7 +5,7 @@ import execa from 'execa'; // Spoof supports-color require('./_supports-color')(__dirname); -const chalk = require('..'); +const chalk = require('../source'); test('don\'t output colors when manually disabled', t => { const oldLevel = chalk.level; diff --git a/test/no-color-support.js b/test/no-color-support.js index 90d934d..dae9bda 100644 --- a/test/no-color-support.js +++ b/test/no-color-support.js @@ -8,7 +8,7 @@ require('./_supports-color')(__dirname, { has16m: false }); -const chalk = require('..'); +const chalk = require('../source'); test.failing('colors can be forced by using chalk.enabled', t => { chalk.enabled = true; diff --git a/test/template-literal.js b/test/template-literal.js index ae4a0bc..ece1428 100644 --- a/test/template-literal.js +++ b/test/template-literal.js @@ -4,7 +4,7 @@ import test from 'ava'; // Spoof supports-color require('./_supports-color')(__dirname); -const chalk = require('..'); +const chalk = require('../source'); test('return an empty string for an empty literal', t => { const instance = new chalk.Instance(); diff --git a/test/visible.js b/test/visible.js index 01eb087..14ecc3c 100644 --- a/test/visible.js +++ b/test/visible.js @@ -3,7 +3,7 @@ import test from 'ava'; // Spoof supports-color require('./_supports-color')(__dirname); -const chalk = require('..'); +const chalk = require('../source'); test('visible: normal output when enabled', t => { const instance = new chalk.Instance({level: 3, enabled: true}); diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 3d73ee9..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "@sindresorhus/tsconfig", - "compilerOptions": { - "noEmit": true, - "allowJs": true - } -} From c25c32a25f4315c1f7ee21cc7b36b497c4f0212a Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 12 Jul 2019 13:59:50 +0700 Subject: [PATCH 139/235] Update dependencies --- index.d.ts | 20 ++++++++++++++++++++ package.json | 16 ++++++++-------- readme.md | 6 ++++-- source/index.js | 7 +++---- source/util.js | 30 +++++++++++++++--------------- test/chalk.js | 4 ++++ test/level.js | 3 ++- 7 files changed, 56 insertions(+), 30 deletions(-) diff --git a/index.d.ts b/index.d.ts index 9ccc725..455ba9a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -261,8 +261,17 @@ declare namespace 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; @@ -280,6 +289,17 @@ declare namespace 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; diff --git a/package.json b/package.json index 764bcbf..b6cbdd4 100644 --- a/package.json +++ b/package.json @@ -40,18 +40,18 @@ "text" ], "dependencies": { - "ansi-styles": "^3.2.1", - "supports-color": "^6.1.0" + "ansi-styles": "^4.0.0", + "supports-color": "^7.0.0" }, "devDependencies": { - "ava": "^1.4.1", - "coveralls": "^3.0.3", - "execa": "^1.0.0", - "import-fresh": "^3.0.0", + "ava": "^2.2.0", + "coveralls": "^3.0.5", + "execa": "^2.0.3", + "import-fresh": "^3.1.0", "matcha": "^0.7.0", - "nyc": "^14.0.0", + "nyc": "^14.1.1", "resolve-from": "^5.0.0", - "tsd": "^0.7.2", + "tsd": "^0.7.4", "xo": "^0.24.0" } } diff --git a/readme.md b/readme.md index d99b712..ede4ee1 100644 --- a/readme.md +++ b/readme.md @@ -13,6 +13,8 @@ +**This readme reflects the next major version that is currently in development. You probably want [the v2 readme](https://www.npmjs.com/package/chalk).** + ## Highlights @@ -180,7 +182,7 @@ Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color= - `magenta` - `cyan` - `white` -- `gray` ("bright black") +- `blackBright` (alias: `gray`, `grey`) - `redBright` - `greenBright` - `yellowBright` @@ -199,7 +201,7 @@ Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color= - `bgMagenta` - `bgCyan` - `bgWhite` -- `bgBlackBright` +- `bgBlackBright` (alias: `bgGray`, `bgGrey`) - `bgRedBright` - `bgGreenBright` - `bgYellowBright` diff --git a/source/index.js b/source/index.js index 0519720..e8d47c2 100644 --- a/source/index.js +++ b/source/index.js @@ -193,10 +193,9 @@ const applyStyle = (self, string) => { } } - // We can move both next actions out of loop, because remaining actions in loop won't have any/visible effect on parts we add here - // Close the styling before a linebreak and reopen - // after next line to fix a bleed issue on macOS - // https://github.com/chalk/chalk/pull/92 + // We can move both next actions out of loop, because remaining actions in loop won't have + // any/visible effect on parts we add here. Close the styling before a linebreak and reopen + // after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92 const lfIndex = string.indexOf('\n'); if (lfIndex !== -1) { string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex); diff --git a/source/util.js b/source/util.js index aaf3d79..d617156 100644 --- a/source/util.js +++ b/source/util.js @@ -6,31 +6,31 @@ const stringReplaceAll = (string, substring, replacer) => { return string; } - const subLen = substring.length; - let end = 0; - let res = ''; + const substringLength = substring.length; + let endIndex = 0; + let returnValue = ''; do { - res += string.substr(end, index - end) + replacer; - end = index + subLen; - index = string.indexOf(substring, end); + returnValue += string.substr(endIndex, index - endIndex) + replacer; + endIndex = index + substringLength; + index = string.indexOf(substring, endIndex); } while (index !== -1); - res += string.substr(end); - return res; + returnValue += string.substr(endIndex); + return returnValue; }; const stringEncaseCRLFWithFirstIndex = (string, prefix, postfix, index) => { - let end = 0; - let res = ''; + let endIndex = 0; + let returnValue = ''; do { const gotCR = string[index - 1] === '\r'; - res += string.substr(end, (gotCR ? index - 1 : index) - end) + prefix + (gotCR ? '\r\n' : '\n') + postfix; - end = index + 1; - index = string.indexOf('\n', end); + returnValue += string.substr(endIndex, (gotCR ? index - 1 : index) - endIndex) + prefix + (gotCR ? '\r\n' : '\n') + postfix; + endIndex = index + 1; + index = string.indexOf('\n', endIndex); } while (index !== -1); - res += string.substr(end); - return res; + returnValue += string.substr(endIndex); + return returnValue; }; module.exports = { diff --git a/test/chalk.js b/test/chalk.js index 92091cb..008a128 100644 --- a/test/chalk.js +++ b/test/chalk.js @@ -101,3 +101,7 @@ 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'); }); + +test('supports blackBright color', t => { + t.is(chalk.blackBright('foo'), '\u001B[90mfoo\u001B[39m'); +}); diff --git a/test/level.js b/test/level.js index 36df016..bb6df47 100644 --- a/test/level.js +++ b/test/level.js @@ -40,5 +40,6 @@ test('propagate enable/disable changes from child colors', t => { }); test('disable colors if they are not supported', async t => { - t.is(await execa.stdout('node', [path.join(__dirname, '_fixture')]), 'test'); + const {stdout} = await execa.node(path.join(__dirname, '_fixture')); + t.is(stdout, 'test'); }); From 87156ce8e2696a6002a51fbd1168e43eb9c70ce4 Mon Sep 17 00:00:00 2001 From: Ahad Birang Date: Fri, 12 Jul 2019 23:19:56 +0430 Subject: [PATCH 140/235] Fix support for nested styles (#335) --- source/util.js | 2 +- test/chalk.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/util.js b/source/util.js index d617156..ca466fd 100644 --- a/source/util.js +++ b/source/util.js @@ -10,7 +10,7 @@ const stringReplaceAll = (string, substring, replacer) => { let endIndex = 0; let returnValue = ''; do { - returnValue += string.substr(endIndex, index - endIndex) + replacer; + returnValue += string.substr(endIndex, index - endIndex) + substring + replacer; endIndex = index + substringLength; index = string.indexOf(substring, endIndex); } while (index !== -1); diff --git a/test/chalk.js b/test/chalk.js index 008a128..2992a09 100644 --- a/test/chalk.js +++ b/test/chalk.js @@ -37,7 +37,7 @@ test('support nesting styles', t => { test('support nesting styles of the same type (color, underline, bg)', t => { t.is( chalk.red('a' + chalk.yellow('b' + chalk.green('c') + 'b') + 'c'), - '\u001B[31ma\u001B[33mb\u001B[32mc\u001B[33mb\u001B[31mc\u001B[39m' + '\u001B[31ma\u001B[33mb\u001B[32mc\u001B[39m\u001B[31m\u001B[33mb\u001B[39m\u001B[31mc\u001B[39m' ); }); From 1f77953f1a358fa8f626f0fd872792d63da6d58a Mon Sep 17 00:00:00 2001 From: Qix Date: Sat, 13 Jul 2019 07:45:31 +0200 Subject: [PATCH 141/235] Remove the `.enabled` property in favor of `.level` (#356) --- index.d.ts | 16 +--------------- index.test-d.ts | 1 - readme.md | 18 ++++-------------- source/index.js | 12 +----------- test/enabled.js | 35 ----------------------------------- test/instance.js | 10 +--------- test/level.js | 2 +- test/no-color-support.js | 4 ++-- test/visible.js | 20 +++++++------------- 9 files changed, 17 insertions(+), 101 deletions(-) delete mode 100644 test/enabled.js diff --git a/index.d.ts b/index.d.ts index 455ba9a..58da80e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -24,13 +24,6 @@ declare namespace chalk { type Level = LevelEnum; interface Options { - /** - Enable or disable Chalk. - - @default true - */ - enabled?: boolean; - /** Specify the color support for Chalk. By default, color support is automatically detected based on the environment. @@ -98,13 +91,6 @@ declare namespace chalk { */ Instance: Instance; - /** - Enable or disable Chalk. - - @default true - */ - enabled: boolean; - /** The color support for Chalk. By default, color support is automatically detected based on the environment. @@ -248,7 +234,7 @@ declare namespace chalk { readonly strikethrough: Chalk; /** - Modifier: Prints the text only when Chalk is enabled. + 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; diff --git a/index.test-d.ts b/index.test-d.ts index fd19d04..5ab486d 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -24,7 +24,6 @@ expectError(chalk.reset.supportsColor); expectType(new chalk.Instance({level: 1})); // -- Properties -- -expectType(chalk.enabled); expectType(chalk.level); // -- Template literal -- diff --git a/readme.md b/readme.md index ede4ee1..0de3051 100644 --- a/readme.md +++ b/readme.md @@ -120,21 +120,11 @@ Chain [styles](#styles) and call the last one as a method with a string argument Multiple arguments will be separated by space. -### chalk.enabled - -Color support is automatically detected, as is the level (see `chalk.level`). However, if you'd like to simply enable/disable Chalk, you can do so via the `.enabled` property. When `chalk.enabled` is `true`, `chalk.level` must *also* be greater than `0` for colored output to be produced. - -Chalk is enabled by default unless explicitly disabled via `new chalk.Instance()` or `chalk.level` is `0`. - -If you need to change this in a reusable module, create a new instance: - -```js -const ctx = new chalk.Instance({enabled: false}); -``` - ### chalk.level -Color support is automatically detected, but you can override it by setting the `level` property. You should however only do this in your own code as it applies globally to all Chalk consumers. When `chalk.level` is greater than `0`, `chalk.enabled` must *also* be `true` for colored output to be produced. +Specifies the level of color support. + +Color support is automatically detected, but you can override it by setting the `level` property. You should however only do this in your own code as it applies globally to all Chalk consumers. If you need to change this in a reusable module, create a new instance: @@ -170,7 +160,7 @@ Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color= - `inverse`- Inverse background and foreground colors. - `hidden` - Prints the text, but makes it invisible. - `strikethrough` - Puts a horizontal line through the center of the text. *(Not widely supported)* -- `visible`- Prints the text only when Chalk is enabled. Can be useful for things that are purely cosmetic. +- `visible`- Prints the text only when Chalk has a color level > 0. Can be useful for things that are purely cosmetic. ### Colors diff --git a/source/index.js b/source/index.js index e8d47c2..9b4b46b 100644 --- a/source/index.js +++ b/source/index.js @@ -28,7 +28,6 @@ const applyOptions = (object, options = {}) => { // Detect level if not set manually const colorLevel = stdoutColor ? stdoutColor.level : 0; object.level = options.level === undefined ? colorLevel : options.level; - object.enabled = 'enabled' in options ? options.enabled : object.level > 0; }; class ChalkClass { @@ -120,15 +119,6 @@ const proto = Object.defineProperties(() => {}, { set(level) { this._generator.level = level; } - }, - enabled: { - enumerable: true, - get() { - return this._generator.enabled; - }, - set(enabled) { - this._generator.enabled = enabled; - } } }); @@ -171,7 +161,7 @@ const createBuilder = (self, _styler, _isEmpty) => { }; const applyStyle = (self, string) => { - if (!self.enabled || self.level <= 0 || !string) { + if (self.level <= 0 || !string) { return self._isEmpty ? '' : string; } diff --git a/test/enabled.js b/test/enabled.js deleted file mode 100644 index 3d9c55f..0000000 --- a/test/enabled.js +++ /dev/null @@ -1,35 +0,0 @@ -import test from 'ava'; - -// Spoof supports-color -require('./_supports-color')(__dirname); - -const chalk = require('../source'); - -test('don\'t output colors when manually disabled', t => { - chalk.enabled = false; - t.is(chalk.red('foo'), 'foo'); - chalk.enabled = true; -}); - -test('enable/disable colors based on overall chalk enabled property, not individual instances', t => { - chalk.enabled = false; - const {red} = chalk; - t.false(red.enabled); - chalk.enabled = true; - t.true(red.enabled); - chalk.enabled = true; -}); - -test('propagate enable/disable changes from child colors', t => { - chalk.enabled = false; - const {red} = chalk; - t.false(red.enabled); - t.false(chalk.enabled); - red.enabled = true; - t.true(red.enabled); - t.true(chalk.enabled); - chalk.enabled = false; - t.false(red.enabled); - t.false(chalk.enabled); - chalk.enabled = true; -}); diff --git a/test/instance.js b/test/instance.js index 8d2c4e1..e936333 100644 --- a/test/instance.js +++ b/test/instance.js @@ -6,21 +6,13 @@ require('./_supports-color')(__dirname); const chalk = require('../source'); test('create an isolated context where colors can be disabled (by level)', t => { - const instance = new chalk.Instance({level: 0, enabled: true}); + const instance = new chalk.Instance({level: 0}); t.is(instance.red('foo'), 'foo'); t.is(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); instance.level = 2; t.is(instance.red('foo'), '\u001B[31mfoo\u001B[39m'); }); -test('create an isolated context where colors can be disabled (by enabled flag)', t => { - const instance = new chalk.Instance({enabled: false}); - t.is(instance.red('foo'), 'foo'); - t.is(chalk.red('foo'), '\u001B[31mfoo\u001B[39m'); - instance.enabled = true; - t.is(instance.red('foo'), '\u001B[31mfoo\u001B[39m'); -}); - test('the `level` option should be a number from 0 to 3', t => { /* eslint-disable no-new */ t.throws(() => { diff --git a/test/level.js b/test/level.js index bb6df47..828de24 100644 --- a/test/level.js +++ b/test/level.js @@ -14,7 +14,7 @@ test('don\'t output colors when manually disabled', t => { chalk.level = oldLevel; }); -test('enable/disable colors based on overall chalk enabled property, not individual instances', t => { +test('enable/disable colors based on overall chalk .level property, not individual instances', t => { const oldLevel = chalk.level; chalk.level = 1; const {red} = chalk; diff --git a/test/no-color-support.js b/test/no-color-support.js index dae9bda..7318452 100644 --- a/test/no-color-support.js +++ b/test/no-color-support.js @@ -10,7 +10,7 @@ require('./_supports-color')(__dirname, { const chalk = require('../source'); -test.failing('colors can be forced by using chalk.enabled', t => { - chalk.enabled = true; +test('colors can be forced by using chalk.level', t => { + chalk.level = 1; t.is(chalk.green('hello'), '\u001B[32mhello\u001B[39m'); }); diff --git a/test/visible.js b/test/visible.js index 14ecc3c..7987712 100644 --- a/test/visible.js +++ b/test/visible.js @@ -5,40 +5,34 @@ require('./_supports-color')(__dirname); const chalk = require('../source'); -test('visible: normal output when enabled', t => { - const instance = new chalk.Instance({level: 3, enabled: true}); +test('visible: normal output when level > 0', t => { + const instance = new chalk.Instance({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 disabled', t => { - const instance = new chalk.Instance({level: 3, enabled: false}); - t.is(instance.red.visible('foo'), ''); - t.is(instance.visible.red('foo'), ''); -}); - test('visible: no output when level is too low', t => { - const instance = new chalk.Instance({level: 0, enabled: true}); + const instance = new chalk.Instance({level: 0}); t.is(instance.visible.red('foo'), ''); t.is(instance.red.visible('foo'), ''); }); -test('test switching back and forth between enabled and disabled', t => { - const instance = new chalk.Instance({level: 3, enabled: true}); +test('test switching back and forth between level == 0 and level > 0', t => { + const instance = new chalk.Instance({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'); t.is(instance.visible('foo'), 'foo'); t.is(instance.red('foo'), '\u001B[31mfoo\u001B[39m'); - instance.enabled = false; + instance.level = 0; t.is(instance.red('foo'), 'foo'); t.is(instance.visible('foo'), ''); t.is(instance.visible.red('foo'), ''); t.is(instance.red.visible('foo'), ''); t.is(instance.red('foo'), 'foo'); - instance.enabled = true; + instance.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'); From 6b4d20683f7490195e51f80829f3d465b9835de1 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Thu, 22 Aug 2019 15:28:25 +0200 Subject: [PATCH 142/235] Export TypeScript types for colors and modifiers (#357) Co-authored-by: Sindre Sorhus --- index.d.ts | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ index.test-d.ts | 4 +++ 2 files changed, 76 insertions(+) diff --git a/index.d.ts b/index.d.ts index 58da80e..c650eb9 100644 --- a/index.d.ts +++ b/index.d.ts @@ -20,6 +20,74 @@ declare const enum LevelEnum { TrueColor = 3 } +/** +Basic foreground colors. + +[More colors here.](https://github.com/chalk/chalk/blob/master/readme.md#256-and-truecolor-color-support) +*/ +declare type ForegroundColor = + | 'black' + | 'red' + | 'green' + | 'yellow' + | 'blue' + | 'magenta' + | 'cyan' + | 'white' + | 'gray' + | 'grey' + | 'blackBright' + | 'redBright' + | 'greenBright' + | 'yellowBright' + | 'blueBright' + | 'magentaBright' + | 'cyanBright' + | 'whiteBright'; + +/** +Basic background colors. + +[More colors here.](https://github.com/chalk/chalk/blob/master/readme.md#256-and-truecolor-color-support) +*/ +declare type BackgroundColor = + | 'bgBlack' + | 'bgRed' + | 'bgGreen' + | 'bgYellow' + | 'bgBlue' + | 'bgMagenta' + | 'bgCyan' + | 'bgWhite' + | 'bgGray' + | 'bgGrey' + | 'bgBlackBright' + | 'bgRedBright' + | 'bgGreenBright' + | 'bgYellowBright' + | 'bgBlueBright' + | 'bgMagentaBright' + | 'bgCyanBright' + | 'bgWhiteBright'; + +/** +Basic colors. + +[More colors here.](https://github.com/chalk/chalk/blob/master/readme.md#256-and-truecolor-color-support) +*/ +declare type Color = ForegroundColor | BackgroundColor; + +declare type Modifiers = + | 'reset' + | 'bold' + | 'dim' + | 'italic' + | 'underline' + | 'inverse' + | 'hidden' + | 'strikethrough' + | 'visible'; + declare namespace chalk { type Level = LevelEnum; @@ -306,6 +374,10 @@ 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: typeof LevelEnum; + Color: Color; + ForegroundColor: ForegroundColor; + BackgroundColor: BackgroundColor; + Modifiers: Modifiers; }; export = chalk; diff --git a/index.test-d.ts b/index.test-d.ts index 5ab486d..1d2df98 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -139,3 +139,7 @@ expectType(chalk.bgWhiteBright`foo`); // -- Complex -- expectType(chalk.red.bgGreen.underline('foo')); expectType(chalk.underline.red.bgGreen('foo')); + +// -- Color types == +expectType('red'); +expectError('hotpink'); From 2a53389d72cf46dbb9d73ab730d99e15cb230c7f Mon Sep 17 00:00:00 2001 From: Yanis Benson Date: Sun, 22 Sep 2019 12:07:33 +0300 Subject: [PATCH 143/235] Add `chalk.stderr` (#359) --- index.d.ts | 1 + index.test-d.ts | 10 ++++++++++ readme.md | 4 ++++ source/index.js | 10 +++++++--- test/_fixture.js | 2 +- test/_supports-color.js | 6 ++++++ test/chalk.js | 5 +++++ test/level.js | 2 +- test/no-color-support.js | 16 ++++++++++++---- 9 files changed, 47 insertions(+), 9 deletions(-) diff --git a/index.d.ts b/index.d.ts index c650eb9..52dd5ae 100644 --- a/index.d.ts +++ b/index.d.ts @@ -378,6 +378,7 @@ declare const chalk: chalk.Chalk & chalk.ChalkFunction & { ForegroundColor: ForegroundColor; BackgroundColor: BackgroundColor; Modifiers: Modifiers; + stderr: chalk.Chalk & {supportsColor: chalk.ColorSupport | false}; }; export = chalk; diff --git a/index.test-d.ts b/index.test-d.ts index 1d2df98..bc3d17a 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -16,6 +16,16 @@ expectType((chalk.supportsColor as chalk.ColorSupport).hasBasic); expectType((chalk.supportsColor as chalk.ColorSupport).has256); expectType((chalk.supportsColor as chalk.ColorSupport).has16m); +// - stderr - +expectType(chalk.stderr); +expectType(chalk.stderr.supportsColor); +expectType((chalk.stderr.supportsColor as chalk.ColorSupport).hasBasic); +expectType((chalk.stderr.supportsColor as chalk.ColorSupport).has256); +expectType((chalk.stderr.supportsColor as chalk.ColorSupport).has16m); + +// -- `stderr` is not a member of the Chalk interface -- +expectError(chalk.reset.stderr); + // -- `supportsColor` is not a member of the Chalk interface -- expectError(chalk.reset.supportsColor); diff --git a/readme.md b/readme.md index 0de3051..aaa8b47 100644 --- a/readme.md +++ b/readme.md @@ -147,6 +147,10 @@ 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 + +`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. + ## Styles diff --git a/source/index.js b/source/index.js index 9b4b46b..686758b 100644 --- a/source/index.js +++ b/source/index.js @@ -1,6 +1,6 @@ 'use strict'; const ansiStyles = require('ansi-styles'); -const {stdout: stdoutColor} = require('supports-color'); +const {stdout: stdoutColor, stderr: stderrColor} = require('supports-color'); const template = require('./templates'); const { stringReplaceAll, @@ -218,5 +218,9 @@ const chalkTag = (chalk, ...strings) => { Object.defineProperties(Chalk.prototype, styles); -module.exports = Chalk(); // eslint-disable-line new-cap -module.exports.supportsColor = stdoutColor; +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; + +module.exports = chalk; diff --git a/test/_fixture.js b/test/_fixture.js index 214a86c..29f34b0 100644 --- a/test/_fixture.js +++ b/test/_fixture.js @@ -1,4 +1,4 @@ 'use strict'; const chalk = require('../source'); -console.log(chalk.hex('#ff6159')('test')); +console.log(`${chalk.hex('#ff6159')('testout')} ${chalk.stderr.hex('#ff6159')('testerr')}`); diff --git a/test/_supports-color.js b/test/_supports-color.js index 490c323..b5c0f78 100644 --- a/test/_supports-color.js +++ b/test/_supports-color.js @@ -7,6 +7,12 @@ const DEFAULT = { hasBasic: true, has256: true, has16m: true + }, + stderr: { + level: 3, + hasBasic: true, + has256: true, + has16m: true } }; diff --git a/test/chalk.js b/test/chalk.js index 2992a09..5e33f5e 100644 --- a/test/chalk.js +++ b/test/chalk.js @@ -105,3 +105,8 @@ test('don\'t emit RGB codes if level is 0', t => { 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'); +}); diff --git a/test/level.js b/test/level.js index 828de24..65d4720 100644 --- a/test/level.js +++ b/test/level.js @@ -41,5 +41,5 @@ 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')); - t.is(stdout, 'test'); + t.is(stdout, 'testout testerr'); }); diff --git a/test/no-color-support.js b/test/no-color-support.js index 7318452..ae88ac9 100644 --- a/test/no-color-support.js +++ b/test/no-color-support.js @@ -2,10 +2,18 @@ import test from 'ava'; // Spoof supports-color require('./_supports-color')(__dirname, { - level: 0, - hasBasic: false, - has256: false, - has16m: false + stdout: { + level: 0, + hasBasic: false, + has256: false, + has16m: false + }, + stderr: { + level: 0, + hasBasic: false, + has256: false, + has16m: false + } }); const chalk = require('../source'); From 4e65299e7bc54949d00ec0c963daf08635d83bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kh=E1=BA=A3i?= Date: Fri, 27 Sep 2019 10:53:54 +0700 Subject: [PATCH 144/235] Fix const enum for TypeScript (#364) --- source/index.js | 12 ++++++++++++ test/level.js | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/source/index.js b/source/index.js index 686758b..6fee0f8 100644 --- a/source/index.js +++ b/source/index.js @@ -223,4 +223,16 @@ chalk.supportsColor = stdoutColor; chalk.stderr = Chalk({level: stderrColor ? stderrColor.level : 0}); // eslint-disable-line new-cap chalk.stderr.supportsColor = stderrColor; +// For TypeScript +chalk.Level = { + None: 0, + Basic: 1, + Ansi256: 2, + TrueColor: 3, + 0: 'None', + 1: 'Basic', + 2: 'Ansi256', + 3: 'TrueColor' +}; + module.exports = chalk; diff --git a/test/level.js b/test/level.js index 65d4720..4fe8fae 100644 --- a/test/level.js +++ b/test/level.js @@ -43,3 +43,15 @@ test('disable colors if they are not supported', async t => { const {stdout} = await execa.node(path.join(__dirname, '_fixture')); t.is(stdout, 'testout testerr'); }); + +test('chalk.Level enum object', t => { + const {Level} = chalk; + t.is(Level.None, 0); + t.is(Level.Basic, 1); + t.is(Level.Ansi256, 2); + t.is(Level.TrueColor, 3); + t.is(Level[Level.None], 'None'); + t.is(Level[Level.Basic], 'Basic'); + t.is(Level[Level.Ansi256], 'Ansi256'); + t.is(Level[Level.TrueColor], 'TrueColor'); +}); From 61aca7cb768cc4e3bc5d11abbad32377c72e1ff3 Mon Sep 17 00:00:00 2001 From: Yanis Benson Date: Fri, 27 Sep 2019 06:55:19 +0300 Subject: [PATCH 145/235] Improve require speed (#358) --- source/index.js | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/source/index.js b/source/index.js index 6fee0f8..53fcc16 100644 --- a/source/index.js +++ b/source/index.js @@ -1,7 +1,6 @@ 'use strict'; const ansiStyles = require('ansi-styles'); const {stdout: stdoutColor, stderr: stderrColor} = require('supports-color'); -const template = require('./templates'); const { stringReplaceAll, stringEncaseCRLFWithFirstIndex @@ -15,9 +14,6 @@ const levelMapping = [ 'ansi16m' ]; -// `color-convert` models to exclude from the Chalk API due to conflicts and such -const skipModels = new Set(['gray']); - const styles = Object.create(null); const applyOptions = (object, options = {}) => { @@ -76,11 +72,9 @@ styles.visible = { } }; -for (const model of Object.keys(ansiStyles.color.ansi)) { - if (skipModels.has(model)) { - continue; - } +const usedModels = ['rgb', 'hex', 'keyword', 'hsl', 'hsv', 'hwb', 'ansi', 'ansi256']; +for (const model of usedModels) { styles[model] = { get() { const {level} = this; @@ -92,11 +86,7 @@ for (const model of Object.keys(ansiStyles.color.ansi)) { }; } -for (const model of Object.keys(ansiStyles.bgColor.ansi)) { - if (skipModels.has(model)) { - continue; - } - +for (const model of usedModels) { const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); styles[bgModel] = { get() { @@ -194,6 +184,7 @@ const applyStyle = (self, string) => { return openAll + string + closeAll; }; +let template; const chalkTag = (chalk, ...strings) => { const [firstString] = strings; @@ -213,6 +204,10 @@ const chalkTag = (chalk, ...strings) => { ); } + if (template === undefined) { + template = require('./templates'); + } + return template(chalk, parts.join('')); }; From 1953816afd7d36e0a6751331a0441822477313b8 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 27 Sep 2019 11:16:49 +0700 Subject: [PATCH 146/235] Update dependencies --- package.json | 14 ++++++++++---- readme.md | 4 ++-- test/chalk.js | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index b6cbdd4..b6ebb06 100644 --- a/package.json +++ b/package.json @@ -40,11 +40,11 @@ "text" ], "dependencies": { - "ansi-styles": "^4.0.0", - "supports-color": "^7.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "devDependencies": { - "ava": "^2.2.0", + "ava": "^2.4.0", "coveralls": "^3.0.5", "execa": "^2.0.3", "import-fresh": "^3.1.0", @@ -52,6 +52,12 @@ "nyc": "^14.1.1", "resolve-from": "^5.0.0", "tsd": "^0.7.4", - "xo": "^0.24.0" + "xo": "^0.25.3" + }, + "xo": { + "rules": { + "unicorn/prefer-string-slice": "off", + "unicorn/prefer-includes": "off" + } } } diff --git a/readme.md b/readme.md index aaa8b47..4a3b646 100644 --- a/readme.md +++ b/readme.md @@ -26,7 +26,7 @@ - Doesn't extend `String.prototype` - Clean and focused - Actively maintained -- [Used by ~40,000 packages](https://www.npmjs.com/browse/depended/chalk) as of March 1, 2019 +- [Used by ~46,000 packages](https://www.npmjs.com/browse/depended/chalk) as of October 1, 2019 ## Install @@ -267,7 +267,7 @@ The following color models can be used: ## Windows -If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) instead of `cmd.exe`. +If you're on Windows, do yourself a favor and use [Windows Terminal](https://github.com/microsoft/terminal) instead of `cmd.exe`. ## Origin story diff --git a/test/chalk.js b/test/chalk.js index 5e33f5e..21f0346 100644 --- a/test/chalk.js +++ b/test/chalk.js @@ -73,7 +73,7 @@ test('don\'t output escape codes if the input is empty', t => { }); test('keep Function.prototype methods', t => { - t.is(chalk.grey.apply(null, ['foo']), '\u001B[90mfoo\u001B[39m'); + t.is(Reflect.apply(chalk.grey, null, ['foo']), '\u001B[90mfoo\u001B[39m'); t.is(chalk.reset(chalk.red.bgGreen.underline.bind(null)('foo') + 'foo'), '\u001B[0m\u001B[31m\u001B[42m\u001B[4mfoo\u001B[24m\u001B[49m\u001B[39mfoo\u001B[0m'); t.is(chalk.red.blue.black.call(null), ''); }); From 48905d08052aad4c8ba53bbd9fbcd8a9faf4f6e5 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 27 Sep 2019 12:07:07 +0700 Subject: [PATCH 147/235] 3.0.0-beta.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b6ebb06..32ea3bd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "2.4.1", + "version": "3.0.0-beta.1", "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk", From eef8c8c191d25deecde8c472e10a37c6f736e2e9 Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Mon, 30 Sep 2019 21:13:15 -0400 Subject: [PATCH 148/235] Replace level list with table in readme.md (#367) * Replace level list with table in readme.md * Capitalize table headings and center level numbers --- readme.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index 4a3b646..6e52c05 100644 --- a/readme.md +++ b/readme.md @@ -132,12 +132,12 @@ If you need to change this in a reusable module, create a new instance: const ctx = new chalk.Instance({level: 0}); ``` -Levels are as follows: - -0. All colors disabled -1. Basic color support (16 colors) -2. 256 color support -3. Truecolor support (16 million colors) +| Level | Description | +| :---: | :--- | +| `0` | All colors disabled | +| `1` | Basic color support (16 colors) | +| `2` | 256 color support | +| `3` | Truecolor support (16 million colors) | ### chalk.supportsColor From fb8e85ab875eb95b55448fd615daacf8c325cf44 Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Tue, 8 Oct 2019 05:02:34 -0400 Subject: [PATCH 149/235] Add `ansi256` and `bgAnsi256` to TypeScript declarations (#368) --- index.d.ts | 10 ++++++++++ index.test-d.ts | 2 ++ readme.md | 4 ++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index 52dd5ae..c50c17e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -213,6 +213,11 @@ declare namespace chalk { */ hwb(hue: number, whiteness: number, blackness: 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. @@ -261,6 +266,11 @@ declare namespace chalk { */ bgHwb(hue: number, whiteness: number, blackness: 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. */ diff --git a/index.test-d.ts b/index.test-d.ts index bc3d17a..dd3ba99 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -49,12 +49,14 @@ expectType(chalk.rgb(0, 0, 0)); expectType(chalk.hsl(0, 0, 0)); expectType(chalk.hsv(0, 0, 0)); expectType(chalk.hwb(0, 0, 0)); +expectType(chalk.ansi256(0)); expectType(chalk.bgHex('#DEADED')); expectType(chalk.bgKeyword('orange')); expectType(chalk.bgRgb(0, 0, 0)); expectType(chalk.bgHsl(0, 0, 0)); expectType(chalk.bgHsv(0, 0, 0)); expectType(chalk.bgHwb(0, 0, 0)); +expectType(chalk.bgAnsi256(0)); // -- Modifiers -- expectType(chalk.reset('foo')); diff --git a/readme.md b/readme.md index 6e52c05..7322f2b 100644 --- a/readme.md +++ b/readme.md @@ -260,9 +260,9 @@ The following color models can be used: - [`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!')` +- [`hwb`](https://en.wikipedia.org/wiki/HWB_color_model) - Example: `chalk.hwb(32, 0, 50).bold('Orange!')` - `ansi16` -- `ansi256` +- [`ansi256`](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) - Example: `chalk.bgAnsi256(194)('Honeydew, more or less')` ## Windows From 4de1841129cf3d0a1db7a5d6638402b7828e1731 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 8 Oct 2019 16:21:40 +0700 Subject: [PATCH 150/235] 3.0.0-beta.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 32ea3bd..d22089b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "3.0.0-beta.1", + "version": "3.0.0-beta.2", "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk", From 628b5954cf1ea07a00dfed13d51bbd95f5d42de1 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 30 Oct 2019 19:38:56 +0700 Subject: [PATCH 151/235] Tidelift tasks --- readme.md | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/readme.md b/readme.md index 7322f2b..aa0070a 100644 --- a/readme.md +++ b/readme.md @@ -275,6 +275,13 @@ If you're on Windows, do yourself a favor and use [Windows Terminal](https://git [colors.js](https://github.com/Marak/colors.js) used to be the most popular string styling module, but it has serious deficiencies like extending `String.prototype` which causes all kinds of [problems](https://github.com/yeoman/yo/issues/68) and the package is unmaintained. Although there are other packages, they either do too much or not enough. Chalk is a clean and focused alternative. +## chalk for enterprise + +Available as part of the Tidelift Subscription. + +The maintainers of chalk and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-chalk?utm_source=npm-chalk&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) + + ## Related - [chalk-cli](https://github.com/chalk/chalk-cli) - CLI for this module @@ -297,16 +304,3 @@ If you're on Windows, do yourself a favor and use [Windows Terminal](https://git - [Sindre Sorhus](https://github.com/sindresorhus) - [Josh Junon](https://github.com/qix-) - - ---- - -
- - Get professional support for Chalk with a Tidelift subscription - -
- - Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies. -
-
From 18c280da2ea2d8a29556891f771c0f7bcf5678ab Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Sat, 9 Nov 2019 01:22:55 -0500 Subject: [PATCH 152/235] Add `ansi` and `bgAnsi` to TypeScript declaration (#369) --- index.d.ts | 17 +++++++++++++++++ index.test-d.ts | 2 ++ readme.md | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index c50c17e..7e22c45 100644 --- a/index.d.ts +++ b/index.d.ts @@ -213,6 +213,14 @@ declare namespace chalk { */ 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. */ @@ -266,6 +274,15 @@ declare namespace chalk { */ 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. */ diff --git a/index.test-d.ts b/index.test-d.ts index dd3ba99..177d6de 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -49,6 +49,7 @@ expectType(chalk.rgb(0, 0, 0)); expectType(chalk.hsl(0, 0, 0)); expectType(chalk.hsv(0, 0, 0)); expectType(chalk.hwb(0, 0, 0)); +expectType(chalk.ansi(30)); expectType(chalk.ansi256(0)); expectType(chalk.bgHex('#DEADED')); expectType(chalk.bgKeyword('orange')); @@ -56,6 +57,7 @@ expectType(chalk.bgRgb(0, 0, 0)); expectType(chalk.bgHsl(0, 0, 0)); expectType(chalk.bgHsv(0, 0, 0)); expectType(chalk.bgHwb(0, 0, 0)); +expectType(chalk.bgAnsi(30)); expectType(chalk.bgAnsi256(0)); // -- Modifiers -- diff --git a/readme.md b/readme.md index aa0070a..54c4aff 100644 --- a/readme.md +++ b/readme.md @@ -261,7 +261,7 @@ The following color models can be used: - [`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!')` -- `ansi16` +- [`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')` From b3930189a54aa84434a2f3ea7a18ec83d6a5ee92 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 9 Nov 2019 13:56:12 +0700 Subject: [PATCH 153/235] Meta tweaks --- package.json | 4 ++-- readme.md | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index d22089b..724c0d5 100644 --- a/package.json +++ b/package.json @@ -45,8 +45,8 @@ }, "devDependencies": { "ava": "^2.4.0", - "coveralls": "^3.0.5", - "execa": "^2.0.3", + "coveralls": "^3.0.7", + "execa": "^3.2.0", "import-fresh": "^3.1.0", "matcha": "^0.7.0", "nyc": "^14.1.1", diff --git a/readme.md b/readme.md index 54c4aff..877cb93 100644 --- a/readme.md +++ b/readme.md @@ -13,8 +13,6 @@ -**This readme reflects the next major version that is currently in development. You probably want [the v2 readme](https://www.npmjs.com/package/chalk).** - ## Highlights From 20002d8bd1dfd6f68bfa8bdacba520ff6027a450 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 9 Nov 2019 13:58:44 +0700 Subject: [PATCH 154/235] 3.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 724c0d5..047adf9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "3.0.0-beta.2", + "version": "3.0.0", "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk", From 0e6fecc7f7fd8158d3c96fb89608b8dfb744fdfa Mon Sep 17 00:00:00 2001 From: Edwin Kofler <24364012+eankeen@users.noreply.github.com> Date: Thu, 12 Dec 2019 12:12:22 -0800 Subject: [PATCH 155/235] Add link to replit run (#379) --- .replit | 2 ++ readme.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 .replit diff --git a/.replit b/.replit new file mode 100644 index 0000000..cf3930d --- /dev/null +++ b/.replit @@ -0,0 +1,2 @@ +language = "nodejs" +run = "cd examples && node rainbow" diff --git a/readme.md b/readme.md index 877cb93..c38fa60 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) +[![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) From 797461ee3232c0013afc9b51d18ea2ba87227f10 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 1 Jan 2020 19:05:40 +0100 Subject: [PATCH 156/235] Meta tweaks --- package.json | 3 ++- readme.md | 14 +------------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 047adf9..0a4aaa9 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk", + "funding": "https://github.com/chalk/chalk?sponsor=1", "main": "source", "engines": { "node": ">=8" @@ -49,7 +50,7 @@ "execa": "^3.2.0", "import-fresh": "^3.1.0", "matcha": "^0.7.0", - "nyc": "^14.1.1", + "nyc": "^15.0.0", "resolve-from": "^5.0.0", "tsd": "^0.7.4", "xo": "^0.25.3" diff --git a/readme.md b/readme.md index c38fa60..a0ca245 100644 --- a/readme.md +++ b/readme.md @@ -13,7 +13,6 @@ - ## Highlights - Expressive API @@ -24,8 +23,7 @@ - Doesn't extend `String.prototype` - Clean and focused - Actively maintained -- [Used by ~46,000 packages](https://www.npmjs.com/browse/depended/chalk) as of October 1, 2019 - +- [Used by ~50,000 packages](https://www.npmjs.com/browse/depended/chalk) as of January 1, 2020 ## Install @@ -33,7 +31,6 @@ $ npm install chalk ``` - ## Usage ```js @@ -107,7 +104,6 @@ console.log(chalk.green('Hello %s'), name); //=> 'Hello Sindre' ``` - ## API ### chalk.`