From b0addb86d6add080d0e3d453b50e17e84d33b495 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 16 Dec 2013 19:25:01 +0100 Subject: [PATCH 001/324] Update index.js --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index a21f702..1a8d3f5 100644 --- a/index.js +++ b/index.js @@ -45,7 +45,7 @@ function init() { return obj[name]; } - } + }; }); return ret; From 13a555ede8773d5bc6e13668573c804ab9a34404 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 16 Dec 2013 21:44:25 +0100 Subject: [PATCH 002/324] readme - add string substitution example Fixes #8 --- readme.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 46813ac..580d4a0 100644 --- a/readme.md +++ b/readme.md @@ -49,7 +49,7 @@ console.log( chalk.red('Hello', chalk.underline.bgBlue('world') + '!') ); console.log( chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz') ); ``` -You can easily define your own themes. +Easily define your own themes. ```js var chalk = require('chalk'); @@ -57,6 +57,14 @@ var 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'; +console.log(chalk.green('Hello %s'), name); +//=> Hello Sindre +``` + ## API From ebf961e585b3f04279ae97bd8b5602a9a244a4c0 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 11 Jan 2014 22:19:36 +0100 Subject: [PATCH 003/324] yay --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 580d4a0..ff70230 100644 --- a/readme.md +++ b/readme.md @@ -18,7 +18,7 @@ - Clean and focused - Auto-detects color support - Actively maintained -- [Used by 150+ modules](https://npmjs.org/browse/depended/chalk) +- [Used by 200+ modules](https://npmjs.org/browse/depended/chalk) ## Install From d99230962138f6d8a3c0c3a9856ca5632d4c1efd Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 11 Feb 2014 20:33:11 +0100 Subject: [PATCH 004/324] Update readme.md --- readme.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/readme.md b/readme.md index ff70230..c23bb46 100644 --- a/readme.md +++ b/readme.md @@ -18,12 +18,14 @@ - Clean and focused - Auto-detects color support - Actively maintained -- [Used by 200+ modules](https://npmjs.org/browse/depended/chalk) +- [Used by 300+ modules](https://npmjs.org/browse/depended/chalk) ## Install -Install with [npm](https://npmjs.org/package/chalk): `npm install --save chalk` +``` +npm install --save chalk +``` ## Example @@ -113,10 +115,10 @@ Example: ```js var chalk = require('chalk'); -var styledString = fromExternal(); +var styledString = getText(); if (!chalk.supportsColor) { - chalk.stripColor(styledString); + styledString = chalk.stripColor(styledString); } ``` @@ -159,8 +161,3 @@ if (!chalk.supportsColor) { ## License MIT © [Sindre Sorhus](http://sindresorhus.com) - - -- - -[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/sindresorhus/chalk/trend.png)](https://bitdeli.com/free "Bitdeli Badge") From af4983c011e23fa4097759f702c383746d6a70c4 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 26 Mar 2014 16:29:42 +0100 Subject: [PATCH 005/324] bump strip-ansi --- .editorconfig | 4 + .gitattributes | 2 +- .travis.yml | 1 - logo.ai | 1614 ------------------------------------------------ package.json | 10 +- test.js | 1 - 6 files changed, 10 insertions(+), 1622 deletions(-) delete mode 100644 logo.ai diff --git a/.editorconfig b/.editorconfig index b0d7fd9..8311fe1 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,5 +8,9 @@ charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true +[package.json] +indent_style = space +indent_size = 2 + [*.md] trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes index 176a458..fcadb2c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -* text=auto +* text eol=lf diff --git a/.travis.yml b/.travis.yml index 2cdacaf..244b7e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,3 @@ language: node_js node_js: - '0.10' - - '0.8' diff --git a/logo.ai b/logo.ai deleted file mode 100644 index e17928e..0000000 --- a/logo.ai +++ /dev/null @@ -1,1614 +0,0 @@ -%PDF-1.5 % -1 0 obj <>/OCGs[5 0 R 25 0 R 44 0 R 63 0 R 82 0 R 101 0 R 120 0 R 139 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream - - - - - application/pdf - - - Web - - - - - Adobe Illustrator CS6 (Macintosh) - 2013-11-10T13:15:16+01:00 - 2013-11-10T13:32:04+01:00 - 2013-11-10T13:32:04+01:00 - - - - 256 - 176 - JPEG - /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAsAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FUj1jzjo+l3Bt5S80y09RIgp417Hky75XLKA52Ds/JlFjYeaIi8xWct1bW6pJW6RZE ZgAAHXktd64+ILp1+SXBPgPNWTWLZ9TbTgGEy96DjsvLxw8YumIyDi4V1xqkEF3HasGLyU+IUoOR oK5jZdbCGQYzzLlQwGUTJC6x5msNKvLa1uY5We6IEbRhSoq3H4qsp+4ZsseAzBI6OHkziBAPVGan qMWn2puZVZlBAotK7/PK4xs05EIcRpA3PmexgjtmCSSSXKh0hUDkAeld+5yQxEtgwk35JwpqAaUr 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 - - - - - - proof:pdf - uuid:65E6390686CF11DBA6E2D887CEACB407 - xmp.did:0180117407206811822ADCBB5C067A70 - uuid:5b50a299-c5b9-7746-a00b-f393a82aaec5 - - uuid:53138140-74df-418f-a148-0d97b4a30ff8 - xmp.did:66A6819719206811822A897E387FE54C - uuid:65E6390686CF11DBA6E2D887CEACB407 - proof:pdf - - - - - saved - xmp.iid:0180117407206811822ADCBB5C067A70 - 2013-11-10T13:15:16+01:00 - Adobe Illustrator CS6 (Macintosh) - / - - - - - - Web - Document - - - 1 - False - False - - 500.000000 - 230.000000 - Pixels - - - - - KGTangledUpInYou - KG Tangled Up In You - Regular - TrueType - Version 1.000 2013 initial release - False - KGTangledUpInYou.ttf - - - - - - Cyan - Magenta - Yellow - - - - - - Default Swatch Group - 0 - - - - White - RGB - PROCESS - 255 - 255 - 255 - - - Black - RGB - PROCESS - 0 - 0 - 0 - - - RGB Red - RGB - PROCESS - 255 - 0 - 0 - - - RGB Yellow - RGB - PROCESS - 255 - 255 - 0 - - - RGB Green - RGB - PROCESS - 0 - 255 - 0 - - - RGB Cyan - RGB - PROCESS - 0 - 255 - 255 - - - RGB Blue - RGB - PROCESS - 0 - 0 - 255 - - - RGB Magenta - RGB - PROCESS - 255 - 0 - 255 - - - R=193 G=39 B=45 - RGB - PROCESS - 193 - 39 - 45 - - - R=237 G=28 B=36 - RGB - PROCESS - 237 - 28 - 36 - - - R=241 G=90 B=36 - RGB - PROCESS - 241 - 90 - 36 - - - R=247 G=147 B=30 - RGB - PROCESS - 247 - 147 - 30 - - - R=251 G=176 B=59 - RGB - PROCESS - 251 - 176 - 59 - - - R=252 G=238 B=33 - RGB - PROCESS - 252 - 238 - 33 - - - R=217 G=224 B=33 - RGB - PROCESS - 217 - 224 - 33 - - - R=140 G=198 B=63 - RGB - PROCESS - 140 - 198 - 63 - - - R=57 G=181 B=74 - RGB - PROCESS - 57 - 181 - 74 - - - R=0 G=146 B=69 - RGB - PROCESS - 0 - 146 - 69 - - - R=0 G=104 B=55 - RGB - PROCESS - 0 - 104 - 55 - - - R=34 G=181 B=115 - RGB - PROCESS - 34 - 181 - 115 - - - R=0 G=169 B=157 - RGB - PROCESS - 0 - 169 - 157 - - - R=41 G=171 B=226 - RGB - PROCESS - 41 - 171 - 226 - - - R=0 G=113 B=188 - RGB - PROCESS - 0 - 113 - 188 - - - R=46 G=49 B=146 - RGB - PROCESS - 46 - 49 - 146 - - - R=27 G=20 B=100 - RGB - PROCESS - 27 - 20 - 100 - - - R=102 G=45 B=145 - RGB - PROCESS - 102 - 45 - 145 - - - R=147 G=39 B=143 - RGB - PROCESS - 147 - 39 - 143 - - - R=158 G=0 B=93 - RGB - PROCESS - 158 - 0 - 93 - - - R=212 G=20 B=90 - RGB - PROCESS - 212 - 20 - 90 - - - R=237 G=30 B=121 - RGB - PROCESS - 237 - 30 - 121 - - - R=199 G=178 B=153 - RGB - PROCESS - 199 - 178 - 153 - - - R=153 G=134 B=117 - RGB - PROCESS - 153 - 134 - 117 - - - R=115 G=99 B=87 - RGB - PROCESS - 115 - 99 - 87 - - - R=83 G=71 B=65 - RGB - PROCESS - 83 - 71 - 65 - - - R=198 G=156 B=109 - RGB - PROCESS - 198 - 156 - 109 - - - R=166 G=124 B=82 - RGB - PROCESS - 166 - 124 - 82 - - - R=140 G=98 B=57 - RGB - PROCESS - 140 - 98 - 57 - - - R=117 G=76 B=36 - RGB - PROCESS - 117 - 76 - 36 - - - R=96 G=56 B=19 - RGB - PROCESS - 96 - 56 - 19 - - - R=66 G=33 B=11 - RGB - PROCESS - 66 - 33 - 11 - - - - - - Grays - 1 - - - - R=0 G=0 B=0 - RGB - PROCESS - 0 - 0 - 0 - - - R=26 G=26 B=26 - RGB - PROCESS - 26 - 26 - 26 - - - R=51 G=51 B=51 - RGB - PROCESS - 51 - 51 - 51 - - - R=77 G=77 B=77 - RGB - PROCESS - 77 - 77 - 77 - - - R=102 G=102 B=102 - RGB - PROCESS - 102 - 102 - 102 - - - R=128 G=128 B=128 - RGB - PROCESS - 128 - 128 - 128 - - - R=153 G=153 B=153 - RGB - PROCESS - 153 - 153 - 153 - - - R=179 G=179 B=179 - RGB - PROCESS - 179 - 179 - 179 - - - R=204 G=204 B=204 - RGB - PROCESS - 204 - 204 - 204 - - - R=230 G=230 B=230 - RGB - PROCESS - 230 - 230 - 230 - - - R=242 G=242 B=242 - RGB - PROCESS - 242 - 242 - 242 - - - - - - Web Color Group - 1 - - - - R=63 G=169 B=245 - RGB - PROCESS - 63 - 169 - 245 - - - R=122 G=201 B=67 - RGB - PROCESS - 122 - 201 - 67 - - - R=255 G=147 B=30 - RGB - PROCESS - 255 - 147 - 30 - - - R=255 G=29 B=37 - RGB - PROCESS - 255 - 29 - 37 - - - R=255 G=123 B=172 - RGB - PROCESS - 255 - 123 - 172 - - - R=189 G=204 B=212 - RGB - PROCESS - 189 - 204 - 212 - - - - - - - - - Adobe PDF library 10.01 - - - - - - - - - - - - - - - - - - - - - - - - - endstream endobj 3 0 obj <> endobj 7 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/Thumb 145 0 R/TrimBox[0.0 0.0 500.0 230.0]/Type/Page>> endobj 141 0 obj <>stream -HtWɮe WxjQ%m -'x/Hqa9bU?~|G?>߾g'U}J)>o_-?_z߾}V2~ozRدj`Y -ȉY?%MJhdFVjwJNDZO"#[2زW='Xյ4ROް>4>mtΩ-_"z>_\SYC"0\r2nWH#˽%ck!ɩfI'Ⱥ2v7ϒdw(y!%$+Bd%,PIKrj,o ԢY-8-u=Ĺ&Q"xMP:s$*l%>KR )ذg%9ʬN٘P=i.)0EX[S'@K; -;)噚bmMaF$ȿB@dJГc@ߜ>bY)[(ةz4奥Β -{mX|>]3fm!9d%ܙު0Y=QqiJ}۽˽$OGE"mZ_w`ջZctB4ENG|5FC˽"CKA7P$AHS`GFm+b H(ָ*3Lk QAjjhҪHZr%w#A֔>ZB3MG&z\F JXgPT:l\;K ޒ_^yH!=4q_lT<HC1܋mLPPw{#.|99Vp[PPcpGTc_+;O;5rtv.ǩLw8T6/+9 |>*/;H(P=V^5LZNV, -)e=P2YyIc[9HsƫJXߵ g@REc+zI;<(iJ74iX P7ܼzu7n\u\b^A/1XBD o -t9 - vevH,"_}gZuS5-Y؛3@!SJޗ+wfW+X婘]aG C.Kn{Ļ;ͩn1ڰ9pGHzbDL -X;bX=bc3:,Wt+uƱd,UxFIp;$01kt7JP|kB:Xu{ݖ}Ye"S -׽*OzC2#IehLK6<|*dwsx7Fۆz"-Q$H`JގY9Rv~ uyOli -d~*UCW}Cx;w%T&ӺZat1VWHX;֊Z^3bRq-0KsI^oHmiC:9i:Avy F,k^frs{>"Fl!l2WՌsE8ph:+|xH2qH/<ƍW)S`"ax\`)\6ODZ;tBPpRyzyi?y -Ejȍ!tR~شz -+4$4ԝ9== # vfzNPb-Z&0gȧ^uB".ܞ5ؖE;tvOm +MRx|Q qnB 2j 0>@V!3AΡ )ȏAh Oq?Rz`0XJR]7ͅZl&.q0BM@͆ 8ؕq= X C2 -CX!U{ 䩾Nf#[kTQW1zaXBt靎d(;&*OT[ۣ3w GxDYQ+Ɉ}06iޱB8T/A@VuO+.3 R׃ݯ!HF%wp\ǃ}bu &k?r]>dPouc%K&Qǔ -Qװm˼#aY\C_͎2fL>_Ȣ+aM'XgcBehWx0Pwx o^r[ 9nbk~vƟGY&l4T$IRuPs@XSz8?Xt1Aͬ0H57ʗ<04y#(c50 &Mqkzr -7GsvýGZC{'~zО;vс  C[!S*:7)D2>_Xjˍ-^7`--#k$t$RŇD:`֡$X, ->œ?o[^@L.?#b 42gyaH[K:7Јh!bdDt6e6]G*p3~R0,Aݕk)sxktmaB 9!}S}j#Rs<@M3^ӟ PIPo( gڷD%^ -Y h -Y:N'>:G76=U8pwzRZ%+-5 @h}w@{μ5V_g@$xLc|/m'7 -B"aԴjqZ)jdߢQw,X;2E!%ޠkx8e) 7>8S -Tj(ee9P))ȟňKzn#XxCLdbx+6wP]2S-sOî%S9q- ^ t}? PcocK큙QDVצ~-z~[4ր$h?w^NW$0.>?Fq/w]{zL"~e?֢|=XϩSe^|h7CfaS6LaA& P33TC1e @cm}JqB-h]:)|g&EmWMMTڡux0^j Sh+z064T"DSGR|4\X\r-bx_9u+Uj0>*W+GLZb:6R y_,,A6BZV5{KMK^@FA#EyQ'Q՘9Ns\ȘF؎=!)K ?/x4AyAIVD^5n@CR6G[84ôԆs=ғ!lNyU,;e\!gQ˂gQx6+,N%ǜ:wsu!iH]7aF<˜۲ M>$,kk6"ZY6;P<' WuTh-BkϨȔؖd|䟖f 9:Ыq{|(AvQ== ~6aꬪQbg, 4X*~KzEj˯l`qz ^4=ګcȌdk"h;vd`ohGY<ʏ g,t|$s B8Ou.*sb}`wY8dPk\y[^Q[Mc*S?NR^/f A=Q5=+ U#-9w SEn#d!An.g?g7cisFZ`h2Րu^p}Ȧn=4)`f,PGA_ f«|K&31D??!h`e.UnP~ '&Bۓ6Rp-Y]0/ - Kl,d0BdƸG-(:\naEԺ_VcKzݳ<[_!`%=ZQ.CCvjšpYkZwnvYp M5vPK ^&5/ľE" ΟlReIsp9]._^҃bu6Yd"g[̌wԫ5R9#_ ܁]aAl -[0QS:IsϠWl3_E✹vM)NawGqJ; 5ڣjUOjjqlke[&SB=]:ͤ?L}IjY;B)L$%ՖRjMxxZmͪP m/)Gu7 C8id Kw5WZ$0b[CՉM5c3v s@i/5P7ഹwOtZfbJU7b߫JabB1.L]1|*"1ozc'*o ߴ(hi%1mfDUJ`UK.R/ԹoMWS6 sH2c*75odHؕScg9o1t$7H`';ZK?xD PiEOm1 4Qd[`:CnΌRђI6 -x-!KUGg7Il%zg}*`@FǘA2 1TiPGq) )`cbKT溶5vYÝ;[6_LKtϜ)SM4pK -58U.x# ]l@l5Gr6`@v#`Ê#%:b1:+BRvW^9=$h?X-i -YޮŒYƔX,ݎGԓ\/݅fQ+PS -Kic|r{]U)T5aLӈ~SHe^~ G?d<וO" f&ˉ֢9VryBGW6O+K -Rٯ(GIܮ: -wmAVFTLue*!8 \p"QEbmT\Zw]m,;Mm\*xHANބk.4e iKŸz5T2IJނ2% sh^ܜe99% =C!z6Z"D! > E'¨ רm'0fQk,5@ҲXeu3d]un\ /EK[tM|呩+#Le^=ኦSrswA ]e!.PPV~=8IV/Qݭ{6x)I|=꒲m|h |f>ޝgf9M*v -B{fKĀ҅V\X/=L$$(&{ڄ=;dэ}\,r1YA欇| j"@{ɩT:Z*}ЮdB*1O 5%:fkϛ}T}^a - Ya5!Hyl)R\H#(J謕c_VvBn|]3xD0Yzw{ ΅ T\݈C6˄@Q8,ܱiAv˂ַն9:X4 8)ހKAKH1[Ny ,&b6r'YꈖIIi^I7R..P"JLv&/%`|*js_uq$K 耔DuFT -q*d-P<+ 䌏t:U \DAa ۪<[ vb2XHD{cYL1,,~zSxU 욹%!seY}$.j/=v jgz4@L -Qѫ^e85 N|ɢNfuPfnNw_p(d߈Pf{3aϟ7((E-Pi9yp/aKtԑT}hfo}if(dtWc;jphB#f?bkaB<Y vfԚ${ɨXU4Qoqi?ԬV -Z52qٌ2ƯV-Vm.f#M#gb~Г@qSB٠ qkH=f:&;py)cH1 hAc6L UdcKr}:&Ys:k:^efƄ;p? x^2}O=V? 6pKer*7S'yc-)X ^\qҀuV![Ԍ ml@Wl@iL:U(r1Yu*K KOH˦GP=Aُp*LW]ވ!] y5c7\ H^+O҈g.~AE"m;"22E7̱,:`C%2&òpv#_>ez -爺E#0ڄ蛁ɇk#(a1QMgɓ,/F: VF VlAgI74@i -wmʚT@R$mn5d8$T=IstA3Y40ZO -ʿ)I- -4͹cT궋VKr )I,g19m|$&0y&$7hrh2vZ_j8! 6_,`b_ 8u#S{ 5{˔;1Fl} 4?G< PBN5>"Y 魵Zoh*N{e=q5苤#T!Ov%?68OMg[ZXl+iY@nƜ),xVP746kHQ,MhlmXŕNVK_3Zog#NJ'PC"Hd F~ZPAYɍ@ahhA^1^q\- FMs5%RÀ)z`]J&' ?18Tz75x㵦E3&:R -i(hqu+G 1h=fA&!An&$C$꺤Y\~k=];& -߂TnE!RKyCl؄x'ͳGN[T尊'ftEBOQi5Ͼq v<Y̯Mag-|)My2ٖ  nP PKѾRfU&^,H# T=Ƥ^FՍуno!* 7 ;t -lkU%&=k5yP+{/Ʊc:D2wqa4ϣǯJE&l";W L]XݔfcYo֥}&?#8Jk}I4f8;k`ȧ|ml -2) kg D"r(%FTtN{uDcs!ײcvQ-!, -u@@.SiBAkwL%6 -;Դɧ"yUˣWk@=°i4UZi&_--RArB@؍Mv\! -<-FJݦq5%Ql1?Ǽ 0*K~`I/"Dv$/y?FMpܒ?W6YH1 -~Rry1CNF5z23弖 -BXPָ:OX?KW ۺ=u`/ڼǂ`>F߱ҕ\!srڛ!kxk3LK -B9M~&W,4\9?cv¢2,RJFȉ~M NTQ][HJQ0eN _KS0DtZʂ35W@F}, Dё-/e'6_ObEu\ ,9 )&y $!E@Zk'H}Ӊt=CIVIfpMdmܔA}LwW@j0kʝ.36,C<1< >)2D9u< E3|puKz.>7o&yey@_%+ɥ(R=eJ 7< %$/#,PJwHyji'hm7ijhW𡩅Yہ.N@DVxʇKd_w͍MպGгiB$B) R'qj/ІzPNU U':%Lb@AtTELխMi<H9ݨgx 'dl2Am7T2-coJ:G?c'L3et& 6'-"mvy0 'AnZ{V޳y-uLmή9>ql>aΟJx Wr{C0ǓKlEv<ٻ3@:ip˹caYŷ{]C{9(IY'rs,Q$^3_3zG-R׷@dGch[] {"}U)_wz"1g<ћ9!( 88!^NhIb R-My ʟo,W|d ěI l=/E \z+TU[Źॴ)iuQnIDώczBCot4*~.P;m_{B4ܿ/GoQxp7<ߗt9e -A^~LySA\.Ęlz׹B8w; }!e :r7Ǥs?k?Z|.q\YfOz`}asMO -߄}Y#wiSKwۚ;&=V#@6B-\3Ҝm_XCu1Q'y}KEOzGky}Nuf%н:^wؖsIj÷&ߡ1^=\] y}ۺp-Nx(>} -y>B0/3vC?w&G~!@CGC*Tt$tS}GBdr冑ޘ64(8ZS2v~d[$}4Mi|hۣ_6P=jّ)Cx$._?;h_([5k0t=s/W/"Y@A(|XDMrfB>hSLۤg/@K,pZoJP+c йW~u|ZdUҘcaUy_b?oэJ&ɼcS!bMR/^%K`ijrT&ܮtF4~, np^%4NϹ%9%p71V^+o 'mD"HT8;ʥ OHHFJ0k.")ewBd7`DdiVUc<"Bl -w)~5z}Q, &+ 1+w[IEQEVI;,i2&͌`gByѐ&E׸qO7kL;x>8mc Lo6k2?zj$V߃3# n4@ⲣShNVIz2nuqʿ$?Bd'5BT© _O(@)gO5K/>s=Ж[X0I[Q[)16^2kC ufwbs+_eGEuPiK7jlR!ojyqKR:>K0C@z+(',v"lr:Xv](W۠b AQf PT=fOWd2q_f]nW3fﮖU˩1rHmAwW<2xzt.Hlx3ՎvB|yc4hTHsYФw63șu}10Xl6b"SKHaK0UZ<T[zؠ%1e%bND -+օ-+ru{BdUE@yZ ,@%QFR+ b1Eݝ:]˽pϜeoiRz1txŚwæ|Շ~a@cNycLmq$a4~;)F4;8Df[>ӝeD -/58ѠIbp!g؎%$}"sѿusWX7r ,kwZι5٭ s8|!,n'*[lS^~Q0a _oAچRpa3 E%:6 ~7Imm<3n6tyTֶh-XXR"M0C<.9aG{pr]hm,Ĝ3W_(Cy9gQXP<]cuhLYJvYt+ʗv0͙v  ::ڑ~ -Ҷ;3ۂ?[rs@VK7O&J,[HI!칤YԖ b{>gr// V?Z=I!p,J<-.g>h>m[wn0wWm -R!u*V;D5sO}d]R_e iMa?ң1֭k䆕mȄn|kn7SWJOwRhZfK40hr!=*sOi[7jcIDwZEۄpۛ_s xg5K3Da+TMkBI{jv GZMŸkɩ0=rW;tX"*%$(=l!ScߊL4PLrJ%@W4uuv[TӒֻkA1D+8Db2-T`5L;̧HCH8rlJSUN֑pJ9{PQb‹&r73 iik  U -TIЦv9lZ7`+ -/SKLMijD Am~..ƛQ%9Bg[|;x<GwE|wf5z_w~!$½`;d 3YV+Ƞvd AEGE7tLp@6H՛w`;r:mN_wA[qF>WyxZ@1PĘVAA+ -k+t}'Dlj4l6۠zbSdjjM4wЇsHCO<0l ڸ؞5!wR盆| -o(i"3su@'YKgK6aM;ԕuԔ:?KEm-mh|!_BXW?'fVLvA ;3+o8XeK}1Flm?.w\ǭ#"E>hm -CJVXI3wg 6JehciNMzާ6P\~\%Q*lw~8O-[$]^JA&9g +qGj -<{֢ -^`ɸ0/EߝQs"m[tfSx - v"RKE^ -w {4ϥtZ'T*A"^o'7S;`XOp{'.ݽ%[tظK\DP#o8t {8M\)`Vvэ A2g w+~8w %+='QQEXNܿne(n3@eviGD>qj)4tHd#2{Ol4e~#=h!w_AwjCgJ=bʁS ='o-M| Jc%ohU1R{g5⽡*)ףց zX^5 ɍ^iRde<EW+ă|LpuDޅ4]~ϑ*r=bU^k>5A.HrKV2I3e x*LΜxv+AKMfLZ>]]@h|*і&DWxWv7Ay d_MwhH9/`(_%:\59C%~IZq7zbTvAΪ#^Lg(&zx@GHDpHrZE:71!W{3EePۘÌ،!GlkDQeNZ/>vD'a+ZƎ}ZFo9?Īsrlc: {~Ӝ|e AIY®`1mPN䨋t#Y/5ݘH7YwSPJOBȓU".K 쮭+^8/4m}}c9G<Ѯbmɷo5,;*[Ƀɕ\ BOA/@hj 'tʂNmv\C^n 3e*&`)U".@p*ٛJ)/MS: G4!rPN&WA~\g7|kr'?Ϯ~ )4m xRoJ{e̳_r0UGDr)BSPԖ['2n(|}qc'=mR!p+UԽȒ/afY -]G4@#0_ǭ1ۭKeJ"~ `9g aT9٤1r -(aI&.!9BK71>ƣTki>%oQ0=ض4:r+m)EKɓ W(VNF[}㭸72d(c{^ɚjxk+-OX`'?(z^_jUK8r""ƻL:a2'x7I¨2EztOQaAdO-q4O=Q8='Y#]e9r9_ r9a>s`;$IMG /r'?߾5Znath=@A2P}M ۤjD]̈&]`-r &XC5 W\i ZP>8ӂ[lɹ!P\f%\(d: e~lˆl+c׺C<:Ey 0Y)8?{QQR4h;^aᙢR!$316\rbQċDd ytQ7m\nDa:5ɦ_6VP(F[.A?I)C0k+0A5^+$A_ܪ-[C$XClVM8K@R(TX:uMJJB]ld= bIo,xF4Wsr0^5q9^5E"Cc("Xo}Zc"&xۢFHOzz.BA pͮ\8vV.UجRZ>6ݴQՂyʖ)͛  Y7KQ[lp|_Oh;-"ŊCO*]EC ~:CϒċrJЊ*4a!D޲¼SXh] ZFjs[Y7v>49z#54}uA'GS#h]ЊF&~DxAcOxxA2da),6^"$CZIAکҜ^"&Y!Mp‚jRfܬ&1L&Y5ΎHu&t ,\,˫˿YU&I7/~9 VC۶Lt'ՖA<[J$$)6_mz.c38v_ ,˞ŲVa%]+{ -XvX:iYM/p9<`"WoꡑiG2"G^`.\ d,*A&)߱3A>Qx6u//<6,R6m#9zs*pJw^ڶxj$5@j\]'7ͅz0 E4%!Q\6u#&ۺ+ܔ)g/`&0~#,Erž%$_*f;ǝO&I(`DDj,C yMQX&Iz!0t˓;&vJ@ST'JmXkĂI-87(ci3i&`&8хAvD0_g-nf9@WhT[3 %,kWo"{+yjO{014b6M'L|s9Qd2pG&̾(u 6pO+xZG2W:fx&<0>TK@C7bE`V5 霔|~p h`%Щ-'N4͇w8xe#_)r iUdFOBތMu S/|Ӹ:OZ0e2hFd? ąb7C-0 hi{ǰ%aWz%ϼ\ހu6ym{'Sȳ=X/;dƀ[2Zȕ-e5U9 `IzRf !9H芣DUt{FiR5%rb]bm.D_n&s6FT 0 G9'rLe*np-,KATu7=֕:H"ښ^!&b wR%BK8LS:% >JnH/ Yv}zF8jNq!<Ʀ]=)-lD_D~JXOaR7{;qg|k|-tmJwarjе _Kpzܿ:J,LE(ˢIgOCGt =5iXcTኇeЁe ˵FjxX .95rOAeŁ^9M!To^q47s")꩏wz\v6ل`~ٷBUWbKk…`\V+.tb-,5 h% }QRΦ@,K~'|evmY%6L͹'"VIpFmTTL[_ҽD=Qw8Jl]tb ]6Xgx@_Fΐ]gO(aK/ Ȓ+HK'#\YPPg7xvxtCs%nh>ų6>3g>^r"x0f4ZH0w/!'n)LLrS[ &;|@z9dXHTdK =r V8(cG;q둧ark$ZZw8*VϑVq8'AX`~F/S\V;*ߪSߞli d+)|t߷ֽӣ)4S]SLtb L 2 \5|IMlf-8T-DKpZf*`g(K :`r4VZkY,Z0{UYFtg?K uz93Zڧ &OcN$\xH֤3|gV} -ٳzTsb mX}ԦsnN,|`-{j,vj]o{z"7J 3(~$ )07ӽ1Kp<tDӔeХŹ?5-fax-] Z&Nʄ`nR@u,ѥjL ̒`&l4cm`bZs5F8RR@u 2ӄ {o`鴦J.>@R]"+lREz9=gfp -ڦK|ycTW损c)`k NB'F4\qSE+ c_8EsZZ聚f -Z : ScՍ`2`T{<xB#`"jH*R/@~iJ%ڽ{p/ݫ.Z]dTx+PS˫> ?n(e`SPnvLP+v0*w6:<jmbٽ9V(P|[&箙E8LYnbZtH]\RY_#j`IE@9^i[w}ЛÖK'0DZ ܹ)3QF|zzF--Jgɦ?弦JܿԔmyӕcLz|rz}D&m|&a`ɶ1%$6*V&)`jq D)k*,s2l6ChkB` lV]\x_-hdX%[Nֹf@ PDc?iVe;+=AYP(ޣAćٗ4(nw2p7Vaa$jM1?Rq`r+t]z"f8IL_ Oũu~5t =|#_i"Ūbcp< @<qCwGD"_d?j[ Ne_?}oz)OpT:?Ode$=u4źCʈ?\kPA8~*|Ͳ1h1[2Lm=;"Ux]Ce"QW2/lA?qҙH׵+(sNt.kAzU4@جPj/>+_>w,՞>O $U!7P}]<ܙD?QJwZU-؅M)#6 -_ tu`#>g{%.E_CD,&A47b,EoB%Id,[AbQ0މ +*Hm h -$B.'GbUQsE[e,[l@%֮'ۗL^j)0lW99)&'T+hC{pld=TM#Β({=%xSCj ./B<ĥ "崆XVA1cΔ(Ul* &F(T!d嘔EtIEN4܄N T>FpS4ɒuU y`@MXKw-Lv0!᳻hHNJ"݋cROEMxvN x"yӮW'8xm{VRj%5uqnp6Ibaʢbx)(ĹzpdXdKؕk':M ;fc2իV$i88 +J*Wb+,*m"ӣa˷=!aw `D+zh!.lث9j%p2ƦN+Kp'B3jDHa,aX33q9X@' `XERٕ*x!*ql}nhG)G kEQ*ɤ*(O.=_  s˩idFgWw@Ӹk.gՁ*z?ᱞIoEբR*3#0.@3J`U1 EQ3ŵ+YSل*_մ5&SN*ʪ -JMGW ش6~^z2fg29"8>dh;>At=\:w?k:%:0LBlOB&3U(0xIW]bt *GyމZG N]P1>Ϲz-G|?ԩMeQahWEM\?lW#R.+h>i:C6@o&5V]4Ԛ5Y?x ocRe$[g)uC˵5K -e{{q-@*2 - Zvf]9oT\٣0{-T&-8o˒g3zQ)?/n*)gd^(mN704vŮ -fXrXT]9hԞOBG8Iwaܚ>[ΰK>kC @ -̗Hk ȯ[.*į;w.11s,UTx2jBq̏śQGe KK 5j(w\_Ú< P'Jv YŽ۔xER=زRxɸ,֎`'Kq};Yda]`akR7 `KoR'͑0PԐoʮE#m\ TuVgm٣7_`w*LCi8:}hܓ(]$6mPB$GJ4 ıO<UͱA XH!d޵ԹbeR4\K߁ޏ`YjT (]$L*܋E2" ේY1Т[+GCDfYQq&5l I76kB f Ul7Qm]8WA(s91=I.NL.R}?†m q؆?Ug]ird_JեIШ[j n)c JIg -Ԟ>ֲQ?޻Q/2ôw4)8<_v6B7{ )IO]tq(Ir7}۱~i?ܦ>:( Bu#h@XO8pK:ƊNEoخr$Kn%SRw@(cܓ3mu<4@wԇ0ZRa&Lu7vre+3\<傶" B6xp׀J bÙ;NB?m^]("-lJ4ͬxT OI!]GG23_\$@C.coD ШhmN€3CEj*=$'.Bn"0 ɕxW0FPs.W5?BR@UXeF0mQ\ 5MGxZTa݃}r ->3+(63xDсd#>aԤiU[[=6Qh3Jҗ5{ Y-//^:Fb#QJ$VKK@e!Q g탪+1cH1c9LkM?f; c`&h#*餏)XH.d S-a{I*@t츎e&1i>= !)< /AЩe'"/@7Q"滨].~.hVegvMXY.$B\5ъU^OS8Ƣ4@$ި;mldUf<)MTxtPkw3܆{(NE5&B5Ş*:==;2}fD>FS=Vb&꺂[3*[ݡ)n)jViI -܅ZӥVEo˩%ٽ^k`}ܣзS5_|8+E'52& Z&gS c/D"Eg*MN<ͨ4d@)iJMܹxhbg"2tExkTy5UB蹙dMFIL幏9l' new ySx)˭"*.+7J:'%DOrכaAUC143 - BIx_c}";f ~bV[c{Υ{ChTj#~S=گ`JdQnXRfrGRؿ`;;ݥytteo͗;GvH{u5[5d(!+t-hPk M6=.j1}0) GIp܁QEαdr$ȶ_+q9X%3%`J0]^ -$2^ݥ])zH -W2-Z~J*=hl#V(yn]d'Iky'D;ᮼ1a;4P\H, k+hX3<#ѭC"V*9= -w5D{qαo ^o@ŔZ)ds^Mli7^کe,ĎwM!*LdP[J@vΕ]fǬq#fCir. .؅Lgj68Jꠇǟ IK:^UZC,TXTYT͜h j@ܭ]uG{|~d-G'We-!]Lj Div+բ.ky|AvzT! ' aSH̽rзAT4 Z#QAT_:#NdFi:&Y#]p󱆎ۂ8U=gj٤:4M$g1smϾywBP /& =Jw%sDNJ MRe3^ -=p07zylh.#Z 9rMQbp;֏cTӆ%]iԨ*S!Ԡݦ͍DB6ˏ]*ju_Z#c LdK"1t 0RΩ=PodCš׹o -Ģ?-o.$WݹBٔTC? M !lsyq>.J/C~%D7zy= -MӲMm[mw -1jHe$&8G 5|.r" y2+ ɬ%>FiW!~csQBabkbG.D%JZ`.ꈯs:ݑLR͵˪$":1}}M>Qtx|BB>GX#04KJ#/g\YR4AmjT? ]~8wDSl2qXX1ut[{S,~X7jo"{ -]֨sd{_ΰ9(),uAS8!z$bIC8Ȥ8֨ffv`WI'l<Ŭ-w|y'==+,:g:j*Ќ4.S[gH??o8Ul`* -_קMV^/M;)ؚH}pBd]IV@/4mh8Co*x1eԺrKْ| -c`9 z!*LISf )tb;(I7]hTY -KuKhќ-wGlSKS٦VMȖYĬ OvlJ+dhs2dW$]ͣ7hBҎFS3!J3op Z878O$uc%"v{` `$6U]FtzlCbV;ūLXc\pd@x8_GHm(,sP)%*S`y@1+AA(뵏k\*V'vWxRRgh ip} -S5O`e!m]\ dD b+,q3Y\3;ҦfQT2M|E5vF`cg$,:/%Z7l -\R?ƾ ٚJM#\'H,-ϫi#tYcffiPiAMz_iz'9f]yiUKwlg(o;"X!n0Tw$BS!LҀ,@^O%G *[᝖g4vF{7ɕm4/p2)-af1٬Qt2<ܼW9UMx_f7Mli̧f\E*ٴaf|ݨm\$=iܰn5W3ԌZz|Dr{+[pʉ -Fʏ1d/ ( 蝞OhVۗoaI]Xgyv0d+XuU?HREE;AodMeA^o$cpO8cn<>,4`ϝSH$5fzzDᅩh9|GM -AL#vTr)33pּ[|l0^] eLcyiz(_l(XDO!IF䞟xo{n@TQjgܟ1dً>5?K2‚1)V>bUPa,6KCxJ)?/L-fzt hS WEY)mv>*D h~*tW&⿘LFxи~rj|!=[_w/yO!FouGCj{ WA9 L2MOG;YZ|΋v(\g+ Si.ULyUMy%]c#Vp^|92/d*$/,3i;!b z8,9GP)#gG341aͧ%NJD_eȃ)5ћPڔ@o`Nf2%@Vc6`:HǠjg譲ua^@ov/^\q"ҞI{.$ǎcpbi LG'z*ws۩Y -捒l/g. " &<3 6ml:9MeqXncRkxa=|-ҸkB&G5TˉMpg:JbkIJ5v/ل3?ة'h{4'BoUe(Y ?u#9iᏀؽgiz~7nʹ3N`i~+jFщG4e tCoq\pKOZed  9M"靉IVJY@4<{Tn!6'@ -,},+X6b_Uy$%YЖ,ŲiHC)-1T  \L>_ΔAsy&~^_&Ok+O4Ĩє$ oU³VVR*"0E$WG2'"RIy\ےSL'<Nj z||I\ ~Ra3@G !a7A4ҥ(;~ vcS3#JEKZe2l -QNa"@[ &PрgrwԤeP -IZH( ^h0CN*Lo0 0s*fAHЙ],.fY}{&Ag5{1-~v ;_&FP5Ƭ.uɯWr|f&2Hud8 y+/WiY,![wYϻGpzFƹ@cf`25=S,0Wƕvrߞ|ղQqJ&& OF8eQFǴp`j& Uqp3!Z?sYM."'J-w3>J#Am0/9Q#\!C@RV5G`%?Q~9*B-`Zm|SuP:kLI弳Q?I)Y0pT@e: - :TV68QnN*rIj:ÓX{6JiH0-&i[yez4IM=ek0T,"*~0VN^BNσyx -꼑EKhj6S WűI`Vh"J;DG - jˑƁ}@Rt aA}l-` >b IR)`3+Tw7RP۠bxVEH0tܭ!hqgg(,Z O(5-]0pบ_(?]{ S/nT a{p-VR) { -73d*ntU,?j:"wy"DBhTSY5}BJz? L!\<)*>XtWtKyB\|B!nHJ7cca*TCz{Ҟ `v: "ML"Y?K@~g8%>  -EM{X|7d)l(A#1߄/gM({Hlm$]X~QoQ4 Z_ -rY<`0{4%;jHj]03;+?/C +Q!> yQP銊Wam~Ikåi~V,.`գ_Zb$qdONP 6KUoahTqW\J1OKqxH`]gli^sl62+D,JgsPD(M# f:tT^rP|6c`In,HB E{Jgy%`JM{Ղ[Bd R't̷:C -LheXYHh#bn5Q|s5]5Dp>@ m -L+u"|H9^nhzy7;Z: /Sm haNo%ۧ枉*ӔrT=Uw`l2ϻiSKuFb㈀竌S祈`mUtƖ{Ϟ(]FcּlO`="\Cb'!ADO-%5AF&5@ѺSqGjj]uR0˲WT xWKJ(&~2TvkG V[RJżjPXzݩ/B^k4=n뮤RkAƴ^_(p"⭄?r c7_A"[C ETgbp[4JU@JI7 >R`!@.v8*(kV`4sIy=)z;,6[h[)XC0(ђaQيRVz3#SϊXGPCU Α%\udnm0Cv =+tY>*3U;g^~;{G* G* I<;Q=W_T7Ly83X3vC'CZpVPk'b+:(~|9#>o_=`s`6=gHu. ޏDOq::%0ZR>.NS֐v!@HHK -0YncDĽSSU -?믯_ㅿ}Alߟ/ekDڻ)Țy;7si" *rX"]3+rJPڊv|;r_w -Pz'ԌfgP}.6[((?/^xcC[Pg)zlaGC$סV"$9jR{dDL[Lt8%}MHz n"T3UTY=Ʒ YMˡo?['z%RWr>3Od+ h֏g#X@Jcl ɯELy:=Gf-[0i#œPO$Ys(PGņCAIӈ@і:rseV!c<Db&rhou 3)H@F -I֣02Y,ҽ<ʩ!7=VOJxgDg\nNsbuL/l];&DP1o{"n}Ș݀63=_ -fF78l܃4睈Z~Znmdߚ][ĩ&p"\CmB DM} ;[:DZUZƝ+d癝+ `^JvuAD)MfآlΦ+ItfmoD>VΤW!D*^2ܰ%BÁ(ORk%5cdwAtPfwj^\7'o1v C:@ 29IѮQmyb~3ϼ |ui^Iy:2X~g3:N5K3pNɇkLoG{$pFgS;e9vpNM']#^h7HqQЅO(BXkB}UE:;ϼ.5W@~db5yxSM@ijsSUeE}# 8r\vdc BABfKI+M1ohy Qo }ěZy `Z2eG(xSi>AǑ=hX;jD8G![C 6""w&rG9EC_U09^[&fmߟ/RFԆZ-2NDi$H9J͉҆A !AePJ +RXzbK6 -Az hWL- q(SQb"[8>&ң8RnQ;_Jf)|n8YJ3c::BEQ"/Js)6Z-eMVU ? [@Q?]-:p~VQWI ,㭡VMj!®;))]sSJwd?\Mؕd}kJ<=piD.-+P90{-~jEOo<h hҌ'j+qbhVCU8v !wITlLvJ+(ʲP|lp -Ƙ`q|w n}\ل?-@wUhnBLP^Ɲ~0ae9@FܝY aMBT,6 mXتJĻjWtYjb8^%/H[4fPh6/*}rY;4"`ccMV۸WBjyl&J~Ɛ7H6V ѓU`ӾRsJaG{R?ǭѲ 4|Uy*\2-$ QR/^#Up.FvX[);.SOZAhF W+g(@OХ%{J FüQL wׅ<[&6}Ƃ'L5hpv4\njxq6PFIl}]bi۸W@mO[%1܍$ ɪ0]~ۿm{ -FC/؟ޖeftbR,!T;"LG$"DՀHE{ʑBmg -{tNWfoa/u[Nsa⟱vCΨg_'$ uq~x&, >1I$D+^THeoOB!QhT5\j0"Egͱ(F=yHO0Z ¾0Ҥ:سm -q*5[ug×(fN㠊]wnJaAj3f~7pg~8 <"Wg('g*>F='^scӲ1DMw$: *ȔiY15>Κ{Xc}jvj/+adqNtSN^*d*x,<ſ[6Xgp:vL˜DׇpK+Oǫg\b:lʉrS j".9oaI 5d%'i'uNpB޾r6>ZzDu=i;ⴏlGi836n}ޡlMKwO>lzq x5;uLDĽ>qT*ȏ~_}~쟏{He ;p ->1BGT;)6WbڇJrմk7 8,\08Bm[.@OL ywׅ<[&ȏ6 n$U#jPRk -0Z:Ku@ߎir{rr**|{Ǿ!Lv?\C "ï= i2)\OkVY_#D~KCdnG≮ g=؂kEy{ -iE# Pv\(ljk;eT$b#7ЬZFU`-hgGU@4rϳ;|vs+bUan}-НbI 4*J.txBM&VXu˕6ꦃ~a뢂SŻw4f9qo4:γռ)y n'VNmCUa&nRs&jjh`ۛJ 'qFK!R;,G$@/O0mI={:$>Wh :Wѵdf82-8Z;v }f3ug؀BY=54d, 6'BXx383!͖>Q6՚q@d#tẖOq&- O=Ơ@@`raI - _)@,oկc!-itm. ,Hh|^:<}|K':!yqf7}a7TZ1&|D++Mz>!D5,#ie#B@̭RDGF<͊y B'n`[A߱z+a}|&RlUJ Gon98.M~q:.$U[ -O<u*Ag0$j֓8~<] I㋷2RdT&8y=1 ?jAwxc=Yao,X͕~M>PN'9= 4EsLTQ 화 V/Lbո'{< -Nb"Y;%}1k^P,4sQ)0GӹRs~29._* zuS 9w7ɂݬW-,-0{L=Xg=Klz"wd\Zr|=T&269;3˗"'m,6Ϡ{YуEyщnv8rye‚%=վ-z Bo^Vn̊qէXqђuDA鱑.B!JkؗgrϛCE.ψwuǪIv1h&i+wՠu -T"-w"K -sqʝ=rIC4!Xz47=f GH**Gx\l(7&ͥM2l -!0ҹe9gCGݜ<],!3MՂAa}BϘXd-x(, -kg4Mʍذ}:8}LO?()BCfL{+ߘRa?ȵ1J 25~f='Gا0C/wHNG@X&8~5&1䲦>箅f~C4,9kl=7WhfdsgxW?.;\jrqR*]5y ; -_2osZ9 61fe;_00{&!\FbAU N<2(vEs#dt'A/@v^7y,|HDLM|%Yޤb/(VÛBn]2PZq^ -hV2֋{}R*r2:RiDUĕS\GA!y[Z%EK7P D&n M+nv[N\@w%[`_ѓ`Twiĩn0bh*(]u⒧<£* Q,(OZoDV 5iģA$(#J(  ʯ~D+5 c|\HKrqU9x0lz86s "A\BHd_jWB;LRVX|r|ё~aKYE^2KMefn_L. rWQ|swt!1copG*@G;N{p_tųrfcV,|<ʏ=UAӺYh[EdyB>n-[d4]$Cԕ -/ 4zBk?#zjUV{;m֔3mLq}" C5CV(ngQ*ef -DH%*U,=b"tݑ LҤ^'B<V9R@Gb3Xd(DSB+tYT8'eil,/mګ08+ax,=[A w|&N -SȐ<)V -/G6Sxl |hLyͷ6qFܨjC/bwHَG`XSoo%10$FFٹ -D<Ai|%Ydb/(RÛBrf]Ji\({UX1?vC[ǯǟ|'? endstream endobj 145 0 obj <>stream -8;X.,0p7/C$q5+"MNcCpWkAER/f7[#"cYYZ)-pn:0*se2ui>AM]T:k!)&1lBuPV%/.$$HW/J7VRPpAe;a'n>(!c? -Nf3J?hkD$DmFA&b(8R.kdrt8.PN&$ZH54=c25]d#2nUd0q/:FoqV>QJb"8KNdI^Xi -DMDGC^6?aI2>f@UgM^#M8T4AEhYMY3^RXnZha^_dZK$/DTj2c1TYB8;SMHVAs6d?j -\7GAoGd6.m]-Z"od2p!Ql4(eIG2@/,E'f<:#[u3Mq4orRh/g2.V"a?t60e-fo1HLJ -B]?Y'k/Q_)6hsM:G+V:f]._%m074hu]m^1dQarTY~> endstream endobj 146 0 obj [/Indexed/DeviceRGB 255 147 0 R] endobj 147 0 obj <>stream -8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 -b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` -E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn -6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( -l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 139 0 obj <> endobj 148 0 obj [/View/Design] endobj 149 0 obj <>>> endobj 144 0 obj <> endobj 143 0 obj [/ICCBased 150 0 R] endobj 150 0 obj <>stream -HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  - 2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 -V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= -x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- -ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 -N')].uJr - wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 -n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! -zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km endstream endobj 142 0 obj <> endobj 151 0 obj <> endobj 152 0 obj <>stream -%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 16.0 %%AI8_CreatorVersion: 16.0.4 %%For: (Sindre Sorhus) () %%Title: (logo.ai) %%CreationDate: 10/11/13 13:32 %%Canvassize: 16383 %%BoundingBox: -90 -192 410 148 %%HiResBoundingBox: -90 -191.8975 410 147.8672 %%DocumentProcessColors: Cyan Magenta Yellow %AI5_FileFormat 12.0 %AI12_BuildNumber: 691 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%RGBProcessColor: 0 0 0 ([Registration]) %AI3_Cropmarks: -90 -191.8975 410 38.1025 %AI3_TemplateBox: 200.5 -75.5 200.5 -75.5 %AI3_TileBox: -236 -382.8975 556 229.1025 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 6 %AI9_ColorModel: 1 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI9_OpenToView: -124.7246 166.9214 1.7753 1448 863 18 0 0 -4 37 0 0 0 1 1 0 1 1 0 1 %AI5_OpenViewLayers: 7 %%PageOrigin:-200 -375 %AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 153 0 obj <>stream -%%BoundingBox: -90 -192 410 148 %%HiResBoundingBox: -90 -191.8975 410 147.8672 %AI7_Thumbnail: 128 88 8 %%BeginData: 14094 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FDFCFFFD36FFCACAFFAEAEFFFFA8FFFFFFCFCFCFFFAFA9A9FFFFFF %A8FFFFFFA8FD64FFCAC39ABCA1AE83FFAE8383FFFFC99FCFFFAF3685FFFF %A8A2A8CBA2A8FD64FFCA9ACACAFFA8AEFFFF83AEFFFFC9CEC9FFA98584FF %FFFFA2CBA2CBFD65FFA1C3CAFFFFA883FFFF8383FFCFC9A6C9FFAF5A85FF %FFA8A8A2A2A8FD64FFCAC3C3FFFFFFA8A8A8FF83AEFFFFC8C9C8FFAF8484 %FFFFFFA2CBA8FD65FFCA9ACAFFFFFFAE838383A883FFA7C8C8C8C9FF5A84 %FFFFA8A8A2CBFD65FFCAC3CAFFFFFFA8A8A8AE83AEFFCFC8C9C8CFAF8584 %FFFFFFA2CBA2FD66FF9AC4FFFFFFAE83FFAE8383FFC8C9C9C8C8FF5A85FF %FFCBA8A2A8A2FD65FFC39ACACAFFA8AEFFFF83AECFC8C9FFC9C9A88584FF %AFFFA2CBA8CBCBFD64FFCAC39ABDC4AE83FFCF8383CFC7CFFFCFC7A85A7E %5A84A8C4A8FFA2A8FD65FFCACAC3FFA8AEFFFF84AFCFCECFFFCFCEA88584 %8584FFA8FFFFFFA8FD64FF8460608B608460856084608560846085608460 %8B6084608B60846084A8FD63FFAF6085608B6085608B6084608B6084608B %6084608B6084608B608460AFFD63FFAFFFFFFFA8FFFFFFA8FFFFFFA8FFFF %FFA8FFFFFFA8FFFFFFA8FFFFFFAFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFD %FCFFFD56FFCBCAC3CAC3CACAFD07FFA8FFAEAEA8AEA8FD09FFA8AEA8AEA8 %FFA8FD0DFFCFCFC9CFC9CFC9FD0DFFFD04A984AF85FD0FFFCBCBA8CBA8CB %A8FD09FFA8CBA8CBA8CBA8FD0BFFCAA1CACACAA1FFA1C3A1C3C3FFFFFFAE %AEA8AFA8A8A8AEA8FD08FFAEA8AEFFFFA8FFA8FD0CFFC9CACFC9C9A6CEC9 %FD0CFF857EA9A9A984A97EFD0DFFA8CBA8CBA8CBA2A8A8FD06FFCBA8CBA8 %CAA2CBA8CBA8FD09FFCAC3FFCACACAC3A1CAC3CAC3C3CAFFFFFFA8AE83AE %A8A8A8FD09FFA8FFA8FFFFAEA8FD0DFFC9CFC8CFC9C8C9CFFD0CFF84FF5A %A9846084A9FD0EFFA8FFA8CBA2CBA8FD07FFA8CBA2CBA2A8A2FFA8FD09FF %C3A1C3A1FFA1C3A8C3A1CA9ACAA1CAFFFFA8A883A883A8A8AEA8FD07FFA8 %AE83AEA883A8FFA8FD0BFFA7CFC9C9A6CEC9C9A7FD0BFFA8A9A9855A847E %857EFD0DFFA8A8A2CBA2A8A2CBA8FD05FFA2CBFD05A2CBA8CBFD08FFFD05 %CAA1CAC3C3CACAC3CAC3CAFD04FFA8AE83AE83AEA8FD09FFA8FF83AEA8AE %AEFD0CFFCFCFCEC9CFC8CEC9CFCFFD0BFFA9A95AA95A85AFA9FD0EFFA8CB %A8CBA2CBA8FD05FFA8FFA8CBA2CBA8CBA8CBFD08FFCACACA9AC3CAC39ACA %A1C3A8CA9AC3A8FFFFFFA88383A883AE8383A8FD07FFAEAEA8FF83AEA8AE %A8FD0BFFC9FFCAC9A6CFC8C9C9CFFD0AFFA9A9A95A5A855A8584FD0DFFA8 %CBFFCBA2CBA8CBA8FFFFFFCBCAFD05A2FD04A8FD07FFCAC3CAC3CAA1C3CA %CA9ACACAC3C3FFC3FD05FF83AE83AE83AEAEFD09FFA8AE83FF83AEAEAEFD %0BFFCFCACECFCFC8CFC9CEC9FD0BFF84FFA9845A858485AFFD0DFFA2CBFF %FFA8FFA8FD04FFCBCBCAA2CBA2A8A2CBCBFD08FFA1C39AC39ACAA1C3A1CA %9ACAA1C3A8CAFD04FFA8A8A88383A883AEA8FD07FFAEAEA8AE83AE83AEA8 %FD0AFFCFC9FFA8C9C9CFA6CEC9C9CFFD09FFAFA9845A84845AA97EFD0DFF %A8FFA8A2A8CBA2CBA8FFFFCBA2A8FD05A2CBA2FD08FFCACAC3C4C3C39ACA %C3C3C3CACACAC3CACAFD05FF83AEA8AE83AEA8FD09FFA8AEA8FF83AEFFAE %FD0AFFCFCFC9CFCFCEC9CFC8CFC9FD0BFF84FF7E8484A97E85FD0EFFA8FF %A8CBCBFFA8FFFFFFA8CBA2CBA2CBA2CBA8FD08FFCACACAC3A1C39AC39ACA %A1FD04FFCAA1FD05FFA8AE83A8A8A883FFA8FD08FFAEA88383AE83AEA8FD %0AFFCFCACFA6CECFC9C9CFC9CFC9FD09FFAF858485845A7EAF7EFD0DFFA8 %CBA2CBA2A2A8CBA8FFA8CBA2A8A2A2A2CBA8CBFD08FFCAC3CAC3C3A1FD04 %C3FD0DFFA8FFA8AEAEAEA8FD09FFA8AEA8A8A8AEA8FD0BFFC9FFC9FFC9CE %CFCEC8CFCFCFFD0AFF84A95A85845A84A9FD0EFFA8CBA2CBA2CBA8FFA8FF %A8A2A2CBA2CBA8CBFD09FFA1FFA1C3A1C39AC3A1FD0DFFA8AE83AEA8A8A8 %AEA8FD07FFA8AE83A8A8A883AEA8FD09FFCAC9A8CFC9CFA7C8C9CFA6CFC9 %FD09FFA8A9A87E5A845A857EFD0DFFA8A8A8CBA2CBA8CBA8CBA8A8FD04A2 %A8CBA8FD08FFCACAC3CACAC3C3CAC3FD0FFFAEFF83FFAEAEA8FD09FFA8FF %83AEA8A883FD0BFFCACFCFCFC8CFCFC9C9CFC9CFFD0AFFA9AF5AA97E85A9 %A9FD0EFFA2CBCBFFA2FFA8CBA8CBA8CBA2CBA8CBCBFD09FFCACACA9ACAA1 %C3A1CAFD0EFFA8AEAEFF83AEFFAEA8FD07FFAEAE83A88383A8AEA8FD09FF %CACFC9C9C9CFA6CFCFC9A6FFC9CFFD08FFA9A9A8845A855A8584FD0DFFA8 %CBA2CACBFFA2CBA8CBA2CBA2A2A2CBA8FD0AFFC3CAC3CAA1C3CACACAFD0F %FFA8AEA8FF83AEAEFD09FFA8FF83A883AEAEAEFD09FFCFCFCEC9C9CFCFC8 %CEFFCFC9CFCFFD09FF84A97E855A85A9A9AFFD0DFFCBCBA8CBCBFFA8FFA8 %CBA2CBA2CBA8FD0AFFCACAA8C39ACA9ACAA8FD0FFFA8A8A8AEA8FFA8AEA8 %FD07FFAEAE83A8838383AEA8FD09FFA7CFC8C9A7C9CAFFA7C9CACFA6CEFD %08FFAF857E5A5A855A857EFD0DFFA8CBA8CBA8A2A8FFA2A2A2A8A2CBA2CB %FD0AFFFD04CAC3A1CACACAFD10FFA8AEAEFFA8FFAEFD09FFA8FF83A883AE %AEAEFD08FFCFCFC9C9C8CFC9CFCFFFCACEC9FFC9FD09FF84A984855AA984 %85FD0EFFCBFFA8CBA8CBA8FFA2CBA2CBCBCBFD0BFFCACAA8C3A1C39ACACA %FD0FFFA8FFA883AEFFA8FFA8FD08FFAE83AE838383AEA8FD08FFCFC9CEC8 %CEA6CFCACEC9CECAC9C9CFCFFD08FF857E8584845AAF84FD0DFFA8CBA8FF %A2A8A2A2A2CBA2A2A8CBCBFD0BFFCACACAA1FD04C3FD11FFA8AEA8AEA8FF %A8FD09FFA8AE83AE83A8A8FD09FFCACFC9CEC9CFC9CEC9CEC8CFCFCEC9FD %09FFA9FF7E85848584A9FD0EFFA8FFCBFFA8CBA8CBA2CBA8CBA8FD0CFFA1 %CAA1C3A1C3A1CAA8FD0FFFA8AE83FD04A8AEA8FD07FFAEAE83A883A883AE %A8FD08FFCFC9C8A7CEC9FFA6CFCFC9A6CFC9CFA7FD07FFA8A984FF845A5A %A984FD0DFFA8CBA8CBA8CBA2A8A8A8A2CBA8FD0DFFCACAC3C3CAC3CAC3FD %11FFA8FF83AEAEAEA8AEAEFFA8FFAEAEA8AEA8FF83FFA8AEAEFD09FFC9CF %C9CEFD04CFC9FFFFCFC9FFCFCFFD08FF85A97EFF848484A9FD0DFFCBCBFF %CBFFA2CBCBCBA2FFA8FD0EFFA1CAA1C3A1C3A1CACAFD0FFFA8AE83AE8383 %A8FFA8AEAEAEA8FFA8AEA8FFA8AE83FFA8A8A8FD07FFCACFC9C9C9CEC9CF %C9CFCAC9CACFC8CFC9FD07FFAFA9A8845A8584857EFD0DFFA8CBFFCBA2CB %A2CBCBCBA2CBFD0EFFCAA1C4C3C3A1CACAFD11FFA8FF83AE8384A8AE83FD %04AEFFA8FFFFAEA8FF83AEAEAEFD07FFCFC9CFC8C9C9FFCAFFC9FFCFC9CA %CFC9CFCFFD07FF84A97E855A85A985FD0EFFA8FFCBCBCBFFA8CBCBCBA8FD %0EFFA2FFA1C3A1C3A1CAFD10FFA8AEA8AE83A8838383AE83A8A884A8FF83 %A8AEA8A8FF83AEA8FD07FFC9C9A6CFC8C8A8CFFFCFA7CFC9C8A7FFC9CFFD %06FFA985845A5AA95A8584FD0DFFA8CBA2CBA8CBA2CBA8A8A2CBA2FD0DFF %CACACAC3C3C3CACAFD11FFA8AE83AE83AEA88483FF84AEFD04FFA8AEFFAE %83FD0AFFCFCFCEC8CFC9CFCFFFFFCFC9CFC9CEC9CFCAFD07FF84FF84857E %AF8485FD0EFFCBFFA8FFCBFFA2FFFFCBA2FFA8FD0CFFC3CA9ACAA1C3A8CA %FD10FFAEAEA8A883A883AEA88383AEA8A8FFFF83FFA8AEAEAE83FFA8FD07 %FFC9C9C9CEC8CFCACFFFFFC9CFC8C9CACEC9CFFD07FFA9FD04845AAF84FD %0DFFA8CBCBCBA2CBA8CBA2CBA8A2A2CBCBFD0BFFCACACA9AFD04CAFD11FF %A8AE83AEA8FF83AEAEAE83FD04AEFF83FFAEAEAEFFA8AEFD06FFCACFC9C8 %C9CFC8CEC9CFC9CFCACFC9CECAFFC9FD07FFA9FF5A85A8A984A9FD0DFFCB %A8CBCBFFA8CBA8CBA2CBCBCBA2CBFD0BFFA1C3A1CA9ACAA8CAFD10FFA8AE %838483A883AE83AEA8AE83AE8383A8AE83AEA8A8A8FFA8FD06FFCFA7C9C9 %C8A6CEC8C9A7C9C9C9A7CFC8C8A8CFCAFD05FFA8A9FD04847EFF7EFD0DFF %A8CBA8A2A8CBA2CBCBCBA8CBA2FFA2FD0BFFCACAC3C3FFC3CACAFD11FFA8 %AEA8AE83AEA8AEAEAEA8FFA8AEA8AEAEFF83FFFFAEA8FD07FFC9FFC9CEC9 %CEC8CFC8CECFCEC8CEC9CEC9CEC9CFFD06FFA9AF5AA9FF8584A9FD0EFFA8 %FFA8CBCBFFCBCBA8FFA8CBA8FFA8FD0AFFA1CACAC3A1FFCACAFD10FFA8AE %A88383AE83AEA8FD08FFAE83FF83AEA8FFA8FD06FFCFC9CFC9C8A6CEC8CE %A6C9C9C9A6C9C8CEC9CFC9FD05FFA9A9A8845AA9AFA97EFD0DFFA8FFA8CB %A8CBA8FFA8CBA8CBA8A8A2CBCBFD09FFCAA1C3CAC3A1FFCAFD11FFA8AEA8 %AEA8AEA8FD09FFA8AE83AEA8AEAEAEFD06FFC9CFC8CFC9C9C9CFC8CFC9C9 %C9CEC8CEC9CECACFFD06FF84AF84AF7E85A9A9AFFD0DFFA8CBA8FFFFCBA8 %CBA8CBA8FFA8CBA8CBFD09FFA1CAA1C3A8C4A1CACAFD0FFFA8AEA8A8A8AE %83AEA8FD08FFAEA8AE83AEA8AEA8FD05FFA8CEC9CFA6C9C9C8A6CEC8C9A6 %C8C9C9A6C9C8CFA7FD05FFAF85848584A97E8584FD0DFFA8CBA2CBA8FFCB %CBA2FFA8A8A2CBA8CBA2FD09FFCAA1FFCAC3CAFFCAFD11FFA8FFA8AEA8FF %A8AFFD08FFA8AEA8AE83AEAFAEFD05FFCFCFCEC8CFC8C9C9CEC9CFC8CEC9 %CEC8CEC8C9C9CFCFFD05FF84AF5AA984AFAFA9FD0EFFCBCBA2FFA8CBA8CB %CBFFA8CBA8CBA8FFA8FD08FFCAC39ACACAC3A1FFCAFD0FFFA8AE83AEA883 %A8FFA8FD08FFAE838383AE83AEA8FD05FFC9CECAC9A6CEFD06C9A6CEC9C9 %A6CEC8C8C9CFFD05FFA9A8A95A8584FF84FD0DFFA8CBA8CAA2CBA2A8A8CB %A2CBA8CBA2A8A8CBA8FD08FFC3FF9BC3CACAC3CAFD10FFA8FF83AEA8AEA8 %FD09FFA8AEA8AE83AEAEFD06FFCFC9C9C9CEC8CFC9FD04CFFFCACFCFCEC8 %CEC9CEC9FD05FFA9A95AAFAFA9A9A9FD0DFFCBA8CBA8CBA2CBA8FFCBCBA8 %CBA8CBA8CBCBCBFD08FFCAA1CAA1C3CACAA1FD0FFFA8AEA8FFA8A8A8AEA8 %FD07FFA8AEFD0583AEA8FD05FFC9CFA6C8C9C9A6CFFD06FFA7CEC8C9A6C9 %C9CFFD04FFA8A9A8845AAF84857EFD0DFFA8FFA8CBA8A8A2CBA8FFA8CBA2 %CBA8CBA2CBA8FD08FFCAC3A1CAC3C3CAFFC4FD0FFFAEAE83FFAEAEA8FD09 %FFAEAE83AEA8A8A8FD05FFCFCFC9CEC9C9C9CFCFFD06FFCFC9C9C9CFC8CF %CAFD05FF85AFA9AF5A85A9A9FD0EFFA8CBFFFFA8CBA8FFFFFFA8FFCBFFCB %CBA2FFA8FD08FFA1CA9ACAC3C3CAFFA1FD0DFFA8AEA8AEA8FFAEAEA8FD08 %FFAE83A883A883AEA8FD04FFCFC9C9A6C9C9C9A7FD07FFCACFC9C9A6CEC8 %C9CAFFFFFFA9A9A85AA8AF5A8584FD0DFFA8CBA8A8CBFFA8CBA8FFFFCBCB %FFA2FFA8A8A8CBA8FD07FFCACACA9ACACAC3CACACAFD04FFCAA1CAFD06FF %A8AEAEFF83FFAEAEFD08FFA8AE83AE83AEAEFD05FFC9CFC8C9C8C9C9CFFD %08FFC9CEC9CEC8CEC9CFFD04FF84FFA984A8AF8485FD0EFFCBFFA8CBCBFF %A8FFFFFFCBCBFFCBA2FFCBCBA8CBFD07FFA8C3A1CA9ACACAC3A1CAA1CAA8 %CA9AFFA1CAFD04FFFD04A883AE8384A8FD07FFAEA883AE83A883AEA8FFFF %FFCFCFA7CEC8C8A6C9C9FD08FFCEA7C8C9CEA6CFC9FFFFFFAFA98484A8A9 %5AFF84AFA8FFA9FFA8FFA8AFA8FFFFFFA8CBA2CBA8CBA8CBA8FFFFFFA2CB %A8CBA2CBA2CBA2CBFD07FFC3C3C3FFC3C3CACAC3FD04CAFFA1CACAFD05FF %83AEAEAE83FFA8FD09FFA8AEA8AE83AEAEAEFD04FFC9CFC8CEC8CEC9CFFD %08FFC9CFCFC9C9CEC9CFFD04FF84FF8485AFFF84AF84A984A984A9848584 %8584FFFFFFA8FFA8FFCBFFA8FD05FFA8CBA8FFA2CBA8FFA8FD08FFA1C39A %CAA1C3CACA9AFD05CAA1CACAFFFFFFA8AE8384A8A883AEA8FD08FFAEA8A8 %83A883AEA8FFFFFFCAC9C9CEC8C9A6C9CFFD08FFCFC9CECAC9A6CFC9CFFF %FFFFA98485A88484FFA8A9FFA984A97EA9A8AFA8A9AFFFA8CBA8FFA2CBFF %CBA8FD04FFCBA8A8A8CBA2A8A8CBA8FD07FFCACACAA1CAC3C3CAFFC3CAFF %CAC3CAC3CAFD04FFA8AE83AEA8AEA8FD09FFA8AEA8AE83AEA8FD04FFCFCA %C9C9CFC8CEC9FD09FFCFCFC9CECFCEC9CFCFFFFFFF84AF5A85A98484FF84 %A9A9857EA9848584FF84FFFFFFA8CBA8CBA8FFA8FD05FFFD04CBA2FFA8A8 %A8CBFD07FFFD04CA9ACAA1C3A1FFA1C3A8C39BFFA1CAFFFFA8AE83A88383 %83AEA8FD07FFA8AE838383AE83A8A8FFFFFFA7CFC9C8A6C9C9CECAFD09FF %C9CFA6C9C9CEA7CFFFFFA88584A95A84A8AF5AAF7E85A8845AAFA8848485 %A8FFA8CBFD04A8A2CBA8FD05FFA2CBA2A8A2CBA2A2A2FD09FFC3C3CAC3CA %CAC3C3FFC4C3CACAC3CACAFFFFFFAEAE83AEA8AEA8FD09FFA8FFA8AEA8AE %83FD04FFCFC9C9C9CEC8CFC9FD0AFFCEC8CFCFC9C9FFC9FFFFFFA9A95AFF %A985A9855AAFA885A9855AAFFFAF84FFFFFFA8CBA2CBA8FFCBFD07FFA8CB %A8CBA2CBA8CBA8FD08FFCAC3A1CAA1C3A8CAA1FFA1C3CAC3A1FFFFFFA8AE %83A883A883A8A8FD07FFAEAEA8FF838383AEA8FFFFCFC9CEC8C8C9CEC8CF %FD0AFFC9C9A6CEC9C8C9CFFFFFA9A9A85A5AFF845A84855AA9848484FF7E %85FFA9A9FFA8A8A2A8A2A2A8CBA8FD06FFCBA2A8A2CBA2A8A2CBA8FD09FF %CAC3CAC3C3CACAC3FFC3CACAFD05FFA8FF83AE83AE83FD09FFA8AE83AE83 %AEA8AEFFFFCFCFC9CFC9C9C9CFCFFD0AFFCFC9CFC8CECACEC9FFFFFF84A9 %A9A95AAF848584AF5AA9A985A9FF84AF84FFFFFFA2CAA2CBA8FFA8FD07FF %CBCBCACBA8CBA2CBCBCBFD0BFFA1CAA1CAA1C3A1CAA8FD05FFAEA883AE83 %A883A8A8FD08FFAE83A8838483AEA8FFFFFFC9CFA6CEC9C9A7FD0BFFCAC9 %C9C9A6C9C9C9CAFFFFA95A8584845A857E847E857E857E847E857EA9FFFF %A8CBA8A8A2CBA8A8A8FD07FFA8CBA8A8A2CAA2A8A8FD36FFCFFFCFFFCFFD %0FFFCFFFCFFDB5FFAFAF84AFAFAFA8FFAFAF84AFAFAFA9AF84AFA8AF84AF %A8AFAFFFA8AFAFAFA8FFAFAF84AFAFAF84AFAFAFA8FFAFAF84AFAFAFA8AF %84AFA8AF84AFA8AFAFFF84AFAFAFA8FFAFAF84AFAFAF84AFAFAFA9FFA9AF %84AFAFAFA8AF84AFA8AF84AFA8AFAFFF84AFAFAFA8FFAFAF84AFAFAF84FD %04AFFF84AF84AFAFAFA8AF84AFAF848B848B848B84AF608B848484AF84AF %84AF606060AF848484AF60FD04848B84AF848B608460AF848584AF608B84 %8484AF84AF84AF606060AF848484AF60858484848584AF848B608484AF84 %85848B60AF8460848B84AF848B606084AF8484848B608BFD0584AF848B60 %8484AF848B848560AF8460848B84AF84AF8484AFFFAF60AF848B848B60AF %848B848B60AF848B848B84AF608BAF8B60AF848B848B60AF848BAF8B84AF %608B848B60AF848B848B60AF848B848B84AF608BAF8B60FF848B848B84AF %848B848B84AF608B848B84AF848B848B60AF848B848B84AF608BAF8B84FF %848B848B84AF848B848B84AF608B848B84AF848B848B84AF84AF8484AF84 %AF608B8460848B608B846060846084608584AF608B8460848460AF846060 %8B6084608B848B60AF8460848B60AF8460608460846085848B608B608484 %8460AF8460608B6084608B848B60AF6060848B60AF8460608460FD04848B %608B6084848460AF8460608B6084848B848460AF6084848460AF60608484 %6084848BAF846184AF60AFAF6084AF608BA88B60AF608B846084AF60AF84 %8B84AF60AFAF8560AF608B846184AF60AF846084AF60AF848B84AF608B84 %6084AF60AF848BAF8B60AFAF8484AF608B8485848B60AF8484848B60AF84 %8B848B608B848484AF60AF848BAF8B60AF846084AF608B848BAF8B60AF84 %85A88B60AF848B848B60AF8484AF8460848B60AFA86060AF6084A88B6085 %60AF606060AF60AFA86084AF6084A884608B84AF6060848B60AFA86084AF %6084A884608560AF6060848B60AF846084AF6085A884608B84AF60608485 %60AF846084AF6084A8846084608B6060848B60AF846084AF608BA860608B %84856060848460AF846084AF608584606084848BAF848BAF8B60AF60AFAF %8B60AF608BAFAF608B848B848B84AF60AFAF8B60AF6085AF8B608B848B8B %8B60AF60AFAF8B84AF608BAF8B608B848B848B84AF60AFAF8B84AF608BAF %8B608B848B848584AF60AFAF8B84AF608BAF8B60AF848B848B848B60FFAF %8584AF608BAF8B608B60AF848584AF84FFAF8B84AF608BAF8B60FF8484AF %6084848460AF8484A88B60AF6060848560AF6084848460AF608BAF8460AF %6060848B60AF6084846060AF608BA88460AF6084848460AF6084846060AF %60AFAF8460AF6060848B848B608B846060AF60AFA88484AF60FD04848B60 %84846060AF60AFAF6084AF60848485848B608B846060AF60AFA86084AF60 %858484848BAF848B608B848484AF608B84AF848B608B848B608B608B848B %848B608B84AF84AF608B848B848B608B848484AF608B84AF848B608B848B %608B608B848B848B60AF84AF848B608B848B848B608B8484848B608B84AF %848B608B848B608B608B608B848B60AF848B848B608B848B8485608B8484 %848B60AF84AF848B608B84AF84FFFFAFFFA8FFFFFFA8FFAFFFA8FFAFFFA8 %FFFFFFA8FFAFFFA8FFAFFFA8FFAFFFA8FFAFFFA8FFAFFFA8FFFFFFA8FFAF %FFA8FFAFFFA8FFFFFFA8FFAFFFA8FFAFFFA8FFAFFFA8FFAFFFA8FFAFFFA8 %FFFFFFA8FFAFFFA8FFAFFFA8FFFFFFA8FFAFFFA8FFAFFFA8FFAFFFA8FFAF %FFA8FFAFFFA8FFFFFFA8FFAFFFA8FFAFFFA8FFAFFF %%EndData endstream endobj 154 0 obj <>stream -%AI12_CompressedDataxr$Ǒ&u~2222#u֎h9+4ˑѠnNAwKyU}$;Cu|ח_}vOןœ~??jCW޽y/~MNzty*Û_Qտ߽oyZ{u/vr[&! WqWwz?s˛gK,,f &Y7~sR8˜|8/߼ݿxoo6z_ʗwoWw߽~ןﮯ_^|˛WYWo7a@}on^ݻ?]K7NK9~yy4 B[yU޶"D_p(/ه׷WX'|!iͯo_Ab}6IoZC6t۷w.2vm&Lۯw/w7Xa2Sd:F.cw fN{L|zAysz _^\yŻק{+ ֝\qUՋ&߾ӫZGb/k^ٝ^ͥmF4unJ;6ߝk{{Խ/uQiwZ]ڝ+u_^}Kyߧo^?[~xw^]=}}x\q{uO/_ S_^c3۝ݿ}yo^]+ooJwx4uswo޼x -• ^_Nū[)+\電N{J}[?iOy7ƙM6uqz9rR8٨6ҕ7 Jkۇ+ыw|RoomzȝO_}_bp:՛ U~Lg:3.]h|yVB+}ѴC)Ou n^<` g\uEw߿woeo/ |F{oȦ.^CpCAӃM/-6_?lyoO+0}+CװN 9` -x{sͷߞ;r>}p 7[:i>/_^w’N!`=m2^ ÞbɧׯD}&,z3=*iW?7{I/et{Q(;˾~R? k/7_)H N>:"ɖ&~)Wϯ^ԋ?_4[(6|ǛÆondOJz]ihTw'*4_=FWol_ c|S֏Wڏ Hû7oU]UZ72q/ywAw -w.R;ȗϭdwHt |_߽"ys[SCū~aكW#:_sy\}h^Ao5_Ui0ackg=ô5;^6޻'QZ2nC?~'액)h% :Ֆ/r֔\]e`ДؔqUf&sSU9 Rvlùtɇ e[ڮOlؔ4L(a5ecW96ZVJWwlYG,1y5K3gC탽-ì1h[ tqo,xbyoϬV.XFo9uPt|,crraW^Q3;tErɾ_o᫜=)#cR㥌v8i<.ٸNjR:rH1iJsZYڦ]HEs*;-mr֔eUrSLMIE*e\ؔ))}[;۟]SZ2Whh=,2]3!Xwٕ.]w=OzD{’V&dedVk϶LeegrfeaVdmwd%YYe腃X^pI Bn?g7Wg~ v̖;y{9_< G><̖ ̝3_Y$l67;H;azg,0 Ca/eϥ;˙ͼ@0([PR&¹tVs'w<(8})3\p; ,L; ƒl2wΥca$l? -S41p&DmbJI6(GR۹V6E6ydede_ȬFt&Rdgb=*^DVz.Ç]*6$60\V ɂMvJ -";p>r;P:H+aBel9dsԩRNy{571^]?z1n*2y̦hI+ȴW:Z=(hEgv+nG ڕ^J+UԿRƃpOt:VH+Ϗ]ѴwmU;;ZGKvk|-3KU)S[blHX)3+>Q?ACQQ]>%HMv#f_n5꫷][]Ǯֹ&+m( )D5O-G_]cj\ۣq2.H3ϼU[h-;XpQ>Y᱕[]c5:/O1~GBz6&7\6Ǽ8FډD J@Pzj@hQ=(=(Mh'ZЖzP)i -.Kj縃\ER]РsӇԇ2!hD\3."UeFPF*GKҎt$hIUEDQd K.Aa j<&*NP"9UO뭖N6HnfoGOCձRJf -N} u52[Rwˀ[PA+z8WˊG8bIPxQq(1>:6mQKkjfԸêUY^VeVyeTllKWl^^a9ֵ;e8R%-f;,2=Z-[vg*ˏneN>^,drT9^ KWs~hCf9BhE͙nޜsbL㼡.笮"$VZَFZR̛KY=£;`PXS5F aBqǸNiBzwEXڗ:u6쵲U]a:L#+ol9yW`*[ŵlaf]֬kY|Q#[2{bG[ƏgnpǮoIfMOFY.9PyNOTL&GۯN4/c/cSR(ie -p4}tC|^44I^Dm-cFS1whڊ'P=}R0bmKTĬQі[ZVm_g4}(IqAK9G~kGf=?l+I+qtq/yFY< $1<(݋1ekWl -E+6v-Sy`Q֛WÞ{!iNbn~>r?|]g&?s6lhX( ( ^ 5RDkKV! & -g.K}_3Z -btڷL7tIpťǰ~GödFZ 9ADAO -gCQ(4^bԭ4Ux,ZEf1QadZϨgliX8(V^R*?1nwQujUD(h SG%$S q5|)#`5J}5nO%X HT}QɎ($)#[*#TFpZC-!H2EHCE(2"=_Tw拼^I]@-^ B ¾ߣ_cWpnwl@Wgnlc87 jWv4dX|騠zA]\]jeCG/x̻`[uP:D}{954d|8#]asٴ>}`wRZ{B#@@T*/{|Gpƍ^ƌD~mM=+.љܢ=鶧o}e+۟oČrm} ۽ŎѣkhAv*tC i@>+śj6[xWp҇Hh/mKwbY0fנ[t_&ٕʹm:kuM߉[a ՕºkurKl6'* QF~a8/=þq hhHFSUVX@w4bN{ǃ,bhExby@~A8!E>KZh:)קxy`~6Y~!«QxfiKC5T~tCj}L9d;3qM{ךYNR[#Ƿ^w4ժ\ k6r.=mK셋 -Du*2\$表(\NuMb.(PNw>s&jFVsi$meyI@Ol;fŸTuet&P7ڔdQ[%vl*ۥ;(G>k*[8<|r[p4I2Fc)vbR.9o,5g:[;z,\7vfLHc K̖33Qu %lGd6isKfwI x)sR.v?ॱ sN+Ɲ*V(MT ǪsO+rY9dLĨ6Xu9ĸvTQ4K+ZjHGrȍǑt,CѺ56ןJ&7B;EumcvɺJ5жȍ@|u`msij`wDv˰+e/!V[Y.+~鿘kpK5U}Y#fʶpb uBd.dy`6sv)ڐ PqC#48B -!%qirOer[Z bmd))1v}<$5{,:,Kg2 0ß8§ŇV(H}厘hL$BB~n_n3&;FX#R5?u `u|>`0Vtp[1(It_- $mW9^wgVjv%O8]8'IPғ]v5=OQnlqSìVg3Ͱ'jx:Q iI)MhA(4V\t0pHu Xh鼐f%&Mv@7Vx$?sk`;Z+p5Tŀ*+|28ZN.ˮO22!š)=UL}֢XsBkuVWK9;_$Ytzn&&ꙪkKDT\[etm(QpfN,3B˓ݢγGSuDɇK&.ET:ogMvF 3֮#wUQuXE],Z9DNGCݞ19g{1t) ?cs[v)=b:RW/g3] A~ ?s`u=Daaz\f&TI2@礮#zs:5eBܤp k{x}|1ox2gi5 fOG߯Q#>n?ۿd؃&A-ܱ6CS>F!WIop?z'yO72g҇@('<>uLyDSj{>vonou}1Ȅzp)Omvsǭ|tUrȒs٘.jR W+@XzhH/^#3Opښ7J;y. HHB8 `2蓵gzj1g??=Y#&N2*_O}?B;45WɭUrOS@&']KqVIDi8YDn6昏{'35}#(Y -_,>.~L䏣'j?L=ْ_2A3Gg<`ϚY )L>Uj !T-|}UsUj3W.;߾Ai*uln9*幄-"L غCU%hp.qiH߁&S#޷+M[ڪ8=Zg5bjw^2xIGh>t~'jPFͺ<վ g4tO o,mRn\M,3.C0zY;q.y햧B(Aănq=duD<&5] yqfYY?."v!ޞfoOmO^|>Suh/ӏ'oPM1;;:$ӂ=Ф%ӇtimtZYM$p{rߙ靛{g6m&̬?Mn/xP#e8^GZ5Xh?x"7x5Is2s1󗇮R5k/acQ9ؕ] +[\*)|R,ԊGL%&Bel -v&ƍ쀋#)ngHy&e7ޒO»\*#:i݁ -reTnaaU)QW@ޥYuwQyGs 6["@A RΒf?ay'y'ZjSoy AvF]rXGZ?@|w=o:((|֚5fS5畒jT옃JOWh;z$N:S^Vr=`6/ `+dzzP#>Iʙ9 -z_=;8#`109,~P@CV+VA{㾐Krnc8i^>n>&S>HDj{~esKsH0tP5<a3>*ҟ'  Ae)nl3EG#}}udY>5N94}9 AYOWfT8uj1 }<=~[5><JI.{V|ҩLܝɎR\s0 ;y)-[Јujz~ -#I -5>S]PډОIӠIVTtfFOC\)Lc9(>l2_ccckanG􋣙y-ȈYcjHQ1EYتfx>v6iG.$.SË1,#< U&C*r/=|$STy*<6=*zk*ݗ7wooFn~D˫oD ?{Û7W~e9Yat a:4IE~s#Ŀo~7//76i.bC!q -OH1jI$"FV J3j7Cڲ7)YZ*Yq "Ô7r"2?NBc<6eI?a˙ϼِOs~O҂+Q@6Ä\$yr}"MwVbd#cLi>a39 DTT 40l/60nl闰4Éjt2EDPz҉p ӐlNƐMH2dM'0 /D㼤4G CUeB‰p(U'fQ:Q9I9Iˤ' HEF( Z|L<Ln[,d#lY,Wx=З:yRGV4~ ɴ]&԰d6Ի8Q#뫷/ t?8^W_P~pjY6_^""M=D"T,t±"waB]du0% Ql%"'\2ADߏaSነ. -NE'^& QIx!,V91]7`wB QPx'WYP;/tntz$ ҭPnWD;0Q]gV}7@VAFaLB;&1`fɛu[u)K3{)0X zM*Lg.Ϭuce 7Ȯ)=*ݭ֑]8AӆNze7};N^Nyj%kZ؜h 7p=Sю$c$C+$d N"i,PIZKp8SqL/s|{SI9׻A/G*K3{oVN*G/ $YWv4 $##V>.[)-֩p, - 2MIZf'֒LE2":j%Y1d1:7) k7H.:?@$+2Ax}a"ӰuJd~e ~ -/"NV -Uԓg8rPDMXB+JeBKc&#Y -pɞV[ rp#c{Gl52{$dT  gX`Xoƚ6~&G?W.0 -lͳ+0[ *chs\v"t;{%("ǣPr4mr(ze<diPV,lYz@ Fט嶷+"P ,j/x  ΋i֚kin/l)13 A?SOǘ056%p7I @mJaK4M PK) mJOe~+ZFhfSܨh>,ܪ$o~u*0F0\ F%r> vkT"ۄ lJ.iZM+T8bgPLJaieRqݤT7)aI2)ˊMIŤEu(K 7($$ +[RrQ-)ȄM%%RLI?,/妤 3qkJ^EMIr_ٕe)`i^ ʔTn„Ș?f& -$lWJf6o TqKߪ5'ǩ-jyCʜTf_K*v"9*IijzڌN%cvzƚTTg.߻15{YC؏<\Fm\Ukj^}wr)BYܚz5-g_wQt74疻+O^> &κs1'oy֚ -nap40474Wk'/ o&h0D.HU_J7TM(40"\. a9#,#Ti[i[NQ)փ;I^[WWV{ʕ}fQlD(P0n 5>v`u Xi>,2UduJ+TybQXNya#GKSoL)ܺppc~=A ֮]چy{m4tJL͜*{w4l4nmR\'Ub(S'u= "u횊=xl{-Vs'nmR+g/T-4-6ӗ'p_ _kŰP]1,@W 1-hEiCpBQq)! wa1ݹfXlp}V[^)Ǘ `&᭴ѝ|5@,tLzxe{E''wO5N1/u,t傋F5 Ҍ* E-ݬ4x -N'iR[PRFn7ԩ)l_JI\׃MÙS0!Zbvƒid P<] 3f'Tj[ϱ9- iZ1fz7uJ䥭7,5cas]SZBi<EbtzPjP~Qg^k[¶Yҟ+_2(KV+:ч+*dX&>LQn:/ZmD*4U(~KP!>m4hCsyB+*ZN\ uԫ<CvЁ)t`ɀIܩo Tj(vOPtyӴL=ž֞+omgG%QXQV0A !]E _JyaHJ#!7me%\AFFP?ת O26({ -MjbPGoc|C߆)"f;>< uiY6 B!2>pCTT0*u^:ucri)0a`qكq݈N*8nX߄ ?zP_j-& iAX vpatȨڔi)-2`c[O릣kp`g* QԘR2w.5S$gR! B]|ij6oX˓jKSX #yȢPEr`^b(z4$aW64. ?XWu?In1h)t;IkrnSCNCYa@BQF!f)KhB.hw -H߸cGS fPE釜+H ޽PT1{8a6lA'>л -wg*pwx>pwxlg"pw (pwj v;PBMYqL>2;)7wlR|gu880 hvM h9_yi@N9BzeXBꅅ\Z}`^yKA߱t^ˎOICIMhGTEO|i r6tzO蕆SoiPV,lYzq;FJ$HAzG@BqDzV=_t (ެ(˳z|\4V V0+hXhXAhX񂭠a_a_a †(|,|9~ +h +x +^6V VȰ+/PpdXAdX;2`[dXhc 2[`XA;.* -s -( s|9N~+@ +H +PVV}h$VV+DXADXDjw~|k*8r4 -V0ﵚkS@AJ[\ʓ5{So2BWj`.Ǭ;ܫ[PXZo)P U2Wa -+OU*.1:amaBaV)+e}M/9>FQL~z¦bڦ -nYlJ4Qڲg#Gj齩,kclLTc>c߮ACi`!'XQ cTR[۶ -uFڴF+˳zK[Y{K8YU4/&V*,[P\9vh)PwNQ˳qzKSV=;u84mj[BN{z, i&i`J]Sѻ9[R brT`0yhڶ -;Z=o Q?U\^yke ?2 P$ZݮBF:!ćhryi(e1MaUGܶU(vO7* K{G%Zi;X;#=~4xh59(:MʚmZvkiR5 BԦ`cR{G0מ+O_˟dR@"*Hȸhn%K#ɴ -Uc"F""h:sӈN+QH׷73kDtd2bybkfuPwA QzI idK -e* Ymnz11J;X;݌^W}R˟bqMјp -n. (Da w)Z헶)')qVwPz\3g4Vꕇ/m䧐#:rHj| -+ <ư(F@P*jq6V.! B& 817wt^VW*mO!ނcN&8*3G q5嫴^8AuXXڦ -ZQ!74^XT/-⧟4sDc VomƅiLoŬc[7OmP~Q -<6t>[Wf[''-1{ށLՖ,J=8iPnQն^C}=VֳǯMw{r}X֧rf"r/mE/gD[]g* . ;~a -s.#?#0h\ٕon%7o_?h}+Gʚ~y{`|mTE<~xq} =#]|̜/;E5Q6 -yQC;7- ~.}@MBcI#xbʕ#uӀFQOK c{.lHST%u"MafNC>H{ьt!»`4ٜq:1gf#Ƞ.$ ; Xd#bBO -]^ba*gޑϰѴ ISB4ǁ6> G*ax= /Ȕn0a!n/z90u8Lsmp>&<qFOȣ-%r"0-6tLAq);,* jz>8'N P֙]j Y=4fJ I;pOЙ8#i(c,z,~})z{9Vi"*$y֖(M ZE *hbRnW  M9й54$H_V8V݉ЁYe'G[/of:y'3ɞ cd@X eP~Ŝ**0 |6C7s/Oʠ; Eub!Co>Q523p"^ʚAig:9Of$/ dcCR)D&, 5pLϋp'0{Z*~$I%}˰̽r;`)^ -02=!%:7u3CJ8fnq#6)r` yL %-Xn~* -¦y73W'j isY@@NvLwAnLJ>+̧xXE15 -82XQ ma*<ޅ.l~ٱC8X 2\ȺB2V8hi &@3| sJ%v'RL% n7B̦2x` R9L?61E5J9("fD"{34=Bæq4З$QqМ {wB~Q<92d|@S MBOk -9 EOZ#wl2ڼy!M1&cI(@ `wb.=z=D Id!'2͍Ç b|HI 9 ؇) S1*.5|h -> ۮkpID! -So\LOSx|]S|:KX\zsxr- -TQӂn`f'PFpL,c.͚g w NDX z ݃GEgfg 0l_%`VLYd'b0g^*( pip>QTS!CY;g9]@/FgD%sZR;4z{2t$#<0N5p:&O瑧e/{fAɑ(`(]%t1%A&L-7CNW2݅g. X2gppdb:a^L"RϖD&̂*v08JK8 .$X1o/9C, 3`"q;C'>ƁQK妋Gj %ʂXY?wX{pd? -ih!)Ҡ NQC%F5I<0rXxxF`@^ h:fLΨ)jvs48cM GayGyQ3?IEy[Xoqى|Å< Ș{p!2H9W1F%&I"`TSsӁ&?f8Gx3!ہ| )#;NZVP'k +Ad ē[H@> -283=U7_].wʭ"mueJ٦BZ&E5o\a -e3t8b 313ݫ`dq$9fKiQ7+MJbF]s3VZF^*ޓ @)݂F k{tqAm #YQ%IE -pa>;_/G 51FYQsUNK%Z@%Sab$EdLS#'AP/>芮`A!"(fL&cӤ#l V7eAWO˸'X.!|l+YIq0{sTMUYan( 0Ф^AN#$apy"fђCiU1@yQi}1뢁{7\bBS -Ԯ~<趀<̓άjF FYds$SsC]Jjq}T'`U&݅mJw"l,i|wQZ A]*ᖖJ,kdF  R2o f9kП -YRa1v"uaѫu9c_L N"gh> -* aoA*mCFl~ -ܠQ RC %ߢ>5EAIqU]G^?'0Iʹf[w6GDHz5AAZ PD8́@] -##5J*z7l5IKwfҏ갛 Q,A ̓N@CEu@3تI$5T>4xQjJE֌) Iu`Ӹ'‘VJGNƱm'Q/Ի/pь|:{{*]xm ֔1)AWh3~!UʚM:Q$jN싪$]g zrQkdd%:22XR=Gui;.xXzR, жݣWotdȴ18i|ʝ PjGhas5xT\gі(BI*0IT3d& wOst I!%4fyS]N8d<8:h'`1*)K a!.{Y;*+H%zwC<΋;iq@uۖAAki1="Fn| -.:,ɉb}NCX̓aYKM°T'ǃf~# 2М - =w.LD0#wb&3c41{4|xXG5jpT,ø¶ȈB.U)>"lgN3B*Yj$&>d;f.t, @C! Ǩ7G@M~N %M$p3~GS"h&Vp| 8|M.I2&W?S.Fpa;YTv-}6!57dk,S022EMAV,%YyZa}iY]Fņ q.J" -i g5$cX;SxgM ^ ,i+ S]gBdpyÌgT]gJ% ¬ԛv۩rsV&^n9 -jP Ȥ&|7[%&`$X%SڣApoH%R?}Ʌ{M9D7(-n`Sǫ+g(c"IĀ#̪T4=3nf^ة"0('Xu9NFcKX_:y Q텘.8x\IcS,x:hj}PaɠDL@0Nqؠ!dִ#!V @ Wonb={^*&0QzfK| L@+TֱN@))ЭU~z(z~CSraJSTaR2XB՗4i.S5QCԘ ;zV0DzWKA`:C -^f -ki)IP}E[n1yQx4\ liP@zBBe435Ɣ\6\F7zPL$agnfQ#sRs1, -Unu+@z1K?Mn3Qꁀޫ|[ =[od v^$UvNyMi4lNО)#|~${ކ 0u,4JL}cܦ {ao,PcH2.Ji1; ly5;Wa'"qU L3@<&%i@VfY=xew iI=s(2:JAD\c_:2 Q6T$3_ xhٗ"$4t0O 97X<Mpe/H1M~q/2ƊC^lYd :s=4<V<$h7" B#WH#AԀBk<"I tfDwnug)EF3ރ jOLT4\Dk##AEQ+zsR+@4N<&NEx?pw$ -BMX!1 vnhoMhg6V"F8˳|bEAàk0VGa]È //]sЄx>z.2E=1葁*2vHZ̻cp7NX"mf, .&1#6Kvymf(X! e6q<[29fTcDy9+cb>Mc 8ˑAʸXdA 0]Apl(oF"AXT E^\ASp%^N/YlIHK8)$eEkc0zTΈٮ"٤̫T/L -Isef%qhi$X6>bflȐ@.;D$Qad\}J`ÊeW,z,U2M@Y|oCx`<]dl^L4ݮ7Iwu%!322"X.dYqMcMuaw|ED]=0qAk73bgbRkPvq;Cn0?Or?R&xg^vĀR=Шj4(vĮwDu˩\ttFxC"K(kòLaV4`Da[@ k"w'r ſ2s#wxcx꾗$~8/Ce Xi|E,/ݓ.lS^?Mqm=/r r+u ڭKy#oVMJ@9B]H cu{$WZ̡kǤeYۄ#>fF y},/fr Zqhᯕ1(6*l)qCDb{F9w`>:ÈOec8E%%NкT@X bj%.wV! - tq -"Tƒd:/iGDp4c_Qv\4y:JWJX⁘8Ry-&syd-S~B>.P1@p\ƪ *9LGM/CM8A3qUa-1m~ur*~&Ǯ?Gmڊ}dܿOE =bY<*5ITyiGs(ZD  <0eH~;~2, GgKC~T&tqB~ni >]B6z5C <mFy\sBsv~gsE\X1ass!%V\S 5|ird=.xs!?7\T/& _B -}krQxHlAeGݍdS&d[/ZwRn 7\[[~rPpޞ7wP.ܘv='}&a -TNJ.M)o |4[8>~ .4[[ ;V+}~+i! P%vg -S$&EHط}&BH%o[\%(? 2jKvOZ1Dev-_O;[yqo@q1Pcu)tPہIr v7|Xܤ+)]JP1QڛKXɍŎlƒ͍<-l,Ɗ{] ˋ{4TW]X&f'CَEZHZccq 6VO765RB%W~0Qcqf8Scq>r Rg .X+]D(oj,dEAr>Q߄K*gh, -_Xf!ŦƎg+ uOf, S<˝ #Rrv/^, ;ܩabRq -)/\ -B}Ԁ)6V,TLe?,R,.~b%4!\fĢnB2tH`I8^ވX^p9ňc8[] -IءRCbb߀X Ƈ #mL%R1 {2~ U 5Zyן6鰼Qw:,K#^рNUIU$0$ - ;òő:)q& - -ΔE]>3ayKXai`<,s= 3;@eJ ,ma~9@zawuQn:Ga bV]c1t|XEKwҀUp-B Kb tc06ؓ뚀X0X1 < -MlˆXjdnERIUNB,Zp!$zQ\Iys"bjZ􆈥I~(/y ~'J0}*@M{ +11NbNń Vzywlw?`!(%^˿Ec hdv -,lxxS€E g#J,|`Py/%4`B5B mE2JLcM~V(=g",+`WWQj+jX'kpGM)+JE|m^}L2y+_mWt}4u_HAi|OYW (浇n~+^w+\\duSDY!ѵ^E*[]v+lC4W]!sG4=tWj1xpW]d:MPp9v0%TWK" :ߨ093\ppZߨj#S]S㷡»,^_|P5<[d6n,Xx9`ډԚWqC N*RE/+łTK`x\DWf`E+*EV+[ -p'5}ytᚲgϠa|LTJ[mE/&]s*ޝhMK8D(8WFsEHƹ4EʔO+BvdE9Q`? -Ev ;5Lqş -ߝݤ%׎|e'1vkw4_8'9["Ep^A $1nksroǶ6lRτڊ԰yB[U23[Y^}>Zډ̸>PxRkspǤ5j Z/N+jFdB܂h qZ!Ap%UHfdwUJ"x[m"]>yYQNYQHB=fW?.؝ -PYo*<.S7#YQ& R er1l +V7xUcE(O;u87~'0VzIr`al 4N+ʈm$V -{XL8=u5;Êv -+ -(ð@X; ,BG*rS)/+ڈ AT9&Qm;M 3:rҀa]j)WچJ ?;K^ |C -V\lWg`Xj Y}? pEaE0 `ZfX"BVjF6ݘGD>:P U13Fw -jٶC;&ߓ<~8r6WkUZa<~' _UYSM*-챺W bL_Ec.1}uWE;UU1Ld`2 o=ڵCWUM󅾊8nǰªwVڟVn"%dža(Vb0 EayPX`11ǞVFkY +}V7 +.Dz 'uv2&iuʗ]=y%2*.?';WY6*/jSaWDhW?l]U%Nx!Jwۥ(U>_ǹSWBC *oU(D5s/ 3-KU L*w*D ljgWiFBeEUfB5]8PဘY^oUHj5`!«^!L*ራ xUaled^TM/5&%XP ^V+TLUel\;WS񉺈9Ѽ+MJjFőq؇JaT/mSX;zgY$UHOD7HQwoqǨ")HPE';B9R'@~*vSw)WƚDtWl=T(C9Fة~~7P"x\"&:"#LVgrSwlj3?Ԕ  ؙlmpՉL&^.Oމ%0@g8,J9&-vRowV*l0 -|R;ɩ5…L*JJ -fցƈTT;!60 EDG1"&Qq3uz5\QQ/V\"|y;etВ=TTd([1Q'0Q7"Aoyw"jZM j[#͡CETuԩJ}sX7zKuVxab?*C$sPBbA!;U"s"P@,>޼٧RLi⪠1N) =E=1n4Ex Fl4\( ;j 8>Vv2&1 Z:9w\79R'AM ?yDldE82'Ph_Wx% qc|x;thC '; \iXH=Y%H+3&RѝÆQ_",B aCF?lr}ZN%*5l%Sv9*0+{m# (Q˕y}ˊw8q)dhN\~2|4cq *yPS@t -VzmzZL@9W]y+nm K.ͥ;  =o,XB?;-%+`@\1ۧ&a'ZJ8% -_W?"q#̪rVh#*?_hң@^mX[RтbB7o8.T @  KT7*N.Ou_ -cIM7{=׉-nw!~*тEy(=m, -P7*6*nK*Aoe:2΍=3u<؋ -r XXm4F MO5ΧW~YS ԎtxF% -[Dґ})b {^z:7Ɠ.ڑ)X`G3.*4(|$`RP>sr_2+{? *hdG=: {=mbZƨP@{H5~AaUFA/le -',^֐ݑ˓鵢 P$沣G*iHw2+γ̘*Oy c -3nj"0,j-k˽FJf rV[J{SaKxV:`=R]PLP\Ie"FL,$!&y&lKd$[K75ċVOUN H1P\-Ql3xc)* /Iqh^iOz'-BH|2P͊,%2J{6HQ'.֑@R2|ް{ֿ79jmP&W -XX$ǨznnxBM :Ƃ"xﴺGĂL&W팰,iL. iusϚXpĮ]=zH'CKoTaU @?^E|tw]%ŷjqO ġꧮX5aDNkز)i6ʢ^X H4'L6槳Jֱ {viT^y$#hQ?Q3PHJ ;7{$^3XwUgTc,.1;jiR1NBWNP5+~v=ifiP٫,'RϬↈXaЌR2di.kJuUCg(FGcuJ*.~ -(YEuB !79bX gg.ګnb |)L뙁M[ ӏPKeGj_;M}/'B! xqOK"1RN!FPV,7.^BAC>Vmxi\vhy,|im bquӅ$,yE"In؎^Nb.#67eƇ7e K+uHqo6!^t(ی"7?u9= wvnI-3ŒnbAtEQSd`c懧k{<1fGUz I' `i# $xh3=A-kYQ2 *qvdi)cMǥ,c3T0Z]iMrox -YJSaю%o>8n69ׄ1!EQHbM|!c.E?h*##؝E[CK<Zus(ZK mHGt* ~4ji=0 pDrv88Q -_s?=+tz maHS(ӾtWk!Z:Du-qLVk.O+asD!/x5_PF."1XXM#-=U/a%\ itL Vޮy z߼M}@PNv)-GX f ~I -;_܎5A%"^L"X!y. rt)Llz~a\N(7 -X8eOu=C߲f"E\.`sI.sC#6EbwzS5FS5F9-Ewwms7}>+.8-(ق;kkՃ=rҌG9ʒ6P9:E{)ͼ'uÀdVlkWʌ -'!ܓJ",)rBx - -\|DUvLgzHsFHu]ѰXH6$`U4[s6bb΢r+AI(}t[/f3Sܴ0`nVOw „䰒Eah1fON=ι)7o&8?;?mʒ+DF0 [DK F QDchɲ|Pwn(U̧FJ Cf, m|R`y0HץsU UOBSI cO>m};&V:'1esyJ1s3;,׶QLȧb,IeKn67^pVdp\4YΫ7Z(ni6BB9<,`awHsg >r` \w'ǺtJ}8#^%sM -R߼dzR@bhn2aխ{X†@9r` Kfx*I+s6à)=t }uX#a&@E)tb%^8 aN|.JeգcU1g0*,%c,J3X9KZG&9[Xf L!__(w6 [`@TwݮПR++{Z!HPw,yŁzrg)pP?Jz0]fI'z5rq'UruX- t(k*zQS]pypmm,)tCT0MhY9. ]芄0z@5yWn8hCJ>Գ˻(Sf 6AZP@" ӊV,Q)w$+t ,d}.JF5p3&"x -!`TQU=Ld+\#2p_vL@p -ю\fXV-Dw*9*;Guףlen'Ϸ98Z$L2x P3a" tYK;o}SUuRl)J/9G U -ȞKJx7<*69D. ;0/>*qܺƴ tKGaϰotP͂{ǘ§PJwOfIcTzm9KKُޏ-7RzUܩqFi^{gaK H1=g2OKhw -St}\w=6baQøn9-`brtQvUtG55˦8׎5iܓP,Z)=am4+TO^.⤭У eIp#Gb"QPwH2?lSM&U٭aHJP^L*GӮb t*9!3X!@V+܄/9^*䈫X\ݸiݙ:Tw.ʙw׍Nr4 E< |%*zDK&&!GEKx&J³-)Ȟc=$1R3 -v PXӬ(:ʒZa%H|OЂQ<?CP?(<Pma:'Zٗ}BԜ3 \+UHRְõw{<臩&|BB~C0]Z+v\ Ւ:8|4PA·:+0n -9X#&&\"*ApH6.@p(ح;bm_QhiQR&IG'5wa,0ΥenY-`!:_!UC$,kF0[( Іl(H~I0f w2BvT%*j"4iPwvF@VWR!F%,,nUKܮ9]Q]-4&3\2LpE]s̉5w]Y -կ7A" kH|jsLD +(Q A]5a{"n7O`ٓfH,.E (2|sE0W-ɿ^)n,a: 6`VNgN8"[8‹X 3=,*V䖒EⒽ  -."l"X>aa VOs,̾Wre]`,<ﭴV ڸ$IӭdD;"( 'qlejܢ)GjīY bYKt )t[)>}܉ZVժ8,jzMK`+]Q(K*3]UɌ+_/x! g(%r|CűȪ?N;{_]JriNeb##k&p`Q~A: -DpFHR"VД !DD F m3w0X8vE=HH:wXr -[/3P5\"MH+>ܺ'`N {<)lG !=.ť ̀O:>;jmFxP>֎-%ji =PLk|&X1+rci즕y j3=E:l'`E -LƏP -D -gl+ 6ܵ͢=abQĚq1RqqWj0LyǧTQhBx/9uIL!ɴP, -;XR=Vo)gg<tΐf pRH3ːN/9Aix[yP=H.0YUW ,D3-Ω<!YmqtJ]z]х-.[J촫P MGngvC*@ -9B -!v>} [pԒ¸OՏiH!1FL5)㰯jh ؆aÿ%qgafR%;GB[]xbac۩p>׏Z{X!`#(h\&:f&:1Zz n9)S5J"W/5sJ_&_ߙ`754B4;Ma@U!W*B)l LzMByk6XżFrxͿڋwM wC^Ҽupzu^7`_"]7s'躩Fr̤.d\cJ>0 -.} x{-\ψH{#< fT)ku`nݫ ';`XðkXU3z`CLԚ˼j=.Cn"Z?cK ?4Yw -_8mҬYQ74k6 iYeDw$ihְYq'6} ̚E6%Yc8C`X水fgY2XSTqBZVV8 XD#־ٹS{YMW8c&KFE<;ņ'z<mkS=8;Nz"эN#ڐ;Quέ!`Y'SoK/Me?h5(jܰ1€M}jGI_Tk`uzxWM1#ene6HêFUߙ:ڵ.şjXPuuhrQx[91HF3 g2z?<=f鳢0 S,@5qzA̧FP@S[#zSISdSq;VS>;/RGO3<KMɩ(5 SW#i};K2bƯqu4HߘY4/$m,a_4jX5(jި -I@] vVӥ'6kBaH*0~CPCpLm.sE˰S8wO߷$|XӠ -mt e6zYqkd/L#uڕYvL#Nm퉘 W$!L fQ &_ 7 ^ބKcKG5bx5O,POc WW%VТ+-/0x ^p3^D=^8iל.t -s'LpŒ6p $ |c|5=gn+Jசƪdΐ~wVu҇`W =Gy#? Ɵ4x{&Ev|n*7zvl4= /1>ʎ$F/FO[xetWqE&V,1HSGJhjYUfED/RaXod3شh04h]jFb;*lf'BtW%4GX͉F(I UpAEvL4"낉>s|b NMC -nii - $-!A\MaK "C_ũС2rC DCÐ3cA04r-ooDZv,4u\n A.S8* C/Iv3z'AH}zK$wy c_3X h:|,x3 c 7O]ꏊ*&Dq3 RIaz[hUg9ԧy^HSp)MhXٝxr)L=hn"9kj2$ŁKZMf\F&Z#WY 4FA@SL͎UA`0chIXa#KJ>'W1hX^{aqQ݇!Wriؕ@#*qFz`tE<冀jM|qOpC?"8(I5h~ :W_)YgCIao\!og4VӤ>c';;f|f@a>_79<;[|Y=(jmq5d;Ax0$|C=0 R ͢=T"*rC`M{,\= `F£c  {/i(VyM3@ -?P'+Y=#جZYà:xQlmӤ=ju.=A3 -)7{fl{fD5$[3-gND큸 *wdjT:39/3.KB|\˺jp>(wg[ɭ}gxI|H]%#2 ط[ϲ>)ƼT|AN',Y!Z_郱#׏L#ң3k0'lS|j[_ϴߘϴVg[*xg$v$D|ig !>"U@k=Jьˈg@ܸMI||f0ǝ˔3?s; 3K ~TI3Ik|}vB-3^3g&[R5a?δA>ӋWs |N@ϴ0W 0ޑHNŒR@[,((m#ieG+#|M3,^gXIgZ4Y63~ ȉ|FfSs D$a>&#vsL'[My|p dsxO߾92a-Pj.P 'oư,3z&,0y!Ӱ3Q瞮sA<x&ψ=|g4Slxg)=x'Н/w38-jh3$v3Ua6?N] -'~aa#P1Tgҕ(>Os?\FG y;5(9:| ^Z3AQ޷9LLc7Q>r0([|U.&z8SNn8#! ÙXq:,<'79X of`ݼfgݐ{rI4`7wK&1CNm~esD6CG1Flr,`3 @l~$y0r ' "*6Z3 -I֌53_f5ϿwT2 Ks=l= $R0XWs:R^ V3 Qs'ڦf߆iQ`ajdb 0͘Iyx4)X3i@U̳ eOʳ>$/;f`H3̧bcCVp 07H3? ->Y'f!ʹ*iH† @nf( -Oֿ`H3|EvF3%f4m*agKL O˦|2ͰH@F3 Gm2͸JԂhk'FS\!3; x=LqώhެF4-/A4"؎h& OOUW8`vD3X2hBO ehdmG400Q%&K ۋ rA3Û:333أn+hZs3H<*^̐%{Vό͈3'hF!MJPQyu58̓ΌV/uc3C@ɨGh(0c=q!3Hj!lqB - -<;d2wjM$3` ,"3zp`Á́d.cnW115>f10%7sIO?k5(Qٻ'`u`ѾfΆ| 77~0CXe-{F]Xef,zq @P=ŒUfW=*Ï`׺Ȧ)oUzJXo Xgs"3ItptXs{8eh# 6DS|f;Ngv]| 4eփph47M,;N^4ezbK L2,*Uq\^th<`5\W'pIͶG?)#xb zs8eZ[pʰ!27Ӎ0Nᔹ!$8e

p+SNXe -$YX2T<X&Wٙ̐5 Ufyp(:m\ar4:qNU^F#&m"~qځ7om|s@aSnLrsxҔ/$"b}q;I{K ܉Q~\e(?7.(CA QvB4qnG(& '347>dLOa&6 L 51b'E^G: BNi4rQ!Bl2EZd` |q"MLs7d&K .u&|ٱӒaX_`GJFA(,{?FbDL[o/12 z ?0tUߑg144JhO Qx0hsR6v|h xw1Ts貜JmK׺Kx9Gr\]L1 q\rGZUNqKeͱxYѤR$nTub$87hcƃ$Ww`E/C55V]$ĻMC'1"lE\p aƖAMqOkKj^(f$[8A|3D|ʞ&o 1FM -a}D_ >-g&q~1 m5oMt+9bk.#8X ZbiG\LAK4O4d;L`Q_:ӵ۳6:6Mp]ݸhl1 ljZ 0APbk;m>*b)Ӧfb:v(Mca83eH"=ń;F pSKz[&EY -y+C3;qdN(8LcsO'q≻IN 86>;J M1N0q&\% UYAJ C-4G$Q&Lo1w 1T G2#ՕG?i(m>7X~|?5f,b6 }L y';+^ ntѱj2a(OH&b #p"8b[[a[a`uwMeWنÏ/#/&v%3͎hX$}1!"9?ɿÿ<7~8Ï˿?D?L~gY39?^_-.?Č]ڏ8|l4t,,C!X}q!8&I,qazT3Qpk[G],vu}?did`r%9ÍyP$ 㾞Ƿ:!ُdSnn#=i7xRÈ9c*z^fExH/ lO/>8ý#_g냔_idDOfworY|}{? _bjÈ{`ݽex/  Gӭźh?͸_f^7a;]췶syGQu˼:v]_qlG}Ez;יn6Q׽`w~ofn,vu}E&}Pz_q6k;}z%{oG] 6:뺾ރ5TB] -tQ'ܗ5/낷3o׶OG]YQn=͙w=Wgm͸՛yQ\>Wg6o˸f^gu]{yߜ_Lކ#/GfelG]~s3~mue|=e:п܃?y γݫ` Dr,|!s2I=ٶW:2`Q_ݧ9tߟ.~qͼ~{M}m۸. y;u]_w&WOazn6 n6vmU3Xlsu}Wv}, 1>oTHm诡q(. y;y܃y5ld7~ay݄mYk[}۶ ߏ3XlQrb}_P3݌UmufݫCn{?2`Gݯ=ԎL_!'"/lu2~s8d|qˋkjb_+e^v岏/tpB?{ZS-z} -®X+ް_7}r; 1n6މӼQ^g'#^sX}C"84o%~u_gٮn|v׺NR~f/l3uݮ [QiGQu˼:v]_w;0}{b>8Ofܯj3;uݫ QijQu˼:v]_w dA+vJ̯HȲVU2Ԑċm/bG] 6:뺾ރ-qoN Ā6~jy]vu7T>22oru{_wXqϗ#rk. kzX1~z]m+u$#)nuж]uu1>ӳï?io]gOƦ}L}wg9'9ɇ:2gnG]|7g> ?S2>q:22oru{_w^_ks7}u'}]}]u>ωmS}@pi -Xkގ )}a!U:W Ɂe< W]3m:ض:2`Q_| 3}Nt3Wؖ^m~_7'~6:e6G}]ח{߷v)L?͸_f^7a[۵mx. y;u]_ 2D?h 1>oʧ< BQO!Ma`n~˼<~E_7u)o{;͸_f^7a]ropkͯz?2~{ܯIoglJ;}s1[o/v}/o[>+T×`ԃ dQ(#v93#W/H6jӦ>cwe<>!m.iG]_܉:<]y>'ĹM- wF;gmst`/]ӻaw۞%C9m{=c|Qo:\.-TXv-OJmlnO Fqx~!أ_9]a_l>ic90g7:_MV=@`y@9m>W^s|tk7.ݫ TL36>+C>y7K9l -2{]:֧2w/{o:1BZӼ~ -Z3$e?fμ?!uIky>>/dd\\~wu_׸}˯?J7B藘۲Mb,wyv4 uBu&CxcJ%sq^ś(|M-_O`}W71q|=eq:tMMۯ]WWˇr4O1+cV=rk>3=c[h+M9p}TMw}s44+3>wZ˷_=%'ɮU5c=-U;}~E6j$z\ @pֿPN}- jsd2% Id9^m7H J D) Fk| -s6m=:@y絾__y߼@opdb3%6%^-`Z~P|Q}Qܤ>l#?tz}H6dTwiƑBuFܟlշXxVx\߲3[ qX3|cGc[_Sָ*criĽƮ`dKݲ'?f8fViwp߫;AY'#Y2^ZSC^r`'52!e1,Sk/kHsXȌmx'}_<# n8Gnyؤ8|wa:cE󸛷-'*\Nlm? uc߿{c3:f?7TEpuohw?t\;9@9rwJ'g11 x Oޣ@sj -r·w#5ƫd`A˩8WIh&/;=cPY鱢xrSa@Kt184dkvے5#I٭6#O|Yri֧YaZh(}sytB?>>ꚳUF凌8½>Vnbq%K `gֳ%Qs{i#=A[ d^KJh9#VT D{If>x⩹,d6c3lXm^ hιi?5l2D 8g-{(b3N?5(,t' j09$i\E_7 +oƃ#mԹF$QϏѤeS`_S5g0NdrNxc*Gghpu&Wn R=הOLe4A;Q0tuon?̇3s/7tW\tE'3cl>-ܯZ!pf/aƓ=: i_3-lnj\o#8 G8k}/3'3O¸;S7sd`::Î XLjKvoHE+n$G@XVChϷ{0͕3rv:,2wgbJsZ}^X{z.7F۶-:Ǒ!s^Vy`W#4ƏA$p++Ǹ-)<п980Ntt]@g+Llgƕ$6Aj2a7ybfavb洅&}c]e4/n\ؽQ曅^g 9T[t7ug ̛% -vs]JݤHw8Oa;C::Y~LwbضWkmH~8h< -@tKn{nZ(c!)w@&P|eK"tMV@!@"_H^X lRB -]w6ܣu\$x:BD xh$M $u_O,J#mFVgU-m2x1+yT,QD䑅kY-ќt/б7vr^ۊ mQ7h>53+W - 6fHj iQ<0Agij'N2S،,[ЖZM %jTl -2V@:` [ɂ BY7G=?KCҌ+Dн.ϰ߯&8 -4wz,YO$iȨ`5i SpoC-/?@DXQFl&UMj'$&NIp#Q3P:O&oP1 HȒךC%@#/l -.BD-IH *K@K*Is0#-Jة -:VpbRΒ,J2kҖg7,UG`Beh^fAû9-X$ɥ jMI=P8t!GF,8tK*KJHCј*s1p<8fBah5FXU[e}Eb6 -Q*sWñHCxp-0ڳ3lsYeQepc]K]~}?,QdQ.(ISEZiv GԨ:BpA6,Iq j#ml]Ă%"sòC~w|n -r"ܜ"i'0-25ZhtL J;X()RF8^l| #6,.X%RG~HvFDZ~aťے[%g9GMt("w@'TA ^tLoSO l4jpelQӉ]:ID@*.zUi"w qr_,܀#gq,t'ZnhUQFA ~:MAnii(P&E+D)2xsR$ҙ,._)ڬ͊r%{4ˡFƔ25Z0Ms *!,R ˏ̑() UfԁyH0 G:i'Q"cvyhѥE`'y1G$w4emc0TqeA/#7peGG]%Ԁ$U>؝Wxw9[ج|-D+1e^EjVUg労 ->WDSB i";XRzl=Yn~8]KRD<򔕕%76N2%HD(H .wO7 CiH(nԀ*\J6 " ^ɘal1{Ek/m:, wd0ek43xR\ɇB/(SA2 2.,~`9lQ.!"[)]ɑI2)ږC2}˅bavQ`\%؇$Jvb%bIY~YtYjT)5NkUQk W]JҎ\P&/e9ٰƊS(23($aG^QD3EvNd̳K -JϊG]QI7\Hn]nݲt*5Yk#mc@4uO"Zm*YØ<錌a@?),-E0F 2eF -c"$K T4s=X9p$14N̙̑ o0Y{pPTG' '`}(H9chT dN/a քy '@g%Lǀ) !>gp sUʪ5 (lA -1}*CcKւĦqi@@- -ja[؍\t[e'2 y&F\ @3Ŏ%eO(LA A0&bQj@EKzSK B,FDJZ_6 >l PqRIm@R90(ūbQ4 p`}Ѐ$>ϱ7EԀ7h}lGe[+9N:yÁt,?dLC>['u,z@<" Mv adbKNE`e@8 ŕB.1TYR{ ªgV*<̥BT 1 @!ъYS}2L4AuW Q? GXAaJZhd@E -a*ɬlW(\yBf"UH|Pim3ODѼhcls݂T5@z,N0<,AfˢdL$k*,g#Iv eY.k$1~g, T{pYP"T /C. ct~,ٲ؀ӒWʔ,,ҕ\L hZ\CQ])ݖRU&5Kx̳^r( -E5@,RNe-?6qVEsH5EyxhA'=; -k(:3Y -Q_ t5M]qd:!O7dX!s?\"˲R*Nk$E{lMDLA')yz=qPD`)##)] -Ѐ\N" {RY L ^dBmX3Ks,[!_=&XHҍ#ߟ+6u0 ukkRd;6Bjղmp: b+bB.h%9!"a,CMV*gĒLnl -#]otWeී.鈶vmduIVx 0GSZ+H٧P \D.L:$ٔtdxSЃ{;vt20T`O)PPKEZN$E㠃-!c&P -].O rtU,0"jGNr) »G$zNeF@sa$w뱜?d݇ƖEdAҌ"'#l%+_2 ,)30P`-!$"VHt&HͳQb2?(2M((eJK` g$8:@WZUU@v JxU%4CgP2;V%0>BCQ2IJ[ i%EJ*Ch%@$p)ڤNT%(::ndgO"8)FRTKhWr8Ř^ },NU&W̾@ -l@6O9 MeFW _$͇1 tt8t씮$h;KsPD/$6S1!vl?e̓(2)Pђt`2"iuBQnU 'r}0c-2eACJp<%x.<.!1&T0W]RYFfv+YI&)'DE+;.BtXrMF6lQJr|Iqs_Z -F&11)"* `s&HU| q 5&4)NiBM2!PʓAJNU3lD˹0vEsW/>f21IID:UdJ(xbbŔSHDF -R ΜɮU)%ěCdqN vcG)RE!s5(sLΉ}H Ʉt&aE` -J Pa`$IHxޙ@ʱ@Oi:QF5 &Œ,)2+-ue٘&ա -,4JA1)U:%)cD.UW$l)Г6AE49Ni(KմXUܬ\RYWBVaUE%S6<"׆Wx6&nD`V< oA&|)S[7I(kcb?ͷT_X\vƃ Ă`[q -jv(H+ _9eDVN3! [YU6/*KĘk%Aao=BXT$eԜhUh"n~@ڊbdE(\k|#ޏ3)b;7t39rSUH_q|4&l@;p: %" .y7D|׸sa>K::w @"ڥӔɏv2![HpQ:̓C19.GU X7Co)2K3 Ǭ A d,XEIauxIPGN `[Xk&D`),mE&cGERzw0Tp| 쌋!f^%an'(/D.owDLl#O[hЬ G̬@G#?Y`ga < YNJ28W2g&%pEbFV` {lL IC1(/C(VQrVI9h)Uun䲔ZSx_ 9QfL@VOiRrF$]8:N ]){ВHXg5kuČ9 -eupI<MzQy#9!i&V["dAG_* -Tl et<=-ꦃ8ZP#/1UP SB{^rJ#S&گB8eE#;rtF溓 -l]eE҂ۜA ^4"6yWdv>>`rI棓#bтWQ*7fU@.՟>'nxRF$ M|DBu YpV2ڮSXy,*"W|'|G[=]Ѧ>ki%t7nIP(逾[6=f,kA$EK mzpJEiE]zI{9 $-Rn?DZ> -ȁ2)w$lTF7ibJh -/g vAtcZtoX0.tPW?:x$)1v `|bXQ# ]Lv &.1"gL0eM+%Cs&mVp6 uwԪ@*tu9%+KI>;@ЉBFv$]Ua &Sٷ{ngs78.p78A3zбK,0\k^Z q:*0ntK#jV2tJ@b')+-3!Q,}W,4%Z-w%뚔ZfLR&N9f眏7-kՒLq$ctgPV B !NѝSf }Ʀ@2NWP4و =): s>8PWQmp++Jr9>F鈣\:"Hvg`!WңR$,o8 #c9 )_rͣ0/ xJgw endstream endobj 155 0 obj <>stream -ZvRPF,lZGSUkC">!Ա(PG6yCaY0;U)\H6Y.ta-DRHHHW̵qW'߶~mUg?o?|xxC}ӟ_|3OkoOE>wѰ3ZO~ O[ʹ7׃Lbp~{/|mO~׃O}:PCtua - Pn3N/K;F[םnkG5Mh]E;^=\ɦ8/|58A6fv{M6bz=c"3zݝv>ڼ63sֽc8N+a9 V1%qor3h.P&hI劮/~&{א> =KtTF׽qg:7Tag[qwlNG7nsmX=9]]&k.RY.<}޻l}W -xUmS? -x9x}f?yTJ`A=%buͻ:^뀏A,NǢnv^9:} N?t.FdaA]6mՎ&ӋOth:tȝn^+^L&h-(`7v͹C4߰.bdl;S]^Nz+cwWkp}car :p2 |pl_[`*;P{ P;Zm5&>c{ǰqf|NMU/V5^Y?M GcZ- P0@țQ8=dv7iOƴ{t;jއ -)ט"5FD7GD?"Gd 9"rG97̸3O?\nly?{7LtL8-l%yW"L~'m]?Ge8Gx(m1"w:r< ƽ]h1Jw.7^~]RKa0\cDnm+BMLCr7h|a4o oڲn; OeۊО݇h_͂oٙ١XXsl0ö|7Yݽl}e8>lϮL1ڕi6Id6lo{S3lW}7*t]Lsveogznl&>pKG8]َ3[-yā3,mg}.p9Fv:pfg.p9Fhw6My '+ m?cw}x4)#:{yu6J< F}$σ{Wq&=Ϟ5o#o{o;߾{^|{Tcn{n۞۞=66s?2&)/~mܟy5F~(?-Zq `@Y{\W;t>mvqj.in/z+QX^g|4Y8WϹ9w&אu)fs. wdl.;;_iҵwJ??<ʃ-'Q޼xZ}op}?遁{WG9 r]]&^ ~}q}6@p=؈q'( -?=;4Fd 9"rG9?3O?\ͷC7}ͮK;ݧ|[?n5;??+ -f9y7E?ϳq&xn#ss^v[[>ys@3%^Ef; ,0l;{跦x?L]ȯj/Y4f7Km6I땶%n~c۵6D_K7Mp{E5Bvyyo{^o.{=~ݧhЛ~7]|7w{}g$jl1 Fs1b?W75@ ?yu8vyPSN{ ^KM6@(R-L@6_Yjۥ.Ea;l sƜ1gosƜ1g;9t9Ѳ61guٽ1K9=-LFkwMS95#;V| eoxTg6ĖhȖhbs4}zG7 =~\w)_Fo-tjjn;ήV*úju~+v"({ڷ6 FW!ϰgx OjB=^oNw]wm`]L?c]YT!+kL[Rh%فvK&11p N Z17֔%ǣ!K\mw(axaƙa9[ޑl2_vh^ \6lxW6MP~yal\T -ոB71?W7##|!݉{&n;bُXBbףaX{Ap/[\}nӮIO{΄"vWzzGe}h>7?qgEVcD!4FdM#Ҝ+|z\KFCe`?}3z;ϖoGd˷#Bp ֶ;~}<;Jndt,dw{f@z?;}gܽNM3L˹:y,v˖-Ɛ(k2]:Yr|.`n#xbԣNrGhAvJGS䰱оIEdu8v5 ~7Ʋ3 SP{9w86óSN6x|ܵ%^/ml8O;xlQV ow ލ;e.g?N-Jl6.HaD[Nx-m!> x> -o_e G7 LsGaF~:|u>>` -GXiV"@~@T3@4l%Nծ sMapKWlkWyܝ'%?Z)]duU"'o , -U?5Eg, -G.j#A$`TM+~81 -ߟR_%R;iEg|t0UbVT&a4$jB|'F״ -h#+ K} ZumhۢHYb<_1-̅.^_(tQVR*ofyG\t|o*%5+ގa܆eA0"lq}s1VW l YVeb8ƾ9#Y93 ; O[0oŠ [506ނߔ}s6p1on9zɳhتE=_tI-9Xtؘ'/iUh\% ~E X2 7A9 b!" $~[< ,؏<0n0u9^K,uɒ`ygIMOiM7XF_oyM"蚾A~/Uc=[-_qU<} B춯Pk:CO/9k_+ERuvP,` ,N t4<}]Ly\dK1š+ h6ͳ~? ;%I -BjZ;S'N%S}Lo89V^;š;YAy-}+in5 *fX(؆MLe~_r-V[|!6A5-Na 4 ~ܹdV02;"[GA J3\7RzU+hQaGZ{o/?iFxo9kcB< XYp'͝A6<3&H>gHv j<Ⱦj.aH :3[A1Ө '%Z~hԿK>1oYL R7/Jm~ů?eH H~<vdm vN_'HFl,~"3yA+ ޽0娖W e3SXbFY=s4Lea_Fx}v\s~6[uCv'?0}80ߘ37Oz9 v̯wA뮅S̅MG^<:t_ ˅r?>gZipU~3Q= ^̒6ִ!b [\+(עi֢)ע)24o3~1OW[%dȖ0%$APUl -2/ -X}j5͑ȤZ̊H H+ " %;i]M&4kM7O7W+;gLY$TADyM,[1bɊV"$s3L.ي_mruE,Y/bzCIRaF JtuWsfG_aQ$_oJ{fz?*w+{6X9hZslv/zg+z h _cK_,~|a)g~ŹS,Œ_, zoA 4~sg -VERJJvXF-1Τ`+_), p}vI5zv.Z,ԃ -Z`%u,]]aN -(.( 6kuVX֪YHվR?L[ЎG8v$`m@è_A!] T@q.bX7ĶSA/fR bS[K\uU,}"K*n#aOΒ P `N~u7WoGS>+5[OM_Źrm-,"] ;7oz9û2,3bt;{:=~ҫ -oXW1y?7Kv0TA~B2m$23( qCKa<KO6Mhj08Շeq|Pέ(aiy*1NifX1#ח8K/ -e[ -s9;˃YޕX&AF3e 'HX\pL6|7y&/SծMzxJ8VKZܔJ!w:GHEtui%K^W,7XPdZ-Жyۥs?G/UѬT"! " :FV%EI= @%i*Ze: LX[KϞPaSp= *C`m;]b& nLy6: Aڴ*ԢP5h:h \)g2, e[t -:#(Wu%4, l__ӳk?RT"YBЙ|WCO{Fnǃu'Bc_蕟ٽ :<%rާ>%G/na\0,4X B͟V*7ؗio~)w߾}Im_MS>b[L<4[֋?Iߜe7s~$^6x6T`f -:yӬ$1L/7ؗg_4'VY9"frDW&ċ ĉ_1, ߜy1TE /^؀C/7Tmf^,r|s jhY&pz/<{zv3KƜ|]y,d"9\*QF6¬g?7:-ASoRUv`"&g)/ceAH)?؁T;ôCG5…BmI~"*2x./UP03AT-R:,4 ivݲNe\ٲHѭ9s:5X8w!bi6ŒWL(Ƕs0V(g! -дMY:9edqD@%e Df*3q7312\3!D9J!`ÙƜ~9,N,i%;Quo5)8#!YBLDhrL Be9!ad289q4$fyw:#".%\De0_ (Ɖ - ~D>Ɔ@ ri7G% ߀+[']Bo2q?/h\N9Q:#n‹Pɖ@Lq;;{HX(͟#$+=GPe ĬX%^&-sNs^NpVhۥIHb %Չ`ܿD0Ɓ@ l 6Gme8x,!bR;,O%Dz=HX?Ebf3A3@X1rlYR xvH9]!-tWyrDUe9wVR@΄;Te;H _N$$R-œM|g#H"XQƜ^ыPj75` k|>X2D)F7Ld J4@7j2v1_0 w^ s>thB3fuxX,Jcى@,]Q HK &XBaœ_F=L"9k.8hEBš$D+Hb"IT&=':1ɔAj&Qalcs,=r+ш Ol?KMQHD"P$='1IAjЍ/M~% -q#qMfϑBD!:$L 鳀Z9gPɬě27wn$ '+O& \C . ({k(nk(ɻ5ƁZ daoZe7w/%qF[2F۸Ъp[gp@emqBekqDem^ٜ2I6'\UV$Te5OkN͝YIt C+I917wj%5掭yWsJnbY5'n$Ԝ橳^@鸹c, 9!7w%4'$I6O\;ΣU 7=Uo6L$]EiG - +Y5O ) ]Shȡ,r8",Cᄅjh -r -٪! -R$akpU9Z|cY˳8cl - $%^{XT @\[.\CL&u7WaZأTj=.lµ||ΰ78;&p-D\Y,' q:.!8x!3P ,)Z!_GLu!,<^RAgoޘu$* Y@/h0>,! ~O**K/Y2У\2d%ܭf`ag-oQ^Vå) k>D'F2:lj#ʤa(C{q|[JWͲ{]xVZ\tm^ؑ*fFD4%ZiHiD||pcEHWs  [1yeG[ݿڛY]n|t2 r#ugOz폻ޙ>0H ??yYQm]J/\1 =AB^k:h -.RLpDkphБpoNVE?~~T{tב,VA\B >Si9Ԁ~_~@MVJ[ :,!ƨ)[{4ew-? ``*'PT vatHQM1WB^7!,ԁ -vY6 aAG?84WtT1hLB&Dt GAP˔яc(J2_u+ U2lФ -*YSY|@e}UCmCaܼح%nykڤMXԦޗ4Ll3?HO&o=[8F(tWz[as%2@^Z]Tzj\wwPVᩜkqjl_W p'O0M}j[/{}l]7 qoA+ҕpX'wveOJ-ϾJjQvB„0=ć4OpJ`8).Na|'[6$p~V\7.;q4PÃz2k _ ko&Z?tqdǝwn,iK|o[OXY^ش _Š3~z~>wGA7TEk:gl .o[@j?65Brj؛@'ֳWgGc?=l/iπg؛qJKcO xIzW7{%^qG5^ |E_s`*ňc"{}y9MXR?Vx5ܠ22;^~v"nhē%(d6īg'yr=|!seWНFLeބS.]e&=~4x7vw H-!KC -,0U-N[M7~MvTQYE -AP%Lk+TQEq%{ە>q͚j+  < FnUQ*wFx#,!ǝ׮lBuQ}ăˮΦ/w]n -IĔ%=iгipǫRv/`̽0.6W] q A=HT,z{~O^c[ -^nT{%sg$^54wG4o_zYBV7{aX@TMuŕZb{F5J -/N.,oN~Y> ^Mb`aZ6Z̐N50Lo@pzp]BverYUݳf,^z4޻iVd[ZptԂ\GBvv(SՓQgW%V3I̽Ffy>]N?t.FYdPy{AU *!,0QgSo -؂X 6H.$âZpS՟ BJp.x2y"%o{}]9"wq{13y7L|X|W塝mjf|/w.BPg/RV˵1t鴇}s޸O+Oo_8Γ/^jqa'o_.bX pxFe7e[,: -ʽzXHWm>ܡe-:[I%tp"Vn<1S7vby/Ty 1OYaJ9guE<`K t:AWlҭU! _"en| -BTx h%'*OWoV[2jY[p6Rƚ5w֞{%;Fs7Rk˹h_xs{? Ԡuz0N.4h,FbؠBn*j0RhYEl)FW4BbRK -HvF+4FC`sI3tq9#1k j?~"2.9 Q0a -V=K` 9pKDPULQ=QJߜ+hX]bv" jp8Ub28{Tn@KxкҀh/4aML0*@3CfBue 1dD肑*T^ ΀ BP떅*#Y2J*J)ZM3ic-Ց1#eIԮb zbf/3= L3v įCv˯/\sQآ"f-Y+ilBT;BL8fEzFYT`<jp*c?ZMد,h5y!RN  p˿3 gZ `QpwKJGLC*v\5B{#>6q]N-TȟVUEإM ;f}I[gJy\m0{=8/lN 8wR > \Y)vXaUȷy"F -d[ iɍ:oب~m siiq@+&uxy'~ 1C F'Liji*,~SQ"o XS*j*+6[Jly4qwxp/0 c;$Bsv✒)6K~‰,v ADیae_JP Z8 I\֯m$JZVVnXL1_[AS) ؓg FJOk>LXp$6b !,Kd0NmUy]qDLBd[n* =ԅ 6tLSfFEN|Q0|aco7߭_`lā_ #Rp&nԭ/a/l9/Y2C{V%96Wې*w z.~-C,b$H`גy! -qI) SR<³Q~!@2W%EVqPmCw: Fcny9tAGH$*Ȭf[9pdFurNܨ*HS%Pg;<hlX3>`DUlBe*() -HhB::u/F1Z98dpisAo}֖םQnŻL35z4ux#u@Zֳ3SGoEOٺ 4>Gݏi}P+'9خcxpպ\Y=_ 8wU-?P#?z.~;ugv?>/|kW=iZ=Ns.LV%eցE-KeTqg39e:&^ k{|:A/6|'?.z 'N_ t:{gc/9ZwWh?+ŘhOs~|{89OOE?ux>YR"TyƂy G^ <2T+MuG''io#"W/\IF&BۧK>6]=,'yI %t:8+aN.Qֺ(YwZ^Lұv2a#:~_9łСի MPzmѩ֎C#24GS/ .altt3 pR/F2֘?,\y針b9^}o%0M^=o|rֈF>V#N{A~`m? eLQKo]bPvKe臍ƫ^~ ˽iunн]OW?-}Cw7\t/G_jX~]oZo{&+f^A?7טpi2m%LCo=u8{DuXj^Lԑ;{wތ3_xѠ׻)D>ǣkx2 eYhEwx"l9#CތN ͠7ε. -SW1|go5Foû/oF> 0-j^Uw81 /mf0ᡭ[0lԇ*:-s u<_ލZԃ8k\K94ӤzuƋ_>:t?yxAԜi0[M(8ٙ~z|/d1+ݫ3 v7^671xB' -Lo ZjFuZSie%jm=3;nK h ?!&8}c?4Hw?p `ǧq^kϽwhи?F^8 TEGBsÒ\C=V"rww, z7,zw?2_ê7CAQ7 na|@Z眒f%ine"dn^@ٖH9=+/rwx -b pCYqb0Cݸ Lh),,2xfY ls`\0-!6gI]*saWˣSV򐶅.kdaз@ݴ>>{3_'|w?(i[5GsU`)^KҹYMמh(&v oX .̬\zrRѺduxt3ִe=]j;i;q}?E[ECx: Ĥ׹faW'1e2U;u#V`#tǞ^jog5hʪ+MZW\5awh^:g=!dQgף)nH?.hukioO! M2}IWPx5иJ, i;"X#^fMnN$z^k]F![){,_tuȱ<+#Xaۿs&5ZZeopg)|}c{h]< m΀抾;iӊeޱs2,lO,(garvdkZlFPv-*iF,oΏ GwCth_O?Fk;3+ KM>=+ooI7^]; xE>9̖#=`DUr}tjx9j%a-/?/z?9Թ?;u}Ѹ)5Mq,P&=Jϒo-tjiuBEinݨttw8|EC.)Gϭ>\90/ly$ M2Ίf 9 7f<Ƶl?\7_z0n_*Z!9r]A(yH3N-,=h{rMs‚~\f]X:kW||gfKM@֖Iz|2d$e^̎.D]C,>{CЉWq](5kg.\:-&uBؓ2  :/Zst)ɨ75Yu/[yg~+ {;)rgII{i9 W5]4:wOړ/qVP -`7;hRn]pag#̒gK.)wd_4R`~^]r_2|wjj蒂 -&+F \ܬԨWp^_}է=K] +fI(uy)k6)EbKS WiRyONy濿m}RkT+/e""=Tׁu'19gh@>{8~%ـmlcXsبRTUOށWBP;tv_ |#&&YPlAƖ~] }9:zֱY5;㺟,Wg)ώjrvjґԵ*NJؑ!ÓCӼJ Zf^g!?:W<͵Z3>G~o* ;v{NW03N>@LC帿]>&+fz{ |gEYc.j]{#KW$-)]oNzǃ.`^1+.ab-52I1Vh͍Jv7Ww{KS,+sbD&u3 -)i{`+ C[ģv_bY -3uzR3 -e⡒WC8*??Œ )g)4@;^_ʞt% :g*Vn@*?z=ԙǝ]9O@KSحPS݊lt-ٱ`cjoiVz_z'~ߏT??Y&ҬPt fQ҅[&i9t ;E|J =i[?X͢M/ -Go$'>tơ5ŋoS4kPnfUd2ZO+Sr_Ҕ 6Woj7r4}]boKB4D5 -gZy<;N2i'n-N <->_[̳S#5D&j%> KV=lN{~XG͆5`@aQn+O0ٜq*QPKaRq -zEʌ}6 )J7ݘcmp8iEi -?[A{^go;@CỦsaqrXMN䏉rhSF%&X}99I!V;< -fM#h`}o̻ y-9E͎ *Тg$wTx\6B+fZ`fS|Y8W> RhEO"g]~O -_]4P?+cJL~Ձ;XW1>.Uߌk]&xHΎG3>+1# 囂+5g%3? \4<ʼnxJ%Rsoܡֽm9uUbV"Sk qsk[{|Ncpy d]۸jKKl723v Vrū` -e+cT76VΒUHO uiw^-zfD%B4ɯ;Ihnŗ+@6#Z1k{bڦo -H2<  !B8P+KS'a[C~f|"k V Þru` O<#90-PNogq?,aG:9pǓvܞrV0Ie,y%]! S -)n&cU[߿x`[F0/,ގB6 1y#0P0Ç-=D&8Ww_Xt|cuBw>1g&n+rl9u:G<y x쌢/WJB⾮JXW*/U6hXADhECbz(Sb*~J3rGThFn֡_<դGf&rٲ&~W(}63c3hsr؜\NoMshe7>|B Ԛ!`rl73o]QCgJ~|gǍz_09zz]q%5gTXi%|KD@**1i=F[̐oKc_us~Ƿ`q\d7,^Rd -Wn~q@ZwƝe#rd18_:SGr^wYu9TEM /V 9SP8%[}fzZ^/wKkN/hk*~ȹ/!ƕƗ>W¡n7M̹nY2='I --Cp䨖JiR}/9OGAgNvG 66(fS\6fI9sg쑲C;0+tNs){VT&V紷hw+ò* rG@T. :p㦾 Pci^%hulm=9UsCe50/lTA&8 `8G1N-M0mtQ;z2d.?@y0d;=es%_sNSsBEu:0΍ -aAlQ Sc-rҮx릸:Kz$ A&{tqCnUIb&+t$g<'+5kܛF1ŪR[c宧Q%%+YH7Vg_@ᵸ -vO6d(.ezl',m<.3kĪ;|0.3q\'8=8ޯX`̒ -V[8 HGޖo C@[(XIG*:w.] )n6RfJC\,6#_aC[{o//9M(t$fT} źr]>0@\o)l~Xnԓ;޶m;XR:xtޝ'(UG>+v,q+-PJoonpZj+5\lʛ:90e0nZ8Ch9'X.z3^x6(ͨ{VX 7L Mvm U c&)m*#Y1vgW wړ%n[NGjߢu}M4Dbt`-h{wa #|q -FN5o)yl9*'Wl.l;ռ|W* 3$5L* G_G'G$kj \_- vuI 87Y قY7ŎR0N'wȋfFٿr;]o#߉sn=0gr^/ԵΨqncov`O2$M7~!Ey}o3_Xr/Ӄ.%^D{34_ n~':wk'^ -r=5:[1qk`uűKz? -'Άps6$D<`r5Wn*ޒttNW"v~YPw`W$)F_k3IKpbKmf &OĤEr;-z -D_D)0@m09MȻ.KzYV׋mG ֋RZ1(2Ww;lʼ&vS0L+dT^'a`0S:nW9ףs(t$}jeȳCA ݽxWHR2*lh+b'2sUԼ0:]${18l0}%E\[[Dq t dKR7>J)/Hԏ yV_^j#9`4Z<1aĄ:x3IҲߖ.˓\5oh@h顣;Yz IIߵOz5 -Pr/0,y! U(bرcZggߊ*|-u.Kf&1̨Sb>Th|?@G >z_lMY -G]f`t:g{?ϸ?K?cފc>蕰`[OФt֘|6—Քf]tO"u2:mOQiZN@Ox6wF+n_O4۵?~?w׽_&u\IKGR' ~rб#8e7TNf;&Q?^}>Yau>/b8y93yuT}Q)!MC%5: ]Nidz+Ux[Umadms+f(㘹9hbf[ m -a\g9Tg54ܘKbnjyF G9Ә df i[,ΖH3 $詆XR{TcTҚ)UXraf#&Vֺ3Xe[aL5vk^~X{gNbah |lP|au75lޫ4ǖ[k4wخdMaI뀝ˌ.J>^Pj*Rl7DWZNo%^UhV-ʀK֍sP&՚L?Q%eiZp*ʯqn֕(6T<+W V+eoP9nvTReX[*K͝VW:L*vtRsUUlI*ZT寊SU YTAJը<:fVc(4jb:ic uBmjh?+g]瓭ZzZZ۽Q2FW1BM9mֵ搶[I#|.flYӞZefk;UtΩ˔jS]+ѵVnpYtswǤ3Cy 0uk>_I*VkZhfy&xNig-a*<|ԁ<&Z3u@px]F y0ڞc$\XFn607/zϻad0,&w74ʱ禢ܘZ4R4j:+Ƭf;)]Ϝ9OeZ._ˣt a+\wFhG^;⶚^ ~>:Z S -gAik3zNSJ-o0{s U.Sv}+WI.wo7:Rb@gERl!R s]HQԝuL[Y]<[A\rUd#!xwCH' -PqMu.Ϻas*w q?\3af?_%~ϗ##LF/j+lјǡ,:ݮ1l_*v֢5F˸.*m<ǏA<BD̞'js61}RDfKV+o-cPKڴU25/,\J9QGg5.O)o\ 1T_3)&1r4Y>e27 gbOћ$2?1k؋Le~vٜsR u}@_yɇBb)YB~h,Ř;+\bq"K(^)/!֕ˑ|]\KK픕OQh*sPx5T^[-65LۨlqmP2T#zٯ/a4Ux/otkJXAhBsM SiF([y8v?Ih/օIt~c.6Zͻe>ҭ6i9t0B+Yup[ -M?PJ-7sV JXw>XyH3z3o3sNA<3Q$lrmtɔ+@\7hW'⹩Lj'72ۼV&qm 3gwʡn|IsG0Z|=:#(մÖo`Ymx\9 U~y`}˓O˴/2Od̳>G`t.llohTW~:wbC;zeӎn9vڗk΄e;:2#sXgǨ<ɠ8'khA8YW*XWCfSAϚux‡!rI-x<=(4&~‘/ b-V63tMa׷imT"˳~;r9N}uZU 9 ߞM{37y\h1SWc߅1RpRP)}w6{E c4-2jקj; -ﻞ -%[Y5j;-~#dd^kܰ%oӈ0<.,a0DlĊÀ9RakC =wv rTsKtkKz_G DIhS?Da:loY"qIS+=&v(Q` *Xxm&Zl~M,Ht0hDpfBhNIaTPϕQx,ZT ٱ[4&1頉g`ő!QRH$Q@4tThxdM]]-/&ɄSı^<}_v(˃f>|8{|ŇOHX9ӑ} v@z\#reVdG(Ǧ -5S "zjׅifMG tib=0nNEZ\:)nG'K{#&j;T=]S'ɠ|SuHm9{l`o4=eC\AKJCOw}WB \Qoʶ - ` )'o_ۣҮ -&=v#4:tvD8Q%5 yIaiy6Q`Og$F[hcSVu+oD4W J=FDDx5V.Qdu%L١*d E"_(JO3d2&(\Ake+&H>h?p:[lZ!Gxѧ/(?Qe131/H"?!Sq0.saGsvx>0 |ۖ3R]3ҝ9iaIÁ(@3"f|ȫ_1?U Ʌg7QQLjxOZn,,ye"ą!`j -F:{u+֪K>';K ̉5EB'4PdWr Zuܯ~c<*ǘ5sx=*!AW " Z : WҒzm` -`@kVe^q "3H;ԁ\[;2>R*; 6$׋i{-(u;϶O$=ꈂ[9|3 Eڵw'QnGk9xcxzoX|t2\4Ļ5^3_ LcȨX'\v,rkv·^9vz G] 01(+ZMy-9Oei4_Gk4:$fIh͇74Zs'n{$Rqik?$ZE{ۑC+jrNm37)lq'$u$::luz1KR0a HnlhWNo`crXV(9$w2Yh-–KaaťŀnB˅KԦ9%IUwB 4F {$F1goct- Ut] 4A "zG _I#:i˺x C'c` \t0v OE]UcO1t܄d 7EF8 Kґ^Щgۅ cHa{$euHoYR._䆘'c=Sȕݳ<,,X9㉦z4Lեgg+.v@st b,oYF*Ş&$>g oǫоTBCg<)+1g@$?"%= -"-cĒA^uC`S kQ|1alL{X(OgN/c)=C~ -gn:+(7pcvH/'L"8kIR-Inv߱5;vg 8uĉM Y^|DA0x|J*TC4eC6nht8>^S0Ը=ؼ/[=%O/1xc/}E$'iF$K-x9am!P8OhuOW"-q`e8{IμnsD&0,\jXn3-i ldD/WO!; mo" Sh@Q{%ʯ'|Tl8bّ" Η,WȉkqD?OFzsbO${!!ɼޑ@qOq"+esdcșW#2R].&g;*SEd8]:#2vD6v>C׫EBFt04^ 핈(Z0{y;"Ah"/<>O<"# 1ch,#,c9''< Q8Gѽa 9++khԅg[4Z)NG%nqrODp%U,I[T=#usTaP<|xw8s81x7{'!c} CUNVx8N#`ԍ gC]MOD(,>{DqR>ĎuRp{ "ٖ2r"Ac}+q3΄l|œ@gt‹:zËàvأV؋P2F/+a#& i -=h٭)Su#DSuंxB4E'nFȺ[F{EeZA˰) -ަ%f|bmh&nUCH)e`듈' R@JG Ra;#Ra+@BkYy}-@$.Mdt2?JxO47CP8fKn]1,PC 8N"A(ܓLl|PL@gI#)7ABP 6uPˉ( Mft <\BC#y*ݷ<sp3K -.AgAKow9nǮ=^x Rx-C3f&-`:fS, f3 -._#Nrq,,6eSP`7X]]!윆/)"JQD nKh*u܈:΂X_Z%Ze啋 lEu -^ ֑-p!z|8N5bDGDSc[фJ(r7kB)7pZyĻLeWR͸9bo*K!LFpamp]jʩ3"SO*1_/<'Ót֦ދE (hd'4PLPtMK6M'xG Y|M'ԔB^@I(~M'tNp62 K'x2N("t/{h:[ch\}M'O6=C u>$NKǭ 4Gt'F=nj|MM'αO\4<ջh:! [!4P C ;NK'콾  /鄘!M'DrmS;MѓOM1Fwsk'yB$z:qdX-GHDpRDғ͖i/U]{0JS.q<FOnF#r}k#=# c,BwcxB\3_)sLàBwoMy;JF;9ٷ1(NBwoQ|?(XN>VI&\#/xc=W, ,ONF.BN4P~5KsY*O ԉ'qEtO%AxdIto?:I %rC@GqPl([$B@>~(x8we' -drua%2Ƥ7m)X3?kfOΒlo*+01,eڻDYYRvW%`=fP7YފVɔC97dJ Cl6 u]hzۜ@HfuQ -N⋅xx D ^`{=.C_+wo[-Sk#hx; -wVRP.I> -w[S_0#/k ߨ0tJq&~|#{P;YwD>m!=oG^8:Fqe(\R LIbE>dRJO17.$5SJ$e\G<1n]9jJ{rϭ9X)5%?qo#rVF(W¹+Wbϼd7ix<\Q) ˮا /^v%q>'dTTeRcIۮۣҗ$C'SM.{?˹%1'~ρ kӥr~_vaħ5oO g=>Zi#jo/̱Xbl>И=9'ZZiBV VWQr1w/(@{>d^E>:a X<\ e2 -P.Pc%ʎU{_B -ȥ^l)'H|Q>')d)wWEX'CωvSE`ȓTQW(?;5-{ PՏb$䒪P'4 ū< K嵪{wCI# %3|gIWJIg(tPPU?׺~C_j]?a b]O|ª~W>/saެ'!WBa@XOE ' fA˭>]N]?ުwkEM' EXOP_U8R]譺~4`SO:Z~+SՏ{?˸ٵS#ud%^/x{W4~,Vn]?iK}}(u)4-C~Yo㓕!{o>POڗ}{c]?y5_ \C/nU7Pi/94I94~&ɪ~/# -[j?{ +-.C~ЯI(~tX>̫uvȱa$Ɋ[r9&X/~ut ك;%n3gIb;_ VO{u^aZOh&8rеrIJ{u7.-54߉o̾ ]C;,xσ-Bib=/&/{Nf P#o絩 3%pum캰D/A x~;_l -^Ϭx㴜MoYzknXYVg}x<&m.pe+4'G Mb;u4]J}h]`F]V{\Ke˵Fيzf8}MW v1o4%tUFgSmy'CyA I%qJ@2uq!fVcMrXxceih]8N'Y7>ʒ3Nb5!Ԥ׆ (.*"f9Ncƃ -tt22M]THF6/p #*i/xڞ0/ay@n=n[+o{qՆJQ|/\\w0?MpGF_3dZ>.Z>gf͜D5JdsB3FPL)gf?joЕ^8Ϣ|}10a*>`,Dr^Qh#ɖ*0l'NЛ"]є4k+&T Kr"5+zWKwQ1IПLn`fClO[i*A훚&iTn7'~ۛ&x)ngHT8 g1OHO{Эa̬vzl|;7"2]_bL;+"!hI|4 >_zmٓѐd_`.a7 -[ZQ)p{ʴmh/cLndcpuXXy2ϓ Vfв{ $\2+Ѿ á7z.9Zs051~oJz_ȍrֿtɱ%&A>gy例s5z+<܍uh 5 ٥fmR5$Tvd+^ clt<[n74_#wRvDr:Y=VwJY޴଴ˁAӀNC!Uo|/&" *+&Ϥm"i\`l_"rӫVkPs@6b0QM\%^tfȶL8vmJfbo RDѢy8&jC3jL6¹ń-;.⮝xs,[}[ƔBcuc[|%ȶЎ9vdh -I"j)X7b[Im+?]h[~M}؄=;m"Wm;S8G!5[ޡG}3P4Oi\Zb!:)k|T09v$k+י{󀸥Y0`XE7ܘfBL:XL+ ; `o֬(dH(" F  klX|&l$yi]_ vܐC,Sҷ*W&PX`nE?%1EQ,ؓI -t/Mׇ15{@)l*%A}g;2 w$؄LVB": Qxo^vRɢlLDq` lB*Y$2Bߒ1Nd, AWtK2i0MfiAڒ0X 76FD*|\tF^PJqOZ8{{{VGmwV{ai %6<'tj#6Dy6&L&N<Þ\@[D-%d}6ĝAD2RgcL.B,JٍB`'1 e'Y`ѡ{Wm*7P"%|7|IOwʝ -,;u0P43T+@DRx .Mg¹@ tv'z H.T=`~ѧp3lhn\VR'0RN3uϤi#?r3Y4*z ɶƽ \Fͨ!mi_ `1qM9f&jTKRCzhyI a#+O~wSQ91%MLJ3;w]n= $bo)6d/T衱Y  `dD?UjNn%SR4 CFmFvܠ/' 8h-Vf'AJx2-.a r"m0A`  ;##{22)Y/`nXCGzŵOd Ӌ9f, se'mi^i#&V ׄ9)ٙn&v: M(X װn;8s@ƌpӴ( wAc]x:Ђ};i6ʅW&f{ a6d鷵BmCgwΧڑ CBaLT8J|aϘG]-[$;mznhao-HJ_ԵQP_T0DMGc, -_rok,xe Ewwސsͩ FN `] 󊮅1¥۽k];@ǎicuA^ H鱴^mIGaZC/m0hSAڐC=ɬGc -Lxt$^=Q{:d#2 "Ёh!15[s2^]F;Uk%z4ogLInpg|a˭PY֘A=9&- -0-'mtzw:ȵ٪?Xdk8@$#60^Juh %>ӂZO>=@ o]AtK`)+i,:Bv&~W#~it9ⳲSUٷWAMu#e<'@71ήb} -2z|@۪}Ҟ7! !6+x={ -l_]n[=@֣(:QR\sjpD%祳Z:]t3=/@ 4Qǐ;?4ѴH`:펈Vx|>⟗ lfv,W?"2lV3\??[d.r6Mg̴GaeНJd[tR봪suVh`ƝzN0}dvzah]㗤o4r_|+A[:͑]YS!,AB@ "^uoYݷkXx>'W>4_u钭|z G/r[$$EҖdcZA+7e6;FPfe\kޯ*E!XU_.[kIFIXk{]X_ز_p/4DN+Boc䳟̢_S7X1ν{ƫ>"v}ei+z/Nwݬ';?ɏ݋?]l8OG+ lA#bO?^?t7/۷xL}ޅ^.W??Sx] "2q_f-<*; ?;GԘ7[7w,?6^{/=F'R]yRVB+Oʊw!ʓ|쳫+Oʊ{RW4!w`ܫ,{rB.g±o&;*$ކ_mo۾fsmem#omƪ>W]ֶg&μ M6D?o]vŪ>[4LywYֱme2o.k?k; ~/nϒ ~ݼرϘ}- ~y -y_dm%yۿ!}ͼıϗ}ziށ+oS>sVdmfiȟ)o.kϚ}A1omᖟ)o7_7o.k;Hys.eP0>~&1Ɓ|{As?ż a#&~߲T¶]?a3?|e[$ِq)_$zXӫv,0-lcK=__~O7ohmi]_V@?÷ڷo~_~Wŏ_~Ʒ/y}W_/Wo~O/ۈ~٧~oq8|Vouu_~~?_|އi?mx_eڟr./~?s'2?!v//~? ?~O㺽/q\=>|a^m>53@S{о˦} t3y: v}<㹼/|0,o}6x_]VY}1M> -9}mr˴ {{i}0 >NK-[ۛs|ѱ6$x11S{v~ox߇e= Oò^Asۊjsmgq G|?>pk8gy쪵mҖe}VܶiFoܮ>U}]]nXmTtn0>Uô۷ ŖaǼW7DqhNv"[ⷹap*Dl[6LlhmߗFVۖ.vXm;ַnNta|Ʒ a8axZjq͖.>ֶc ?⪆8/҈hT}s۳Łm㶶MdžA0- %?-kؽmc:3Ak817\NF7lm':m }׺$< {zWnX8FCe6'Gq;6=|,Ʈ.{;Զ^fZ ovfX缞Ι@q0!0p9~2ov&cgmѐp 6)-9+l?OS@ -{O;?X0}#d,7uڏ=8px7`Cj 6&Lúv];G!`ly Vl^7ӇI46;g,dNX~m(<}v({P -Fߡ/O[4llX>OtwۂinYsXb&p v7B wa/:));`ϡ*}jJA93m jXph̽saԐ*G!h  ,lo[T.@;޼wGpOi0ح݉c^ 7y@ålÚ7Ie.6ԞƉ= m |~4WpiÛǺvll43l?9M!U `,߹ ,St vn lq֚y{3v 11?Mےc6vH<^n:)bow۰v x[#_vBMmCp6\WoHӝ,Mu_\133)ɉ( xwc&,env z2ʼHZOW?gW5黎>467 h\Ӟr>Ρgy _v)ck_Ѳgl kAY 8#nF҄2gˍsÀݶM%@I6IHi;R0 f>F7fәsto<x plvhݐ~%G&07%u_n`n#l iuѤs3Cl1M;h\&ހ0#Ezw)_7VFJ?sDonBW@rvX'Ƥ;0Rh -sLY)(a0:'D[|Y8ثb!) p1?Uieh}º^w7\߯ysj&@{c̍Y'dlX>fc2ϼ6ID{]Y Y)Ü T8Z0a%G~F5)ѽI1r5FؐaÊ)6fh% 5N58^qEbevMJ*"sUVx޹fŜXL9B$kL%ΞAxVמ7-cQY^->!HVBZXGg/ _C -@r2P%FςleZ憛7ɑH" 3ZԡIIs$gH7<mIb,{zT"L3)q}NE;Lᄻ,(,\[ (O3.l6)g/~Ȋ|pYb^uݜWeDj8B8<޵£ --y^& .sHj@=t4š̛Jx١i걞`[4sЯ- ɻG/~5@xH`|ܾ+&BB ?aqw=`E2toaCH$quDZJoFGVOd!0!yKv5N:ɞW[VXLLs;aⴙwmWE&(lC9M!FK#Rw^=Keuia9M՝tԤ0m':{;}a̟Ku )JK)X8&aͽ&ah-`};azbȤlIkD݄]h,BZ} ]Gᬛ_|: -ƴ'`!wuf k/}F?`#=3SlzX.!I3ʝc1>N*>58 .'$ (}[U{O=hY%z^XPfu 7]7 7;w{fZ$CPOaJ2=j91}J1چ>d괦#6{bwa 8MCsťV: qLaJ ݽ_l ,E8nna; y> RpK$ERQ44I[ qdTRS 59=RAaZcLŠ>rEIC=i0<:I bۮS5™9 -aO6nnYZHXC{xݬr1_11bq@ܥ락5fCa.BAa#]7Ǻ^' w[\cYi®z]j6j% -KQ5u^>%Ƨqb= p^7R nG?/^wLoNVv0y†EђeX#He(c~VX^ $P%͂ ΢+O'IFf̑ZN|Wm#@d;~Q'@&^O9.aii&tPSG<&~ğ;<8L?"Qlos#{ܗ-eM ڙ/GuHo*$vAWύ9u-E)k֢[ -V"%((̅ę[d؃I Y0D- -C G0aU2bh$tPLQQT&KYyPOyzvm0ϣx3^m_37hHv(>O뢚ojAQ(}v捗((8z䆊`*z[)x䲑ojv䲼ٯn+E-&*P0]=0zE+ʖ+J z~wZAQC[j4jQ5MN6Aٺ?zwXy -ܛ 1]^BCybn5hQ;l-; \oسH=uKjZ]u͵cv@1uε{ r)EVcUK!-}޻HI<֩{hoVZZJ -c-zwt -ZL&5&V()C`?`3r"mYNAgRDi]a$8axmhB&D1R5M ܆f//B[o1YBK5m2zIr Ƨ2 '&VŴyUChYH9up -,TxӵOxIɸ9lV/G2S(0<Jf;cyD˃:aAL,zT_}J!9.=Ip3k*RXױ.9oUqB̹wF^ëɿt*}4f]w,^--}=?!,Aui4Q-e0BM'j,YF -K`XonsCUY6)y6;jX' c6yDH||>m^yf>)ZwarG~+orsCz$x?}[ERa<-5zJr8G-X{(+]GZZ$% d0 +v"꾣-!rf:m@& ś MyQ0V ô-itJ',3: -+pp74^V"#=Lcwƒ C/-s#^GXZ(Bb Zf=b5.jž?*ƾJ hvn"8fvq za3SEk- -dLnDmݢ ZQgܻZ#G@0XSqӗ񷞇3rj-xc`.gTo֣D鞘MVТo^EyC{3l Ʃ02Aw1>r@Qw_LAiӊ_9!3fwBE邖L*oirI0|+2/bS6+7ױi(\@q@K9 s. 2zjae2#:*K5{>X&S;I5PUA*2/Ћ4{) +A< 2z -r*z -~BPxZT%`0`'[\}ӰWĺI;' -ױ7;l,.̇yk6,8ı-f" yKHy?dJXjYታ֜0~(jްՐzi Y\#Rb]CYz[l0(˘-)v rSC1Ί6ƪwo)zBm5Kyk݂+ gM'$7^W3%5{:2.S^mcSQj$M痄K2|Ƚ 5\Ӱ n:=,xW:Yp>J`͔kWW^OW*" -TBK,I@d-khb -~V(18H$rCvi\|l91aOydS 79v[0!$bGop ]NuLQob9RR `# GTxOUZ 旆 qN1alFWW[ǥn\^&do}vB_|IIiЏaۅ!GѪW31.XyZ$:ȽUP#h8ue~ -_Y`wL&>wuP/ލs W(p6p2kb֗̌ ^kEiR/~*kUO9<Ғ+ڗ+BK@QTD֭6Е&7ijX*$ -݁Xn!r49,k|pp)P{|0ޔMD,h+=RT]IXxfiWd$ӷ$¿=jG};$0oPMa脃`rSB`p4ã,T,,EN4χ+07Y|4R jALcC$={Oxţ#3T1*60Q`KsЦ 2at,L=ޮ5kxcp=V(Ǧ7'AO&*DEE"$[%~+4( ek#:Q!n(恲(A gm]Xre߀k0nF[=K,rƤ[e~JPD 8RBդrDH|#/ħTF`Lɬuħ 'b:OmdyHUQj;:uO܇ tj;> I^OϨ @PG9&rH{z}b`U$\EYqWVڽnk|+dS(DʛFg9XHj<{$볽bծ춞\-O+[dom.ĭ<},]}^4:T"K+N^/Z7J)?wQ5|L#',B1)ֽ\RI&9MURm(Վ8"]dmlaZS_K -e,9rkL8$ -( N肈쟠9Mebhݲ.SF OFEkFo2x h"[ hu:DA7(~|sCvl2rB_}f+hЬF$zEڎj"-x(yA֑ ( q&6 `?S_\;]l(q@d[MBXvu ~ P!_0_k<*lqrI:eK#6c姳SW+B@kZR'O, &8erfL᭶ZV),)9)i}@aVvq2\Jqɠ۶m$ZJۨF͢jC5 7{ -s@)ԕ.[.&W2CIgqH:gsy*82mJT[>{*"%y1Á x;چ0PrXh{ ^"+vr,/:AsOr/i(04Zcin|#qH~J?L@G - TA-GkOG@m[8* 4bϭukƙmY2jEզrG1;o3YbzŹ{B?=guF1 -I 7}3d5t,Sm{Vk4ۊXnu0GסY2VC5=Q+ʚ|9Y'| AH3;k,6YcMu9kqZUy­'T5hGNB:m)C=;k*bJDB9ǷBMVJ/CD'IR_#-/8OE(Dzqܮ!2Wtg^Xĕq'皌( zoGA\̼Kpʹ:k*Y tg#8{ɣd(lTluEEs!pNX5;C9}~0NU39ϻEg!O -8 -FOx !9+-ni﷎M=Ee29%ض3MPYF (ŷI%MC@u_]:V 6𥊜iR #i>luԼCޞYd4Etjn'>5 ;\q`Ca:; Kg]̇^b>+^Z(/`fԱ?;} i~UGP< 5lV0Y;Ch(u:Pȱgo@.dWÎcuP.=%f9Ws,9̱e]73LCu: Ht ueS{l߸e*q1$hFyo{f$UovhEb5 4hCd&mg<;rH͆6^T]&^}JPsu-/y(ZEv+j UT!ɺu -5fzH\~NR%boZxwB]\Ϗ/MBEESxJ?MrI){DӧOLX_>WUVN)Ee2#il+)GtW~FJ-ULEgz]TdYG}6 -){fkPTzY,H׃W2x(Xz-Ѝz_:hGbh -tg!j0ՅJNCP-'f *f<&󍹵tV.y|8,9jn+'3y#HDoYJP\Kz1덎+Yj{V6<Յ ^p08j#[2DP}!jƵ~>6Z] MjejF%@3#iXw:2Mpdd=TQ7sBGwQ^U:}:}O+Hx(Dէ* ( 20x|ձ68l.AheBJgNmL(K Peu!w *6b}-aS/k/OF.6XI@E+1Ż˩Ip*(OM䩵3GF\GfVK*YH.%YN[dNLۍT9D%JJ(:+$TzyGLL:loN\U۷4O{0$8@Ev%v1J."ywځb|~ -yi:wI~r`D㡄% -rfTft` F9@he2&!\mjv%gi~GtT\Σ%UށV -{9$ *C-B %F:,%Z,]:MnzKP6Tđ&5#t$HJnMr&wŻ*18!+re%i岔)Vœm`xi<4ya0tײ&Z1,IbFX`YVX̲ypJ*2M_ -iJ*U,ݛac~]_ѵ疠|;bO!M-ae|̜IH%f eG1u8;#` AUń<+fMɮjoK}3餼*Nu%V2c*A*ѦȵgDﹻb_gj )qnEɬ*!dy2靠:DQ9hFZ P $(B,0"UPf䝐RI]It'V+H[D(Uܖ\7tHnlvF$y'VJ#j؞rddp~gu\^Tv⹄?3O37~Ly+P0 DNA*5w.Wm`[ übGT&)' -(zR/0Xy0zg-1$RA:Z ԔbL'؜P[:r i&))5³ %v)(NjVDl،wg1LKRIFKFAcMsj\B-.셖".vL*=]e3~i)j_bݾ gd“ H2;&.1/HCIf&֐9GTK~/  /}#M}(} N1eQBc93=C^Q͋ȫ$5V_\d1TiSn6tEֿ.5 =[|CҤܭFѓyH3ox}nc4m;Uʫ&[Np瞵_;E_P.Is'zuT -Z$-]J;ko -oA3O78CAּk9W0𞋗~ AU6 +^5PE -"li]fO:8tViMoh׉\jr`eem"yXN\U2f| -"CEbKE{”U!{TE~AfWwU.C]TlrQ5u+tİ<1TuL`.hr'EdrVySM.u^1в2V(?CPR&?l+I HuE{QInD.1zF.&ޓvKPe qJ#4 Ri)dRRB*=Rþ0xM~P#9wBawi;\wBax Q٦ WZ(d $`t_Y:("^޺0+JrQL[9$d5 -,usrO&urcĚOgR6t5$]BzRZ8\n肉kٯ3 :v F M1Uu{0[X{<#SRV$ɑdE \ #HH4!`=ɩI7jSg6]ۻGP<f{ߚ-Pf]*SdyOlIN<*Yt$V#TMx^2< ҭq}a)x^]7uZNu5/N=!r\WSY/TiB2SBJ"F5qH`r="{xlIFdi&qpk)_9AR~ܙX В<3Io=NL衸*WAx,93B j3rC1!O|,n38BOܔy)a$)A48&C֮kוm?s:w8î{}e>Wf?lU\zyTu÷iXRaπzY%##KdASzYa_ZNByWBu -*sH"[]W]k(cN16yEe#8{0ywgt?Į}֦dX`0mGx~.m˕ a9VkomPY5Z?BgVF AլUfnX5;qQ!mS>'m0!:I6EW.mfNPmCwN+Jub&d&'`ҥл١Z8rtz3XpRGV#. ?6;Zcm4`R `^dv9J񄥵P>b` YM +; /ʨujPbd<1Fo^>傛ϱ9sLś3J^Zv}z:s»0 ierвxxX^赍~5M {~NAw<6z="K¼ D\7 ht# Hxd/%WU#h&Me)wMV3%|\F{Wojzu9ɇ!'0_uR)֭ aPH؇ͫ fbzZ=DO1/_oGW[=eB6ŒΟ*KezUcلk÷N{VG?NE!!˷=:H[@!6< 9# aN;$"GeS;e\LY ,k`qkj7㣋E -LS7)%Wzgm+ͣ۶: :-~frQT /Aq˗lGSQ֩x= -)mx L|JMk|DOewg:6ycF6. FN}Ey󄻥c9bVSY꘦qCb4' 0:k4R[`{7 vuQyj: I2}DιM5Gkk"&OteI,9Ğ)D-LG+M;U(1(UjZ6u2e~MvS15t`Ĵ;=ҍ5nK+F|ߞ`ma0y \iaBeb6 .x(aƷ M6!kQH>^Zq5N~X~DMUR;퉪Ÿ$̝O(K&A[Z(͙M=`~\k\/lFt#h.2o$JF.PI߯#,pE+Eƿ,ާX",,aq\mkGh2˱mHQI5ts~Ѥ()PkV5SEO8ȉ@MLːe= L4L7mLBu֩j)yz˒Y]i &6 [ד8 6*% %&r>jIZH;X7o4eppͽq~\5h.MTf-AQmy7S0C9z\7U=l:/o׸9NhDIx9sr ~ԇ\J$ZZܰѓh׌N1튰~A*m6n'i )(ج{t..q~rRY=Fh'E/.bѺ]ʊLI$21?A21dr2$~I878L};, ALPRJ4i\p -ʼ#0It4itߐ6yC+w vʭ".q1xARJg # -1, $<)RwDk>Lp{5gN̞A'+O1ka'f|PG&ڔͮ.zVYY IWʝtn0v1;e@5K'⦥̏!Bxڂ2% -PA"s* G`Fm -IŒÄ#;GqX$jf` XiM,BMs㬱cup͊OZm6fWm1E`q_R=4&e 'y -cy,[T1d|EUƀOXxeyVtsnQݦQqBNJL=$YVOÔpÑAk^w'l -쫇Pad@$,7DzFY$J)VY,آxu&R+•>ɇI3(x,@A0=VWXNB#[,y(z[L7\Mׁ,:2n &T{nFfÉ挍-z D^pM(c2Ϡp>Y`ƐIqt!'\wSP<[4>|z$*-K4WlR'Z -Nt@ bn=VeuވuCYBzN?h|^,x)ư=<}88T/b]E2(PFΕc6G2 ^2#lqWRLh$ ӹ z pl2)8[_Յ - u"i0Nxe 9T2ndEWc=zd6W PYdEiEWQ d $?3+v.%lV]#Iyu>30Cw  ƙy V/(BFd#8-ȘQlI=q -cMƅ[gb{ -RtA -l6Dm %B45RW:j9|ĆcpKQNEzAw>5]eg)(C>ˣ:]XA:Q)Mn@AoԥÉ^(VT4oŽuF򋗖IMJ_O?\_K/~Rr\劖F{J-!0U6ut.H3 %$Y'GŜ%=gBɪ1( -zѩ'0Jб--wc @b&H&WfΏ,f4َhr PJe -sYe ta[tfOyv1 Y[QQ|&>K.* (裠 J#("4fgT@aaskF"j"/ا,15"R `m*x% qXVHKhtTރTtE$z"ðҊ`-1)ypxXX˂-$r**{}Lޛτ)Er jWJXrLIjH*+zm]oR6+ CZkeST &ۅn(y\HpIR{^bTRd襧A?+# S98o9r xp0 -Nt %Sҋi,KFnsl)+CQ$a,BΌCrROPյX~ͫX1 ٯyMmC&y>(tQ² ZЯby%=V0r_1鐩 gn5X=˃%He/"$ҼO2r|،#Wtrx_.$ YzGC󒃹Hm|Hf]$745CJ47Z^=~eӐ -l]'-Lnk -'h$ D-ݦ%+R,J&[njzG#DSYR ,4cz> ژ]t]7y!T*c2Z?36l%C{+~IRN_zI}ζՋsHW%@1~OIF MH#.L$&EHm9az2$`N$O=sDz -_T¦$U9A<@ +J@]A?'IՒV@6+.׭Z4˶!fb\z]2}$f&JY\7J^+ -4I98h3^$O}R\(UXթ^ld)ԴM^Jx &T4Xam,Rp7f0츇{t{ЎۏVx! -m8T>N|Ŧ8[- ~D$԰՜!*Ud=ޢe4>P#5cXD X|uɍ=l W8O*rm"ׇkʮݷn,NьqUTC\P ѳ)q:hʚA&~2SO ʁdR*Tƒt).)U֝zB6G;/c7H>B24%H-WXf>ryw:!_/UP ½pݬϧ5P_XyYtr^%է0VQXYϷ,Ma*&,f={Jg!kMLKU:0v F:'$LRV:m -K@|ĥHJ -Ҕ?tzJD`9U%ѹ*'¶鈄/oWLWl0mh#F@ -uleH+8zHihϑJ)HÐ Vhd 7mn(Mxxd=?Cõ+B0:˙Dk׭S:eK0V: ގ宛rVo$%: %s_jS^[L;KNtz3.G'j4V2&ב%:nQ#*roxK)|u(HlW)>f`(©O$WҟEeVnn05U,tN ˮ[ɘ(A-Z]f7z"^_ijSlgCFmJyF =t ^^$*dH;7UL!Ij5 p=ǚ:ʲ,击 W7HoꞺZ6$6Zg e]L执!Y|.?DXx+GG\) *n{1EUaɶEcy6*(󮉬 -K+P#GLfhCeȿQ|sC'}e!|Iz.d&o[ɡ (]ev@VMHy;)g/{ -rZ$\{7#]XnMMzFۍ_]7[G$)ڔd+,%yn2AuurleB֏ՀBO+c }٫m褃cβw` 9ART-X&B--봐j8;/G~Y: +rZ\*Z\Ս[zXgѣhytc3j$>z.zz +2^ uP>tMw^Q]T*TN/^K" kF>t%?c{ (QzGDӌ=nql)=FqҾ[ؑ2]-HR.jnh>;-)hjL]ҬCTKKJmҺg6hXoc6(M+a[v I,tfU/:˽Uhu~)aQLn՘]N6m~.}[ pVK"[BG<{ٛ=0 Nv@@Hy endstream endobj 156 0 obj <>stream -*;Gf=f+~(L T nMGG8gPZzF}{ݬQڔ0FXyx+A\[|}BܴƧMS®))8P`,ŽzĴ~h*+y]^uNHMO`5Qn,;h!#X},۟GNaCDj8?&NoC[yt7GM`΄CZR ԼGB^Ar -%&.r@G>{ui$+lݳ1u5% uO[iXiKc;ٺRuʶ}P4Һ#xl%wiC;wc4 -ӊh* RFǘ3|>'Al^s~ !{Ņk܁ -o cQ:ZJշ-3HM\=W.@cûnB\NvˡS;BJ& -lah ;_ǡ>apy6܎m0w5{5>J?Nw5ܳ(G1Ojt;%{Ox:Ęq@pCǔ[.r -S?-/lUC񪽑iYe2}m:dyx@t/,4ΤWͳ*Vrd -1|b6Uv3<m6fOzr}4rv?~t1ez4 ,l?V>uU> GH|^1˗5{XBhsP|*|c/"%o' -L6Gt1\ pZ(/%Ƙf売, & :Ssb3ZϗgdvZ,J3FNwDFXCNi}]Y -yݱF|ՋZ7~j":Rwȟ&'Yi E[!K,Ѧny0x% -JyX>ux Ҧ-[ 9G`ϰv_dVt=&R -CzMd=)l9=x\]7'nzzmV^Z] -3O+ 8 ?,# V^`ƣFbu\)3mۤ+ -r1EM+t'o\#?}Kb[*B="u-yih'>O/0|w?4=w7d[0f0FD4 ᢨdVUn «(g%`.aS`2ُj*! -KLD\VUUAllEXK usމKtN7[6gcSPW3.aV=p-%uuSS~ -KDBt]ᮟ8 i3QqC=RߵmiWXɢ?lPa9zo5fū$в=װx@$K -l=_ l6<+l4i6L޿nlX1F/B) j&*ô&OD~Q (:$qԟ ٻ{KF//o#()ap087H8R2HB מ -wEVTV%ڠ`@4;8J=H ,,sxD_-^VypnSqi<Şc[N=jTAB',SvD\.Rę /L@eLca,eNv`: -k $#2TnJ:!q CQ:>{w;Ex~d )Y+*czZ9߲g9(Iޮm0[`\dƝCGxn [gN҆>p9+t ֭* B٫H6g@u/;4|}KK^li{q8_7>r|LsO 59AP+*pdYcLYbIɰ`s%iAS7T!h2}:8 J^bkR2w$ktQ#J4h_Spj1vtSXS^O7lqtsl%CsjwxvVDZ9]U hI4ބ/ | P< -,Wۣļlm( -/ "Rܯu ]Z%@Hl9PBfrQ-ݚV꺊>Τ2Ag¨ 7y&k)$S}pI1Y`coƪ,)OZzD8>Gʏ/}6яOOm٫rh"Ëƨ8 *eMR-4q7NR6xm2Y& ]"VPXzt9 |椀c2,>Oq`>h+nd uћZ7UY͝RXݻdqzSR ؔɪE=!jQVъn/FZCD]n*r,D6Wg -F#Z7FY q@VY9@~ǓluDҪLjT;Вi@qqB~Ayj͹n½iV^#gFb\BT#Eðݳw~̽>NJzlNk,:WɞNH悥L5Hb:e&7L^0 jp}mؖ.N)3,Rmq^!%?aM%86 >+XS_gh(ej7z.[rug) =,,.{(v.tMM5|<Ƨ -}fMVc)EP mJ aSF@ki%oaf((A=D1Ԉ^"~xxPQ!fG=D'ėfFRz(SRRho5^Oͧ3+"]WO;9wOȥ ìd꺹\IUE/02`RF-lwSLdfc<$f녢McKfYu8hͱB`PQSbrX^yi.-oMQorD^R^s [5\y|*F9 OC@tvV6@RE ^5}in.Rؘp}DP I`!'Fv +M"ͷhh;繧̀]77wl!edxͫ"B~39Fs?LrLn-&]Ow30= rAJ>DcM뮛)Yb-) @iJj-0uf<JӃJ@>[ N; yX9W%7∢i[lLj=x^0֠+ԚL,9<9O)&6y\)2@CV>ε4xThc"@zQq},ݑ#p[^yFZξmh~r*R]8RܫFHv9"EFbSe?< }"@Db5{]a  ٗRݠ8O@tXBH -*D}3H_HbI] L|6Ry6rV_re0Zҫ0ZR&+p.XH;x5MGi^3=m;9GuMiwF;K:]Z<Φ/̆2"umztM.MEa[vBK8]/{;-dxy"mjTBn+Duu?&_Sd%M;fg?( Cnus<TC5sc,)ON&]7^v_[$r[2ž]B4QaEL*-@R3 鸅(*w,@g+j!5y3 sSٚL9|Fb)H!@ zlq.9w8jƶ^y"2݅LuLu[Mu!0sw􆓷akUң^6dqVR_yoDZY5 ǯڼBF - -+y4)Ʈ:@5/1IyS=Iۄ4φF<<K;t+Nw3:V.57g߃j3dXU 1`NlOVڜ6eM!}bB)h&?>i&VS*?2 9!`|^ў61sf6jRĝ! =v?&ᐱ34`=gl)5{F>[<}=4|6{wh<^z09TG߽S+ j+ŬIt?ZX ̘88LuxQiY:֫baf=&ÉIP 2d[phSH[aX6;;mB]=@T9y2DP3^b؂;/o1?W!t:-6xÞѥuY]}7}CߌbPdK22hnr*v˜QG}:izP;&E U0^yn:)|ZJ CvF{dn\ؔ\uu'w;#4e&Q+Q\?aٷ)E +(!,* xuΣ -4q!7T /]筽B8X|C4q:R^ݣd1fFXU={}')6tv%uG&I뎮`h3m#X9۔%T/fߧ9*!tep_=Wz(K;2j^ؚ|9-9#ܡwAk=/WJ S-X# m~QvzלwxSM?XWTTqk|ȠLj]-/ ~vF`L{5\t~.-P!tZ5,ɦs"}#n@5 LX()hz/) 7oY#?gh8^"n?j+RH -7rؔMd=ªD@43o@~=uփ]/nrDL2##Sf/ND9 -%yOXo0$JDl50'x\}Ωt4#-=KVx/WcB71?,ܘ=ubB ܛeh4\JsY^1=^aq58kN5HvoF>:WHr6#\@-ցʢVlUցj[(Ka,ӰƫIN(6SvxXwSjώVF-Oˈ0%a1Heą[H(>PO}k2=Vdƶ5T57}dje`»C+]K/nfoz 5lcn`C' -;dAҫfKf[Pm`k* F00FD]zٰhlZbJ)8/1@@y!ϳɓLR{Imԍmw.`ٍٱ縌wH o%h{2ugxztN  ]p5.Dt+挧KOӦpAk%_>'is6'u jZhB/}r1sbXJ.D6Yh)푱3p -3X%5+gAE\1q ]`U6( -}Ukة BQED8(X蹤z~6kGC0&?HWEfG#E}*N?qU1cdW남zJn֡)oƻ4G,0L6$2_TRRJ  _'܉}<0Fao,}@j2AKem I2-"L;m1Ê,RoT -{ 4}pq6"ya/4:_g &!/)b$Ki1& 7i!u}Ǭ6I$t2]NJIOĤEj'v4*DpSt*I#'^ @Q AP4: qDI W똞 [ ib n&CkHN=27Naޘ=A 6vݭjE)=ꠒ2Wz-k,R14"k-,|eJ$fg$XzbA T|L=]N GT{BVIz\-i!>OFTLH+Q=;NFէM 5ʊm 54A23R#<"J! ⹊$I+XOR -!Xn6{jXPLC -͹Nu5.w5S 8Q,lbOWZHW{|} (8%4=jFj,d2}e<X%{2XPI3~X _|n5RxL$0R'2^ k.y%3?#s'$0Fb pcّJ òA1yŋ=\-%Āvd^ɏ3/ P6Nu%nhƴ~&c+cA2%rHFe‰XmW_aC/2ue%`腀ʈ2p'^= -KK[PF7I I$i֒JT!S{8L^`'ZSlG$4ZDY %PYG=o h+c ?Q\0MoQ@YW%;+,}/ F1 plw(4! Jcb -Q"ta쫰xVfe:үJh -I~c7&jc6d.%ȯ'@N /M1H_iyiIi3|^J!NRf9>'zd!i6`SJ fgФE&Mmϫ\K~B!㣲{ -hcmQ^V>DT`(@iMdKgK)>. 'Jm ec^]o\16ZYT.^'|{=bM;\<**ѼCNd\$kL#]+ȭaJFg0VI!(!M)9`ݵHalI{XiɺwLhl*'c'Ý*;iѩ0Q1v7쯇OƤ'XW' WpJ|VQ4SST'G!HNM^xL@a]aO>0,)]ӈmo"c / EhkS9YU_!4ZI}悞s]oczZ3{{+@L|Ӌ^I7bS0b?zxC=YPiXpk&_$Ls-Dk/I:凫8ҎRD,"~Ka RI9_T>t[8֋2WDU,X!'՝a "ekp) !YIe̯w$_^r(5ʫ,5^j 5~|J$ KD&0=I3$rHE$F ^>񻿃"SLPd<$ij[5!s;:x?Y^~9BN[H΃SjGtwr/!. v1%?I t%3[C<MΓQyiREJi9Yƒ^(C PeJOj>{F0bJ2/G!FS;QEEd^O1&9~b"z{REfFnKxXp:dyV'IizPy>Wq!EhIHc2V§J[<}as˗VHʯv8.S SHA(d|sh(#atؑAK!FO1r|eHqDr$%-cPr9{y/iᜍ @=t0Ԛi}9ٴ}}u&NG%QD6- ^ -^@G|ɧjʀ -힌r==Vvx 2@D*VY| E6.a@q:zמ3_pN.C-?&"tdGh׸eJ*~TQ3$}u-BDW3sVhzx^} 'u-Tu^3@>E$`Ji ,)lӹo@a Ӻ4kCed^[ͲsbJe%zN B_s._zˮJָR $)w_)5BGK$_Td E3!y r/rgVKulv iv J($-8'r a.{Av^XuƁ%)~rt2*|`\w?DR8fHgJ[.tI>D)sK%`ߑGɷh7o]o3?ExMIv[Uw1CctOR_J qt1l//,_ -o,r?JyKŴI -ys^OcѦ/*ϿަL,os|q$gG\u?+g4VigpW,oƌR!63:dnywQ=yf҇';xȲ8,x݈=4.~9gϴA'S8j9B^HZOjkqä0i,{u-vwxqճKZ }7G[j03>%WHs%$Q9LX䲇ҁ-dlǛ$'!i`EZ'-^WEm"҃,[ +kϿBQ_U죌I۾>Dxy]p^(W*D$(XT0*;1+ 8m I2'-CdU1@7-֮Hx~1KhqLܭASIc/OCCOƼ>YZeaRZ}%ȻK.gK*D)_w^OBt,G^#qY#/&I tURme P%4(--4Xb2d޲EJ]nGڛRT X^)DnzzfʗmӽVH8*[/Г%+3DRufrv܊=PH"ב&d䥨gt^YRvڳ)$zΑcRRnkODb?/1%F%y=oRLEV|5i]LsBϴ-$E HR 2ՙ$&g%r@ECڀE74kIS 8彙$e'<$NM'J:Xd+zǭ[K#7yI["F*\|)ƸF"nRuDfɽv=뇻r+yBsA_hό©ɰCGq$_vLLК1Q۠·mŭ&K2g}l8Cllu9N]0ZeI -l.ZhyϜ)"Z -)!/ (y\dJq"%[y~ON4Xi9JqFۖT6d5(NcJrF]`83wglwˆ5!)=֯G*9jfcЉL{MZjrF-^ -yB}Fsj%]YJ> PY4&0͙Ԓal9΁-H"J ¶&ΑO4>'ČTbl6&~"*iqҳگ"Wf.J":z bftIoQ[D]ϳdK\iT -wyc= zsWj^<(ɂ!<ܙW) E2nNwZphQ3&ж%›S(TWZpm4mWR)JդȬSR'zWH\JzHꓯ^ЌIa%K~4N]Jp~d:f*^ORfyop䛩'ij8uq8KpD쫐ş<'Ր;C,FA[J;U5iy\y:1g-5䠒MxPiQ!}.{Y1} 錕Bv2C %26"!f' G:C d"J1_⾓mHӼ$+MR8#ub99o4 ͙c6I%tn VD&sƫ*Gt TdSuz\#KýO*tI+Jj"t<]%6Ъ&.S^G\`M_4 sªKHh G%FD rbk#'D>:\w=W 8TǶo!Fᓥؖ3SFI!+!T8t ʿ0d2s1MD[lFF& -ٺ qmR:n?˚SJ`GP/v*P-,^'{wȭWGAh4nӃõG@~odXէJL$Hvyt#@ٽngʫ3#%3Klc񫏳\y^aa~M'1mdYNP,}9qoj}9,!B(CKAX{ͪnu.5a7p(+aЎ<Bno/G?ʔmV8ثJ3M^Nj'%@c~){;RK>굗E'n #r 19/;*Σny?yA:5Ҡ{D(P%!\#4h8zmyXG,y$+Ԯ8EP%o\JspdTyR-D -gqR3 97C5;-D9EtEg?RL%f\H_eJgJ 2ti?B8^ή[&x -٘y* -mh#X8 $L5㭮17ڽ.' -,E'X:S3KK!RnЮ'>&?1.2^ WD߯cgٷ{(oA2œMi:zxZ(eD $3]"oe˷q/AbP+==+_+Rs -r/ޫKa_)h&B9xK&=({^0Z[z{O"J༕ȗ{/ -]K8x/R@"5Y$n/b` *#"PщQ&D hj\J;0b!"vwGgϚ)>0сɆo-hFX[ C"vP8bQS'HDinAq=nİGH7%[$UAsٖe,\ 4u{=Zmo?it0rYDײpUGD>A=:3xHwwe(oqjDan#R\n Rga ^ӈR/l>da}\^\cL>qמ6y^׶/p>tNcfDhݺV"DDAOs*7,@4ş -zkѦ* uZ|#5bGܕ\I_̠]Ol2'yʍ,ݵqlBW6v->aif5[Fv|>_t[(W} -z4^8F\Z\#* 頒^ʩBl*n;m\=uEѧQhGmQT\f p^hdK }5"{e_@mF۠8+:7wiiea>un_qpaXIDRhBW;,HI/j{q1Ȱq~kZ}9dhu=ɮJl8D];ەMS0isר-4Kb] x!Gnzay=\ },&`EƲB\ډXlTG{J}1x}Pv#!%sm4iK1*6@=".D`<6Y{6ۑ#Fg . -ljٹ@Om/{iK 5C> ί¬G(*X E{}?Y/A7q٬-@9-m/#1 }o%̖=Flrf:S][LC3=//p^(!bۡ}!,Jgj UahlDn4U"9~7J ShIaXA' 5#O$y9.ۚ6^R&Lm,H/%yG?z+b, ۬$АghxN/+_EPrw= 2\[A4# [1B6<u8']OV <}ؗ@3ra!sᕩH'{:&?\~Ͻ4T!oRY4:\٬s~1(VDQ*P#1LݾX5EZ >+Ai6Mօڼa VE$v > bxyq՜,hZMmi/;;vi7 `"x[)O+'{ 3V,4Z!y@}&B0w^t[fvb}#T۠O=xĜ̮4{㡤U Psy6& Cz{ywh17.ꈄDBKv -˰ -&HPעsCO!bf5DE9IAI||'r%UHCkq[.+GlOV3- ىaⱞEkV@E.CW6V++Byfpp20:AmÆ,[br h-mШS첈Y [10a?B.%Fmy'LbĈI.꟠W޲ȾԑM[ֈndPWVS.w$B34. 5Ҭ܊II\:@JhhMI\cuB{6ecQ"ldRr YkȤ[S|Kfv/@#H@%SIeהm8915BV"Zr:kŸH N{ۡ@hMuOn@i vu`:4-5<;6Iz00F\+3"D"imR0͐kX4MUAPcxnqx7! SkLۢ\.h7? -c9m|OgzŤ}LW51/8ؤ -ZFj=Exu<6mmAz,S -m8+@g - ^1Y:{M>CaIrHV_#s&hc #J>㉤M}9U#Hpޠ2t&BqOt|K-(SbG2%)}eRp4w1Qh *LIl\ ~of57 ͑ƍUԛ3[=2/k+ ;rqru'm~{Q%1r>c;mCiVZ0TpҲ; J `쨔PBtu-25n~;ZJc\5WnhP2To([O^NsQ:-{1ZνwUV4zy?Vpىq"gM71/c=  qGi8C)PճjxV6+֔牖5O{ќh;e*Qm܋Biּ e4`NO -nJ|A䍱Kwm4-T]lZV"ǭή!$Qyx,K3S X (3q ؉.-G8q nF&Mfk6  gCpM+y\)-I|ᙡHMD><%<y^&\+i؀.NlD w8OMӘ1v9I$6!zZ3fy oÜsη%7 -Dz iX\H |(XDwMZ\]iљsp}0IOys ΦK8hCtlxIn{`<<;{ڈY+8QdzѨh߭I1m6*׹<H񦢭@|v;T=|p^)PǶUyHX"ާDjT -bYnu{#*DAc`-̃H5eTǪҒ 'N/]e%,RS-z镈sղȅ29{bhރM[h]ۚ|qD҉;EX2-r1dn89w'\S+@.J|C3I -1 G=!1B'92UT7 v.C&7pF8ӊ\F]'VJ0|кRNMJDgەH~fz:ư/%f) TiBMvU]5&UdKAm%ٻz%kC([%y"Y6|`ᱹ~X<9]l08>u!ے3#x8Ԇ H*:x5]<&EhB\"7h1Q {rC|ϹY?~F{@e̞*V!J)*iנ(cn'WFPȾʘ zy|Aƒ(˱5~&FFr5u>peti>* >J ηR^g[*q,R %֊΋j}m?/rOyRυIfӄg#mhYKoE1>(_J|1(NDQ0#g./.ƧE Lt"h i#O/QuK5 -TR$7}5rQ!gqn%=GДHJY*ѡ>1TU] G0/?@EeNY"I}C mX"'֘Nm$Tp@IOKyD|bb4 -\yX/`YƼ)7T/~`~aڙ ߌ6 6JVD"~3񍍔xDz"~3ڤ#0̜D"~3WpoF9$ղ36IC@nӱ%fo#9=A&q}Xflr!~azD?tߟgz7 7vjRLewƾ,f"NB9#P~;M^lZnLsSPnc@[|4""f&:';bė}Ȝ1̷&\n]QUQ֊y^o`爥VgC e@e1D\&I,!C'Cw8+Dln{e$m7M*'?<.B n}zQ -lƎ6`^Lޓ 'pSp'pQ}Va+>O%onxT:Q15 -sj h<_7q5"0f4V&5V}+_v";Q3K < ˭ L閜%G'*ɪcWiZ϶,n|r --AgM3HG-zpC~KS"w]Y4cPKzy덉p\pOXXIqV1TOx[X*rQ 20X7S'v^INBVD2Ȍ\Ad#iL&W.sK{xfj9_,@EO&9h=D$&G4 =|?>W[?%R>7Y)$ߌM "x^3N{ ;D!+i Y & ~lH#@~96v " -a^G^d-5߼%WKd{<6hCr~{n7,RҖa+b~3vӯh5WW4zDlӤ(c5hnGJQٷ( "AQ"_s2qpQ8Α ~8 qVp+p5jÓ/4nnM#yܚVCe? :MB #0!jČ٢# q8/pnM85t'~%1CïJDm8n3ϗQhdG6b>E6Wtb ݈^49OLkFu*Ō0^JxEy$>^~Й*7& -r^~Btcv]6۳z{ P#>l7/Gd!DÔѹv(rF.,y tD&7o3y\ h$fa[bEd52 }t -:~(B,GΗMfqFѐV >35kCq/|eFg~]cAU Fb!w|Vy(W"7OT+1bo-fX7:؂ {. wBʑVV&~\uDVR1T/vn2gZEzuxLDHC\$@{|(crMhr"z,!?q)]hO3덅# !{n_0iyN4rq'Gc?KK}Z}Bu }M6AvDNHl2DK6}D9ȕ}LNíWD~> endobj 25 0 obj <> endobj 44 0 obj <> endobj 63 0 obj <> endobj 82 0 obj <> endobj 101 0 obj <> endobj 120 0 obj <> endobj 129 0 obj [/View/Design] endobj 130 0 obj <>>> endobj 110 0 obj [/View/Design] endobj 111 0 obj <>>> endobj 91 0 obj [/View/Design] endobj 92 0 obj <>>> endobj 72 0 obj [/View/Design] endobj 73 0 obj <>>> endobj 53 0 obj [/View/Design] endobj 54 0 obj <>>> endobj 34 0 obj [/View/Design] endobj 35 0 obj <>>> endobj 15 0 obj [/View/Design] endobj 16 0 obj <>>> endobj 140 0 obj [139 0 R] endobj 157 0 obj <> endobj xref 0 158 0000000004 65535 f -0000000016 00000 n -0000000250 00000 n -0000055206 00000 n -0000000006 00000 f -0000275341 00000 n -0000000008 00000 f -0000055257 00000 n -0000000009 00000 f -0000000010 00000 f -0000000011 00000 f -0000000012 00000 f -0000000013 00000 f -0000000014 00000 f -0000000017 00000 f -0000276543 00000 n -0000276574 00000 n -0000000018 00000 f -0000000019 00000 f -0000000020 00000 f -0000000021 00000 f -0000000022 00000 f -0000000023 00000 f -0000000024 00000 f -0000000026 00000 f -0000275411 00000 n -0000000027 00000 f -0000000028 00000 f -0000000029 00000 f -0000000030 00000 f -0000000031 00000 f -0000000032 00000 f -0000000033 00000 f -0000000036 00000 f -0000276427 00000 n -0000276458 00000 n -0000000037 00000 f -0000000038 00000 f -0000000039 00000 f -0000000040 00000 f -0000000041 00000 f -0000000042 00000 f -0000000043 00000 f -0000000045 00000 f -0000275482 00000 n -0000000046 00000 f -0000000047 00000 f -0000000048 00000 f -0000000049 00000 f -0000000050 00000 f -0000000051 00000 f -0000000052 00000 f -0000000055 00000 f -0000276311 00000 n -0000276342 00000 n -0000000056 00000 f -0000000057 00000 f -0000000058 00000 f -0000000059 00000 f -0000000060 00000 f -0000000061 00000 f -0000000062 00000 f -0000000064 00000 f -0000275553 00000 n -0000000065 00000 f -0000000066 00000 f -0000000067 00000 f -0000000068 00000 f -0000000069 00000 f -0000000070 00000 f -0000000071 00000 f -0000000074 00000 f -0000276195 00000 n -0000276226 00000 n -0000000075 00000 f -0000000076 00000 f -0000000077 00000 f -0000000078 00000 f -0000000079 00000 f -0000000080 00000 f -0000000081 00000 f -0000000083 00000 f -0000275624 00000 n -0000000084 00000 f -0000000085 00000 f -0000000086 00000 f -0000000087 00000 f -0000000088 00000 f -0000000089 00000 f -0000000090 00000 f -0000000093 00000 f -0000276079 00000 n -0000276110 00000 n -0000000094 00000 f -0000000095 00000 f -0000000096 00000 f -0000000097 00000 f -0000000098 00000 f -0000000099 00000 f -0000000100 00000 f -0000000102 00000 f -0000275695 00000 n -0000000103 00000 f -0000000104 00000 f -0000000105 00000 f -0000000106 00000 f -0000000107 00000 f -0000000108 00000 f -0000000109 00000 f -0000000112 00000 f -0000275961 00000 n -0000275993 00000 n -0000000113 00000 f -0000000114 00000 f -0000000115 00000 f -0000000116 00000 f -0000000117 00000 f -0000000118 00000 f -0000000119 00000 f -0000000000 00000 f -0000275769 00000 n -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000275843 00000 n -0000275875 00000 n -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000100200 00000 n -0000276659 00000 n -0000055614 00000 n -0000103192 00000 n -0000100506 00000 n -0000100392 00000 n -0000098989 00000 n -0000099636 00000 n -0000099686 00000 n -0000100274 00000 n -0000100306 00000 n -0000100543 00000 n -0000103268 00000 n -0000103492 00000 n -0000104513 00000 n -0000118803 00000 n -0000184392 00000 n -0000249981 00000 n -0000276686 00000 n -trailer <<382E4B4BCD954B649F12E6602B9AE52E>]>> startxref 276869 %%EOF \ No newline at end of file diff --git a/package.json b/package.json index 448f75a..813e8d7 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "url": "http://sindresorhus.com" }, "engines": { - "node": ">=0.8.0" + "node": ">=0.10.0" }, "scripts": { "test": "mocha" @@ -40,11 +40,11 @@ "text" ], "dependencies": { - "has-color": "~0.1.0", - "ansi-styles": "~1.0.0", - "strip-ansi": "~0.1.0" + "ansi-styles": "^1.0.0", + "has-color": "^0.1.0", + "strip-ansi": "^0.2.0" }, "devDependencies": { - "mocha": "~1.x" + "mocha": "*" } } diff --git a/test.js b/test.js index 76a6b60..6434156 100644 --- a/test.js +++ b/test.js @@ -1,4 +1,3 @@ -/*global describe, it */ 'use strict'; var assert = require('assert'); var chalk = require('./index'); From d5d08a09953a1a4a048f32e96990c04d0c8970aa Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 3 Apr 2014 22:57:06 +0200 Subject: [PATCH 006/324] Update readme.md --- readme.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/readme.md b/readme.md index c23bb46..e03250f 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,7 @@ > Terminal string styling done right -[![Build Status](https://secure.travis-ci.org/sindresorhus/chalk.png?branch=master)](http://travis-ci.org/sindresorhus/chalk) +[![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) [colors.js](https://github.com/Marak/colors.js) is currently 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. @@ -23,12 +23,12 @@ ## Install -``` -npm install --save chalk +```bash +$ npm install --save chalk ``` -## Example +## Usage Chalk comes with an easy to use composable API where you just chain and nest the styles you want. @@ -160,4 +160,4 @@ if (!chalk.supportsColor) { ## License -MIT © [Sindre Sorhus](http://sindresorhus.com) +[MIT](http://opensource.org/licenses/MIT) © [Sindre Sorhus](http://sindresorhus.com) From 449fa45b4062916a9954de89f3f1b66f74822171 Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Sun, 18 May 2014 03:30:42 +0300 Subject: [PATCH 007/324] update "used by" (number of dependents) --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index e03250f..8a7fca2 100644 --- a/readme.md +++ b/readme.md @@ -18,7 +18,7 @@ - Clean and focused - Auto-detects color support - Actively maintained -- [Used by 300+ modules](https://npmjs.org/browse/depended/chalk) +- [Used by 850+ modules](https://npmjs.org/browse/depended/chalk) ## Install From fa9bd4ebd9a3acb775c96e246aa7770c3b8e512b Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 4 Jun 2014 01:38:03 +0200 Subject: [PATCH 008/324] bump ansi-styles --- package.json | 2 +- readme.md | 50 +++++++++++++++++++++++++------------------------ screenshot.png | Bin 24914 -> 51856 bytes 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index 813e8d7..c5b734e 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "text" ], "dependencies": { - "ansi-styles": "^1.0.0", + "ansi-styles": "^1.1.0", "has-color": "^0.1.0", "strip-ansi": "^0.2.0" }, diff --git a/readme.md b/readme.md index 8a7fca2..e1eb086 100644 --- a/readme.md +++ b/readme.md @@ -8,7 +8,7 @@ **Chalk is a clean and focused alternative.** -![screenshot](screenshot.png) +![screenshot](https://github.com/sindresorhus/ansi-styles/raw/master/screenshot.png) ## Why @@ -127,35 +127,37 @@ if (!chalk.supportsColor) { ### General -- reset -- bold -- italic -- underline -- inverse -- strikethrough +- `reset` +- `bold` +- `dim` +- `italic` *(not widely supported)* +- `underline` +- `inverse` +- `hidden` +- `strikethrough` *(not widely supported)* ### Text colors -- black -- red -- green -- yellow -- blue -- magenta -- cyan -- white -- gray +- `black` +- `red` +- `green` +- `yellow` +- `blue` +- `magenta` +- `cyan` +- `white` +- `gray` ### Background colors -- bgBlack -- bgRed -- bgGreen -- bgYellow -- bgBlue -- bgMagenta -- bgCyan -- bgWhite +- `bgBlack` +- `bgRed` +- `bgGreen` +- `bgYellow` +- `bgBlue` +- `bgMagenta` +- `bgCyan` +- `bgWhite` ## License diff --git a/screenshot.png b/screenshot.png index 9bb464a6c922bbfbd6034286adffd3dfa0fd6d7b..de2dd7bf8089a8053a455a91c5401dae8213518c 100644 GIT binary patch literal 51856 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 From cf7eb2d0c7ac20ad6864773451dd59210e7a4612 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 4 Jun 2014 01:43:07 +0200 Subject: [PATCH 009/324] various tweaks --- .gitattributes | 2 +- .jshintrc | 8 ++------ index.js | 10 +++++----- license | 21 +++++++++++++++++++++ readme.md | 6 +++--- test.js | 22 +++++++++++----------- 6 files changed, 43 insertions(+), 26 deletions(-) create mode 100644 license diff --git a/.gitattributes b/.gitattributes index fcadb2c..176a458 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -* text eol=lf +* text=auto diff --git a/.jshintrc b/.jshintrc index ac35c13..c511975 100644 --- a/.jshintrc +++ b/.jshintrc @@ -7,14 +7,10 @@ "eqeqeq": true, "immed": true, "indent": 4, - "latedef": true, "newcap": true, "noarg": true, "quotmark": "single", - "regexp": true, "undef": true, - "unused": true, - "strict": true, - "trailing": true, - "smarttabs": true + "unused": "vars", + "strict": true } diff --git a/index.js b/index.js index 1a8d3f5..1cc7434 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ 'use strict'; -var ansi = require('ansi-styles'); +var ansiStyles = require('ansi-styles'); var stripAnsi = require('strip-ansi'); var hasColor = require('has-color'); var defineProps = Object.defineProperties; @@ -8,9 +8,9 @@ var chalk = module.exports; var styles = (function () { var ret = {}; - ansi.grey = ansi.gray; + ansiStyles.grey = ansiStyles.gray; - Object.keys(ansi).forEach(function (key) { + Object.keys(ansiStyles).forEach(function (key) { ret[key] = { get: function () { this._styles.push(key); @@ -36,7 +36,7 @@ function init() { } return self._styles.reduce(function (str, name) { - var code = ansi[name]; + var code = ansiStyles[name]; return str ? code.open + str + code.close : ''; }, str); }, styles); @@ -53,7 +53,7 @@ function init() { defineProps(chalk, init()); -chalk.styles = ansi; +chalk.styles = ansiStyles; chalk.stripColor = stripAnsi; chalk.supportsColor = hasColor; diff --git a/license b/license new file mode 100644 index 0000000..654d0bf --- /dev/null +++ b/license @@ -0,0 +1,21 @@ +The MIT License (MIT) + +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: + +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. diff --git a/readme.md b/readme.md index e1eb086..7841d1b 100644 --- a/readme.md +++ b/readme.md @@ -23,7 +23,7 @@ ## Install -```bash +```sh $ npm install --save chalk ``` @@ -100,7 +100,7 @@ Generally not useful, but you might need just the `.open` or `.close` escape cod var chalk = require('chalk'); console.log(chalk.styles.red); -//=> {open: '\x1b[31m', close: '\x1b[39m'} +//=> {open: '\u001b[31m', close: '\u001b[39m'} console.log(chalk.styles.red.open + 'Hello' + chalk.styles.red.close); ``` @@ -162,4 +162,4 @@ if (!chalk.supportsColor) { ## License -[MIT](http://opensource.org/licenses/MIT) © [Sindre Sorhus](http://sindresorhus.com) +MIT © [Sindre Sorhus](http://sindresorhus.com) diff --git a/test.js b/test.js index 6434156..c65e55b 100644 --- a/test.js +++ b/test.js @@ -4,37 +4,37 @@ var chalk = require('./index'); describe('chalk', function () { it('should style string', function () { - assert.equal(chalk.underline('foo'), '\x1b[4mfoo\x1b[24m'); - assert.equal(chalk.red('foo'), '\x1b[31mfoo\x1b[39m'); - assert.equal(chalk.bgRed('foo'), '\x1b[41mfoo\x1b[49m'); + 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'), '\x1b[4m\x1b[42m\x1b[31mfoo\x1b[39m\x1b[49m\x1b[24m'); - assert.equal(chalk.underline.red.bgGreen('foo'), '\x1b[42m\x1b[31m\x1b[4mfoo\x1b[24m\x1b[39m\x1b[49m'); + assert.equal(chalk.red.bgGreen.underline('foo'), '\u001b[4m\u001b[42m\u001b[31mfoo\u001b[39m\u001b[49m\u001b[24m'); + assert.equal(chalk.underline.red.bgGreen('foo'), '\u001b[42m\u001b[31m\u001b[4mfoo\u001b[24m\u001b[39m\u001b[49m'); }); it('should support nesting styles', function () { assert.equal( chalk.red('foo' + chalk.underline.bgBlue('bar') + '!'), - '\x1b[31mfoo\x1b[44m\x1b[4mbar\x1b[24m\x1b[49m!\x1b[39m' + '\u001b[31mfoo\u001b[44m\u001b[4mbar\u001b[24m\u001b[49m!\u001b[39m' ); }); it('should reset all styles with `.reset()`', function () { - assert.equal(chalk.reset(chalk.red.bgGreen.underline('foo') + 'foo'), '\x1b[0m\x1b[4m\x1b[42m\x1b[31mfoo\x1b[39m\x1b[49m\x1b[24mfoo\x1b[0m'); + assert.equal(chalk.reset(chalk.red.bgGreen.underline('foo') + 'foo'), '\u001b[0m\u001b[4m\u001b[42m\u001b[31mfoo\u001b[39m\u001b[49m\u001b[24mfoo\u001b[0m'); }); it('should alias gray to grey', function () { - assert.equal(chalk.grey('foo'), '\x1b[90mfoo\x1b[39m'); + assert.equal(chalk.grey('foo'), '\u001b[90mfoo\u001b[39m'); }); it('should support variable number of arguments', function () { - assert.equal(chalk.red('foo', 'bar'), '\x1b[31mfoo bar\x1b[39m'); + assert.equal(chalk.red('foo', 'bar'), '\u001b[31mfoo bar\u001b[39m'); }); it('should support falsy values', function () { - assert.equal(chalk.red(0), '\x1b[31m0\x1b[39m'); + assert.equal(chalk.red(0), '\u001b[31m0\u001b[39m'); }); it('don\'t output escape codes if the input is empty', function () { @@ -52,7 +52,7 @@ describe('chalk.enabled', function () { describe('chalk.styles', function () { it('should expose the styles as ANSI escape codes', function () { - assert.equal(chalk.styles.red.open, '\x1b[31m'); + assert.equal(chalk.styles.red.open, '\u001b[31m'); }); }); From 90f012c79363640f8a790e3060921d7049373a4f Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 8 Jun 2014 01:54:47 +0200 Subject: [PATCH 010/324] =?UTF-8?q?1000+=20dependents!=20=E2=9C=8C?= =?UTF-8?q?=E2=8A=82(=E2=9C=B0=E2=80=BF=E2=9C=B0)=E3=81=A4=E2=9C=8C?= 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 7841d1b..ef8aa86 100644 --- a/readme.md +++ b/readme.md @@ -18,7 +18,7 @@ - Clean and focused - Auto-detects color support - Actively maintained -- [Used by 850+ modules](https://npmjs.org/browse/depended/chalk) +- [Used by 1000+ modules](https://npmjs.org/browse/depended/chalk) ## Install From 144421dc16c4e323fa6d1d074ede9abf75323b5d Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 14 Jun 2014 03:49:42 +0200 Subject: [PATCH 011/324] has-color => supports-color --- index.js | 4 ++-- package.json | 4 ++-- readme.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index 1cc7434..a7a7f48 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,7 @@ 'use strict'; var ansiStyles = require('ansi-styles'); var stripAnsi = require('strip-ansi'); -var hasColor = require('has-color'); +var supportsColor = require('supports-color'); var defineProps = Object.defineProperties; var chalk = module.exports; @@ -55,7 +55,7 @@ defineProps(chalk, init()); chalk.styles = ansiStyles; chalk.stripColor = stripAnsi; -chalk.supportsColor = hasColor; +chalk.supportsColor = supportsColor; // detect mode if not set manually if (chalk.enabled === undefined) { diff --git a/package.json b/package.json index c5b734e..1a35463 100644 --- a/package.json +++ b/package.json @@ -41,8 +41,8 @@ ], "dependencies": { "ansi-styles": "^1.1.0", - "has-color": "^0.1.0", - "strip-ansi": "^0.2.0" + "strip-ansi": "^0.2.0", + "supports-color": "^0.2.0" }, "devDependencies": { "mocha": "*" diff --git a/readme.md b/readme.md index ef8aa86..c19fe21 100644 --- a/readme.md +++ b/readme.md @@ -84,7 +84,7 @@ Color support is automatically detected, but you can override it. ### chalk.supportsColor -Detect whether the terminal [supports color](https://github.com/sindresorhus/has-color). +Detect whether the terminal [supports color](https://github.com/sindresorhus/supports-color). Can be overridden by the user with the flags `--color` and `--no-color`. From 1ec4985bc01f3f9b72683afdb166a9be4b70b2b2 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 22 Jun 2014 01:31:17 +0200 Subject: [PATCH 012/324] Delete screenshot.png --- screenshot.png | Bin 51856 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 screenshot.png diff --git a/screenshot.png b/screenshot.png deleted file mode 100644 index de2dd7bf8089a8053a455a91c5401dae8213518c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51856 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 Date: Sat, 21 Jun 2014 06:22:24 +0200 Subject: [PATCH 013/324] Adds support for nested chalk expressions. green(a + blue(b) + c) will now look the same as green(a) + blue(b) + green(c), as expected. In the previous implementation the output would have been green(a) + blue(b) + c, because the reset code of the second expression would close all expressions around it as well. Now this reset code is replaced by a start code of the outer lying expression, both stopping the inner and re-starting the outer. --- index.js | 20 +++++++++++++++++++- readme.md | 3 +++ test.js | 7 +++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index a7a7f48..3929a8c 100644 --- a/index.js +++ b/index.js @@ -22,6 +22,19 @@ var styles = (function () { return ret; })(); +// enrich each ansiStyle object with regular expression matching +// all instances of the corresponding code.close +(function () { + var _matchUnescapedCharacters = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g; + function escapeStr(str) { + return str.replace(_matchUnescapedCharacters, '\\$&'); + } + + Object.keys(ansiStyles).forEach(function (key) { + ansiStyles[key].closeRe = new RegExp(escapeStr(ansiStyles[key].close), 'g'); + }); +})(); + function init() { var ret = {}; @@ -37,7 +50,12 @@ function init() { return self._styles.reduce(function (str, name) { var code = ansiStyles[name]; - return str ? code.open + str + code.close : ''; + return str ? + // Replace any instances already present with a re-opening code + // otherwise only the part of the string until said closing code will be coloured, and the rest will be + // simply 'plain'. + code.open + str.replace(code.closeRe, code.open) + code.close : + ''; }, str); }, styles); diff --git a/readme.md b/readme.md index c19fe21..1982c3e 100644 --- a/readme.md +++ b/readme.md @@ -47,6 +47,9 @@ console.log( chalk.blue.bgRed.bold('Hello world!') ); // nest styles console.log( chalk.red('Hello', chalk.underline.bgBlue('world') + '!') ); +// nest styles of the same type even (colour, underline, background) +console.log( chalk.green('Hello, I'm a green line ' + chalk.blue('with a blue substring') + ' that becomes green again!') ); + // pass in multiple arguments console.log( chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz') ); ``` diff --git a/test.js b/test.js index c65e55b..0dc8eef 100644 --- a/test.js +++ b/test.js @@ -21,6 +21,13 @@ describe('chalk', function () { ); }); + it('should support nesting styles of the same type (color, underline, bg)', function () { + assert.equal( + chalk.red('a' + chalk.blue('b' + chalk.green('c') + 'b') + 'c'), + '\u001b[31ma\u001b[34mb\u001b[32mc\u001b[34mb\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[4m\u001b[42m\u001b[31mfoo\u001b[39m\u001b[49m\u001b[24mfoo\u001b[0m'); }); From 763b167349022480c8ab0c4d194919e3fe855f74 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 24 Jun 2014 17:13:41 +0200 Subject: [PATCH 014/324] refactor and extract the RegExp escaping --- index.js | 25 +++++++------------------ package.json | 1 + test.js | 2 +- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/index.js b/index.js index 3929a8c..9854660 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,5 @@ 'use strict'; +var escapeStringRegexp = require('escape-string-regexp'); var ansiStyles = require('ansi-styles'); var stripAnsi = require('strip-ansi'); var supportsColor = require('supports-color'); @@ -11,6 +12,8 @@ var styles = (function () { ansiStyles.grey = ansiStyles.gray; Object.keys(ansiStyles).forEach(function (key) { + ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); + ret[key] = { get: function () { this._styles.push(key); @@ -22,19 +25,6 @@ var styles = (function () { return ret; })(); -// enrich each ansiStyle object with regular expression matching -// all instances of the corresponding code.close -(function () { - var _matchUnescapedCharacters = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g; - function escapeStr(str) { - return str.replace(_matchUnescapedCharacters, '\\$&'); - } - - Object.keys(ansiStyles).forEach(function (key) { - ansiStyles[key].closeRe = new RegExp(escapeStr(ansiStyles[key].close), 'g'); - }); -})(); - function init() { var ret = {}; @@ -50,12 +40,11 @@ function init() { return self._styles.reduce(function (str, name) { var code = ansiStyles[name]; - return str ? + return str ? code.open + // Replace any instances already present with a re-opening code - // otherwise only the part of the string until said closing code will be coloured, and the rest will be - // simply 'plain'. - code.open + str.replace(code.closeRe, code.open) + code.close : - ''; + // otherwise only the part of the string until said closing code + // will be colored, and the rest will simply be 'plain'. + str.replace(code.closeRe, code.open) + code.close : ''; }, str); }, styles); diff --git a/package.json b/package.json index 1a35463..effe6e8 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ ], "dependencies": { "ansi-styles": "^1.1.0", + "escape-string-regexp": "^1.0.0", "strip-ansi": "^0.2.0", "supports-color": "^0.2.0" }, diff --git a/test.js b/test.js index 0dc8eef..8c3da0c 100644 --- a/test.js +++ b/test.js @@ -1,6 +1,6 @@ 'use strict'; var assert = require('assert'); -var chalk = require('./index'); +var chalk = require('./'); describe('chalk', function () { it('should style string', function () { From eff96c2c157c578f63b6041d9fecbe2705ff5a75 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 24 Jun 2014 17:23:43 +0200 Subject: [PATCH 015/324] readme tweaks --- readme.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index 1982c3e..d28f99d 100644 --- a/readme.md +++ b/readme.md @@ -13,8 +13,9 @@ ## Why -- **Doesn't extend String.prototype** +- Doesn't extend String.prototype - Expressive API +- Ability to nest styles - Clean and focused - Auto-detects color support - Actively maintained @@ -44,14 +45,14 @@ console.log( chalk.blue('Hello'), 'World' + chalk.red('!') ); // compose multiple styles using the chainable API console.log( chalk.blue.bgRed.bold('Hello world!') ); +// pass in multiple arguments +console.log( chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz') ); + // nest styles console.log( chalk.red('Hello', chalk.underline.bgBlue('world') + '!') ); -// nest styles of the same type even (colour, underline, background) -console.log( chalk.green('Hello, I'm a green line ' + chalk.blue('with a blue substring') + ' that becomes green again!') ); - -// pass in multiple arguments -console.log( chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz') ); +// nest styles of the same type even (color, underline, background) +console.log( chalk.green('I am a green line ' + chalk.blue('with a blue substring') + ' that becomes green again!') ); ``` Easily define your own themes. From 90bd6477d6d3e2d31dee9b2ee3e721026521bd47 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 24 Jun 2014 21:34:11 +0200 Subject: [PATCH 016/324] add `.hasColor()` method - fixes #23 --- index.js | 2 ++ package.json | 3 ++- readme.md | 4 ++++ test.js | 7 +++++++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 9854660..057ac62 100644 --- a/index.js +++ b/index.js @@ -2,6 +2,7 @@ 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 chalk = module.exports; @@ -61,6 +62,7 @@ function init() { defineProps(chalk, init()); chalk.styles = ansiStyles; +chalk.hasColor = hasAnsi; chalk.stripColor = stripAnsi; chalk.supportsColor = supportsColor; diff --git a/package.json b/package.json index effe6e8..5a21291 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,8 @@ "dependencies": { "ansi-styles": "^1.1.0", "escape-string-regexp": "^1.0.0", - "strip-ansi": "^0.2.0", + "has-ansi": "^0.1.0", + "strip-ansi": "^0.2.2", "supports-color": "^0.2.0" }, "devDependencies": { diff --git a/readme.md b/readme.md index d28f99d..942ba51 100644 --- a/readme.md +++ b/readme.md @@ -109,6 +109,10 @@ 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/sindresorhus/has-ansi). + ### chalk.stripColor(string) [Strip color](https://github.com/sindresorhus/strip-ansi) from a string. diff --git a/test.js b/test.js index 8c3da0c..5d588d4 100644 --- a/test.js +++ b/test.js @@ -63,6 +63,13 @@ describe('chalk.styles', function () { }); }); +describe('chalk.hasColor()', function () { + it('should detect whether a string has color', function () { + assert(chalk.hasColor(chalk.blue('foo'))); + assert(!chalk.hasColor(chalk.stripColor(chalk.blue('foo')))); + }); +}); + describe('chalk.stripColor()', function () { it('should strip color from string', function () { assert.equal(chalk.stripColor(chalk.underline.red.bgGreen('foo')), 'foo'); From 732fb08e2bbb3e6de2ea034d4f701b6c819d3241 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 24 Jun 2014 21:34:27 +0200 Subject: [PATCH 017/324] bump strip-ansi --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5a21291..5a9cd30 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "ansi-styles": "^1.1.0", "escape-string-regexp": "^1.0.0", "has-ansi": "^0.1.0", - "strip-ansi": "^0.2.2", + "strip-ansi": "^0.3.0", "supports-color": "^0.2.0" }, "devDependencies": { From b0523a44384a29987f75540afc761f381aedd798 Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Tue, 24 Jun 2014 22:59:31 +0200 Subject: [PATCH 018/324] Performance optimizations (ca. Factor 75) - Precomputed style function - Skip arguments to array + join if there's only one argument (the common case) - Merge multiple return statements to one To calculate the performance benefit: ```javascript var chalk = require('./index.js'); console.time('100000 iterations'); for (var i = 0; i < 100000; i++) { chalk.red('A string that is about 80 characters long (normal use I think?)'); } console.timeEnd('100000 iterations'); ``` Running this before this commit: ```shell for i in {1..5}; do node time.js; done 100000 iterations: 19485ms 100000 iterations: 18933ms 100000 iterations: 19365ms 100000 iterations: 19332ms 100000 iterations: 18660ms ``` After: ```shell 100000 iterations: 268ms 100000 iterations: 261ms 100000 iterations: 264ms 100000 iterations: 259ms 100000 iterations: 254ms ``` Performance gain, taking the middle result of both: ```shell 19332 / 261 = 74.~ ``` Closes #16 --- index.js | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/index.js b/index.js index 9854660..6d9ce69 100644 --- a/index.js +++ b/index.js @@ -25,32 +25,32 @@ var styles = (function () { return ret; })(); +function applyStyle() { + // support varags, but simply cast to string in case there's only one arg + var str = arguments.length === 1 ? arguments[0] + '' : [].slice.call(arguments).join(' '); + + if (!chalk.enabled || !str) { + return str; + } + + return applyStyle._styles.reduce(function (str, name) { + var code = ansiStyles[name]; + // 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'. + return code.open + str.replace(code.closeRe, code.open) + code.close; + }, str) ; +} + function init() { var ret = {}; Object.keys(styles).forEach(function (name) { + var style = defineProps(applyStyle, styles); ret[name] = { get: function () { - var obj = defineProps(function self() { - var str = [].slice.call(arguments).join(' '); - - if (!chalk.enabled) { - return str; - } - - return self._styles.reduce(function (str, name) { - var code = ansiStyles[name]; - return str ? code.open + - // 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.replace(code.closeRe, code.open) + code.close : ''; - }, str); - }, styles); - - obj._styles = []; - - return obj[name]; + style._styles = []; + return style[name]; } }; }); From d9d6e9d7f499730d30bbb8f5240ef243a404e5fe Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 26 Jun 2014 00:18:23 +0200 Subject: [PATCH 019/324] Update readme.md --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 942ba51..d83df5f 100644 --- a/readme.md +++ b/readme.md @@ -3,6 +3,7 @@ > Terminal string styling done right [![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) +![](http://img.shields.io/badge/unicorn-approved-ff69b4.svg) [colors.js](https://github.com/Marak/colors.js) is currently 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 c8fe7c39665fd8b86739c2ecc6c3987d5b8e52c4 Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Thu, 26 Jun 2014 00:25:40 +0200 Subject: [PATCH 020/324] Adds myself - jbnicolai - as a contributor. --- package.json | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 5a9cd30..7fc8ba7 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,10 @@ "description": "Terminal string styling done right. Created because the `colors` module does some really horrible things.", "license": "MIT", "repository": "sindresorhus/chalk", - "author": { - "name": "Sindre Sorhus", - "email": "sindresorhus@gmail.com", - "url": "http://sindresorhus.com" - }, + "maintainers": [ + "Sindre Sorhus (http://sindresorhus.com)", + "Joshua Appelman " + ], "engines": { "node": ">=0.10.0" }, From 580fe4d7183fc7771b3bad638085b912fb98266a Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Thu, 26 Jun 2014 00:15:15 +0200 Subject: [PATCH 021/324] Replaces Array.prototype.reduce with a for loop. As this is possibly the hottest code path, this speeds up average total execution time with about 25%, benchmarking shows. --- index.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index fa744fc..6614c21 100644 --- a/index.js +++ b/index.js @@ -34,13 +34,17 @@ function applyStyle() { return str; } - return applyStyle._styles.reduce(function (str, name) { - var code = ansiStyles[name]; + var nestedStyles = applyStyle._styles; + + for (var i = 0; i < nestedStyles.length; i++) { + var code = ansiStyles[nestedStyles[i]]; // 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'. - return code.open + str.replace(code.closeRe, code.open) + code.close; - }, str) ; + str = code.open + str.replace(code.closeRe, code.open) + code.close; + } + + return str; } function init() { From e12289964d8d3fb697c0c12a06010a2ca1847cac Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 26 Jun 2014 15:09:37 +0200 Subject: [PATCH 022/324] use String constructor rather than + for coercion --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 6614c21..bc19485 100644 --- a/index.js +++ b/index.js @@ -28,7 +28,7 @@ var styles = (function () { function applyStyle() { // support varags, but simply cast to string in case there's only one arg - var str = arguments.length === 1 ? arguments[0] + '' : [].slice.call(arguments).join(' '); + var str = arguments.length === 1 ? String(arguments[0]) : [].slice.call(arguments).join(' '); if (!chalk.enabled || !str) { return str; From 3026d71e0eea14f71d9f8779d2e12305d6aa67e2 Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Fri, 4 Jul 2014 21:21:44 +0200 Subject: [PATCH 023/324] Adds benchmarking using matcha. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run through: ```shell ./node_modules/matcha/bin/matcha benchmark.js ``` Results against current HEAD: ```shell 1,863,195 op/s » add colour 2,215,812 op/s » add several styles 323,213 op/s » add nested styles ``` Results against the latest revision before optiziations, e122899 ```shell 26,714 op/s » add colour 26,752 op/s » add several styles 13,414 op/s » add nested styles ``` Closes #21 --- benchmark.js | 20 ++++++++++++++++++++ package.json | 1 + 2 files changed, 21 insertions(+) create mode 100644 benchmark.js diff --git a/benchmark.js b/benchmark.js new file mode 100644 index 0000000..dcee1e7 --- /dev/null +++ b/benchmark.js @@ -0,0 +1,20 @@ +// ran through matcha +// ./node_modules/matcha/bin/matcha benchmark.js + +var chalk = require('./index.js'); + +suite('chalk', function(){ + + bench('add colour', function(){ + chalk.red('the fox jumps over the lazy dog'); + }); + + bench('add several styles', function(){ + chalk.blue.bgRed.bold('the fox jumps over the lazy dog') ; + }); + + bench('add nested styles', function(){ + chalk.red('the fox jumps ', chalk.underline.bgBlue('over the lazy dog') + '!') ; + }); + +}); diff --git a/package.json b/package.json index 7fc8ba7..26db021 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "supports-color": "^0.2.0" }, "devDependencies": { + "matcha": "^0.5.0", "mocha": "*" } } From 2b859bb9751114dcc56c3bd21624278a65f6abca Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Fri, 4 Jul 2014 21:29:01 +0200 Subject: [PATCH 024/324] Adds performance to readme. --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index d83df5f..3b5aa08 100644 --- a/readme.md +++ b/readme.md @@ -14,6 +14,7 @@ ## Why +- Highly performant - Doesn't extend String.prototype - Expressive API - Ability to nest styles From 0dde0473e03ded958099456a7a86880193a386df Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 4 Jul 2014 22:28:30 +0200 Subject: [PATCH 025/324] add benchmark to package.json run with `npm run bench` --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 26db021..5c4d560 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "node": ">=0.10.0" }, "scripts": { - "test": "mocha" + "test": "mocha", + "bench": "matcha benchmark.js" }, "files": [ "index.js" From d255f42a9e3a337f8e3975cd751741feaed2fff9 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 4 Jul 2014 22:29:02 +0200 Subject: [PATCH 026/324] bench - minor code style tweaks --- benchmark.js | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/benchmark.js b/benchmark.js index dcee1e7..c47172e 100644 --- a/benchmark.js +++ b/benchmark.js @@ -1,20 +1,15 @@ -// ran through matcha -// ./node_modules/matcha/bin/matcha benchmark.js +var chalk = require('./'); -var chalk = require('./index.js'); - -suite('chalk', function(){ - - bench('add colour', function(){ +suite('chalk', function () { + bench('single style', function () { chalk.red('the fox jumps over the lazy dog'); }); - bench('add several styles', function(){ - chalk.blue.bgRed.bold('the fox jumps over the lazy dog') ; + bench('several styles', function () { + chalk.blue.bgRed.bold('the fox jumps over the lazy dog'); }); - bench('add nested styles', function(){ - chalk.red('the fox jumps ', chalk.underline.bgBlue('over the lazy dog') + '!') ; + bench('nested styles', function () { + chalk.red('the fox jumps', chalk.underline.bgBlue('over the lazy dog') + '!'); }); - }); From 3ab833de62108295cd86cc9fd699f4e109e4fdbe Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 4 Jul 2014 22:32:23 +0200 Subject: [PATCH 027/324] bench - increase iterations for more reliable results --- benchmark.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/benchmark.js b/benchmark.js index c47172e..da9ed8d 100644 --- a/benchmark.js +++ b/benchmark.js @@ -1,6 +1,8 @@ var chalk = require('./'); suite('chalk', function () { + set('iterations', 100000); + bench('single style', function () { chalk.red('the fox jumps over the lazy dog'); }); From af175295fbd0e8344f0f5ef3eaf9df44ea606244 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 4 Jul 2014 23:23:45 +0200 Subject: [PATCH 028/324] use rawgithub to workaround npm website bug with relative image paths --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 3b5aa08..239c791 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -# chalk +# chalk > Terminal string styling done right From 3073fa3110134e840ee79eaffb61866182b4b7fa Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 4 Jul 2014 23:24:19 +0200 Subject: [PATCH 029/324] 0.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5c4d560..7a94654 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "0.4.0", + "version": "0.5.0", "description": "Terminal string styling done right. Created because the `colors` module does some really horrible things.", "license": "MIT", "repository": "sindresorhus/chalk", From 42918337e5503c1ec358f485dcd2cc295214b5f9 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Tue, 8 Jul 2014 20:43:54 -0700 Subject: [PATCH 030/324] return a new function for each getter - defines the getters onto a proto - the function returned has its __proto__ set to our proto fixes #32 --- .jshintrc | 1 + benchmark.js | 5 +++++ index.js | 23 +++++++++++++++++------ test.js | 11 +++++++++++ 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/.jshintrc b/.jshintrc index c511975..3e1760c 100644 --- a/.jshintrc +++ b/.jshintrc @@ -9,6 +9,7 @@ "indent": 4, "newcap": true, "noarg": true, + "proto": true, "quotmark": "single", "undef": true, "unused": "vars", diff --git a/benchmark.js b/benchmark.js index da9ed8d..ce3f2c4 100644 --- a/benchmark.js +++ b/benchmark.js @@ -11,6 +11,11 @@ suite('chalk', function () { chalk.blue.bgRed.bold('the fox jumps over the lazy dog'); }); + var cached = chalk.blue.bgRed.bold; + bench('cached styles', function () { + cached('the fox jumps over the lazy dog'); + }); + bench('nested styles', function () { chalk.red('the fox jumps', chalk.underline.bgBlue('over the lazy dog') + '!'); }); diff --git a/index.js b/index.js index bc19485..b512746 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,17 @@ var supportsColor = require('supports-color'); var defineProps = Object.defineProperties; var chalk = module.exports; +function build(_styles) { + var builder = function builder() { + return applyStyle.apply(builder, arguments); + }; + builder._styles = _styles; + // __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; + return builder; +} + var styles = (function () { var ret = {}; @@ -17,8 +28,7 @@ var styles = (function () { ret[key] = { get: function () { - this._styles.push(key); - return this; + return build(this._styles.concat(key)); } }; }); @@ -26,6 +36,8 @@ var styles = (function () { return ret; })(); +var proto = defineProps(function chalk() {}, styles); + function applyStyle() { // support varags, but simply cast to string in case there's only one arg var str = arguments.length === 1 ? String(arguments[0]) : [].slice.call(arguments).join(' '); @@ -34,7 +46,8 @@ function applyStyle() { return str; } - var nestedStyles = applyStyle._styles; + /*jshint validthis: true*/ + var nestedStyles = this._styles; for (var i = 0; i < nestedStyles.length; i++) { var code = ansiStyles[nestedStyles[i]]; @@ -51,11 +64,9 @@ function init() { var ret = {}; Object.keys(styles).forEach(function (name) { - var style = defineProps(applyStyle, styles); ret[name] = { get: function () { - style._styles = []; - return style[name]; + return build([name]); } }; }); diff --git a/test.js b/test.js index 5d588d4..3e073a6 100644 --- a/test.js +++ b/test.js @@ -32,6 +32,17 @@ describe('chalk', function () { assert.equal(chalk.reset(chalk.red.bgGreen.underline('foo') + 'foo'), '\u001b[0m\u001b[4m\u001b[42m\u001b[31mfoo\u001b[39m\u001b[49m\u001b[24mfoo\u001b[0m'); }); + it('should be able to cache multiple styles', function() { + var red = chalk.red; + var blue = chalk.blue; + var redBold = red.bold; + var blueBold = blue.bold; + + assert.notEqual(red('foo'), blue('foo')); + assert.notEqual(redBold('bar'), blueBold('bar')); + assert.notEqual(blue('baz'), blueBold('baz')); + }); + it('should alias gray to grey', function () { assert.equal(chalk.grey('foo'), '\u001b[90mfoo\u001b[39m'); }); From 7ef6f4c48a3eae587e8bc7db32d5aaa809565e1b Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Tue, 8 Jul 2014 21:08:09 -0700 Subject: [PATCH 031/324] dont use slice on arguments ~21% increase with multiple arguments --- index.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index b512746..ac1f168 100644 --- a/index.js +++ b/index.js @@ -40,7 +40,15 @@ var proto = defineProps(function chalk() {}, styles); function applyStyle() { // support varags, but simply cast to string in case there's only one arg - var str = arguments.length === 1 ? String(arguments[0]) : [].slice.call(arguments).join(' '); + var args = arguments; + var argsLen = args.length; + var str = argsLen !== 0 && String(arguments[0]); + if (argsLen > 1) { + // don't slice `arguments`, it prevents v8 optimizations + for (var a = 1; a < argsLen; a++) { + str += ' ' + args[a]; + } + } if (!chalk.enabled || !str) { return str; From 994758f01293f1fdcf63282e9917cb9f2cfbdaac Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Wed, 9 Jul 2014 22:25:13 +0200 Subject: [PATCH 032/324] 0.5.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7a94654..e58fe48 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "0.5.0", + "version": "0.5.1", "description": "Terminal string styling done right. Created because the `colors` module does some really horrible things.", "license": "MIT", "repository": "sindresorhus/chalk", From 03b92b1bb8eaa7da06a44ebe7998e76e79db2974 Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Sat, 12 Jul 2014 02:38:57 +0200 Subject: [PATCH 033/324] Bumps escape-string-regexp to 1.0.1, slight speed improvement. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e58fe48..d77624a 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ ], "dependencies": { "ansi-styles": "^1.1.0", - "escape-string-regexp": "^1.0.0", + "escape-string-regexp": "^1.0.1", "has-ansi": "^0.1.0", "strip-ansi": "^0.3.0", "supports-color": "^0.2.0" From bc4f81d3529bd69950419e741e215ee74042bc47 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 13 Aug 2014 21:32:50 +0200 Subject: [PATCH 034/324] bump deps --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index d77624a..47409c8 100644 --- a/package.json +++ b/package.json @@ -42,9 +42,9 @@ "dependencies": { "ansi-styles": "^1.1.0", "escape-string-regexp": "^1.0.1", - "has-ansi": "^0.1.0", - "strip-ansi": "^0.3.0", - "supports-color": "^0.2.0" + "has-ansi": "^1.0.0", + "strip-ansi": "^2.0.0", + "supports-color": "^1.0.0" }, "devDependencies": { "matcha": "^0.5.0", From 0234fe987d2c45c3efe0b61d0e9bfd123913b0d4 Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Fri, 22 Aug 2014 21:28:38 +0200 Subject: [PATCH 035/324] Reverses application of styles, now left-to-right The styles' application order used to to be right-to-left e.g.: ```javascript console.log(chalk.red.reset.blue('something')) // red ``` Where now it has been reversed. E.g.: ```javascript console.log(chalk.red.reset.blue('something')) // blue ``` It seems to me that this is the more intuitive application order. Closes #41 --- index.js | 3 ++- test.js | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index ac1f168..aec1d4d 100644 --- a/index.js +++ b/index.js @@ -57,7 +57,8 @@ function applyStyle() { /*jshint validthis: true*/ var nestedStyles = this._styles; - for (var i = 0; i < nestedStyles.length; i++) { + var i = nestedStyles.length; + while (i--) { var code = ansiStyles[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/test.js b/test.js index 3e073a6..ceaaee4 100644 --- a/test.js +++ b/test.js @@ -10,14 +10,14 @@ describe('chalk', function () { }); it('should support applying multiple styles at once', function () { - assert.equal(chalk.red.bgGreen.underline('foo'), '\u001b[4m\u001b[42m\u001b[31mfoo\u001b[39m\u001b[49m\u001b[24m'); - assert.equal(chalk.underline.red.bgGreen('foo'), '\u001b[42m\u001b[31m\u001b[4mfoo\u001b[24m\u001b[39m\u001b[49m'); + 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 () { assert.equal( chalk.red('foo' + chalk.underline.bgBlue('bar') + '!'), - '\u001b[31mfoo\u001b[44m\u001b[4mbar\u001b[24m\u001b[49m!\u001b[39m' + '\u001b[31mfoo\u001b[4m\u001b[44mbar\u001b[49m\u001b[24m!\u001b[39m' ); }); @@ -29,7 +29,7 @@ describe('chalk', function () { }); it('should reset all styles with `.reset()`', function () { - assert.equal(chalk.reset(chalk.red.bgGreen.underline('foo') + 'foo'), '\u001b[0m\u001b[4m\u001b[42m\u001b[31mfoo\u001b[39m\u001b[49m\u001b[24mfoo\u001b[0m'); + 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() { From 75f63a837ac80aaddc283d02f25842d9b65fbfba Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Fri, 22 Aug 2014 21:47:59 +0200 Subject: [PATCH 036/324] Updates documentation regarding style application order. --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 239c791..061f0d5 100644 --- a/readme.md +++ b/readme.md @@ -80,7 +80,7 @@ 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. +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. From 410bd76ad3012276c894605f6ede3fa4ee7b5c9e Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Sat, 30 Aug 2014 22:53:00 +0200 Subject: [PATCH 037/324] Linewraps at 80 where markdown syntax allows. --- readme.md | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/readme.md b/readme.md index 061f0d5..c8f6e32 100644 --- a/readme.md +++ b/readme.md @@ -5,7 +5,11 @@ [![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) ![](http://img.shields.io/badge/unicorn-approved-ff69b4.svg) -[colors.js](https://github.com/Marak/colors.js) is currently 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. +[colors.js](https://github.com/Marak/colors.js) is currently 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.** @@ -33,7 +37,8 @@ $ npm install --save chalk ## Usage -Chalk comes with an easy to use composable API where you just chain and nest the styles you want. +Chalk comes with an easy to use composable API where you just chain and nest +the styles you want. ```js var chalk = require('chalk'); @@ -65,7 +70,8 @@ var 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). +Take advantage of console.log [string +substitution](http://nodejs.org/docs/latest/api/console.html#console_console_log_data). ```js var name = 'Sindre'; @@ -80,7 +86,10 @@ 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. @@ -90,7 +99,8 @@ Color support is automatically detected, but you can override it. ### chalk.supportsColor -Detect whether the terminal [supports color](https://github.com/sindresorhus/supports-color). +Detect whether the terminal [supports +color](https://github.com/sindresorhus/supports-color). Can be overridden by the user with the flags `--color` and `--no-color`. @@ -98,9 +108,11 @@ Used internally and handled for you, but exposed for convenience. ### chalk.styles -Exposes the styles as [ANSI escape codes](https://github.com/sindresorhus/ansi-styles). +Exposes the styles as [ANSI escape +codes](https://github.com/sindresorhus/ansi-styles). -Generally not useful, but you might need just the `.open` or `.close` escape code if you're mixing externally styled strings with yours. +Generally not useful, but you might need just the `.open` or `.close` escape +code if you're mixing externally styled strings with yours. ```js var chalk = require('chalk'); @@ -119,7 +131,8 @@ Check whether a string [has color](https://github.com/sindresorhus/has-ansi). [Strip color](https://github.com/sindresorhus/strip-ansi) from a string. -Can be useful in combination with `.supportsColor` to strip color on externally styled text when it's not supported. +Can be useful in combination with `.supportsColor` to strip color on externally +styled text when it's not supported. Example: From 9864ba45814f76d459ffd96b6871dd997b249130 Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Sat, 30 Aug 2014 23:05:34 +0200 Subject: [PATCH 038/324] Bumps the number of dependants to 1700. --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index c8f6e32..480d54c 100644 --- a/readme.md +++ b/readme.md @@ -25,7 +25,7 @@ ones, they either do too much or not enough. - Clean and focused - Auto-detects color support - Actively maintained -- [Used by 1000+ modules](https://npmjs.org/browse/depended/chalk) +- [Used by 1700+ modules](https://npmjs.org/browse/depended/chalk) ## Install From d55efc39b5b988a796a917dce602a737d9ee1732 Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Sat, 30 Aug 2014 23:06:34 +0200 Subject: [PATCH 039/324] Rephrases, since Colors is no longer the most popular string styling module. See: http://npm-stat.com/charts.html?package=chalk versus http://npm-stat.com/charts.html?package=colors --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 480d54c..03857a5 100644 --- a/readme.md +++ b/readme.md @@ -5,7 +5,7 @@ [![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) ![](http://img.shields.io/badge/unicorn-approved-ff69b4.svg) -[colors.js](https://github.com/Marak/colors.js) is currently the most popular +[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 From a7b3e31cd39c8059a087a6bf135329d3480c610b Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Sat, 30 Aug 2014 23:08:28 +0200 Subject: [PATCH 040/324] Adds code tags around String.prototype. --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 03857a5..840573f 100644 --- a/readme.md +++ b/readme.md @@ -7,7 +7,7 @@ [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 +`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. @@ -19,7 +19,7 @@ ones, they either do too much or not enough. ## Why - Highly performant -- Doesn't extend String.prototype +- Doesn't extend `String.prototype` - Expressive API - Ability to nest styles - Clean and focused From 84b90410fe70def44f65543b4264456a2e3976d2 Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Sat, 30 Aug 2014 23:10:03 +0200 Subject: [PATCH 041/324] Removes $ prefix from shell command, to allow for syntax highlighting. --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 840573f..f2544e7 100644 --- a/readme.md +++ b/readme.md @@ -31,7 +31,7 @@ ones, they either do too much or not enough. ## Install ```sh -$ npm install --save chalk +npm install --save chalk ``` From 299f7d1724f1426954ebdb929257b17c3eeeb74b Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Sat, 30 Aug 2014 23:13:42 +0200 Subject: [PATCH 042/324] Removes console.log to simplify the example, and place the nested example on several lines. --- readme.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index f2544e7..c44bc56 100644 --- a/readme.md +++ b/readme.md @@ -44,22 +44,26 @@ the styles you want. var chalk = require('chalk'); // style a string -console.log( chalk.blue('Hello world!') ); +chalk.blue('Hello world!'); // combine styled and normal strings -console.log( chalk.blue('Hello'), 'World' + chalk.red('!') ); +chalk.blue('Hello'), 'World' + chalk.red('!'); // compose multiple styles using the chainable API -console.log( chalk.blue.bgRed.bold('Hello world!') ); +chalk.blue.bgRed.bold('Hello world!'); // pass in multiple arguments -console.log( chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz') ); +chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz'); // nest styles -console.log( chalk.red('Hello', chalk.underline.bgBlue('world') + '!') ); +chalk.red('Hello', chalk.underline.bgBlue('world') + '!'); // nest styles of the same type even (color, underline, background) -console.log( chalk.green('I am a green line ' + chalk.blue('with a blue substring') + ' that becomes green again!') ); +chalk.green( + 'I am a green line ' + + chalk.blue.underline.bold('with a blue substring') + + ' that becomes green again!' +); ``` Easily define your own themes. From 2c9044cc49ddf01bfa4ed952217b502ecda222b4 Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Sat, 30 Aug 2014 23:16:28 +0200 Subject: [PATCH 043/324] Minor rephrasing. --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index c44bc56..1e51fe9 100644 --- a/readme.md +++ b/readme.md @@ -116,7 +116,7 @@ Exposes the styles as [ANSI escape codes](https://github.com/sindresorhus/ansi-styles). Generally not useful, but you might need just the `.open` or `.close` escape -code if you're mixing externally styled strings with yours. +code if you're mixing externally styled strings with your own. ```js var chalk = require('chalk'); From 32ff12e4c357ada156da6a3e0d64f2019204ca68 Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Sat, 30 Aug 2014 23:25:53 +0200 Subject: [PATCH 044/324] Adds a section on 256-colors. Closes #35. References #44. --- readme.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/readme.md b/readme.md index 1e51fe9..4c685fb 100644 --- a/readme.md +++ b/readme.md @@ -186,6 +186,14 @@ if (!chalk.supportsColor) { - `bgCyan` - `bgWhite` +## 256-colors + +Chalk does not support 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. ## License From 0f22588c59f95bece6c206e98566ea097d046c33 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 31 Aug 2014 00:51:39 +0200 Subject: [PATCH 045/324] readme - don't hard-wrap no good reason to force a set line length when any editor supports soft-wrapping where you can set your own preferred size. --- readme.md | 39 ++++++++++----------------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/readme.md b/readme.md index 4c685fb..64487fb 100644 --- a/readme.md +++ b/readme.md @@ -2,14 +2,9 @@ > Terminal string styling done right -[![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) -![](http://img.shields.io/badge/unicorn-approved-ff69b4.svg) +[![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) ![](http://img.shields.io/badge/unicorn-approved-ff69b4.svg) -[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. +[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.** @@ -37,8 +32,7 @@ npm install --save chalk ## Usage -Chalk comes with an easy to use composable API where you just chain and nest -the styles you want. +Chalk comes with an easy to use composable API where you just chain and nest the styles you want. ```js var chalk = require('chalk'); @@ -74,8 +68,7 @@ var 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). +Take advantage of console.log [string substitution](http://nodejs.org/docs/latest/api/console.html#console_console_log_data). ```js var name = 'Sindre'; @@ -90,10 +83,7 @@ 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. @@ -103,8 +93,7 @@ Color support is automatically detected, but you can override it. ### chalk.supportsColor -Detect whether the terminal [supports -color](https://github.com/sindresorhus/supports-color). +Detect whether the terminal [supports color](https://github.com/sindresorhus/supports-color). Can be overridden by the user with the flags `--color` and `--no-color`. @@ -112,11 +101,9 @@ Used internally and handled for you, but exposed for convenience. ### chalk.styles -Exposes the styles as [ANSI escape -codes](https://github.com/sindresorhus/ansi-styles). +Exposes the styles as [ANSI escape codes](https://github.com/sindresorhus/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. +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'); @@ -135,8 +122,7 @@ Check whether a string [has color](https://github.com/sindresorhus/has-ansi). [Strip color](https://github.com/sindresorhus/strip-ansi) from a string. -Can be useful in combination with `.supportsColor` to strip color on externally -styled text when it's not supported. +Can be useful in combination with `.supportsColor` to strip color on externally styled text when it's not supported. Example: @@ -188,12 +174,7 @@ if (!chalk.supportsColor) { ## 256-colors -Chalk does not support 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 does not support 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. ## License From 21143174c43c9978bc95ccc41e6baed852a1643b Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 23 Nov 2014 18:56:00 +0700 Subject: [PATCH 046/324] bump ansi-styles the gray alias is now in ansi-styles --- index.js | 4 +--- package.json | 6 +++--- readme.md | 6 ++++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index aec1d4d..0bbc27c 100644 --- a/index.js +++ b/index.js @@ -21,8 +21,6 @@ function build(_styles) { var styles = (function () { var ret = {}; - ansiStyles.grey = ansiStyles.gray; - Object.keys(ansiStyles).forEach(function (key) { ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); @@ -54,7 +52,7 @@ function applyStyle() { return str; } - /*jshint validthis: true*/ + /*jshint validthis: true */ var nestedStyles = this._styles; var i = nestedStyles.length; diff --git a/package.json b/package.json index 47409c8..94fb785 100644 --- a/package.json +++ b/package.json @@ -40,14 +40,14 @@ "text" ], "dependencies": { - "ansi-styles": "^1.1.0", + "ansi-styles": "^2.0.0", "escape-string-regexp": "^1.0.1", "has-ansi": "^1.0.0", "strip-ansi": "^2.0.0", - "supports-color": "^1.0.0" + "supports-color": "^1.2.0" }, "devDependencies": { - "matcha": "^0.5.0", + "matcha": "^0.6.0", "mocha": "*" } } diff --git a/readme.md b/readme.md index 64487fb..a1da5f7 100644 --- a/readme.md +++ b/readme.md @@ -138,7 +138,7 @@ if (!chalk.supportsColor) { ## Styles -### General +### Modifiers - `reset` - `bold` @@ -149,7 +149,7 @@ if (!chalk.supportsColor) { - `hidden` - `strikethrough` *(not widely supported)* -### Text colors +### Colors - `black` - `red` @@ -172,10 +172,12 @@ if (!chalk.supportsColor) { - `bgCyan` - `bgWhite` + ## 256-colors Chalk does not support 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. + ## License MIT © [Sindre Sorhus](http://sindresorhus.com) From 0b1c65dfd3b086827819adf03035e64f419cc186 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 23 Nov 2014 18:57:13 +0700 Subject: [PATCH 047/324] bump dependents count. now 2200+ \o/ --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index a1da5f7..824a1cb 100644 --- a/readme.md +++ b/readme.md @@ -20,7 +20,7 @@ - Clean and focused - Auto-detects color support - Actively maintained -- [Used by 1700+ modules](https://npmjs.org/browse/depended/chalk) +- [Used by 2200+ modules](https://npmjs.org/browse/depended/chalk) ## Install From fc6a9b27dc1b58985b3eb8ae0fc712be9be42488 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 5 Dec 2014 16:11:13 +0700 Subject: [PATCH 048/324] force `blue` color to be use bright blue on Windows - fixes #36 as the normal blue color is illegible --- index.js | 5 +++++ readme.md | 2 +- test.js | 18 +++++++++--------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index 0bbc27c..6274189 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,11 @@ var supportsColor = require('supports-color'); var defineProps = Object.defineProperties; var chalk = module.exports; +// use bright blue on Windows as the normal blue color is illegible +if (process.platform === 'win32') { + ansiStyles.blue.open = '\u001b[94m'; +} + function build(_styles) { var builder = function builder() { return applyStyle.apply(builder, arguments); diff --git a/readme.md b/readme.md index 824a1cb..2b13d66 100644 --- a/readme.md +++ b/readme.md @@ -155,7 +155,7 @@ if (!chalk.supportsColor) { - `red` - `green` - `yellow` -- `blue` +- `blue` *(on Windows the bright version is used as normal blue is illegible)* - `magenta` - `cyan` - `white` diff --git a/test.js b/test.js index ceaaee4..ca5049e 100644 --- a/test.js +++ b/test.js @@ -23,8 +23,8 @@ describe('chalk', function () { it('should support nesting styles of the same type (color, underline, bg)', function () { assert.equal( - chalk.red('a' + chalk.blue('b' + chalk.green('c') + 'b') + 'c'), - '\u001b[31ma\u001b[34mb\u001b[32mc\u001b[34mb\u001b[31mc\u001b[39m' + chalk.red('a' + chalk.yellow('b' + chalk.green('c') + 'b') + 'c'), + '\u001b[31ma\u001b[33mb\u001b[32mc\u001b[33mb\u001b[31mc\u001b[39m' ); }); @@ -34,13 +34,13 @@ describe('chalk', function () { it('should be able to cache multiple styles', function() { var red = chalk.red; - var blue = chalk.blue; + var green = chalk.green; var redBold = red.bold; - var blueBold = blue.bold; + var greenBold = green.bold; - assert.notEqual(red('foo'), blue('foo')); - assert.notEqual(redBold('bar'), blueBold('bar')); - assert.notEqual(blue('baz'), blueBold('baz')); + 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 () { @@ -76,8 +76,8 @@ describe('chalk.styles', function () { describe('chalk.hasColor()', function () { it('should detect whether a string has color', function () { - assert(chalk.hasColor(chalk.blue('foo'))); - assert(!chalk.hasColor(chalk.stripColor(chalk.blue('foo')))); + assert(chalk.hasColor(chalk.green('foo'))); + assert(!chalk.hasColor(chalk.stripColor(chalk.green('foo')))); }); }); From c11f8b527a31b2e7b702de4139f8e1585d6300dd Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 5 Dec 2014 17:31:57 +0700 Subject: [PATCH 049/324] add recommendation about using `cmder` instead of `cmd.exe` --- readme.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/readme.md b/readme.md index 2b13d66..bcaf381 100644 --- a/readme.md +++ b/readme.md @@ -178,6 +178,11 @@ if (!chalk.supportsColor) { Chalk does not support 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. +## Windows + +If you're on Windows, do yourself a favor and use [`cmder`](http://bliker.github.io/cmder/) instead of `cmd.exe`. + + ## License MIT © [Sindre Sorhus](http://sindresorhus.com) From 847d932a207bbd67e816bf98a88f87909e419cec Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Sun, 28 Dec 2014 12:15:16 +0100 Subject: [PATCH 050/324] Bumps has-ansi to 1.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 94fb785..cd025b0 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "dependencies": { "ansi-styles": "^2.0.0", "escape-string-regexp": "^1.0.1", - "has-ansi": "^1.0.0", + "has-ansi": "^1.0.1", "strip-ansi": "^2.0.0", "supports-color": "^1.2.0" }, From 30dfb6d2d3cbf6328e27598a46c3470c06e0c008 Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Sun, 28 Dec 2014 12:33:26 +0100 Subject: [PATCH 051/324] Fixes incorrect string concatenation in example. Issue got introduced in 299f7d17 when removing console.log from the examples to shorten them. References #44. --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index bcaf381..c454223 100644 --- a/readme.md +++ b/readme.md @@ -41,7 +41,7 @@ var chalk = require('chalk'); chalk.blue('Hello world!'); // combine styled and normal strings -chalk.blue('Hello'), 'World' + chalk.red('!'); +chalk.blue('Hello') + 'World' + chalk.red('!'); // compose multiple styles using the chainable API chalk.blue.bgRed.bold('Hello world!'); From 83bed4f598bfb9923725c66c7f50c9a8d8f4b723 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 20 Jan 2015 01:09:51 +0800 Subject: [PATCH 052/324] minify the logo --- logo.png | Bin 25696 -> 25676 bytes logo.svg | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/logo.png b/logo.png index 1228ccf1fae1934de0746789590e6d5b7a0a9660..dad567465028939942870c3c97a80cb9e1857ccc 100644 GIT binary patch delta 25412 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݇shs#)usB?cK7SP0SYRSUm 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 delta 25432 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 T0xWjP00000NkvXXu0mjf-4&u_ diff --git a/logo.svg b/logo.svg index 28d1881..fcc3ea1 100644 --- a/logo.svg +++ b/logo.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From b5468366e708ee753a592b0ee6829e729db038c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20K=C3=BChnel?= Date: Thu, 22 Jan 2015 10:05:01 +0100 Subject: [PATCH 053/324] Update readme.md Visually harmonize style of badges :cop: --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index c454223..87c7845 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,7 @@ > Terminal string styling done right -[![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) ![](http://img.shields.io/badge/unicorn-approved-ff69b4.svg) +[![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) ![](http://img.shields.io/badge/unicorn-approved-ff69b4.svg?style=flat) [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 aa7e67741f4b01467a6fa0fe136b052b368441d0 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 22 Jan 2015 17:14:01 +0800 Subject: [PATCH 054/324] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 87c7845..0945581 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,7 @@ > Terminal string styling done right -[![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) ![](http://img.shields.io/badge/unicorn-approved-ff69b4.svg?style=flat) +[![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) [![](http://img.shields.io/badge/unicorn-approved-ff69b4.svg?style=flat)](https://www.youtube.com/watch?v=Sm368W0OsHo) [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 b897d1955bc279a0acb1e53214c0da450461d1cc Mon Sep 17 00:00:00 2001 From: Noam Okman Date: Wed, 4 Feb 2015 17:31:11 +0200 Subject: [PATCH 055/324] Update readme.md Just changed the url to point to the new npm website --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 0945581..32f3c0d 100644 --- a/readme.md +++ b/readme.md @@ -20,7 +20,7 @@ - Clean and focused - Auto-detects color support - Actively maintained -- [Used by 2200+ modules](https://npmjs.org/browse/depended/chalk) +- [Used by 2200+ modules](https://www.npmjs.com/browse/depended/chalk) ## Install From 4d9c98c6038b5380a95f4bab882456c485397774 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 8 Feb 2015 16:59:13 +0700 Subject: [PATCH 056/324] Update .travis.yml --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 244b7e8..dedfc07 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,6 @@ +sudo: false language: node_js node_js: + - 'iojs' + - '0.12' - '0.10' From 72d1c11e43a00c0ea64ea3591342d68ef4b46244 Mon Sep 17 00:00:00 2001 From: David Keijser Date: Tue, 17 Feb 2015 15:18:18 +0700 Subject: [PATCH 057/324] Close #54 PR: export classy chalk object to create isolated ctx. Fixes #46, Fixes #46 --- index.js | 33 +++++++++++++++++++-------------- readme.md | 5 ++++- test.js | 8 ++++++++ 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/index.js b/index.js index 6274189..511e2d7 100644 --- a/index.js +++ b/index.js @@ -5,7 +5,15 @@ var stripAnsi = require('strip-ansi'); var hasAnsi = require('has-ansi'); var supportsColor = require('supports-color'); var defineProps = Object.defineProperties; -var chalk = module.exports; + +function Chalk(options) { + // detect mode if not set manually + if (!options || options.enabled === undefined) { + this.enabled = supportsColor; + } else { + this.enabled = options.enabled; + } +} // use bright blue on Windows as the normal blue color is illegible if (process.platform === 'win32') { @@ -17,6 +25,7 @@ function build(_styles) { return applyStyle.apply(builder, arguments); }; builder._styles = _styles; + builder.enabled = this.enabled; // __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; @@ -31,7 +40,7 @@ var styles = (function () { ret[key] = { get: function () { - return build(this._styles.concat(key)); + return build.call(this, this._styles.concat(key)); } }; }); @@ -53,7 +62,7 @@ function applyStyle() { } } - if (!chalk.enabled || !str) { + if (!this.enabled || !str) { return str; } @@ -78,7 +87,7 @@ function init() { Object.keys(styles).forEach(function (name) { ret[name] = { get: function () { - return build([name]); + return build.call(this, [name]); } }; }); @@ -86,14 +95,10 @@ function init() { return ret; } -defineProps(chalk, init()); +defineProps(Chalk.prototype, init()); -chalk.styles = ansiStyles; -chalk.hasColor = hasAnsi; -chalk.stripColor = stripAnsi; -chalk.supportsColor = supportsColor; - -// detect mode if not set manually -if (chalk.enabled === undefined) { - chalk.enabled = chalk.supportsColor; -} +module.exports = new Chalk(); +module.exports.styles = ansiStyles; +module.exports.hasColor = hasAnsi; +module.exports.stripColor = stripAnsi; +module.exports.supportsColor = supportsColor; diff --git a/readme.md b/readme.md index 32f3c0d..9fadbd6 100644 --- a/readme.md +++ b/readme.md @@ -89,7 +89,10 @@ Multiple arguments will be separated by space. ### chalk.enabled -Color support is automatically detected, but you can override it. +Color support is automatically detected, but you can override it by setting the +`enabled` property or by creating a new instance just for your usage. Changing +the property should only be done from end-user facing applications as it +affects all consumers of the default chalk instance ### chalk.supportsColor diff --git a/test.js b/test.js index ca5049e..5787e18 100644 --- a/test.js +++ b/test.js @@ -68,6 +68,14 @@ describe('chalk.enabled', function () { }); }); +describe('chalk.constructor', function () { + it('should create a isolated context where colors can be disabled', function () { + var ctx = new chalk.constructor({enabled: false}); + assert.equal(ctx.red('foo'), 'foo'); + 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'); From eb7a5db36aabb6b66430c068cc9cb181e8394fe9 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 17 Feb 2015 15:21:54 +0700 Subject: [PATCH 058/324] minor meta files tweak --- .editorconfig | 1 - .jshintrc | 4 ---- 2 files changed, 5 deletions(-) diff --git a/.editorconfig b/.editorconfig index 8311fe1..86c8f59 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,4 +1,3 @@ -# editorconfig.org root = true [*] diff --git a/.jshintrc b/.jshintrc index 3e1760c..804f8af 100644 --- a/.jshintrc +++ b/.jshintrc @@ -4,13 +4,9 @@ "bitwise": true, "camelcase": true, "curly": true, - "eqeqeq": true, "immed": true, - "indent": 4, "newcap": true, "noarg": true, - "proto": true, - "quotmark": "single", "undef": true, "unused": "vars", "strict": true From 99614e760f887b12a2de606cdb09a445cf3013ac Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 17 Feb 2015 15:24:13 +0700 Subject: [PATCH 059/324] ternarify --- index.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/index.js b/index.js index 511e2d7..4138a64 100644 --- a/index.js +++ b/index.js @@ -8,11 +8,7 @@ var defineProps = Object.defineProperties; function Chalk(options) { // detect mode if not set manually - if (!options || options.enabled === undefined) { - this.enabled = supportsColor; - } else { - this.enabled = options.enabled; - } + this.enabled = !options || options.enabled === undefined ? supportsColor : options.enabled; } // use bright blue on Windows as the normal blue color is illegible From c799a8aaed1b99c519dd4a6bbd7b4c0fad57efc1 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 17 Feb 2015 15:57:40 +0700 Subject: [PATCH 060/324] readme tweaks --- package.json | 2 +- readme.md | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index cd025b0..b9f261b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "chalk", "version": "0.5.1", - "description": "Terminal string styling done right. Created because the `colors` module does some really horrible things.", + "description": "Terminal string styling done right. Much color.", "license": "MIT", "repository": "sindresorhus/chalk", "maintainers": [ diff --git a/readme.md b/readme.md index 9fadbd6..1b9a8d8 100644 --- a/readme.md +++ b/readme.md @@ -20,13 +20,13 @@ - Clean and focused - Auto-detects color support - Actively maintained -- [Used by 2200+ modules](https://www.npmjs.com/browse/depended/chalk) +- [Used by ~3000 modules](https://www.npmjs.com/browse/depended/chalk) ## Install -```sh -npm install --save chalk +``` +$ npm install --save chalk ``` @@ -89,10 +89,13 @@ Multiple arguments will be separated by space. ### chalk.enabled -Color support is automatically detected, but you can override it by setting the -`enabled` property or by creating a new instance just for your usage. Changing -the property should only be done from end-user facing applications as it -affects all consumers of the default chalk instance +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. + +If you need to change this in a reusable module create a new instance: + +```js +var ctx = new chalk.constructor({enabled: false}); +``` ### chalk.supportsColor From 2b872f214589e7884d65202b90e2f89d58e9e54f Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Sun, 22 Feb 2015 10:26:34 +0100 Subject: [PATCH 061/324] Updates maintainer info. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b9f261b..edd3de3 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "repository": "sindresorhus/chalk", "maintainers": [ "Sindre Sorhus (http://sindresorhus.com)", - "Joshua Appelman " + "Joshua Appelman (http://jbnicolai.com)" ], "engines": { "node": ">=0.10.0" From e520cec3e1aca12a056a69426f3f409ec43b3300 Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Sun, 22 Feb 2015 10:32:55 +0100 Subject: [PATCH 062/324] Bumps deps. --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index edd3de3..613afd1 100644 --- a/package.json +++ b/package.json @@ -40,11 +40,11 @@ "text" ], "dependencies": { - "ansi-styles": "^2.0.0", - "escape-string-regexp": "^1.0.1", - "has-ansi": "^1.0.1", - "strip-ansi": "^2.0.0", - "supports-color": "^1.2.0" + "ansi-styles": "^2.0.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^1.0.3", + "strip-ansi": "^2.0.1", + "supports-color": "^1.2.1" }, "devDependencies": { "matcha": "^0.6.0", From 19935d6484811c5e468817f846b7b3d417d7bf4a Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 23 Feb 2015 14:03:03 +0700 Subject: [PATCH 063/324] add support for `FORCE_COLOR` environment variable to force color https://github.com/sindresorhus/supports-color/pull/18 --- package.json | 2 +- readme.md | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 613afd1..bb067b8 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "escape-string-regexp": "^1.0.2", "has-ansi": "^1.0.3", "strip-ansi": "^2.0.1", - "supports-color": "^1.2.1" + "supports-color": "^1.3.0" }, "devDependencies": { "matcha": "^0.6.0", diff --git a/readme.md b/readme.md index 1b9a8d8..34878e0 100644 --- a/readme.md +++ b/readme.md @@ -99,11 +99,9 @@ var ctx = new chalk.constructor({enabled: false}); ### chalk.supportsColor -Detect whether the terminal [supports color](https://github.com/sindresorhus/supports-color). +Detect whether the terminal [supports color](https://github.com/sindresorhus/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`. - -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`. ### chalk.styles From 3edf7923979b64eb0064ace5629071d43d730d15 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 23 Feb 2015 14:38:38 +0700 Subject: [PATCH 064/324] readme - improve logo presentation --- readme.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 34878e0..43c7064 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,9 @@ -# chalk +

+
+ chalk +
+
+

> Terminal string styling done right From 8864d3563313ed15574a38dd5c9d5966080c46ce Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 23 Feb 2015 14:41:32 +0700 Subject: [PATCH 065/324] 1.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bb067b8..f6d23b1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "0.5.1", + "version": "1.0.0", "description": "Terminal string styling done right. Much color.", "license": "MIT", "repository": "sindresorhus/chalk", From acf38095ea62abc090289db66dc7df87d8f81059 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 25 Mar 2015 20:20:58 +0800 Subject: [PATCH 066/324] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 43c7064..8be6ccb 100644 --- a/readme.md +++ b/readme.md @@ -7,7 +7,7 @@ > Terminal string styling done right -[![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) [![](http://img.shields.io/badge/unicorn-approved-ff69b4.svg?style=flat)](https://www.youtube.com/watch?v=Sm368W0OsHo) +[![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) [![](http://img.shields.io/badge/unicorn-approved-ff69b4.svg?style=flat)](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 04cb2d21ae59037efe0db1d8418cb5662e09bead Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 11 Apr 2015 22:50:22 +0700 Subject: [PATCH 067/324] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 8be6ccb..147b1d1 100644 --- a/readme.md +++ b/readme.md @@ -7,7 +7,7 @@ > Terminal string styling done right -[![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) [![](http://img.shields.io/badge/unicorn-approved-ff69b4.svg?style=flat)](https://www.youtube.com/watch?v=9auOCbH5Ns4) +[![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) [![](http://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 e3272e8449989406c4abb0f171f1ae9a6e7cb103 Mon Sep 17 00:00:00 2001 From: Wei Kin Huang Date: Sun, 26 Apr 2015 15:57:41 +0700 Subject: [PATCH 068/324] Close #60 PR: Don't override windows blue when in xterm mode. Fixes #59 --- index.js | 2 +- package.json | 5 ++++- test.js | 45 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 4138a64..2bad21b 100644 --- a/index.js +++ b/index.js @@ -12,7 +12,7 @@ function Chalk(options) { } // use bright blue on Windows as the normal blue color is illegible -if (process.platform === 'win32') { +if (process.platform === 'win32' && !/^xterm/i.test(process.env.TERM || '')) { ansiStyles.blue.open = '\u001b[94m'; } diff --git a/package.json b/package.json index f6d23b1..68c75f1 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,9 @@ }, "devDependencies": { "matcha": "^0.6.0", - "mocha": "*" + "mocha": "*", + "require-uncached": "^1.0.2", + "resolve-from": "^1.0.0", + "semver": "^4.3.3" } } diff --git a/test.js b/test.js index 5787e18..b7359bf 100644 --- a/test.js +++ b/test.js @@ -1,5 +1,8 @@ 'use strict'; var assert = require('assert'); +var requireUncached = require('require-uncached'); +var resolveFrom = require('resolve-from'); +var semver = require('semver'); var chalk = require('./'); describe('chalk', function () { @@ -32,7 +35,7 @@ describe('chalk', 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 be able to cache multiple styles', function() { + it('should be able to cache multiple styles', function () { var red = chalk.red; var green = chalk.green; var redBold = red.bold; @@ -60,6 +63,46 @@ describe('chalk', function () { }); }); +describe('chalk on windows', function () { + var originalEnv; + var 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 () { + originalEnv = process.env; + originalPlatform = process.platform; + }); + + after(function () { + process.env = originalEnv; + Object.defineProperty(process, 'platform', {value: originalPlatform}); + }); + + beforeEach(function () { + 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 replace blue foreground color in cmd.exe', function () { + process.env.TERM = 'dumb'; + var chalkCtx = requireUncached('./'); + 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('./'); + assert.equal(chalkCtx.blue('foo'), '\u001b[34mfoo\u001b[39m'); + }); +}); + describe('chalk.enabled', function () { it('should not output colors when manually disabled', function () { chalk.enabled = false; From 6a506dc9b35131bd528df23a0f4629316b07913d Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Sun, 24 May 2015 07:25:32 +0300 Subject: [PATCH 069/324] update dependents to ~4k on may 24, 2015 --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 147b1d1..30f6564 100644 --- a/readme.md +++ b/readme.md @@ -25,7 +25,7 @@ - Clean and focused - Auto-detects color support - Actively maintained -- [Used by ~3000 modules](https://www.npmjs.com/browse/depended/chalk) +- [Used by ~4000 modules](https://www.npmjs.com/browse/depended/chalk) as of May 24, 2015 ## Install From b630e70855e2bfc34b7437bfd7a935c0751f943c Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Mon, 25 May 2015 01:37:33 -0700 Subject: [PATCH 070/324] add coverage reporting using nyc and coveralls --- .gitignore | 2 ++ .travis.yml | 1 + package.json | 6 +++++- readme.md | 2 ++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3c3629e..16628a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules +coverage +nyc_output diff --git a/.travis.yml b/.travis.yml index dedfc07..3da5271 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,3 +4,4 @@ node_js: - 'iojs' - '0.12' - '0.10' +after_success: npm run coveralls diff --git a/package.json b/package.json index 68c75f1..3d0b3e7 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,9 @@ }, "scripts": { "test": "mocha", - "bench": "matcha benchmark.js" + "bench": "matcha benchmark.js", + "coverage": "nyc npm test && nyc report", + "coveralls": "nyc npm test && nyc report --reporter=text-lcov | coveralls" }, "files": [ "index.js" @@ -47,8 +49,10 @@ "supports-color": "^1.3.0" }, "devDependencies": { + "coveralls": "^2.11.2", "matcha": "^0.6.0", "mocha": "*", + "nyc": "^2.1.4", "require-uncached": "^1.0.2", "resolve-from": "^1.0.0", "semver": "^4.3.3" diff --git a/readme.md b/readme.md index 147b1d1..e597515 100644 --- a/readme.md +++ b/readme.md @@ -8,6 +8,8 @@ > Terminal string styling done right [![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) [![](http://img.shields.io/badge/unicorn-approved-ff69b4.svg)](https://www.youtube.com/watch?v=9auOCbH5Ns4) +[![Coverage Status](https://coveralls.io/repos/sindresorhus/chalk/badge.svg?branch=)](https://coveralls.io/r/sindresorhus/chalk?branch=) + [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 c8e08f5e7939909b968a847334d7ffd721cf3f8c Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 25 May 2015 13:18:05 +0200 Subject: [PATCH 071/324] minor tweaks --- .gitignore | 2 +- package.json | 6 ++++-- readme.md | 7 ++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 16628a8..1fd04da 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ node_modules coverage -nyc_output +.nyc_output diff --git a/package.json b/package.json index 3d0b3e7..5f1f563 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "license": "MIT", "repository": "sindresorhus/chalk", "maintainers": [ - "Sindre Sorhus (http://sindresorhus.com)", - "Joshua Appelman (http://jbnicolai.com)" + "Sindre Sorhus (sindresorhus.com)", + "Joshua Appelman (jbnicolai.com)" ], "engines": { "node": ">=0.10.0" @@ -28,7 +28,9 @@ "console", "cli", "string", + "str", "ansi", + "style", "styles", "tty", "formatting", diff --git a/readme.md b/readme.md index 75db54c..9862b3c 100644 --- a/readme.md +++ b/readme.md @@ -7,15 +7,16 @@ > Terminal string styling done right -[![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) [![](http://img.shields.io/badge/unicorn-approved-ff69b4.svg)](https://www.youtube.com/watch?v=9auOCbH5Ns4) -[![Coverage Status](https://coveralls.io/repos/sindresorhus/chalk/badge.svg?branch=)](https://coveralls.io/r/sindresorhus/chalk?branch=) +[![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) +[![Coverage Status](https://coveralls.io/repos/sindresorhus/chalk/badge.svg?branch=master)](https://coveralls.io/r/sindresorhus/chalk?branch=master) +[![](http://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. **Chalk is a clean and focused alternative.** -![screenshot](https://github.com/sindresorhus/ansi-styles/raw/master/screenshot.png) +![](https://github.com/sindresorhus/ansi-styles/raw/master/screenshot.png) ## Why From c63e95c58b9b5015459d1cb2dc23405f1e50c2b8 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 2 Jun 2015 17:12:01 +0200 Subject: [PATCH 072/324] code style --- index.js | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/index.js b/index.js index 2bad21b..b4a8488 100644 --- a/index.js +++ b/index.js @@ -16,18 +16,6 @@ if (process.platform === 'win32' && !/^xterm/i.test(process.env.TERM || '')) { ansiStyles.blue.open = '\u001b[94m'; } -function build(_styles) { - var builder = function builder() { - return applyStyle.apply(builder, arguments); - }; - builder._styles = _styles; - builder.enabled = this.enabled; - // __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; - return builder; -} - var styles = (function () { var ret = {}; @@ -46,11 +34,27 @@ var styles = (function () { var proto = defineProps(function chalk() {}, styles); +function build(_styles) { + var builder = function builder() { + return applyStyle.apply(builder, arguments); + }; + + builder._styles = _styles; + builder.enabled = this.enabled; + // __proto__ is used because we must return a function, but there is + // no way to create a function with a different prototype. + /*eslint no-proto: 0 */ + builder.__proto__ = 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]); + if (argsLen > 1) { // don't slice `arguments`, it prevents v8 optimizations for (var a = 1; a < argsLen; a++) { @@ -62,12 +66,12 @@ function applyStyle() { return str; } - /*jshint validthis: true */ var nestedStyles = this._styles; - var i = nestedStyles.length; + while (i--) { var code = ansiStyles[nestedStyles[i]]; + // 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'. From bd73784b9027a2614c58849b82ba1a753cad4ae9 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 30 Jun 2015 19:55:37 +0200 Subject: [PATCH 073/324] update references --- package.json | 2 +- readme.md | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 5f1f563..4c08641 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "description": "Terminal string styling done right. Much color.", "license": "MIT", - "repository": "sindresorhus/chalk", + "repository": "chalk/chalk", "maintainers": [ "Sindre Sorhus (sindresorhus.com)", "Joshua Appelman (jbnicolai.com)" diff --git a/readme.md b/readme.md index 9862b3c..13d64c8 100644 --- a/readme.md +++ b/readme.md @@ -1,14 +1,14 @@


- chalk + chalk

> Terminal string styling done right -[![Build Status](https://travis-ci.org/sindresorhus/chalk.svg?branch=master)](https://travis-ci.org/sindresorhus/chalk) -[![Coverage Status](https://coveralls.io/repos/sindresorhus/chalk/badge.svg?branch=master)](https://coveralls.io/r/sindresorhus/chalk?branch=master) +[![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) @@ -16,7 +16,7 @@ **Chalk is a clean and focused alternative.** -![](https://github.com/sindresorhus/ansi-styles/raw/master/screenshot.png) +![](https://github.com/chalk/ansi-styles/raw/master/screenshot.png) ## Why @@ -107,13 +107,13 @@ var ctx = new chalk.constructor({enabled: false}); ### chalk.supportsColor -Detect whether the terminal [supports color](https://github.com/sindresorhus/supports-color). Used internally and handled for you, but exposed for convenience. +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`. ### chalk.styles -Exposes the styles as [ANSI escape codes](https://github.com/sindresorhus/ansi-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. @@ -128,11 +128,11 @@ console.log(chalk.styles.red.open + 'Hello' + chalk.styles.red.close); ### chalk.hasColor(string) -Check whether a string [has color](https://github.com/sindresorhus/has-ansi). +Check whether a string [has color](https://github.com/chalk/has-ansi). ### chalk.stripColor(string) -[Strip color](https://github.com/sindresorhus/strip-ansi) from a 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. From 8bc283ab600c06a372bd1146171a6692728b31ca Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 30 Jun 2015 19:56:59 +0200 Subject: [PATCH 074/324] move the logo into a `/media` --- logo.png => media/logo.png | Bin logo.svg => media/logo.svg | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename logo.png => media/logo.png (100%) rename logo.svg => media/logo.svg (100%) diff --git a/logo.png b/media/logo.png similarity index 100% rename from logo.png rename to media/logo.png diff --git a/logo.svg b/media/logo.svg similarity index 100% rename from logo.svg rename to media/logo.svg From c7476c9b52c5ae1e94ea9123ebc50d8f839220f4 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 30 Jun 2015 19:57:59 +0200 Subject: [PATCH 075/324] readme - give logo more breathing room --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 13d64c8..f2e082d 100644 --- a/readme.md +++ b/readme.md @@ -1,8 +1,10 @@

+

chalk

+

> Terminal string styling done right From 81c3ef9efa4e7a5010d18b8e34f97bec9ff33eb3 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 30 Jun 2015 21:22:46 +0200 Subject: [PATCH 076/324] readme - add related section --- readme.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/readme.md b/readme.md index f2e082d..b65c6fc 100644 --- a/readme.md +++ b/readme.md @@ -197,6 +197,15 @@ Chalk does not support support anything other than the base eight colors, which If you're on Windows, do yourself a favor and use [`cmder`](http://bliker.github.io/cmder/) instead of `cmd.exe`. +## Related + +- [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 + + ## License MIT © [Sindre Sorhus](http://sindresorhus.com) From 425e3a7ee802b15c053eb9c12d1f305f2bf15288 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 30 Jun 2015 22:04:07 +0200 Subject: [PATCH 077/324] bump deps --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 4c08641..1ee0a18 100644 --- a/package.json +++ b/package.json @@ -46,15 +46,15 @@ "dependencies": { "ansi-styles": "^2.0.1", "escape-string-regexp": "^1.0.2", - "has-ansi": "^1.0.3", - "strip-ansi": "^2.0.1", - "supports-color": "^1.3.0" + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" }, "devDependencies": { "coveralls": "^2.11.2", "matcha": "^0.6.0", "mocha": "*", - "nyc": "^2.1.4", + "nyc": "^3.0.0", "require-uncached": "^1.0.2", "resolve-from": "^1.0.0", "semver": "^4.3.3" From dde728719284a1701e69709fbf586d0a28a83f93 Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Wed, 1 Jul 2015 01:59:40 +0200 Subject: [PATCH 078/324] Removes needless "|| ''". --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index b4a8488..96f0ccb 100644 --- a/index.js +++ b/index.js @@ -12,7 +12,7 @@ function Chalk(options) { } // use bright blue on Windows as the normal blue color is illegible -if (process.platform === 'win32' && !/^xterm/i.test(process.env.TERM || '')) { +if (process.platform === 'win32' && !/^xterm/i.test(process.env.TERM)) { ansiStyles.blue.open = '\u001b[94m'; } From 7d5955a91aedaca4916f07569d6ae1d1ab0864fe Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 1 Jul 2015 03:01:07 +0200 Subject: [PATCH 079/324] add reference to `chalk-cli https://github.com/chalk/chalk-cli --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index b65c6fc..f757e59 100644 --- a/readme.md +++ b/readme.md @@ -199,6 +199,7 @@ If you're on Windows, do yourself a favor and use [`cmder`](http://bliker.github ## 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 - [strip-ansi](https://github.com/chalk/strip-ansi) - Strip ANSI escape codes From 922ac4b0aa67c42b7e0e79ca4a5a7c33beb3e858 Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Wed, 1 Jul 2015 02:21:39 +0200 Subject: [PATCH 080/324] Makes dim when gray a noop on windows terminals. Fixes #58 --- index.js | 14 +++++++++++++- test.js | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 96f0ccb..cbe9288 100644 --- a/index.js +++ b/index.js @@ -5,6 +5,7 @@ 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); function Chalk(options) { // detect mode if not set manually @@ -12,7 +13,7 @@ function Chalk(options) { } // use bright blue on Windows as the normal blue color is illegible -if (process.platform === 'win32' && !/^xterm/i.test(process.env.TERM)) { +if (isSimpleWindowsTerm) { ansiStyles.blue.open = '\u001b[94m'; } @@ -69,6 +70,14 @@ function applyStyle() { var nestedStyles = this._styles; var 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; + if (isSimpleWindowsTerm && (nestedStyles.indexOf('gray') !== -1 || nestedStyles.indexOf('grey') !== -1)) { + ansiStyles.dim.open = ''; + } + while (i--) { var code = ansiStyles[nestedStyles[i]]; @@ -78,6 +87,9 @@ function applyStyle() { str = code.open + str.replace(code.closeRe, code.open) + code.close; } + // 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/test.js b/test.js index b7359bf..bc39470 100644 --- a/test.js +++ b/test.js @@ -101,6 +101,25 @@ describe('chalk on windows', function () { var chalkCtx = requireUncached('./'); 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('./'); + 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('./'); + 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('./'); + assert.equal(chalkCtx.blue.dim('foo'), '\u001b[94m\u001b[2mfoo\u001b[22m\u001b[39m'); + }); + }); describe('chalk.enabled', function () { From ed03714ec28411c1c02fc6943a4dc224af7959c9 Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Wed, 1 Jul 2015 15:28:52 +0200 Subject: [PATCH 081/324] Bump ansi-styles version. Fixes #63 as ansi-styles now exposes a unique object per required instance. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1ee0a18..4e79255 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "text" ], "dependencies": { - "ansi-styles": "^2.0.1", + "ansi-styles": "^2.1.0", "escape-string-regexp": "^1.0.2", "has-ansi": "^2.0.0", "strip-ansi": "^3.0.0", From e9bb6e6000b1c5d4508afabfdc85dd70f582f515 Mon Sep 17 00:00:00 2001 From: Joshua Appelman Date: Wed, 1 Jul 2015 15:31:59 +0200 Subject: [PATCH 082/324] 1.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4e79255..d3726a7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "1.0.0", + "version": "1.1.0", "description": "Terminal string styling done right. Much color.", "license": "MIT", "repository": "chalk/chalk", From 632bd4a088f0cb685179f66df73a3b687926f8bd Mon Sep 17 00:00:00 2001 From: Qix Date: Wed, 1 Jul 2015 07:32:17 -0600 Subject: [PATCH 083/324] added Qix as maintainer --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 4e79255..6dc34e9 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "repository": "chalk/chalk", "maintainers": [ "Sindre Sorhus (sindresorhus.com)", - "Joshua Appelman (jbnicolai.com)" + "Joshua Appelman (jbnicolai.com)", + "JD Ballard (github.com/qix-)" ], "engines": { "node": ">=0.10.0" From 388e21aed744c37b5d5c4c102c0e2415edf725de Mon Sep 17 00:00:00 2001 From: Daniel Husar Date: Fri, 3 Jul 2015 14:16:30 +0100 Subject: [PATCH 084/324] Fix typo in readme --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index f757e59..f2d0219 100644 --- a/readme.md +++ b/readme.md @@ -189,7 +189,7 @@ if (!chalk.supportsColor) { ## 256-colors -Chalk does not support 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 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. ## Windows From 6142553bb5d7b3e7fbcea76b8ccf876f373e1bf1 Mon Sep 17 00:00:00 2001 From: Qix Date: Thu, 16 Jul 2015 14:34:28 -0600 Subject: [PATCH 085/324] updated # of dependents to ~4.5k --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index f2d0219..66b8c54 100644 --- a/readme.md +++ b/readme.md @@ -30,7 +30,7 @@ - Clean and focused - Auto-detects color support - Actively maintained -- [Used by ~4000 modules](https://www.npmjs.com/browse/depended/chalk) as of May 24, 2015 +- [Used by ~4500 modules](https://www.npmjs.com/browse/depended/chalk) as of July 15, 2015 ## Install From 4006cc0b4109df1c8fd7941c4871c8f8a66fbfad Mon Sep 17 00:00:00 2001 From: Luke Page Date: Wed, 19 Aug 2015 16:57:06 +0100 Subject: [PATCH 086/324] Remove un-necessary function name. Fixes #80 --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index cbe9288..7e3aa6c 100644 --- a/index.js +++ b/index.js @@ -36,7 +36,7 @@ var styles = (function () { var proto = defineProps(function chalk() {}, styles); function build(_styles) { - var builder = function builder() { + var builder = function () { return applyStyle.apply(builder, arguments); }; From fb6332df4fc6838f6a789f8dfb9a3d13e6c9e97d Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 20 Aug 2015 03:02:09 +0700 Subject: [PATCH 087/324] readme - add `wrap-ansi` to related section --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 66b8c54..5cf111e 100644 --- a/readme.md +++ b/readme.md @@ -205,6 +205,7 @@ If you're on Windows, do yourself a favor and use [`cmder`](http://bliker.github - [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 +- [wrap-ansi](https://github.com/chalk/wrap-ansi) - Wordwrap a string with ANSI escape codes ## License From 409f95eef525bcee56d1baafcee0b8f18cb72349 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 20 Aug 2015 03:05:43 +0700 Subject: [PATCH 088/324] add XO https://github.com/sindresorhus/xo --- .editorconfig | 2 +- .jshintrc | 13 ------------- benchmark.js | 2 ++ index.js | 2 +- package.json | 11 +++++++++-- test.js | 1 - 6 files changed, 13 insertions(+), 18 deletions(-) delete mode 100644 .jshintrc diff --git a/.editorconfig b/.editorconfig index 86c8f59..8f9d77e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,7 +7,7 @@ charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -[package.json] +[{package.json,*.yml}] indent_style = space indent_size = 2 diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 804f8af..0000000 --- a/.jshintrc +++ /dev/null @@ -1,13 +0,0 @@ -{ - "node": true, - "esnext": true, - "bitwise": true, - "camelcase": true, - "curly": true, - "immed": true, - "newcap": true, - "noarg": true, - "undef": true, - "unused": "vars", - "strict": true -} diff --git a/benchmark.js b/benchmark.js index ce3f2c4..5c26a87 100644 --- a/benchmark.js +++ b/benchmark.js @@ -1,3 +1,5 @@ +/* globals set bench */ +'use strict'; var chalk = require('./'); suite('chalk', function () { diff --git a/index.js b/index.js index 7e3aa6c..2d85a91 100644 --- a/index.js +++ b/index.js @@ -44,7 +44,7 @@ function build(_styles) { builder.enabled = this.enabled; // __proto__ is used because we must return a function, but there is // no way to create a function with a different prototype. - /*eslint no-proto: 0 */ + /* eslint-disable no-proto */ builder.__proto__ = proto; return builder; diff --git a/package.json b/package.json index daabdd1..6ccf96e 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "node": ">=0.10.0" }, "scripts": { - "test": "mocha", + "test": "xo && mocha", "bench": "matcha benchmark.js", "coverage": "nyc npm test && nyc report", "coveralls": "nyc npm test && nyc report --reporter=text-lcov | coveralls" @@ -58,6 +58,13 @@ "nyc": "^3.0.0", "require-uncached": "^1.0.2", "resolve-from": "^1.0.0", - "semver": "^4.3.3" + "semver": "^4.3.3", + "xo": "*" + }, + "xo": { + "envs": [ + "node", + "mocha" + ] } } diff --git a/test.js b/test.js index bc39470..1e6d75e 100644 --- a/test.js +++ b/test.js @@ -119,7 +119,6 @@ describe('chalk on windows', function () { var chalkCtx = requireUncached('./'); assert.equal(chalkCtx.blue.dim('foo'), '\u001b[94m\u001b[2mfoo\u001b[22m\u001b[39m'); }); - }); describe('chalk.enabled', function () { From 8b554e254e89c85c1fd04dcc444beeb15824e1a5 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 20 Aug 2015 03:10:52 +0700 Subject: [PATCH 089/324] 1.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6ccf96e..7054997 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chalk", - "version": "1.1.0", + "version": "1.1.1", "description": "Terminal string styling done right. Much color.", "license": "MIT", "repository": "chalk/chalk", From 14603cd0f527247d5bb36f35983f048b95376c87 Mon Sep 17 00:00:00 2001 From: Qix Date: Sun, 23 Aug 2015 17:33:33 -0600 Subject: [PATCH 090/324] =?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 091/324] 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 092/324] 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 093/324] 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 094/324] 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 095/324] 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 096/324] 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 097/324] 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 098/324] 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 099/324] 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 100/324] 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 101/324] =?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 102/324] 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 103/324] 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 104/324] 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 105/324] 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 106/324] 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 107/324] 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 108/324] 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 109/324] 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 110/324] 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 111/324] =?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 112/324] 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 113/324] 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 114/324] 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 115/324] 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 116/324] 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 117/324] 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 118/324] 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 119/324] 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 120/324] 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 121/324] 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 122/324] 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 123/324] 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 124/324] 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 125/324] 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 126/324] 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 127/324] 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 128/324] 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 129/324] 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 130/324] 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 131/324] 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 132/324] 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 133/324] 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 134/324] 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 135/324] 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 136/324] 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 137/324] 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 138/324] 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 139/324] 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 140/324] 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 141/324] 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 142/324] 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 143/324] 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 144/324] 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 145/324] 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 146/324] 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 147/324] 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 148/324] 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 149/324] 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 150/324] 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 151/324] 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 152/324] 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 153/324] 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 154/324] 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 155/324] 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 156/324] 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 157/324] 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 158/324] 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 159/324] 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 160/324] 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 161/324] 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 162/324] 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 163/324] 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 164/324] 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 165/324] 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 166/324] 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 167/324] 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 168/324] 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 169/324] 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 170/324] 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 171/324] 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 172/324] 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 173/324] 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 174/324] 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 175/324] 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 176/324] 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 177/324] 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 178/324] 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 179/324] 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 180/324] 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 181/324] 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 182/324] 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 183/324] 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 184/324] 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 185/324] 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 186/324] 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 187/324] 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 188/324] 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 189/324] 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 190/324] 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 191/324] 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 192/324] 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 193/324] 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 194/324] 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 195/324] 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 196/324] 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 197/324] 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 198/324] 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 199/324] 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 200/324] 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 201/324] 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 202/324] 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 203/324] 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 204/324] 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 205/324] 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 206/324] 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 207/324] 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 208/324] 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 209/324] 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 210/324] 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 211/324] 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 212/324] 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 213/324] 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 214/324] 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 215/324] 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 216/324] 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 217/324] 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 218/324] 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 219/324] =?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 220/324] 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 221/324] 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 222/324] 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 223/324] 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 224/324] 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 225/324] 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 226/324] 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 227/324] 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 228/324] 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 229/324] 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 230/324] 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 231/324] 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 232/324] 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 233/324] 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 234/324] 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 235/324] 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 236/324] 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 237/324] 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 238/324] 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 239/324] 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 240/324] 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 241/324] 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 242/324] 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 243/324] 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 244/324] 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 245/324] 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.`