UNPKG

colog

Version:

colog - console log with colors

1,181 lines (976 loc) 27.7 kB
'use strict'; var util = require('util'), colog; /** * Colorful console logging * @returns {Log} * @constructor */ function Colog() { /** * Always create new object */ if ((this instanceof Colog) === false) { return new Colog(); } /** * Self * @type Colog */ var self = this; /** * This is base for all effects. Replace %d [ or use util.format() ] with code number * @type {string} */ var base = '\x1B[%dm'; /** * This will reset all effects * @type {number} */ var reset = 0; /** * Add 60 to color number to bright it out * @type {number} */ var colorLightValueChange = 60; /** * Last command executed */ var lastCommand = 'log'; /** * Last line printed in console * @type {number} */ var lastLineLength = 0; /** * Available colors * @type {{black: Array, red: Array, green: Array, yellow: Array, blue: Array, magenta: Array, cyan: Array, white: Array}} */ var color = { 'black': [30, 39], 'red': [31, 39], 'green': [32, 39], 'yellow': [33, 39], 'blue': [34, 39], 'magenta': [35, 39], 'cyan': [36, 39], 'white': [37, 39] }; /** * Available backgrounds * @type {{black: Array, red: Array, green: Array, yellow: Array, blue: Array, magenta: Array, cyan: Array, white: Array}} */ var background = { 'black': [40, 49], 'red': [41, 49], 'green': [42, 49], 'yellow': [43, 49], 'blue': [44, 49], 'magenta': [45, 49], 'cyan': [46, 49], 'white': [47, 49] }; /** * Available effects * @type {{bold: Array, underline: Array, strike: Array, inverse: Array}} */ var effect = { 'b': [1, 22], 'u': [4, 24], 'i': [7, 27], 's': [9, 29], 'bold': [1, 22], 'underline': [4, 24], 'inverse': [7, 27], 'strike': [9, 29] }; /** * Progress bar values * @type {Array} */ var progress = [ 0, 100 ]; /** * Default progress bar values * @type {{progress: {zero: string, one: string, left: string, right: string, showPostfix: boolean, prefixText: string}}} */ var defaults = { progress: { zero: '░', one: '▓', length: 40, sufix: ' ~ %d%% (%s / %s)', effects: ['colorYellow'], description: '' } }; var beSilent = false; var consoleWidth = 100; if (process.stdout.isTTY) { consoleWidth = process.stdout.getWindowSize()[0]; process.stdout.on('resize', function () { consoleWidth = process.stdout.getWindowSize()[0]; }); } /** * Create effect from code. For colors set lightColor true to bright them up * @param code * @param lightColor * @returns {*} */ function use(code, lightColor) { return util.format(base, (lightColor === true) ? code + colorLightValueChange : code); } /** * Apply effect on both side of the string * @param message * @param effect * @param lightColor * @returns {string} */ function text(message, effect, lightColor) { return [ use(effect[0], lightColor), String(message), use(effect[1], lightColor) ].join(''); } /** * Clear line until last new line white character */ function clearLine() { if (process.stdout.clearLine) { process.stdout.clearLine(); process.stdout.cursorTo(0); } else { var str = '\r', i = 0; for (i = 0; i < lastLineLength; i++) { str += ' '; } process.stdout.write(str); } lastLineLength = 0; return self; } this.silent = function (isSilent) { beSilent = (isSilent) ? true : false; } this.getWidth = function () { return consoleWidth; }; /** * Configure progress bar * @param zero - character for 0 status * @param one - character for 1 status * @param left - character on the left of the bar * @param right - character on the right of the bar * @param showPostfix - show postfix after bar [like: (19 of 20)] * @param prefixText - show prefix text before bar * @returns {*} */ this.configureProgress = function (zero, one, length, effects) { length = Math.abs(parseInt(length, 10)); defaults.progress.zero = (zero !== undefined) ? zero : defaults.progress.zero; defaults.progress.one = (one !== undefined) ? one : defaults.progress.one; defaults.progress.length = (length > 0) ? length : defaults.progress.length; defaults.progress.effects = (effects instanceof Array) ? effects : defaults.progress.effects; return this; }; this.setProgressDescription = function (text) { text = String(text); defaults.progress.description = text; return this; }; /** * Generate progress bar. Don't pass arguments to increase progress bar value * @param int - each int will add one more progress bar */ this.progress = function (minOrChange, max, effects, returnString) { if (beSilent) { return this; } if (lastCommand === 'progress') { clearLine(); } var i = 0, prc = 0, fullBarsToDraw = 0, emptyBarsToDraw = 0, totalBars = defaults.progress.length; // Prepare values minOrChange = Math.abs(parseInt(minOrChange, 10)); max = Math.abs(parseInt(max, 10)); if (isNaN(minOrChange)) { minOrChange = 0; } if (isNaN(max)) { max = 0; } if (max > 0) { // create new progress bar progress[0] = minOrChange; progress[1] = max; } else { if (minOrChange === 0) { minOrChange = 1; } // add to current progress bar progress[0] += minOrChange; } minOrChange = progress[0]; max = progress[1]; if (minOrChange > max) { minOrChange = max; } if (max === 0) { prc = 100; } else { prc = Math.floor((minOrChange / max) * 100); } fullBarsToDraw = Math.floor((prc / 100) * totalBars); emptyBarsToDraw = totalBars - fullBarsToDraw; var str = '\r'; if (returnString !== true) { clearLine(); } for (i = 0; i < fullBarsToDraw; i++) { str = str + defaults.progress.one; } for (i = 0; i < emptyBarsToDraw; i++) { str = str + defaults.progress.zero; } str = str + this.getFormat(defaults.progress.sufix, prc, minOrChange, max); if (effects instanceof Array) { str = this.apply(str, effects); } else { str = this.apply(str, defaults.progress.effects); } if (defaults.progress.description.length) { str = str + ' ' + this.getFormat(defaults.progress.description); } //str = str.substr(0, consoleWidth); if (returnString === true) { lastCommand = 'progress'; return str; } this.write(str); lastCommand = 'progress'; return this; }; /** * Return "reset all effects" code * @returns {*} */ this.reset = function () { return use(reset); }; /** * Short alias for bold * @param message * @returns {string} */ this.b = function (message) { return text(message, effect.bold); }; /** * Short alias for underline * @param message * @returns {string} */ this.u = function (message) { return text(message, effect.underline); }; /** * Short alias for strike * @param message * @returns {string} */ this.s = function (message) { return text(message, effect.strike); }; /** * Short alias for inverse * @param message * @returns {string} */ this.i = function (message) { return text(message, effect.inverse); }; /** * Make given text bold * @param message * @returns {string} */ this.bold = function (message) { return this.b(message); }; /** * Apply underline to text * @param message * @returns {string} */ this.underline = function (message) { return this.u(message); }; /** * Draw line on the text * @param message * @returns {string} */ this.strike = function (message) { return this.s(message); }; /** * Switch foreground and background colors * @param message * @returns {string} */ this.inverse = function (message) { return this.i(message); }; /** * Apply color on text by name * @param message * @param name * @param light * @returns {string} */ this.color = function (message, name, light) { if (color[name] === undefined) { var colors = [], c; for (c in color) { if (color.hasOwnProperty(c)) { colors.push(c); } } throw new Error('Undefined color. Use: ' + colors.join(', ')); } return text(message, color[name], light); }; /** * Apply black color * @param message * @param light * @returns {string} */ this.black = function (message, light) { return text(message, color.black, light); }; /** * Apply red color * @param message * @param light * @returns {string} */ this.red = function (message, light) { return text(message, color.red, light); }; /** * Apply green color * @param message * @param light * @returns {string} */ this.green = function (message, light) { return text(message, color.green, light); }; /** * Apply yellow color * @param message * @param light * @returns {string} */ this.yellow = function (message, light) { return text(message, color.yellow, light); }; /** * Apply blue color * @param message * @param light * @returns {string} */ this.blue = function (message, light) { return text(message, color.blue, light); }; /** * Apply magenta color * @param message * @param light * @returns {string} */ this.magenta = function (message, light) { return text(message, color.magenta, light); }; /** * Apply cyan color * @param message * @param light * @returns {string} */ this.cyan = function (message, light) { return text(message, color.cyan, light); }; /** * Apply white color * @param message * @param light * @returns {string} */ this.white = function (message, light) { return text(message, color.white, light); }; /** * Apply black color * @param message * @param light * @returns {string} */ this.colorBlack = function (message, light) { return this.black(message, light); }; /** * Apply red color * @param message * @param light * @returns {string} */ this.colorRed = function (message, light) { return this.red(message, light); }; /** * Apply green color * @param message * @param light * @returns {string} */ this.colorGreen = function (message, light) { return this.green(message, light); }; /** * Apply yellow color * @param message * @param light * @returns {string} */ this.colorYellow = function (message, light) { return this.yellow(message, light); }; /** * Apply blue color * @param message * @param light * @returns {string} */ this.colorBlue = function (message, light) { return this.blue(message, light); }; /** * Apply magenta color * @param message * @param light * @returns {string} */ this.colorMagenta = function (message, light) { return this.magenta(message, light); }; /** * Apply cyan color * @param message * @param light * @returns {string} */ this.colorCyan = function (message, light) { return this.cyan(message, light); }; /** * Apply white color * @param message * @param light * @returns {string} */ this.colorWhite = function (message, light) { return this.white(message, light); }; /** * Apply background color by name * @param message * @param name * @param light * @returns {string} */ this.background = function (message, name, light) { if (background[name] === undefined) { var backgrounds = [], b; for (b in background) { if (background.hasOwnProperty(b)) { backgrounds.push(b); } } throw new Error('Undefined color. Use: ' + backgrounds.join(', ')); } return text(message, background[name], light); }; /** * Apply black background * @param message * @param light * @returns {string} */ this.bgBlack = function (message, light) { return text(message, background.black, light); }; /** * Apply red background * @param message * @param light * @returns {string} */ this.bgRed = function (message, light) { return text(message, background.red, light); }; /** * Apply green background * @param message * @param light * @returns {string} */ this.bgGreen = function (message, light) { return text(message, background.green, light); }; /** * Apply yellow background * @param message * @param light * @returns {string} */ this.bgYellow = function (message, light) { return text(message, background.yellow, light); }; /** * Apply blue background * @param message * @param light * @returns {string} */ this.bgBlue = function (message, light) { return text(message, background.blue, light); }; /** * Apply magenta background * @param message * @param light * @returns {string} */ this.bgMagenta = function (message, light) { return text(message, background.magenta, light); }; /** * Apply cyan background * @param message * @param light * @returns {string} */ this.bgCyan = function (message, light) { return text(message, background.cyan, light); }; /** * Apply white background * @param message * @param light * @returns {string} */ this.bgWhite = function (message, light) { return text(message, background.white, light); }; /** * Apply black background * @param message * @param light * @returns {string} */ this.backgroundBlack = function (message, light) { return this.bgBlack(message, light); }; /** * Apply red background * @param message * @param light * @returns {string} */ this.backgroundRed = function (message, light) { return this.bgRed(message, light); }; /** * Apply green background * @param message * @param light * @returns {string} */ this.backgroundGreen = function (message, light) { return this.bgGreen(message, light); }; /** * Apply yellow background * @param message * @param light * @returns {string} */ this.backgroundYellow = function (message, light) { return this.bgYellow(message, light); }; /** * Apply blue background * @param message * @param light * @returns {string} */ this.backgroundBlue = function (message, light) { return this.bgBlue(message, light); }; /** * Apply magenta background * @param message * @param light * @returns {string} */ this.backgroundMagenta = function (message, light) { return this.bgMagenta(message, light); }; /** * Apply cyan background * @param message * @param light * @returns {string} */ this.backgroundCyan = function (message, light) { return this.bgCyan(message, light); }; /** * Apply white background * @param message * @param light * @returns {string} */ this.backgroundWhite = function (message, light) { return this.bgWhite(message, light); }; /** * Alias for console.log * @param message * @param light * @returns {string} */ this.log = function (message) { if (beSilent) { return this; } if (lastCommand === 'progress' || lastCommand === 'write') { this.write('\n'); } lastCommand = 'log'; console.log(message); message += ''; lastLineLength = message.length; return this; }; /** * Write to stdout * @param message * @param light * @returns {string} */ this.write = function (message) { if (beSilent) { return this; } lastCommand = 'write'; process.stdout.write(message); message = String(message); if (lastCommand === 'write') { lastLineLength += message.length; } else { lastLineLength = message.length; } return this; }; /** * Log with bold white text * @param message * @returns {string} */ this.info = function (message, returnString) { var str = this.apply(message, ['bold', 'white']); return returnString === true ? str : this.log(str); }; /** * Log with bold green text * @param message * @returns {string} */ this.success = function (message, returnString) { var str = this.apply(message, ['bold', 'green']); return returnString === true ? str : this.log(str); }; /** * Log with bold yellow text * @param message * @returns {string} */ this.warning = function (message, returnString) { var str = this.apply(message, ['bold', 'yellow']); return returnString === true ? str : this.log(str); }; /** * Log with bold red text * @param message * @returns {string} */ this.error = function (message, returnString) { var str = this.apply(message, ['bold', 'red']); return returnString === true ? str : this.log(str); }; /** * Log with bold cyan text * @param message * @returns {string} */ this.question = function (message, returnString) { var str = this.apply(message, ['bold', 'cyan']); return returnString === true ? str : this.log(str); }; /** * Log with bold magenta text * @param message * @returns {string} */ this.answer = function (message, returnString) { var str = this.apply(message, ['bold', 'magenta']); return returnString === true ? str : this.log(str); }; /** * Log with bold black text and white background * @param message * @returns {string} */ this.headerInfo = function (message, returnString) { var str = this.apply(message, ['bold', 'black', 'bgWhite']); return returnString === true ? str : this.log(str); }; /** * Log with bold white text and green background * @param message * @returns {string} */ this.headerSuccess = function (message, returnString) { var str = this.apply(message, ['bold', 'white', 'bgGreen']); return returnString === true ? str : this.log(str); }; /** * Log with bold black text and yellow background * @param message * @returns {string} */ this.headerWarning = function (message, returnString) { var str = this.apply(message, ['bold', 'black', 'bgYellow']); return returnString === true ? str : this.log(str); }; /** * Log with bold white text and red background * @param message * @returns {string} */ this.headerError = function (message, returnString) { var str = this.apply(message, ['bold', 'white', 'bgRed']); return returnString === true ? str : this.log(str); }; /** * Log with bold white text and cyan background * @param message * @returns {string} */ this.headerQuestion = function (message, returnString) { var str = this.apply(message, ['bold', 'white', 'bgCyan']); return returnString === true ? str : this.log(str); }; /** * Log with bold white text and magenta background * @param message * @returns {string} */ this.headerAnswer = function (message, returnString) { var str = this.apply(message, ['bold', 'white', 'bgMagenta']); return returnString === true ? str : this.log(str); }; /** * Apply effects to message * @param message * @param effects * @returns {*} */ this.apply = function (message, effects) { if ((effects instanceof Array) === false) { throw new Error('Effects must be an array'); } if (!effects.length) { return message; } var i = 0, limit = effects.length; for (i = 0; i < limit; i++) { if (this.hasOwnProperty(effects[i]) && typeof this[effects[i]] === 'function') { message = this[effects[i]](message); } else { var allEffects = [], e = ''; for (e in this) { if (this.hasOwnProperty(e) && ((e.indexOf('color') === 0 && e !== 'color') || (e.indexOf('background') === 0 && e !== 'background') || effect[e] !== undefined)) { allEffects.push(e); } } throw new Error(util.format('Invalid effect "%s", you can use "%s"', effects[i], allEffects.join('", "'))); } } return message; }; /** * Alias for console.log that allow you to apply effects to dump * @param variable * @param effects * @returns {*} */ this.dump = function (variable, effects) { if (beSilent) { return this; } if (!(effects instanceof Array)) { effects = []; } effects = this.apply('\n', effects); effects = effects.split('\n'); this.write(effects[0]); this.write(util.inspect((typeof variable === 'function') ? variable.toString() : variable)); this.write(effects[1] + '\n'); return this; }; /** * Get list of available effects * @returns {Array} */ this.getAllEffects = function () { var allEffects = [], e = ''; for (e in this) { if (this.hasOwnProperty(e) && ((e.indexOf('color') === 0 && e !== 'color') || ((e.indexOf('background') === 0 || e.indexOf('bg') === 0) && e !== 'background') || effect[e] !== undefined || color[e] !== undefined)) { allEffects.push(e); } } return allEffects; }; /** * Log message with xml tags using effects name. For example <b>text</b> * @param message * @param log * @returns {*} */ this.format = function () { if (beSilent) { return this; } this.log(this.getFormat.apply(this.getFormat, arguments)); return this; }; /** * Log message with xml tags using effects name. For example <b>text</b> * @param message * @param log * @returns {*} */ this.getFormat = function () { var message = arguments.length > 0 ? arguments[0] : ''; message = util.format.apply(util.format, arguments); var all = self.getAllEffects(), i = 0, limit = all.length, applyCallback = function (match, content) { return self.apply(content, [all[i]]); }; for (i = 0; i < limit; i++) { message = message.replace(new RegExp(util.format('<%s>([\\s\\S]*?)<\/%s>', all[i], all[i]), 'g'), applyCallback); } return message; }; this.stripFormat = function () { var message = arguments.length > 0 ? arguments[0] : ''; message = util.format.apply(util.format, arguments); var all = this.getAllEffects(), i = 0, limit = all.length, applyCallback = function (match, content) { return content; }; for (i = 0; i < limit; i++) { message = message.replace(new RegExp(util.format('<%s>([\\s\\S]*?)<\/%s>', all[i], all[i]), 'g'), applyCallback); } return message; }; /** * Print new line * @returns {*} */ this.nl = function () { this.write('\n'); return this; }; /** * Alias for nl * @type {*} */ this.newLine = this.nl; this.status = function (text, status, textEffects, statusEffects, returnString) { if (beSilent) { return this; } if (text instanceof Object) { text = text.toString(); } if (status instanceof Object) { status = status.toString(); } var textLen = this.stripFormat(text).length, statusLen = this.stripFormat(status).length, emptyLength = consoleWidth - (textLen + statusLen), emptyString = '', i = 0, str = ''; text = this.getFormat(text); status = this.getFormat(status); if (textEffects instanceof Array) { text = this.apply(text, textEffects); } if (statusEffects instanceof Array) { status = this.apply(status, statusEffects); } if (emptyLength < 2) { emptyLength = 2; } emptyLength -= 1; for (i = 0; i < emptyLength; i++) { emptyString = emptyString + ' '; } str = text + emptyString + status; if (returnString === true) { return str; } this.log(str); return this; }; } if (!colog) { colog = new Colog(); } module.exports = colog;