123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- 'use strict';
- const ansiStyles = require('ansi-styles');
- const {stdout: stdoutColor, stderr: stderrColor} = require('supports-color');
- const {
- stringReplaceAll,
- stringEncaseCRLFWithFirstIndex
- } = require('./util');
- // `supportsColor.level` → `ansiStyles.color[name]` mapping
- const levelMapping = [
- 'ansi',
- 'ansi',
- 'ansi256',
- 'ansi16m'
- ];
- const styles = Object.create(null);
- const applyOptions = (object, options = {}) => {
- if (options.level > 3 || options.level < 0) {
- throw new Error('The `level` option should be an integer from 0 to 3');
- }
- // Detect level if not set manually
- const colorLevel = stdoutColor ? stdoutColor.level : 0;
- object.level = options.level === undefined ? colorLevel : options.level;
- };
- class ChalkClass {
- constructor(options) {
- return chalkFactory(options);
- }
- }
- const chalkFactory = options => {
- const chalk = {};
- applyOptions(chalk, options);
- chalk.template = (...arguments_) => chalkTag(chalk.template, ...arguments_);
- Object.setPrototypeOf(chalk, Chalk.prototype);
- Object.setPrototypeOf(chalk.template, chalk);
- chalk.template.constructor = () => {
- throw new Error('`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.');
- };
- chalk.template.Instance = ChalkClass;
- return chalk.template;
- };
- function Chalk(options) {
- return chalkFactory(options);
- }
- for (const [styleName, style] of Object.entries(ansiStyles)) {
- styles[styleName] = {
- get() {
- const builder = createBuilder(this, createStyler(style.open, style.close, this._styler), this._isEmpty);
- Object.defineProperty(this, styleName, {value: builder});
- return builder;
- }
- };
- }
- styles.visible = {
- get() {
- const builder = createBuilder(this, this._styler, true);
- Object.defineProperty(this, 'visible', {value: builder});
- return builder;
- }
- };
- const usedModels = ['rgb', 'hex', 'keyword', 'hsl', 'hsv', 'hwb', 'ansi', 'ansi256'];
- for (const model of usedModels) {
- styles[model] = {
- get() {
- const {level} = this;
- return function (...arguments_) {
- const styler = createStyler(ansiStyles.color[levelMapping[level]][model](...arguments_), ansiStyles.color.close, this._styler);
- return createBuilder(this, styler, this._isEmpty);
- };
- }
- };
- }
- for (const model of usedModels) {
- const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1);
- styles[bgModel] = {
- get() {
- const {level} = this;
- return function (...arguments_) {
- const styler = createStyler(ansiStyles.bgColor[levelMapping[level]][model](...arguments_), ansiStyles.bgColor.close, this._styler);
- return createBuilder(this, styler, this._isEmpty);
- };
- }
- };
- }
- const proto = Object.defineProperties(() => {}, {
- ...styles,
- level: {
- enumerable: true,
- get() {
- return this._generator.level;
- },
- set(level) {
- this._generator.level = level;
- }
- }
- });
- const createStyler = (open, close, parent) => {
- let openAll;
- let closeAll;
- if (parent === undefined) {
- openAll = open;
- closeAll = close;
- } else {
- openAll = parent.openAll + open;
- closeAll = close + parent.closeAll;
- }
- return {
- open,
- close,
- openAll,
- closeAll,
- parent
- };
- };
- const createBuilder = (self, _styler, _isEmpty) => {
- const builder = (...arguments_) => {
- // Single argument is hot path, implicit coercion is faster than anything
- // eslint-disable-next-line no-implicit-coercion
- return applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' '));
- };
- // `__proto__` is used because we must return a function, but there is
- // no way to create a function with a different prototype
- builder.__proto__ = proto; // eslint-disable-line no-proto
- builder._generator = self;
- builder._styler = _styler;
- builder._isEmpty = _isEmpty;
- return builder;
- };
- const applyStyle = (self, string) => {
- if (self.level <= 0 || !string) {
- return self._isEmpty ? '' : string;
- }
- let styler = self._styler;
- if (styler === undefined) {
- return string;
- }
- const {openAll, closeAll} = styler;
- if (string.indexOf('\u001B') !== -1) {
- while (styler !== undefined) {
- // Replace any instances already present with a re-opening code
- // otherwise only the part of the string until said closing code
- // will be colored, and the rest will simply be 'plain'.
- string = stringReplaceAll(string, styler.close, styler.open);
- styler = styler.parent;
- }
- }
- // We can move both next actions out of loop, because remaining actions in loop won't have
- // any/visible effect on parts we add here. Close the styling before a linebreak and reopen
- // after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92
- const lfIndex = string.indexOf('\n');
- if (lfIndex !== -1) {
- string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
- }
- return openAll + string + closeAll;
- };
- let template;
- const chalkTag = (chalk, ...strings) => {
- const [firstString] = strings;
- if (!Array.isArray(firstString)) {
- // If chalk() was called by itself or with a string,
- // return the string itself as a string.
- return strings.join(' ');
- }
- const arguments_ = strings.slice(1);
- const parts = [firstString.raw[0]];
- for (let i = 1; i < firstString.length; i++) {
- parts.push(
- String(arguments_[i - 1]).replace(/[{}\\]/g, '\\$&'),
- String(firstString.raw[i])
- );
- }
- if (template === undefined) {
- template = require('./templates');
- }
- return template(chalk, parts.join(''));
- };
- Object.defineProperties(Chalk.prototype, styles);
- const chalk = Chalk(); // eslint-disable-line new-cap
- chalk.supportsColor = stdoutColor;
- chalk.stderr = Chalk({level: stderrColor ? stderrColor.level : 0}); // eslint-disable-line new-cap
- chalk.stderr.supportsColor = stderrColor;
- // For TypeScript
- chalk.Level = {
- None: 0,
- Basic: 1,
- Ansi256: 2,
- TrueColor: 3,
- 0: 'None',
- 1: 'Basic',
- 2: 'Ansi256',
- 3: 'TrueColor'
- };
- module.exports = chalk;
|