Spaces:
Running
Running
; | |
const escapeStringRegexp = require('escape-string-regexp'); | |
const ansiStyles = require('ansi-styles'); | |
const stdoutColor = require('supports-color').stdout; | |
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']; | |
// `color-convert` models to exclude from the Chalk API due to conflicts and such | |
const skipModels = new Set(['gray']); | |
const styles = Object.create(null); | |
function applyOptions(obj, options) { | |
options = options || {}; | |
// 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; | |
} | |
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 | |
if (isSimpleWindowsTerm) { | |
ansiStyles.blue.open = '\u001B[94m'; | |
} | |
for (const key of Object.keys(ansiStyles)) { | |
ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); | |
styles[key] = { | |
get() { | |
const codes = ansiStyles[key]; | |
return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); | |
} | |
}; | |
} | |
styles.visible = { | |
get() { | |
return build.call(this, this._styles || [], true, 'visible'); | |
} | |
}; | |
ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); | |
for (const model of Object.keys(ansiStyles.color.ansi)) { | |
if (skipModels.has(model)) { | |
continue; | |
} | |
styles[model] = { | |
get() { | |
const level = this.level; | |
return function () { | |
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], this._empty, model); | |
}; | |
} | |
}; | |
} | |
ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); | |
for (const model of Object.keys(ansiStyles.bgColor.ansi)) { | |
if (skipModels.has(model)) { | |
continue; | |
} | |
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 codes = { | |
open, | |
close: ansiStyles.bgColor.close, | |
closeRe: ansiStyles.bgColor.closeRe | |
}; | |
return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); | |
}; | |
} | |
}; | |
} | |
const proto = Object.defineProperties(() => {}, styles); | |
function build(_styles, _empty, key) { | |
const builder = function () { | |
return applyStyle.apply(builder, arguments); | |
}; | |
builder._styles = _styles; | |
builder._empty = _empty; | |
const self = this; | |
Object.defineProperty(builder, 'level', { | |
enumerable: true, | |
get() { | |
return self.level; | |
}, | |
set(level) { | |
self.level = level; | |
} | |
}); | |
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'; | |
// `__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 | |
return builder; | |
} | |
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 = String(arguments[0]); | |
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; | |
} | |
// 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 | |
// will be colored, and the rest will simply be 'plain'. | |
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 macOS | |
// 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 | |
ansiStyles.dim.open = originalDim; | |
return str; | |
} | |
function chalkTag(chalk, strings) { | |
if (!Array.isArray(strings)) { | |
// 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++) { | |
parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); | |
parts.push(String(strings.raw[i])); | |
} | |
return template(chalk, parts.join('')); | |
} | |
Object.defineProperties(Chalk.prototype, styles); | |
module.exports = Chalk(); // eslint-disable-line new-cap | |
module.exports.supportsColor = stdoutColor; | |
module.exports.default = module.exports; // For TypeScript | |