| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- import ansiStyles from '#ansi-styles';
- import supportsColor from '#supports-color';
- import { // eslint-disable-line import/order
- stringReplaceAll,
- stringEncaseCRLFWithFirstIndex,
- } from './utilities.js';
- const {stdout: stdoutColor, stderr: stderrColor} = supportsColor;
- const GENERATOR = Symbol('GENERATOR');
- const STYLER = Symbol('STYLER');
- const IS_EMPTY = Symbol('IS_EMPTY');
- // `supportsColor.level` → `ansiStyles.color[name]` mapping
- const levelMapping = [
- 'ansi',
- 'ansi',
- 'ansi256',
- 'ansi16m',
- ];
- const styles = Object.create(null);
- const applyOptions = (object, options = {}) => {
- if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
- 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;
- };
- export class Chalk {
- constructor(options) {
- // eslint-disable-next-line no-constructor-return
- return chalkFactory(options);
- }
- }
- const chalkFactory = options => {
- const chalk = (...strings) => strings.join(' ');
- applyOptions(chalk, options);
- Object.setPrototypeOf(chalk, createChalk.prototype);
- return chalk;
- };
- function createChalk(options) {
- return chalkFactory(options);
- }
- Object.setPrototypeOf(createChalk.prototype, Function.prototype);
- for (const [styleName, style] of Object.entries(ansiStyles)) {
- styles[styleName] = {
- get() {
- const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
- 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 getModelAnsi = (model, level, type, ...arguments_) => {
- if (model === 'rgb') {
- if (level === 'ansi16m') {
- return ansiStyles[type].ansi16m(...arguments_);
- }
- if (level === 'ansi256') {
- return ansiStyles[type].ansi256(ansiStyles.rgbToAnsi256(...arguments_));
- }
- return ansiStyles[type].ansi(ansiStyles.rgbToAnsi(...arguments_));
- }
- if (model === 'hex') {
- return getModelAnsi('rgb', level, type, ...ansiStyles.hexToRgb(...arguments_));
- }
- return ansiStyles[type][model](...arguments_);
- };
- const usedModels = ['rgb', 'hex', 'ansi256'];
- for (const model of usedModels) {
- styles[model] = {
- get() {
- const {level} = this;
- return function (...arguments_) {
- const styler = createStyler(getModelAnsi(model, levelMapping[level], 'color', ...arguments_), ansiStyles.color.close, this[STYLER]);
- return createBuilder(this, styler, this[IS_EMPTY]);
- };
- },
- };
- const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1);
- styles[bgModel] = {
- get() {
- const {level} = this;
- return function (...arguments_) {
- const styler = createStyler(getModelAnsi(model, levelMapping[level], 'bgColor', ...arguments_), ansiStyles.bgColor.close, this[STYLER]);
- return createBuilder(this, styler, this[IS_EMPTY]);
- };
- },
- };
- }
- 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) => {
- // Single argument is hot path, implicit coercion is faster than anything
- // eslint-disable-next-line no-implicit-coercion
- const builder = (...arguments_) => applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' '));
- // We alter the prototype because we must return a function, but there is
- // no way to create a function with a different prototype
- Object.setPrototypeOf(builder, proto);
- builder[GENERATOR] = self;
- builder[STYLER] = _styler;
- builder[IS_EMPTY] = _isEmpty;
- return builder;
- };
- const applyStyle = (self, string) => {
- if (self.level <= 0 || !string) {
- return self[IS_EMPTY] ? '' : string;
- }
- let styler = self[STYLER];
- if (styler === undefined) {
- return string;
- }
- const {openAll, closeAll} = styler;
- if (string.includes('\u001B')) {
- 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;
- };
- Object.defineProperties(createChalk.prototype, styles);
- const chalk = createChalk();
- export const chalkStderr = createChalk({level: stderrColor ? stderrColor.level : 0});
- export {
- modifierNames,
- foregroundColorNames,
- backgroundColorNames,
- colorNames,
- // TODO: Remove these aliases in the next major version
- modifierNames as modifiers,
- foregroundColorNames as foregroundColors,
- backgroundColorNames as backgroundColors,
- colorNames as colors,
- } from './vendor/ansi-styles/index.js';
- export {
- stdoutColor as supportsColor,
- stderrColor as supportsColorStderr,
- };
- export default chalk;
|