diff --git a/colorize.js b/colorize.js index 0186c6e..b0a21c8 100644 --- a/colorize.js +++ b/colorize.js @@ -1,5 +1,6 @@ 'use strict'; +const { EnvManager } = require('./env-manager'); const colors = require('@colors/colors/safe'); const { LEVEL, MESSAGE } = require('triple-beam'); @@ -24,6 +25,10 @@ class Colorizer { this.addColors(opts.colors); } + if (!opts.env) { + opts.env = new EnvManager(); + } + this.options = opts; } @@ -65,6 +70,10 @@ class Colorizer { message = level; } + if (this.options.env.isColorDisabled) { + return message; + } + // // If the color for the level is just a string // then attempt to colorize the message with it. diff --git a/env-manager.js b/env-manager.js new file mode 100644 index 0000000..bd4eed8 --- /dev/null +++ b/env-manager.js @@ -0,0 +1,22 @@ +/* eslint-disable no-process-env */ +'use strict'; + +class EnvManager { + constructor( + opts = {} + ) { + if (opts.disableColor === undefined) { + opts.disableColor = process.env.NO_COLOR && + process.env.NO_COLOR !== '0' && + process.env.NO_COLOR !== 'false'; + } + + this.opts = opts; + } + + get isColorDisabled() { + return this.opts.disableColor; + } +} + +module.exports.EnvManager = EnvManager; diff --git a/test/cli.test.js b/test/cli.test.js index 734d892..99317ef 100644 --- a/test/cli.test.js +++ b/test/cli.test.js @@ -9,13 +9,18 @@ const { infoify, setupLevels } = require('./helpers'); +const { EnvManager } = require('../env-manager'); const { LEVEL, MESSAGE } = require('triple-beam'); describe('cli', () => { before(setupLevels); it('cli() (default) sets info[MESSAGE]', assumeFormatted( - cli(), + cli({ + env: new EnvManager({ + disableColor: false + }) + }), infoify({ level: 'info', message: 'whatever' }), (info) => { assume(info.level).is.a('string'); diff --git a/test/colorize.test.js b/test/colorize.test.js index 7cd046b..88562a0 100644 --- a/test/colorize.test.js +++ b/test/colorize.test.js @@ -11,12 +11,16 @@ const { infoify, setupLevels } = require('./helpers'); +const { EnvManager } = require('../env-manager'); + +const ENABLED_COLOR_ENV = new EnvManager({ disableColor: false }); +const DISABLED_COLOR_ENV = new EnvManager({ disableColor: true }); describe('colorize', () => { before(setupLevels); it('colorize() (default)', assumeFormatted( - colorize(), + colorize({ env: ENABLED_COLOR_ENV }), infoify({ level: 'info', message: 'whatever' }), info => { assume(info.level).is.a('string'); @@ -26,8 +30,19 @@ describe('colorize', () => { } )); + it('not output color colorize() (default) when NO_COLOR env var is enabled', assumeFormatted( + colorize({ env: DISABLED_COLOR_ENV }), + infoify({ level: 'info', message: 'whatever' }), + info => { + assume(info.level).is.a('string'); + assume(info.message).is.a('string'); + assume(info.level).equals('info'); + assume(info.message).equals('whatever'); + } + )); + it('colorize({ level: true })', assumeFormatted( - colorize({ level: true }), + colorize({ level: true, env: ENABLED_COLOR_ENV }), infoify({ level: 'info', message: 'whatever' }), info => { assume(info.level).is.a('string'); @@ -37,8 +52,19 @@ describe('colorize', () => { } )); + it('not output color colorize({ level: true }) when NO_COLOR env var is enabled', assumeFormatted( + colorize({ level: true, env: DISABLED_COLOR_ENV }), + infoify({ level: 'info', message: 'whatever' }), + info => { + assume(info.level).is.a('string'); + assume(info.message).is.a('string'); + assume(info.level).equals('info'); + assume(info.message).equals('whatever'); + } + )); + it('colorize{ message: true })', assumeFormatted( - colorize({ message: true }), + colorize({ message: true, env: ENABLED_COLOR_ENV }), infoify({ level: 'info', message: 'whatever' }), info => { assume(info.level).is.a('string'); @@ -48,8 +74,19 @@ describe('colorize', () => { } )); + it('not output color colorize{ message: true }) when NO_COLOR env var is enabled', assumeFormatted( + colorize({ message: true, env: DISABLED_COLOR_ENV }), + infoify({ level: 'info', message: 'whatever' }), + info => { + assume(info.level).is.a('string'); + assume(info.message).is.a('string'); + assume(info.level).equals('info'); + assume(info.message).equals('whatever'); + } + )); + it('colorize({ level: true, message: true })', assumeFormatted( - colorize({ level: true, message: true }), + colorize({ level: true, message: true, env: ENABLED_COLOR_ENV }), infoify({ level: 'info', message: 'whatever' }), info => { assume(info.level).is.a('string'); @@ -59,8 +96,19 @@ describe('colorize', () => { } )); + it('not output color colorize({ level: true, message: true }) when NO_COLOR env var is enabled', assumeFormatted( + colorize({ level: true, message: true, env: DISABLED_COLOR_ENV }), + infoify({ level: 'info', message: 'whatever' }), + info => { + assume(info.level).is.a('string'); + assume(info.message).is.a('string'); + assume(info.level).equals('info'); + assume(info.message).equals('whatever'); + } + )); + it('colorize({ all: true })', assumeFormatted( - colorize({ all: true }), + colorize({ all: true, env: ENABLED_COLOR_ENV }), infoify({ level: 'info', message: 'whatever' }), info => { assume(info.level).is.a('string'); @@ -70,8 +118,19 @@ describe('colorize', () => { } )); + it('not output color colorize({ all: true }) when NO_COLOR env var is enabled', assumeFormatted( + colorize({ all: true, env: DISABLED_COLOR_ENV }), + infoify({ level: 'info', message: 'whatever' }), + info => { + assume(info.level).is.a('string'); + assume(info.message).is.a('string'); + assume(info.level).equals('info'); + assume(info.message).equals('whatever'); + } + )); + it('colorize({ all: true }) [custom message]', assumeFormatted( - colorize({ all: true }), + colorize({ all: true, env: ENABLED_COLOR_ENV }), { level: 'info', [LEVEL]: 'info', @@ -88,8 +147,28 @@ describe('colorize', () => { } )); + it('not output color colorize({ all: true }) [custom message] when NO_COLOR env var is enabled', assumeFormatted( + colorize({ all: true, env: DISABLED_COLOR_ENV }), + { + level: 'info', + [LEVEL]: 'info', + message: 'whatever', + [MESSAGE]: '[info] whatever custom' + }, + info => { + assume(info.level).is.a('string'); + assume(info.message).is.a('string'); + assume(info[LEVEL]).equals('info'); + assume(info.level).equals('info'); + assume(info.message).equals('whatever'); + assume(info[MESSAGE]).equals('[info] whatever custom'); + } + )); + it('colorizes when LEVEL !== level', assumeFormatted( - colorize(), + colorize({ + env: ENABLED_COLOR_ENV + }), { [LEVEL]: 'info', level: 'INFO', message: 'whatever' }, info => { assume(info.level).is.a('string'); @@ -97,6 +176,18 @@ describe('colorize', () => { assume(info.level).equals(colors.green('INFO')); } )); + + it('not output color colorizes when LEVEL !== level and NO_COLOR env var is enabled', assumeFormatted( + colorize({ + env: DISABLED_COLOR_ENV + }), + { [LEVEL]: 'info', level: 'INFO', message: 'whatever' }, + info => { + assume(info.level).is.a('string'); + assume(info.message).is.a('string'); + assume(info.level).not.equals(colors.green('INFO')); + } + )); }); describe('Colorizer', () => { @@ -130,7 +221,9 @@ describe('Colorizer', () => { }); describe('#colorize(LEVEL, level, message)', () => { - const instance = new Colorizer(); + const instance = new Colorizer({ + env: ENABLED_COLOR_ENV + }); it('colorize(level) [single color]', () => { assume(instance.colorize('weird', 'weird')).equals(colors.cyan('weird')); @@ -152,4 +245,26 @@ describe('Colorizer', () => { ); }); }); + + describe('not output color #colorize(LEVEL, level, message) when NO_COLOR env var is enabled', () => { + const instance = new Colorizer({ + env: DISABLED_COLOR_ENV + }); + + it('colorize(level) [single color]', () => { + assume(instance.colorize('weird', 'weird')).equals('weird'); + }); + + it('colorize(level) [multiple colors]', () => { + assume(instance.colorize('multiple', 'multiple')).equals('multiple'); + }); + + it('colorize(level, message) [single color]', () => { + assume(instance.colorize('weird', 'weird', 'message')).equals('message'); + }); + + it('colorize(level, message) [multiple colors]', () => { + assume(instance.colorize('multiple', 'multiple', 'message')).equals('message'); + }); + }); }); diff --git a/test/env-manager.test.js b/test/env-manager.test.js new file mode 100644 index 0000000..6407205 --- /dev/null +++ b/test/env-manager.test.js @@ -0,0 +1,46 @@ +/* eslint-disable no-process-env */ +'use strict'; + +const assume = require('assume'); +const { EnvManager } = require('../env-manager'); + +describe('EnvManager', () => { + it('should disable color if NO_COLOR is set to a truthy value', () => { + process.env.NO_COLOR = '1'; + const envManager = new EnvManager(); + assume(envManager.isColorDisabled).to.be.true; + delete process.env.NO_COLOR; + }); + + it('should not disable color if NO_COLOR is set to "0"', () => { + process.env.NO_COLOR = '0'; + const envManager = new EnvManager(); + assume(envManager.isColorDisabled).to.be.false; + delete process.env.NO_COLOR; + }); + + it('should not disable color if NO_COLOR is set to "false"', () => { + process.env.NO_COLOR = 'false'; + const envManager = new EnvManager(); + assume(envManager.isColorDisabled).to.be.false; + delete process.env.NO_COLOR; + }); + + it('should not disable color if NO_COLOR is not set', () => { + delete process.env.NO_COLOR; + const envManager = new EnvManager(); + assume(envManager.isColorDisabled).to.be.false; + }); + + it('should use the disableColor option if provided', () => { + const envManager = new EnvManager({ disableColor: true }); + assume(envManager.isColorDisabled).to.be.true; + }); + + it('should override the disableColor option with NO_COLOR environment variable', () => { + process.env.NO_COLOR = '0'; + const envManager = new EnvManager({ disableColor: true }); + assume(envManager.isColorDisabled).to.be.false; + delete process.env.NO_COLOR; + }); +}); diff --git a/test/uncolorize.test.js b/test/uncolorize.test.js index 52da897..437e3d6 100644 --- a/test/uncolorize.test.js +++ b/test/uncolorize.test.js @@ -8,6 +8,7 @@ const format = require('../format'); const simple = require('../simple'); const uncolorize = require('../uncolorize'); const { assumeFormatted, infoify, setupLevels } = require('./helpers'); +const { EnvManager } = require('../env-manager'); const { LEVEL, MESSAGE } = require('triple-beam'); const COLORED = Symbol.for('colored'); @@ -25,14 +26,13 @@ const rememberColors = format(info => { return info; }); - /* * Helper function to return a testable format that * transitions from colors to uncolored */ -function addAndRemoveColors(opts = {}) { +function addAndRemoveColors(opts = {}, disableColor = false) { return combine( - colorize({ all: true }), + colorize({ all: true, env: new EnvManager({ disableColor }) }), simple(), rememberColors(), uncolorize(opts) @@ -70,7 +70,30 @@ describe('uncolorize', () => { info.level = info.level.toUpperCase(); return info; })(), - colorize(), + colorize({ + env: new EnvManager({ disableColor: false }) + }), + uncolorize() + ), + { [LEVEL]: 'info', level: 'info', message: 'whatever' }, + info => { + assume(info.level).is.a('string'); + assume(info.message).is.a('string'); + + assume(info.level).equals('INFO'); + assume(info.message).equals('whatever'); + } + )); + + it('same uncolorize() (default) preserves mutable level formatting when NO_COLOR env var is enabled', assumeFormatted( + combine( + format(info => { + info.level = info.level.toUpperCase(); + return info; + })(), + colorize({ + env: new EnvManager({ disableColor: true }) + }), uncolorize() ), { [LEVEL]: 'info', level: 'info', message: 'whatever' }, @@ -89,7 +112,9 @@ describe('uncolorize', () => { info.level = info.level.toUpperCase(); return info; })(), - colorize(), + colorize({ + env: new EnvManager({ disableColor: false }) + }), uncolorize() ), infoify({ level: 'info', message: Symbol() }), @@ -115,6 +140,22 @@ describe('uncolorize', () => { } )); + it( + 'same uncolorize({ level: false }) removes color from { message, [MESSAGE] } when NO_COLOR env var is enabled', + assumeFormatted( + addAndRemoveColors({ level: false }, true), + infoify({ level: 'info', message: 'whatever' }), + info => { + assume(info.level).is.a('string'); + assume(info.message).is.a('string'); + + assume(info.level).equals('info'); + assume(info.message).equals('whatever'); + assume(info[MESSAGE]).equals('info: whatever'); + } + ) + ); + it('uncolorize({ message: false }) removes color from { level, [MESSAGE] }', assumeFormatted( addAndRemoveColors({ message: false }), infoify({ level: 'info', message: 'whatever' }),