From bdbda7e7b704d18034819803fc1f587815e9de82 Mon Sep 17 00:00:00 2001 From: biodiscus Date: Sun, 5 Nov 2023 16:10:14 +0100 Subject: [PATCH] fix: missing export for strip() and extend() functions --- .codecov.yml | 2 +- .github/workflows/test.yml | 4 +- CHANGELOG.md | 10 + README.md | 94 +++--- examples/ansi256.js | 2 +- examples/ansis-logo.js | 2 +- examples/ansis-styles-demo.js | 2 +- examples/index.js | 10 +- examples/package.json | 8 + package.json | 30 +- {package => pkg}/package.json | 11 +- rollup.config.js | 15 +- src/index.js | 86 +----- src/index.mjs | 74 +++++ src/package.json | 6 + test/cli/output.js | 24 +- test/cli/package.json | 5 + test/flags.test.js | 88 ++++++ test/index.test.js | 535 +--------------------------------- test/jest.config.js | 2 +- test/package.test.js | 56 ++++ test/package/README.md | 23 -- test/package/cjs/index.js | 24 -- test/package/cjs/package.json | 4 +- test/package/cjs/test.cjs | 49 ++++ test/package/esm/index.js | 22 -- test/package/esm/package.json | 4 +- test/package/esm/test.mjs | 47 +++ test/package/package.json | 14 - test/package/ts/index.ts | 2 +- test/unit.test.js | 434 +++++++++++++++++++++++++++ test/utils/helpers.js | 54 ++++ 32 files changed, 978 insertions(+), 765 deletions(-) create mode 100644 examples/package.json rename {package => pkg}/package.json (88%) create mode 100644 src/index.mjs create mode 100644 src/package.json create mode 100644 test/cli/package.json create mode 100644 test/flags.test.js create mode 100644 test/package.test.js delete mode 100644 test/package/README.md delete mode 100644 test/package/cjs/index.js create mode 100644 test/package/cjs/test.cjs delete mode 100644 test/package/esm/index.js create mode 100644 test/package/esm/test.mjs delete mode 100644 test/package/package.json create mode 100644 test/unit.test.js create mode 100644 test/utils/helpers.js diff --git a/.codecov.yml b/.codecov.yml index c346db7..8f1cab3 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -8,4 +8,4 @@ coverage: target: 90% ignore: - - test/.* + - test/**/* diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 38700cf..cc00edd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,9 @@ jobs: strategy: matrix: os: [ ubuntu-latest ] - node-version: [ 14, 16, 18, 20 ] + # rollup require node >= 18 + #node-version: [ 14, 16, 18, 20 ] + node-version: [ 18, 20 ] runs-on: ${{ matrix.os }} steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index 5970855..bc865c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Change log +## 2.0.1 (2023-11-03) + +- fix: missing exports of ansis.strip() and ansis.export() functions (issue was introduced in v2.0.0) +- refactor: optimize code to reduce distributed size +- test: add test for generated npm package in CJS and ESM mode +- test: add test for env variables and CLI flags +- test: add test to detect Deno +- test: add test to detect Next.js runtime +- docs: update readme + ## 2.0.0 (2023-11-03) - feat: add supports the Deno diff --git a/README.md b/README.md index e2f5df6..630f40a 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ and [benchmarks](https://github.com/webdiscus/ansis#benchmark) of most popular N - supports both **ESM** and **CommonJS** - supports **Deno**, **Next.JS** runtime - up to **x3 faster** than **chalk**, [see benchmarks](#benchmark) -- dist code is only **5 KB** incl. named import of all styles +- only **3 KB** dist code - [standard API](#base-colors) like **chalk** - default import `import ansis from 'ansis'`, usage `ansis.red('error')` - [named import](#named-import) `import { red } from 'ansis'`, usage ``` red('error') ``` @@ -132,6 +132,16 @@ import { red, hex, italic } from 'ansis'; red.bold('text'); ``` +Default import and named import can be combined. + +```js +// default and named import +import ansis, { red } from 'ansis'; + +const redText = red('text'); // colorized ANSI string +const text = ansis.strip(redText); // pure string without ANSI codes +``` + ## Template literals @@ -454,61 +464,64 @@ Defaults, the output in terminal console is colored and output in a file is unco ### Environment variables -_example.js_ +To force disable or enable colored output use environment variables `NO_COLOR` and `FORCE_COLOR`. -```js -import ansis from 'ansis'; +The `NO_COLOR` variable should be presents with any not empty value. +The value is not important, e.g., `NO_COLOR=1` `NO_COLOR=true` disable colors. +See standard description by [NO_COLOR](https://no-color.org/). -console.log(ansis.red`COLOR`); -``` +The `FORCE_COLOR` variable should be presents with one of values:\ +`FORCE_COLOR=0` force disable colors\ +`FORCE_COLOR=1` force enable colors -``` -$ node example.js #=> color -$ node example.js > log.txt #=> no color +For example, _app.js_: + +```js +import { red } from 'ansis'; + +console.log(red`red color`); ``` -To force disable or enable colored output use environment variables `NO_COLOR` and `FORCE_COLOR`. +Execute the script in a terminal: ``` -$ NO_COLOR=1 node example.js #=> force disable colors -$ FORCE_COLOR=0 node example.js #=> force disable colors -$ FORCE_COLOR=1 node example.js > log.txt #=> force enable colors +$ node app.js # colored output in terminal +$ node app.js > log.txt # output in file without ANSI codes + +$ NO_COLOR=1 node app.js # force disable colors, non colored output in terminal +$ FORCE_COLOR=0 node app.js # force disable colors, non colored output in terminal +$ FORCE_COLOR=1 node app.js > log.txt # force enable colors, output in file with ANSI codes ``` -> **Note** -> -> The `NO_COLOR` variable should be presents with any not empty value. -> The value is not important, see standard description by [NO_COLOR](https://no-color.org/).\ -> `NO_COLOR=1` `NO_COLOR=true` disable colors -> -> The `FORCE_COLOR` variable should be presents with one of values:\ -> `FORCE_COLOR=0` force disable colors\ -> `FORCE_COLOR=1` force enable colors +### CLI arguments -### Arguments for executable script +Use arguments `--no-color` or `--color=false` to disable colors and `--color` to enable ones. -If you have an executable script.\ -_example.js_ +For example, an executable script _app.js_: ```js #!/usr/bin/env node -import ansis from 'ansis'; +import { red } from 'ansis'; -console.log(ansis.red`COLOR`); +console.log(red`red color`); ``` -Use arguments `--no-color` or `--color=false` to disable colors and `--color` to enable ones. +Execute the script in a terminal: ``` -$ ./example.js #=> color -$ ./example.js --no-color #=> no color -$ ./example.js --color=false #=> no color +$ ./app.js # colored output in terminal +$ ./app.js --no-color # non colored output in terminal +$ ./app.js --color=false # non colored output in terminal -$ ./example.js > log.txt #=> no color -$ ./example.js --color > log.txt #=> color -$ ./example.js --color=true > log.txt #=> color +$ ./app.js > log.txt # output in file without ANSI codes +$ ./app.js --color > log.txt # output in file with ANSI codes +$ ./app.js --color=true > log.txt # output in file with ANSI codes ``` +> **Warning** +> +> The command line arguments have a higher priority than environment variable. + ## Comparison of most popular libraries @@ -523,7 +536,7 @@ $ ./example.js --color=true > log.txt #=> color | [`picocolors`][picocolors]
**2.6KB**
`❌ named import` | **standard**
`8` colors | ❌ | ❌ | ❌ | ❌ | ❌ | `NO_COLOR`
`FORCE_COLOR`
`--no-color`
`--color` | | [`kleur`][kleur]
**2.7KB**
`✅ named import` | **standard**
`8` colors | ❌ | ❌ | ✅ | ❌ | ❌ | only
`NO_COLOR`
`FORCE_COLOR` | | [`chalk`][chalk]
**15KB**
`❌ named import` | **standard**
`16` colors | ✅ | ✅ | ✅ | ❌ | ✅ | `NO_COLOR`
`FORCE_COLOR`
`--no-color`
`--color` | -| [`ansis`][ansis]
**5KB**
`✅ named import` | **standard**
`16` colors | ✅ | ✅ | ✅ | ✅ | ✅ | `NO_COLOR`
`FORCE_COLOR`
`--no-color`
`--color` | +| [`ansis`][ansis]
**3.2KB**
`✅ named import` | **standard**
`16` colors | ✅ | ✅ | ✅ | ✅ | ✅ | `NO_COLOR`
`FORCE_COLOR`
`--no-color`
`--color` | > **Note** > @@ -577,19 +590,12 @@ npm run demo -## Benchmark - -### Setup +## Run benchmark ```bash git clone https://github.com/webdiscus/ansis.git -cd ./ansis/bench +cd ./ansis npm i -``` - -### Run benchmark - -```bash npm run bench ``` diff --git a/examples/ansi256.js b/examples/ansi256.js index 2af6fd2..047b1d4 100755 --- a/examples/ansi256.js +++ b/examples/ansi256.js @@ -1,4 +1,4 @@ -import { fg, bg } from '../src/index.js'; +import { fg, bg } from 'ansis'; let out; let n; diff --git a/examples/ansis-logo.js b/examples/ansis-logo.js index e3ca1b0..92e4f48 100644 --- a/examples/ansis-logo.js +++ b/examples/ansis-logo.js @@ -1,4 +1,4 @@ -import ansis from '../src/index.js'; +import ansis from 'ansis'; const colorizeASCII = ({ ascii, data }, paddingLeft = 5) => { // start index in logo is 1, because first char is \n diff --git a/examples/ansis-styles-demo.js b/examples/ansis-styles-demo.js index 4cc1407..abbac8a 100644 --- a/examples/ansis-styles-demo.js +++ b/examples/ansis-styles-demo.js @@ -15,7 +15,7 @@ import { underline, white, whiteBright, yellow, yellowBright, -} from '../src/index.js'; +} from 'ansis'; const out = `${bold`bold`} ${dim`dim`} ${italic`italic`} ${underline`underline`} ${strikethrough`strikethrough`} ${inverse`inverse`} ${bold.italic.underline.strike`bold italic underline strike`}` + '\n' + diff --git a/examples/index.js b/examples/index.js index 327dd29..1100f8e 100755 --- a/examples/index.js +++ b/examples/index.js @@ -3,7 +3,8 @@ import chalk from 'chalk'; import ansis, { - Ansis, red, + Ansis, + red, green, blue, cyan, @@ -16,7 +17,7 @@ import ansis, { inverse, visible, hex, -} from '../src/index.js'; +} from 'ansis'; import { ansi256Table } from './ansi256.js'; import { ansisLogo } from './ansis-logo.js'; @@ -189,7 +190,7 @@ ansis.extend({ log(ansis.pink('pink')); log(ansis.orange('orange')); log(ansis.orange.bold('orange')); -//log(ansis.bold.orange('orange')); // => error +//log(ansis.bold.orange('orange')); // => error, but by 2nd extension it works, see the `side effect` below /** * Problem description @@ -227,7 +228,8 @@ ansis2.extend({ }); log(ansis2.pink('pink')); -log(ansis2.bold.orange('orange')); +// SIDE EFFECT: here works only because the ansis is already extended: ansis.extend({orange:'..'}), see above +log(ansis2.italic.orange('orange')); /** * Misc diff --git a/examples/package.json b/examples/package.json new file mode 100644 index 0000000..a1599b0 --- /dev/null +++ b/examples/package.json @@ -0,0 +1,8 @@ +{ + "name": "demo", + "private": true, + "type": "module", + "scripts": { + "demo": "node ./" + } +} diff --git a/package.json b/package.json index d307bba..3892854 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ansis", - "version": "2.0.0", + "version": "2.0.1", "description": "Colorize text in terminal or console output with ANSI colors & styles", "keywords": [ "ansi", @@ -59,38 +59,46 @@ "types": "./src/index.d.ts", "exports": { ".": { - "import": "./index.js", + "import": "./index.mjs", "require": "./index.js" }, "./colors": { - "import": "./index.js", + "import": "./index.mjs", "require": "./index.js" } }, "scripts": { - "demo": "node ./examples/index.js", - "bench": "node ./bench/index.js", "build": "rollup -c", + "postinstall": "npm run build && npm i ./dist -D", + "demo": "node --experimental-modules ./examples/index.js", + "bench": "(cd ./bench/ && npm install); node ./bench/index.js", "test": "NODE_OPTIONS=--experimental-vm-modules jest --detectOpenHandles", + "test:unit": "NODE_OPTIONS=--experimental-vm-modules jest --detectOpenHandles --runTestsByPath ./test/unit.test.js", + "test:index": "NODE_OPTIONS=--experimental-vm-modules jest --detectOpenHandles --runTestsByPath ./test/index.test.js", + "test:flags": "NODE_OPTIONS=--experimental-vm-modules jest --detectOpenHandles --runTestsByPath ./test/flags.test.js", + "test:package": "NODE_OPTIONS=--experimental-vm-modules jest --detectOpenHandles --runTestsByPath ./test/package.test.js", + "test:cjs": "node ./test/package/cjs/test.cjs", + "test:esm": "node ./test/package/esm/test.mjs", "test:coverage": "NODE_OPTIONS=--experimental-vm-modules jest --detectOpenHandles --collectCoverage", - "publish:public": "rollup -c && npm publish ./dist --access public", - "publish:beta": "rollup -c && npm publish ./dist --tag beta" + "publish:public": "(npm run build) && npm publish ./dist --access public", + "publish:beta": "(npm run build) && npm publish ./dist --tag beta" }, - "files": [ - "dist" - ], "engines": { "node": ">=12.13" }, "devDependencies": { "@babel/core": "^7.23.2", "@babel/preset-env": "^7.23.2", + "@rollup/plugin-replace": "^5.0.5", "@rollup/plugin-terser": "^0.4.4", "@types/jest": "^29.5.7", + "@types/node": "^20.8.10", + "ansis": "file:dist", "jest": "^29.7.0", "prettier": "^3.0.3", "rollup": "^4.2.0", "rollup-plugin-copy": "^3.5.0", - "rollup-plugin-dts": "^6.1.0" + "rollup-plugin-dts": "^6.1.0", + "terser": "^5.24.0" } } diff --git a/package/package.json b/pkg/package.json similarity index 88% rename from package/package.json rename to pkg/package.json index 7dbf434..17c5620 100644 --- a/package/package.json +++ b/pkg/package.json @@ -1,6 +1,6 @@ { "name": "ansis", - "version": "2.0.0", + "version": "2.0.1", "description": "Colorize text in terminal or console output with ANSI colors & styles", "keywords": [ "ansi", @@ -54,12 +54,12 @@ "types": "./index.d.ts", "exports": { ".": { - "import": "./index.js", - "require": "./index.js" + "require": "./index.js", + "import": "./index.mjs" }, "./colors": { - "import": "./index.js", - "require": "./index.js" + "require": "./index.js", + "import": "./index.mjs" } }, "engines": { @@ -68,6 +68,7 @@ "files": [ "index.d.ts", "index.js", + "index.mjs", "package.json", "LICENSE", "README.md" diff --git a/rollup.config.js b/rollup.config.js index 44cf18e..4f89970 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,6 +1,8 @@ import terser from '@rollup/plugin-terser'; +import replace from '@rollup/plugin-replace'; import copy from 'rollup-plugin-copy'; import dts from 'rollup-plugin-dts'; +import { minify } from 'terser'; // last ECMA version compatible with node.js 12 const ecma = 2019; @@ -17,6 +19,12 @@ export default [ }, ], plugins: [ + replace({ + preventAssignment: false, // allow modifying exports + // the order of exports is other than is needed + 'exports.Ansis = Ansis': 'module.exports = ansis', // firstly must be defined default export + 'exports.default = ansis': 'module.exports.Ansis = Ansis', // then on the next line can be named export + }), terser({ ecma, compress: { @@ -27,7 +35,12 @@ export default [ }), copy({ targets: [ - { src: 'package/package.json', dest: 'dist/' }, + { + src: 'src/index.mjs', + dest: 'dist/', + transform: async (contents, name) => (await minify(contents.toString())).code, + }, + { src: 'pkg/package.json', dest: 'dist/' }, { src: 'README.md', dest: 'dist/' }, { src: 'LICENSE', dest: 'dist/' }, ], diff --git a/src/index.js b/src/index.js index e9e7fc7..893811a 100644 --- a/src/index.js +++ b/src/index.js @@ -118,8 +118,8 @@ const wrap = (strings, values, props) => { }; const styleMethods = { - ansi: (code) => fnAnsi256(clamp(code, 0, 255)), - bgAnsi: (code) => fnBgAnsi256(clamp(code, 0, 255)), + fg: (code) => fnAnsi256(clamp(code, 0, 255)), + bg: (code) => fnBgAnsi256(clamp(code, 0, 255)), hex: (hex) => fnRgb(...hexToRgb(hex)), bgHex: (hex) => fnBgRgb(...hexToRgb(hex)), rgb: (r, g, b) => fnRgb( @@ -146,81 +146,15 @@ for (let name in styleMethods) { }; } +// TODO: DEPRECATE ansi and bgAnsi // define method aliases for compatibility with chalk -styles.ansi256 = styles.fg = styles.ansi; -styles.bgAnsi256 = styles.bg = styles.bgAnsi; +styles.ansi256 = styles.ansi = styles.fg; +styles.bgAnsi256 = styles.bgAnsi = styles.bg; const ansis = new Ansis(); -export { Ansis, ansis as default }; - -export const { - // color functions - ansi256, - ansi, - fg, - bgAnsi256, - bgAnsi, - bg, - rgb, - bgRgb, - hex, - bgHex, - - // misc - reset, - inverse, - hidden, - visible, - - // styles - bold, - dim, - faint, - italic, - underline, - doubleUnderline, - strikethrough, - strike, - frame, - encircle, - overline, - - // foreground colors - black, - red, - green, - yellow, - blue, - magenta, - cyan, - white, - gray, - grey, - blackBright, - redBright, - greenBright, - yellowBright, - blueBright, - magentaBright, - cyanBright, - whiteBright, - - // background colors - bgBlack, - bgRed, - bgGreen, - bgYellow, - bgBlue, - bgMagenta, - bgCyan, - bgWhite, - bgBlackBright, - bgRedBright, - bgGreenBright, - bgYellowBright, - bgBlueBright, - bgMagentaBright, - bgCyanBright, - bgWhiteBright, -} = ansis; +// for distribution code, the export will be replaced (via @rollup/plugin-replace) with the following export: +// module.exports = ansis; +// module.exports.Ansis = Ansis; + +export { ansis as default, Ansis }; diff --git a/src/index.mjs b/src/index.mjs new file mode 100644 index 0000000..e5cb236 --- /dev/null +++ b/src/index.mjs @@ -0,0 +1,74 @@ +import ansis, { Ansis } from './index.js'; + +export { Ansis, ansis as default }; + +export const { + // color functions + ansi256, + ansi, + fg, + bgAnsi256, + bgAnsi, + bg, + rgb, + bgRgb, + hex, + bgHex, + + // misc + reset, + inverse, + hidden, + visible, + + // styles + bold, + dim, + faint, + italic, + underline, + doubleUnderline, + strikethrough, + strike, + frame, + encircle, + overline, + + // foreground colors + black, + red, + green, + yellow, + blue, + magenta, + cyan, + white, + gray, + grey, + blackBright, + redBright, + greenBright, + yellowBright, + blueBright, + magentaBright, + cyanBright, + whiteBright, + + // background colors + bgBlack, + bgRed, + bgGreen, + bgYellow, + bgBlue, + bgMagenta, + bgCyan, + bgWhite, + bgBlackBright, + bgRedBright, + bgGreenBright, + bgYellowBright, + bgBlueBright, + bgMagentaBright, + bgCyanBright, + bgWhiteBright, +} = ansis; diff --git a/src/package.json b/src/package.json new file mode 100644 index 0000000..79790cd --- /dev/null +++ b/src/package.json @@ -0,0 +1,6 @@ +{ + "name": "ansis-src", + "description": "", + "sideEffects": false, + "type": "module" +} diff --git a/test/cli/output.js b/test/cli/output.js index 2a9e25c..d1da2f7 100644 --- a/test/cli/output.js +++ b/test/cli/output.js @@ -1,14 +1,16 @@ -import ansis from '../../src/index.js'; -const c = ansis; +#!/usr/bin/env node +import { red, rgb, bgRgb, hex, bgHex } from '../../src/index.mjs'; + +// test output into terminal, depends on flags (--no-color, --color) and environment variables (NO_COLOR, FORCE_COLOR) console.log( - c.red('red') + - '|' + - c.rgb(80, 80, 80)('rgb') + - '|' + - c.bgRgb(80, 80, 80)('bgRgb') + - '|' + - c.hex('#fff')('hex') + - '|' + - c.bgHex('#fff')('bgHex') + red('red') + + '|' + + rgb(80, 80, 80)('rgb') + + '|' + + bgRgb(80, 80, 80)('bgRgb') + + '|' + + hex('#fff')('hex') + + '|' + + bgHex('#fff')('bgHex'), ); \ No newline at end of file diff --git a/test/cli/package.json b/test/cli/package.json new file mode 100644 index 0000000..1239544 --- /dev/null +++ b/test/cli/package.json @@ -0,0 +1,5 @@ +{ + "name": "ansis-esm", + "description": "ESM version", + "type": "module" +} diff --git a/test/flags.test.js b/test/flags.test.js new file mode 100644 index 0000000..368d011 --- /dev/null +++ b/test/flags.test.js @@ -0,0 +1,88 @@ +import path from 'path'; +import { esc, execScriptSync } from './utils/helpers.js'; + +const TEST_PATH = path.resolve('./test/'); + +// CLI with flags and environment variables +// Note: using child_process.execSync the stdout.isTTY is always false +// TODO: +// - test FORCE_COLOR=0 +// - test NO_COLOR=1 + +describe('enable colors', () => { + test(`--color`, (done) => { + const filename = path.join(TEST_PATH, './cli/output.js'); + const received = execScriptSync(filename, ['--color']); + const expected = + '\x1b[31mred\x1b[39m|\x1b[38;2;80;80;80mrgb\x1b[39m|\x1b[48;2;80;80;80mbgRgb\x1b[49m|\x1b[38;2;255;255;255mhex\x1b[39m|\x1b[48;2;255;255;255mbgHex\x1b[49m'; + expect(esc(received)).toEqual(esc(expected)); + done(); + }); + + test(`--color=true`, (done) => { + const filename = path.join(TEST_PATH, './cli/output.js'); + const received = execScriptSync(filename, ['--color=true']); + const expected = + '\x1b[31mred\x1b[39m|\x1b[38;2;80;80;80mrgb\x1b[39m|\x1b[48;2;80;80;80mbgRgb\x1b[49m|\x1b[38;2;255;255;255mhex\x1b[39m|\x1b[48;2;255;255;255mbgHex\x1b[49m'; + expect(esc(received)).toEqual(esc(expected)); + done(); + }); + + test(`--color=always`, (done) => { + const filename = path.join(TEST_PATH, './cli/output.js'); + const received = execScriptSync(filename, ['--color=always']); + const expected = + '\x1b[31mred\x1b[39m|\x1b[38;2;80;80;80mrgb\x1b[39m|\x1b[48;2;80;80;80mbgRgb\x1b[49m|\x1b[38;2;255;255;255mhex\x1b[39m|\x1b[48;2;255;255;255mbgHex\x1b[49m'; + expect(esc(received)).toEqual(esc(expected)); + done(); + }); + + test(`FORCE_COLOR=true`, (done) => { + const filename = path.join(TEST_PATH, './cli/output.js'); + const received = execScriptSync(filename, [], ['FORCE_COLOR=true']); + const expected = + '\x1b[31mred\x1b[39m|\x1b[38;2;80;80;80mrgb\x1b[39m|\x1b[48;2;80;80;80mbgRgb\x1b[49m|\x1b[38;2;255;255;255mhex\x1b[39m|\x1b[48;2;255;255;255mbgHex\x1b[49m'; + + expect(esc(received)).toEqual(esc(expected)); + done(); + }); + + test(`FORCE_COLOR=1`, (done) => { + const filename = path.join(TEST_PATH, './cli/output.js'); + const received = execScriptSync(filename, [], ['FORCE_COLOR=1']); + const expected = + '\x1b[31mred\x1b[39m|\x1b[38;2;80;80;80mrgb\x1b[39m|\x1b[48;2;80;80;80mbgRgb\x1b[49m|\x1b[38;2;255;255;255mhex\x1b[39m|\x1b[48;2;255;255;255mbgHex\x1b[49m'; + + expect(esc(received)).toEqual(esc(expected)); + done(); + }); +}); + +describe('disable colors', () => { + test(`--no-color`, (done) => { + const filename = path.join(TEST_PATH, './cli/output.js'); + // flags has priority over env variable + const received = execScriptSync(filename, ['--no-color'], ['FORCE_COLOR=1']); + const expected = 'red|rgb|bgRgb|hex|bgHex'; + expect(esc(received)).toEqual(esc(expected)); + done(); + }); + + test(`--color=false`, (done) => { + const filename = path.join(TEST_PATH, './cli/output.js'); + // flags has priority over env variable + const received = execScriptSync(filename, ['--color=false'], ['FORCE_COLOR=1']); + const expected = 'red|rgb|bgRgb|hex|bgHex'; + expect(esc(received)).toEqual(esc(expected)); + done(); + }); + + test(`--color=never`, (done) => { + const filename = path.join(TEST_PATH, './cli/output.js'); + // flags has priority over env variable + const received = execScriptSync(filename, ['--color=never'], ['FORCE_COLOR=1']); + const expected = 'red|rgb|bgRgb|hex|bgHex'; + expect(esc(received)).toEqual(esc(expected)); + done(); + }); +}); \ No newline at end of file diff --git a/test/index.test.js b/test/index.test.js index 0e5c02a..15f9e67 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,141 +1,5 @@ -import { execSync } from 'child_process'; -import path from 'path'; - -// test distributed version -import { hexToRgb, clamp } from '../src/utils.js'; -import { isSupported } from '../src/ansi-codes.js'; -import ansis, { Ansis, green, red, yellow } from '../src/index.js'; - -const TEST_PATH = path.resolve('./test/'); - -/** - * Return output of javascript file. - * - * @param {string} file - * @param {array} flags - * @return {string} - */ -const execScriptSync = (file, flags = []) => { - const result = execSync('node ' + file + ' ' + flags.join(' ')); - // replace last newline in result - return result.toString().replace(/\n$/, ''); -}; - -/** - * Escape the slash `\` in ESC-symbol. - * Use it to show by an error the received ESC sequence string in console output. - * - * @param {string} str - * @returns {string} - */ -const esc = (str) => str.replace(/\x1b/g, '\\x1b'); - -beforeAll(() => { -}); - -beforeEach(() => { -}); - -describe('default tests', () => { - test(`self test`, (done) => { - const received = 'OK'; - const expected = 'OK'; - expect(esc(received)).toEqual(esc(expected)); - done(); - }); - - test(`ansis()`, (done) => { - const received = ansis('OK'); - const expected = 'OK'; - expect(esc(received)).toEqual(esc(expected)); - done(); - }); -}); - -describe('utils tests', () => { - test(`strip()`, (done) => { - const received = ansis.strip('\x1b[36m\x1b[1m\x1b[4m\x1b[3mfoo\x1b[23m\x1b[24m\x1b[22m\x1b[39m'); - const expected = 'foo'; - expect(esc(received)).toEqual(esc(expected)); - done(); - }); - - test(`hexToRgb('FFAA99')`, (done) => { - const received = hexToRgb('FFAA99'); - const expected = [255, 170, 153]; - expect(received).toEqual(expected); - done(); - }); - - test(`hexToRgb('#FFAA99')`, (done) => { - const received = hexToRgb('#FFAA99'); - const expected = [255, 170, 153]; - expect(received).toEqual(expected); - done(); - }); - - test(`hexToRgb('#FA9')`, (done) => { - const received = hexToRgb('#FA9'); - const expected = [255, 170, 153]; - expect(received).toEqual(expected); - done(); - }); - - test(`hexToRgb('#FF99')`, (done) => { - const received = hexToRgb('#FF99'); - const expected = [0, 0, 0]; - expect(received).toEqual(expected); - done(); - }); - - test(`hexToRgb('something')`, (done) => { - const received = hexToRgb('something'); - const expected = [0, 0, 0]; - expect(received).toEqual(expected); - done(); - }); - - test(`clamp(3, 0, 2)`, (done) => { - const received = clamp(3, 0, 2); - const expected = 2; - expect(received).toEqual(expected); - done(); - }); - - test(`clamp(0, 1, 2)`, (done) => { - const received = clamp(0, 1, 2); - const expected = 1; - expect(received).toEqual(expected); - done(); - }); -}); - -describe('node script flags', () => { - test(`flag --color`, (done) => { - const filename = path.join(TEST_PATH, './cli/output.js'); - const received = execScriptSync(filename, ['--color']); - const expected = - '\x1b[31mred\x1b[39m|\x1b[38;2;80;80;80mrgb\x1b[39m|\x1b[48;2;80;80;80mbgRgb\x1b[49m|\x1b[38;2;255;255;255mhex\x1b[39m|\x1b[48;2;255;255;255mbgHex\x1b[49m'; - expect(esc(received)).toEqual(esc(expected)); - done(); - }); - - test(`flag --color=false`, (done) => { - const filename = path.join(TEST_PATH, './cli/output.js'); - const received = execScriptSync(filename, ['--color=false']); - const expected = 'red|rgb|bgRgb|hex|bgHex'; - expect(esc(received)).toEqual(esc(expected)); - done(); - }); - - test(`flag --no-color`, (done) => { - const filename = path.join(TEST_PATH, './cli/output.js'); - const received = execScriptSync(filename, ['--no-color']); - const expected = 'red|rgb|bgRgb|hex|bgHex'; - expect(esc(received)).toEqual(esc(expected)); - done(); - }); -}); +import { esc } from './utils/helpers.js'; +import ansis, { Ansis, red, yellow, green } from '../src/index.mjs'; describe('style tests', () => { test(`ansis.visible('foo')`, (done) => { @@ -242,6 +106,13 @@ describe('style tests', () => { }); describe('functional tests', () => { + test(`ansis('OK')`, (done) => { + const received = ansis('OK'); + const expected = 'OK'; + expect(esc(received)).toEqual(esc(expected)); + done(); + }); + test(`nested styles`, (done) => { const received = ansis.red('foo' + ansis.underline.bgBlue('bar') + '!'); const expected = '\x1b[31mfoo\x1b[4m\x1b[44mbar\x1b[49m\x1b[24m!\x1b[39m'; @@ -273,6 +144,13 @@ describe('functional tests', () => { expect(esc(received)).toEqual(esc(expected)); done(); }); + + test(`strip()`, (done) => { + const received = ansis.strip('\x1b[36m\x1b[1m\x1b[4m\x1b[3mfoo\x1b[23m\x1b[24m\x1b[22m\x1b[39m'); + const expected = 'foo'; + expect(esc(received)).toEqual(esc(expected)); + done(); + }); }); describe('alias tests', () => { @@ -383,385 +261,4 @@ describe('extend base colors tests', () => { expect(esc(received)).toEqual(esc(expected)); done(); }); -}); - -// Node.JS -describe('Node.JS isSupported', () => { - test(`process undefined`, (done) => { - // save original `process` object - const processOriginal = process; - process = undefined; - - const received = isSupported(undefined); - const expected = false; - expect(received).toEqual(expected); - - // restore original `process` object - process = processOriginal; - done(); - }); - - test(`processMock undefined`, (done) => { - const received = isSupported(undefined); - const expected = true; - expect(received).toEqual(expected); - done(); - }); - - test(`processMock {}`, (done) => { - const received = isSupported({}); - const expected = false; - expect(received).toEqual(expected); - done(); - }); - - test(`colors in linux terminal`, (done) => { - const received = isSupported({ - process: { - platform: 'linux', - env: { TERM: 'xterm' }, - argv: [], - stdout: { isTTY: true }, - stderr: { isTTY: true }, - }, - }); - const expected = true; - expect(received).toEqual(expected); - done(); - }); - - test(`colors on windows platform`, (done) => { - const received = isSupported({ - process: { - platform: 'win32', - env: {}, - argv: [], - }, - - }); - const expected = true; - expect(received).toEqual(expected); - done(); - }); - - test(`colors in any CI`, (done) => { - const received = isSupported({ - process: { - platform: 'linux', - env: { CI: 'GITLAB_CI' }, - argv: [], - }, - - }); - const expected = true; - expect(received).toEqual(expected); - done(); - }); - - test(`no colors, unsupported terminal`, (done) => { - const received = isSupported({ - process: { - env: { TERM: 'dumb' }, - argv: [], - stdout: { isTTY: true }, - stderr: { isTTY: true }, - }, - - }); - const expected = false; - expect(received).toEqual(expected); - done(); - }); - - test(`no colors, simulate output in file > log.txt`, (done) => { - const received = isSupported({ - process: { - env: { TERM: 'xterm' }, - argv: [], - }, - - }); - const expected = false; - expect(received).toEqual(expected); - done(); - }); - - test(`enable colors via --color`, (done) => { - const received = isSupported({ - process: { - platform: 'linux', - env: {}, - argv: ['--color'], - }, - - }); - const expected = true; - expect(received).toEqual(expected); - done(); - }); - - test(`enable colors via -color`, (done) => { - const received = isSupported({ - process: { - platform: 'linux', - env: {}, - argv: ['-color'], - }, - - }); - const expected = true; - expect(received).toEqual(expected); - done(); - }); - - test(`enable colors via --color=true`, (done) => { - const received = isSupported({ - process: { - platform: 'linux', - env: { TERM: 'dumb' }, - argv: ['--color=true'], - stdout: { isTTY: true }, - stderr: { isTTY: true }, - }, - - }); - const expected = true; - expect(received).toEqual(expected); - done(); - }); - - test(`enable colors via -color=true`, (done) => { - const received = isSupported({ - process: { - platform: 'linux', - env: { TERM: 'dumb' }, - argv: ['-color=true'], - stdout: { isTTY: true }, - stderr: { isTTY: true }, - }, - - }); - const expected = true; - expect(received).toEqual(expected); - done(); - }); - - test(`disable colors via --color=false`, (done) => { - const received = isSupported({ - process: { - platform: 'linux', - env: { TERM: 'xterm' }, - argv: ['--color=false'], - stdout: { isTTY: true }, - stderr: { isTTY: true }, - }, - - }); - const expected = false; - expect(received).toEqual(expected); - done(); - }); - - test(`disable colors via NO_COLOR=1`, (done) => { - const received = isSupported({ - process: { - platform: 'linux', - env: { NO_COLOR: '1', TERM: 'xterm' }, - argv: [], - stdout: { isTTY: true }, - stderr: { isTTY: true }, - }, - - }); - const expected = false; - expect(received).toEqual(expected); - done(); - }); - - test(`disable colors via FORCE_COLOR=0`, (done) => { - const received = isSupported({ - process: { - platform: 'linux', - env: { FORCE_COLOR: '0', TERM: 'xterm' }, - argv: [], - stdout: { isTTY: true }, - stderr: { isTTY: true }, - }, - - }); - const expected = false; - expect(received).toEqual(expected); - done(); - }); - - test(`disable colors via FORCE_COLOR=false`, (done) => { - const received = isSupported({ - process: { - platform: 'linux', - env: { FORCE_COLOR: 'false', TERM: 'xterm' }, - argv: [], - stdout: { isTTY: true }, - stderr: { isTTY: true }, - }, - - }); - const expected = false; - expect(received).toEqual(expected); - done(); - }); - - test(`enable colors via FORCE_COLOR=1`, (done) => { - const received = isSupported({ - process: { - platform: 'linux', - env: { FORCE_COLOR: '1' }, - argv: [], - }, - - }); - const expected = true; - expect(received).toEqual(expected); - done(); - }); - - test(`enable colors via FORCE_COLOR=true`, (done) => { - const received = isSupported({ - process: { - platform: 'linux', - env: { FORCE_COLOR: 'true' }, - argv: [], - }, - - }); - const expected = true; - expect(received).toEqual(expected); - done(); - }); - -}); - -// Deno -describe('Deno isSupported', () => { - test(`env TERM`, (done) => { - const received = isSupported({ - Deno: { - env: { - toObject: () => ({ TERM: 'xterm-256color' }), - }, - args: [], - build: { - os: 'linux', // win32 - }, - isatty: (rid) => rid === 1, // analog to process.stdout.isTTY in node - }, - - }); - const expected = true; - expect(received).toEqual(expected); - done(); - }); - - test(`platform win`, (done) => { - const received = isSupported({ - Deno: { - env: { - toObject: () => ({ TERM: '' }), - }, - args: [], - build: { - os: 'win32', - }, - isatty: (rid) => false, // analog to process.stdout.isTTY in node - }, - - }); - const expected = true; - expect(received).toEqual(expected); - done(); - }); - - test(`FORCE_COLOR`, (done) => { - const received = isSupported({ - Deno: { - env: { - toObject: () => ({ FORCE_COLOR: 1 }), - }, - args: [], - build: { - os: 'linux', - }, - isatty: (rid) => false, // analog to process.stdout.isTTY in node - }, - - }); - const expected = true; - expect(received).toEqual(expected); - done(); - }); - - test(`flag '--color'`, (done) => { - const received = isSupported({ - Deno: { - env: { - toObject: () => ({}), - }, - args: ['--color'], - build: { - os: 'linux', - }, - isatty: (rid) => false, // analog to process.stdout.isTTY in node - }, - - }); - const expected = true; - expect(received).toEqual(expected); - done(); - }); -}); - -// Next.JS -describe('Next.JS isSupported', () => { - test(`runtime experimental-edge`, (done) => { - const received = isSupported({ - process: { - platform: 'linux', - env: { NEXT_RUNTIME: 'experimental-edge', TERM: 'xterm-256color' }, - argv: [], - }, - - }); - const expected = true; - expect(received).toEqual(expected); - done(); - }); - - test(`runtime edge`, (done) => { - const received = isSupported({ - process: { - platform: 'linux', - env: { NEXT_RUNTIME: 'edge', TERM: 'xterm-256color' }, - argv: [], - }, - - }); - const expected = true; - expect(received).toEqual(expected); - done(); - }); - - test(`runtime nodejs`, (done) => { - const received = isSupported({ - process: { - platform: 'linux', - env: { NEXT_RUNTIME: 'nodejs', TERM: 'xterm-256color' }, - argv: [], - stdout: { isTTY: true }, - stderr: { isTTY: true }, - }, - - }); - const expected = true; - expect(received).toEqual(expected); - done(); - }); }); \ No newline at end of file diff --git a/test/jest.config.js b/test/jest.config.js index 73d2ba6..f80a5cf 100644 --- a/test/jest.config.js +++ b/test/jest.config.js @@ -21,7 +21,7 @@ module.exports = { // collectCoverage: false, // An array of glob patterns indicating a set of files for which coverage information should be collected - // collectCoverageFrom: ['src/**/*.js'], + collectCoverageFrom: ['../src/**/*.js'], // The directory where Jest should output its coverage files // coverageDirectory: null, diff --git a/test/package.test.js b/test/package.test.js new file mode 100644 index 0000000..83d6e4a --- /dev/null +++ b/test/package.test.js @@ -0,0 +1,56 @@ +import path from 'path'; +import { esc, execScriptSync } from './utils/helpers.js'; + +const TEST_PATH = path.resolve('./test/'); + +describe('Usage `ansis` npm package', () => { + test(`CommonJS mode`, (done) => { + const filename = path.join(TEST_PATH, './package/cjs/test.cjs'); + const received = execScriptSync(filename, ['--color']); + const expected = + '\x1b[38;5;227m\x1b[7m -= [ansis package] CommonJS =- \x1b[27m\x1b[39m\n' + + '\x1b[31m\x1b[1m\x1b[4mred.bold.underline(\'red\')\x1b[24m\x1b[22m\x1b[39m\n' + + '\x1b[31m\x1b[1m\x1b[4mansis.red.bold.underline(red)\x1b[24m\x1b[22m\x1b[39m\n' + + '\x1b[38;2;250;255;99m\x1b[1mhex(\'#FFAB40\').bold(\'#63ffc6\')\x1b[22m\x1b[39m\n' + + '\x1b[38;2;250;255;99m\x1b[1mansis.hex(\'#FFAB40\').bold(#63ffc6)\x1b[22m\x1b[39m\n' + + '\x1b[38;2;255;117;209mansis.pink\x1b[39m\n' + + '\x1b[38;2;255;171;64mansis.orange\x1b[39m\n' + + '\x1b[38;2;255;171;64m\x1b[1mansis.orange.bold\x1b[22m\x1b[39m\n' + + '\x1b[1m\x1b[31mansis2.bold.red\x1b[39m\x1b[22m\n' + + '\x1b[38;2;255;117;209mextend: ansis2.pink\x1b[39m\n' + + '\x1b[3m\x1b[38;2;255;171;64mextend: ansis2.italic.orange\x1b[39m\x1b[23m\n' + + 'colored: \x1b[32mgreen text\x1b[39m\n' + + 'striped: green text\n' + + '--- OLD named import: \x1b[33mconst { magenta, cyan, blue } = require(\'ansis/colors\');\x1b[39m\n' + + '\x1b[35mmagenta\x1b[39m\n' + + '\x1b[36m\x1b[1mcyan bold\x1b[22m\x1b[39m\n' + + '\x1b[34m\x1b[3mblue italic\x1b[23m\x1b[39m'; + expect(esc(received)).toEqual(esc(expected)); + done(); + }); + + test(`ESM mode`, (done) => { + const filename = path.join(TEST_PATH, './package/esm/test.mjs'); + const received = execScriptSync(filename, ['--color']); + const expected = + '\x1b[38;5;208m\x1b[7m -= [ansis package] ESM =- \x1b[27m\x1b[39m\n' + + '\x1b[31m\x1b[1m\x1b[4mred.bold.underline(\'red\')\x1b[24m\x1b[22m\x1b[39m\n' + + '\x1b[31m\x1b[1m\x1b[4mansis.red.bold.underline(red)\x1b[24m\x1b[22m\x1b[39m\n' + + '\x1b[38;2;250;255;99m\x1b[1mhex(\'#FFAB40\').bold(\'#63ffc6\')\x1b[22m\x1b[39m\n' + + '\x1b[38;2;250;255;99m\x1b[1mansis.hex(\'#FFAB40\').bold(#63ffc6)\x1b[22m\x1b[39m\n' + + '\x1b[38;2;255;117;209mansis.pink\x1b[39m\n' + + '\x1b[38;2;255;171;64mansis.orange\x1b[39m\n' + + '\x1b[38;2;255;171;64m\x1b[1mansis.orange.bold\x1b[22m\x1b[39m\n' + + '\x1b[1m\x1b[31mansis2.bold.red\x1b[39m\x1b[22m\n' + + '\x1b[38;2;255;117;209mextend: ansis2.pink\x1b[39m\n' + + '\x1b[3m\x1b[38;2;255;171;64mextend: ansis2.italic.orange\x1b[39m\x1b[23m\n' + + 'colored: \x1b[32mgreen text\x1b[39m\n' + + 'striped: green text\n' + + '--- OLD named import: \x1b[33mimport { magenta, cyan, blue } from \'ansis/colors\';\x1b[39m\n' + + '\x1b[35mmagenta\x1b[39m\n' + + '\x1b[36m\x1b[1mcyan bold\x1b[22m\x1b[39m\n' + + '\x1b[34m\x1b[3mblue italic\x1b[23m\x1b[39m'; + expect(esc(received)).toEqual(esc(expected)); + done(); + }); +}); \ No newline at end of file diff --git a/test/package/README.md b/test/package/README.md deleted file mode 100644 index 1874e4f..0000000 --- a/test/package/README.md +++ /dev/null @@ -1,23 +0,0 @@ -1. Build `ansis` package from source into `dist/` directory. - - Run from project directory: - ``` - npm run build - ``` - -2. Install `ansis` as local `dist/` directory: - - ``` - cd ./test/package/ - npm i - ``` - -3. Test in CommonJS mode: - ``` - npm run test:cjs - ``` - -4. Test in ESM mode: - ``` - npm run test:esm - ``` \ No newline at end of file diff --git a/test/package/cjs/index.js b/test/package/cjs/index.js deleted file mode 100644 index c947c78..0000000 --- a/test/package/cjs/index.js +++ /dev/null @@ -1,24 +0,0 @@ -const ansis = require('ansis'); - -// test new named import -const { Ansis, red, yellow, green } = require('ansis'); - -// test old named import -const { magenta, cyan, blue } = require('ansis/colors'); - -const log = console.log; - -const ansis2 = new Ansis(); - -log(ansis.green.inverse(' CommonJS ')); -log(ansis2.bgCyanBright('const ansis = new Ansis();')); - -log(`--- NEW named import: ${yellow`const { red, yellow, green } = require('ansis');`}`); -log(red('red')); -log(green.bold('green bold')); -log(yellow.italic`yellow italic`); - -log(`--- OLD named import: ${yellow`const { magenta, cyan, blue } = require('ansis/colors');`}`); -log(magenta`magenta`); -log(cyan.bold`cyan bold`); -log(blue.italic`blue italic`); \ No newline at end of file diff --git a/test/package/cjs/package.json b/test/package/cjs/package.json index ba0dde7..8562c81 100644 --- a/test/package/cjs/package.json +++ b/test/package/cjs/package.json @@ -1,5 +1,5 @@ { - "name": "ansis", + "name": "package-ansis-cjs", "description": "CommonJS version", "type": "commonjs" -} +} \ No newline at end of file diff --git a/test/package/cjs/test.cjs b/test/package/cjs/test.cjs new file mode 100644 index 0000000..049071e --- /dev/null +++ b/test/package/cjs/test.cjs @@ -0,0 +1,49 @@ +const ansis = require('ansis'); + +// test new named import +const { Ansis, red, green, yellow, hex } = require('ansis'); + +// test old named import +const { magenta, cyan, blue } = require('ansis/colors'); + +const log = console.log; + +log(ansis.ansi256(227).inverse(' -= [ansis package] CommonJS =- ')); + +// styles +log(red.bold.underline(`red.bold.underline('red')`)); +log(ansis.red.bold.underline(`ansis.red.bold.underline(red)`)); + +log(hex('#faff63').bold(`hex('#FFAB40').bold('#63ffc6')`)); +log(ansis.hex('#faff63').bold(`ansis.hex('#FFAB40').bold(#63ffc6)`)); + +// extend +ansis.extend({ + pink: '#FF75D1', + orange: '#FFAB40', +}); + +log(ansis.pink('ansis.pink')); +log(ansis.orange('ansis.orange')); +log(ansis.orange.bold('ansis.orange.bold')); + +const ansis2 = new Ansis(); +log(ansis2.bold.red('ansis2.bold.red')); + +ansis2.extend({ + pink: '#FF75D1', + orange: '#FFAB40', +}); + +log(ansis2.pink('extend: ansis2.pink')); +log(ansis2.italic.orange('extend: ansis2.italic.orange')); + +// strip +const greenText = green`green text`; +log('colored: ', greenText); +log('striped: ', ansis.strip(greenText)); + +log(`--- OLD named import: ${yellow`const { magenta, cyan, blue } = require('ansis/colors');`}`); +log(magenta`magenta`); +log(cyan.bold`cyan bold`); +log(blue.italic`blue italic`); \ No newline at end of file diff --git a/test/package/esm/index.js b/test/package/esm/index.js deleted file mode 100644 index 0be9710..0000000 --- a/test/package/esm/index.js +++ /dev/null @@ -1,22 +0,0 @@ -// test new named import -import ansis, { Ansis, red, yellow, green } from 'ansis'; - -// test old named import -import { magenta, cyan, blue } from 'ansis/colors'; - -const log = console.log; - -const ansis2 = new Ansis(); - -log(ansis.green.inverse(' ESM ')); -log(ansis2.bgCyanBright('const ansis = new Ansis();')); - -log(`--- NEW named import: ${yellow`import { red, yellow, green } from 'ansis';`}`); -log(red('red')); -log(green.bold('green bold')); -log(yellow.italic`yellow italic`); - -log(`--- OLD named import: ${yellow`import { magenta, cyan, blue } from 'ansis/colors';`}`); -log(magenta`magenta`); -log(cyan.bold`cyan bold`); -log(blue.italic`blue italic`); \ No newline at end of file diff --git a/test/package/esm/package.json b/test/package/esm/package.json index 9fe733c..12b9be9 100644 --- a/test/package/esm/package.json +++ b/test/package/esm/package.json @@ -1,5 +1,5 @@ { - "name": "ansis", + "name": "package-ansis-esm", "description": "ESM version", "type": "module" -} +} \ No newline at end of file diff --git a/test/package/esm/test.mjs b/test/package/esm/test.mjs new file mode 100644 index 0000000..a90618c --- /dev/null +++ b/test/package/esm/test.mjs @@ -0,0 +1,47 @@ +// test new named import +import ansis, { Ansis, red, green, yellow, hex } from 'ansis'; + +// test old named import +import { magenta, cyan, blue } from 'ansis/colors'; + +const log = console.log; + +log(ansis.ansi256(208).inverse(' -= [ansis package] ESM =- ')); + +// styles +log(red.bold.underline(`red.bold.underline('red')`)); +log(ansis.red.bold.underline(`ansis.red.bold.underline(red)`)); + +log(hex('#faff63').bold(`hex('#FFAB40').bold('#63ffc6')`)); +log(ansis.hex('#faff63').bold(`ansis.hex('#FFAB40').bold(#63ffc6)`)); + +// extend +ansis.extend({ + pink: '#FF75D1', + orange: '#FFAB40', +}); + +log(ansis.pink('ansis.pink')); +log(ansis.orange('ansis.orange')); +log(ansis.orange.bold('ansis.orange.bold')); + +const ansis2 = new Ansis(); +log(ansis2.bold.red('ansis2.bold.red')); + +ansis2.extend({ + pink: '#FF75D1', + orange: '#FFAB40', +}); + +log(ansis2.pink('extend: ansis2.pink')); +log(ansis2.italic.orange('extend: ansis2.italic.orange')); + +// strip +const greenText = green`green text`; +log('colored: ', greenText); +log('striped: ', ansis.strip(greenText)); + +log(`--- OLD named import: ${yellow`import { magenta, cyan, blue } from 'ansis/colors';`}`); +log(magenta`magenta`); +log(cyan.bold`cyan bold`); +log(blue.italic`blue italic`); \ No newline at end of file diff --git a/test/package/package.json b/test/package/package.json deleted file mode 100644 index 08a4286..0000000 --- a/test/package/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "@webdiscus/ansis-test", - "version": "1.0.0", - "description": "Test npm package in CJS and ESM modes.", - "main": "index.js", - "scripts": { - "test:cjs": "node ./cjs/index.js", - "test:esm": "node ./esm/index.js" - }, - "devDependencies": { - "@types/node": "^18.7.15", - "ansis": "file:../../dist" - } -} \ No newline at end of file diff --git a/test/package/ts/index.ts b/test/package/ts/index.ts index 90e6371..a97dbc2 100644 --- a/test/package/ts/index.ts +++ b/test/package/ts/index.ts @@ -14,7 +14,7 @@ ansis.extend({ orange: '#FFAB40', }); -// `AnsiColorsExtend` is extendable type for TS to add a custom color +// `AnsiColorsExtend` is an extendable type for TS to add a custom color const write = (style: AnsiColorsExtend<'pink' | 'orange'>, message: string) => { console.log(ansis[style](message)); }; diff --git a/test/unit.test.js b/test/unit.test.js new file mode 100644 index 0000000..f6a6d7d --- /dev/null +++ b/test/unit.test.js @@ -0,0 +1,434 @@ +import { hexToRgb, clamp } from '../src/utils.js'; +import { isSupported } from '../src/ansi-codes.js'; + +describe('utils tests', () => { + test(`hexToRgb('FFAA99')`, (done) => { + const received = hexToRgb('FFAA99'); + const expected = [255, 170, 153]; + expect(received).toEqual(expected); + done(); + }); + + test(`hexToRgb('#FFAA99')`, (done) => { + const received = hexToRgb('#FFAA99'); + const expected = [255, 170, 153]; + expect(received).toEqual(expected); + done(); + }); + + test(`hexToRgb('#FA9')`, (done) => { + const received = hexToRgb('#FA9'); + const expected = [255, 170, 153]; + expect(received).toEqual(expected); + done(); + }); + + test(`hexToRgb('#FF99')`, (done) => { + const received = hexToRgb('#FF99'); + const expected = [0, 0, 0]; + expect(received).toEqual(expected); + done(); + }); + + test(`hexToRgb('something')`, (done) => { + const received = hexToRgb('something'); + const expected = [0, 0, 0]; + expect(received).toEqual(expected); + done(); + }); + + test(`clamp(3, 0, 2)`, (done) => { + const received = clamp(3, 0, 2); + const expected = 2; + expect(received).toEqual(expected); + done(); + }); + + test(`clamp(0, 1, 2)`, (done) => { + const received = clamp(0, 1, 2); + const expected = 1; + expect(received).toEqual(expected); + done(); + }); +}); + +// Node.JS +describe('Node.JS isSupported', () => { + test(`process undefined`, (done) => { + // save original `process` object + const processOriginal = process; + process = undefined; + + const received = isSupported(undefined); + const expected = false; + expect(received).toEqual(expected); + + // restore original `process` object + process = processOriginal; + done(); + }); + + test(`processMock undefined`, (done) => { + const received = isSupported(undefined); + const expected = true; + expect(received).toEqual(expected); + done(); + }); + + test(`processMock {}`, (done) => { + const received = isSupported({}); + const expected = false; + expect(received).toEqual(expected); + done(); + }); + + test(`colors in linux terminal`, (done) => { + const received = isSupported({ + process: { + platform: 'linux', + env: { TERM: 'xterm' }, + argv: [], + stdout: { isTTY: true }, + stderr: { isTTY: true }, + }, + }); + const expected = true; + expect(received).toEqual(expected); + done(); + }); + + test(`colors on windows platform`, (done) => { + const received = isSupported({ + process: { + platform: 'win32', + env: {}, + argv: [], + }, + + }); + const expected = true; + expect(received).toEqual(expected); + done(); + }); + + test(`colors in any CI`, (done) => { + const received = isSupported({ + process: { + platform: 'linux', + env: { CI: 'GITLAB_CI' }, + argv: [], + }, + + }); + const expected = true; + expect(received).toEqual(expected); + done(); + }); + + test(`no colors, unsupported terminal`, (done) => { + const received = isSupported({ + process: { + env: { TERM: 'dumb' }, + argv: [], + stdout: { isTTY: true }, + stderr: { isTTY: true }, + }, + + }); + const expected = false; + expect(received).toEqual(expected); + done(); + }); + + test(`no colors, simulate output in file > log.txt`, (done) => { + const received = isSupported({ + process: { + env: { TERM: 'xterm' }, + argv: [], + }, + + }); + const expected = false; + expect(received).toEqual(expected); + done(); + }); + + test(`enable colors via --color`, (done) => { + const received = isSupported({ + process: { + platform: 'linux', + env: {}, + argv: ['--color'], + }, + + }); + const expected = true; + expect(received).toEqual(expected); + done(); + }); + + test(`enable colors via -color`, (done) => { + const received = isSupported({ + process: { + platform: 'linux', + env: {}, + argv: ['-color'], + }, + + }); + const expected = true; + expect(received).toEqual(expected); + done(); + }); + + test(`enable colors via --color=true`, (done) => { + const received = isSupported({ + process: { + platform: 'linux', + env: { TERM: 'dumb' }, + argv: ['--color=true'], + stdout: { isTTY: true }, + stderr: { isTTY: true }, + }, + + }); + const expected = true; + expect(received).toEqual(expected); + done(); + }); + + test(`enable colors via -color=true`, (done) => { + const received = isSupported({ + process: { + platform: 'linux', + env: { TERM: 'dumb' }, + argv: ['-color=true'], + stdout: { isTTY: true }, + stderr: { isTTY: true }, + }, + + }); + const expected = true; + expect(received).toEqual(expected); + done(); + }); + + test(`disable colors via --color=false`, (done) => { + const received = isSupported({ + process: { + platform: 'linux', + env: { TERM: 'xterm' }, + argv: ['--color=false'], + stdout: { isTTY: true }, + stderr: { isTTY: true }, + }, + + }); + const expected = false; + expect(received).toEqual(expected); + done(); + }); + + test(`disable colors via NO_COLOR=1`, (done) => { + const received = isSupported({ + process: { + platform: 'linux', + env: { NO_COLOR: '1', TERM: 'xterm' }, + argv: [], + stdout: { isTTY: true }, + stderr: { isTTY: true }, + }, + + }); + const expected = false; + expect(received).toEqual(expected); + done(); + }); + + test(`disable colors via FORCE_COLOR=0`, (done) => { + const received = isSupported({ + process: { + platform: 'linux', + env: { FORCE_COLOR: '0', TERM: 'xterm' }, + argv: [], + stdout: { isTTY: true }, + stderr: { isTTY: true }, + }, + + }); + const expected = false; + expect(received).toEqual(expected); + done(); + }); + + test(`disable colors via FORCE_COLOR=false`, (done) => { + const received = isSupported({ + process: { + platform: 'linux', + env: { FORCE_COLOR: 'false', TERM: 'xterm' }, + argv: [], + stdout: { isTTY: true }, + stderr: { isTTY: true }, + }, + + }); + const expected = false; + expect(received).toEqual(expected); + done(); + }); + + test(`enable colors via FORCE_COLOR=1`, (done) => { + const received = isSupported({ + process: { + platform: 'linux', + env: { FORCE_COLOR: '1' }, + argv: [], + }, + + }); + const expected = true; + expect(received).toEqual(expected); + done(); + }); + + test(`enable colors via FORCE_COLOR=true`, (done) => { + const received = isSupported({ + process: { + platform: 'linux', + env: { FORCE_COLOR: 'true' }, + argv: [], + }, + + }); + const expected = true; + expect(received).toEqual(expected); + done(); + }); + +}); + +// Deno +describe('Deno isSupported', () => { + test(`env TERM`, (done) => { + const received = isSupported({ + Deno: { + env: { + toObject: () => ({ TERM: 'xterm-256color' }), + }, + args: [], + build: { + os: 'linux', // win32 + }, + isatty: (rid) => rid === 1, // analog to process.stdout.isTTY in node + }, + + }); + const expected = true; + expect(received).toEqual(expected); + done(); + }); + + test(`platform win`, (done) => { + const received = isSupported({ + Deno: { + env: { + toObject: () => ({ TERM: '' }), + }, + args: [], + build: { + os: 'win32', + }, + isatty: (rid) => false, // analog to process.stdout.isTTY in node + }, + + }); + const expected = true; + expect(received).toEqual(expected); + done(); + }); + + test(`FORCE_COLOR`, (done) => { + const received = isSupported({ + Deno: { + env: { + toObject: () => ({ FORCE_COLOR: 1 }), + }, + args: [], + build: { + os: 'linux', + }, + isatty: (rid) => false, // analog to process.stdout.isTTY in node + }, + + }); + const expected = true; + expect(received).toEqual(expected); + done(); + }); + + test(`flag '--color'`, (done) => { + const received = isSupported({ + Deno: { + env: { + toObject: () => ({}), + }, + args: ['--color'], + build: { + os: 'linux', + }, + isatty: (rid) => false, // analog to process.stdout.isTTY in node + }, + + }); + const expected = true; + expect(received).toEqual(expected); + done(); + }); +}); + +// Next.JS +describe('Next.JS isSupported', () => { + test(`runtime experimental-edge`, (done) => { + const received = isSupported({ + process: { + platform: 'linux', + env: { NEXT_RUNTIME: 'experimental-edge', TERM: 'xterm-256color' }, + argv: [], + }, + + }); + const expected = true; + expect(received).toEqual(expected); + done(); + }); + + test(`runtime edge`, (done) => { + const received = isSupported({ + process: { + platform: 'linux', + env: { NEXT_RUNTIME: 'edge', TERM: 'xterm-256color' }, + argv: [], + }, + + }); + const expected = true; + expect(received).toEqual(expected); + done(); + }); + + test(`runtime nodejs`, (done) => { + const received = isSupported({ + process: { + platform: 'linux', + env: { NEXT_RUNTIME: 'nodejs', TERM: 'xterm-256color' }, + argv: [], + stdout: { isTTY: true }, + stderr: { isTTY: true }, + }, + + }); + const expected = true; + expect(received).toEqual(expected); + done(); + }); +}); \ No newline at end of file diff --git a/test/utils/helpers.js b/test/utils/helpers.js new file mode 100644 index 0000000..e038a87 --- /dev/null +++ b/test/utils/helpers.js @@ -0,0 +1,54 @@ +import { execSync } from 'child_process'; + +/** + * Escape the slash `\` in ESC-symbol. + * Use it to show by an error the received ESC sequence string in console output. + * + * @param {string} str + * @returns {string} + */ +export const esc = (str) => str.replace(/\x1b/g, '\\x1b'); + +/** + * Return output of javascript file. + * + * @param {string} file + * @param {Array} flags + * @param {Array} env + * @return {string} + */ +export const execScriptSync = (file, flags = [], env = []) => { + const envVars = env.length ? '' + env.join(' ') + ' ' : ''; + const cmd = envVars + 'node ' + file + ' ' + flags.join(' '); + const result = execSync(cmd); + + // replace last newline in result + return result.toString().replace(/\n$/, ''); +}; + +// TODO: get colorized output in process.stdout using child_process.execSync +// export const execScriptOutSync = (file, flags = [], env = []) => { +// const envVars = env.length ? '' + env.join(' ') + ' ' : ''; +// const cmd = envVars + 'node ' + file + ' ' + flags.join(' '); +// +// //const stdout = jest.spyOn(process.stdout, 'write').mockImplementation(() => {}); +// const stdout = jest.spyOn(process.stdout, 'write').mockImplementation(() => {}); +// +// const result = execSync( +// cmd, +// // reset stdio to enable isTTY for colorized output +// { stdio: 'inherit' }, +// //{ stdio: [0, process.stdout, process.stderr] }, +// //{ stdio: [1] }, +// ); +// +// const { calls } = stdout.mock; +// let output = calls.length > 0 ? calls[0][0] : ''; +// +// stdout.mockClear(); +// stdout.mockRestore(); +// console.log('--> ', { cmd, output, calls, stdout: stdout.mock }, stdout); +// //console.log('--> ', result.toString()); +// +// return output; +// }; \ No newline at end of file