Projekt

Obecné

Profil

Stáhnout (6.29 KB) Statistiky
| Větev: | Revize:
1
'use strict';
2
const escapeStringRegexp = require('escape-string-regexp');
3
const ansiStyles = require('ansi-styles');
4
const stdoutColor = require('supports-color').stdout;
5

    
6
const template = require('./templates.js');
7

    
8
const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm');
9

    
10
// `supportsColor.level` → `ansiStyles.color[name]` mapping
11
const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m'];
12

    
13
// `color-convert` models to exclude from the Chalk API due to conflicts and such
14
const skipModels = new Set(['gray']);
15

    
16
const styles = Object.create(null);
17

    
18
function applyOptions(obj, options) {
19
	options = options || {};
20

    
21
	// Detect level if not set manually
22
	const scLevel = stdoutColor ? stdoutColor.level : 0;
23
	obj.level = options.level === undefined ? scLevel : options.level;
24
	obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0;
25
}
26

    
27
function Chalk(options) {
28
	// We check for this.template here since calling `chalk.constructor()`
29
	// by itself will have a `this` of a previously constructed chalk object
30
	if (!this || !(this instanceof Chalk) || this.template) {
31
		const chalk = {};
32
		applyOptions(chalk, options);
33

    
34
		chalk.template = function () {
35
			const args = [].slice.call(arguments);
36
			return chalkTag.apply(null, [chalk.template].concat(args));
37
		};
38

    
39
		Object.setPrototypeOf(chalk, Chalk.prototype);
40
		Object.setPrototypeOf(chalk.template, chalk);
41

    
42
		chalk.template.constructor = Chalk;
43

    
44
		return chalk.template;
45
	}
46

    
47
	applyOptions(this, options);
48
}
49

    
50
// Use bright blue on Windows as the normal blue color is illegible
51
if (isSimpleWindowsTerm) {
52
	ansiStyles.blue.open = '\u001B[94m';
53
}
54

    
55
for (const key of Object.keys(ansiStyles)) {
56
	ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g');
57

    
58
	styles[key] = {
59
		get() {
60
			const codes = ansiStyles[key];
61
			return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key);
62
		}
63
	};
64
}
65

    
66
styles.visible = {
67
	get() {
68
		return build.call(this, this._styles || [], true, 'visible');
69
	}
70
};
71

    
72
ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g');
73
for (const model of Object.keys(ansiStyles.color.ansi)) {
74
	if (skipModels.has(model)) {
75
		continue;
76
	}
77

    
78
	styles[model] = {
79
		get() {
80
			const level = this.level;
81
			return function () {
82
				const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments);
83
				const codes = {
84
					open,
85
					close: ansiStyles.color.close,
86
					closeRe: ansiStyles.color.closeRe
87
				};
88
				return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model);
89
			};
90
		}
91
	};
92
}
93

    
94
ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g');
95
for (const model of Object.keys(ansiStyles.bgColor.ansi)) {
96
	if (skipModels.has(model)) {
97
		continue;
98
	}
99

    
100
	const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1);
101
	styles[bgModel] = {
102
		get() {
103
			const level = this.level;
104
			return function () {
105
				const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments);
106
				const codes = {
107
					open,
108
					close: ansiStyles.bgColor.close,
109
					closeRe: ansiStyles.bgColor.closeRe
110
				};
111
				return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model);
112
			};
113
		}
114
	};
115
}
116

    
117
const proto = Object.defineProperties(() => {}, styles);
118

    
119
function build(_styles, _empty, key) {
120
	const builder = function () {
121
		return applyStyle.apply(builder, arguments);
122
	};
123

    
124
	builder._styles = _styles;
125
	builder._empty = _empty;
126

    
127
	const self = this;
128

    
129
	Object.defineProperty(builder, 'level', {
130
		enumerable: true,
131
		get() {
132
			return self.level;
133
		},
134
		set(level) {
135
			self.level = level;
136
		}
137
	});
138

    
139
	Object.defineProperty(builder, 'enabled', {
140
		enumerable: true,
141
		get() {
142
			return self.enabled;
143
		},
144
		set(enabled) {
145
			self.enabled = enabled;
146
		}
147
	});
148

    
149
	// See below for fix regarding invisible grey/dim combination on Windows
150
	builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey';
151

    
152
	// `__proto__` is used because we must return a function, but there is
153
	// no way to create a function with a different prototype
154
	builder.__proto__ = proto; // eslint-disable-line no-proto
155

    
156
	return builder;
157
}
158

    
159
function applyStyle() {
160
	// Support varags, but simply cast to string in case there's only one arg
161
	const args = arguments;
162
	const argsLen = args.length;
163
	let str = String(arguments[0]);
164

    
165
	if (argsLen === 0) {
166
		return '';
167
	}
168

    
169
	if (argsLen > 1) {
170
		// Don't slice `arguments`, it prevents V8 optimizations
171
		for (let a = 1; a < argsLen; a++) {
172
			str += ' ' + args[a];
173
		}
174
	}
175

    
176
	if (!this.enabled || this.level <= 0 || !str) {
177
		return this._empty ? '' : str;
178
	}
179

    
180
	// Turns out that on Windows dimmed gray text becomes invisible in cmd.exe,
181
	// see https://github.com/chalk/chalk/issues/58
182
	// If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop.
183
	const originalDim = ansiStyles.dim.open;
184
	if (isSimpleWindowsTerm && this.hasGrey) {
185
		ansiStyles.dim.open = '';
186
	}
187

    
188
	for (const code of this._styles.slice().reverse()) {
189
		// Replace any instances already present with a re-opening code
190
		// otherwise only the part of the string until said closing code
191
		// will be colored, and the rest will simply be 'plain'.
192
		str = code.open + str.replace(code.closeRe, code.open) + code.close;
193

    
194
		// Close the styling before a linebreak and reopen
195
		// after next line to fix a bleed issue on macOS
196
		// https://github.com/chalk/chalk/pull/92
197
		str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`);
198
	}
199

    
200
	// Reset the original `dim` if we changed it to work around the Windows dimmed gray issue
201
	ansiStyles.dim.open = originalDim;
202

    
203
	return str;
204
}
205

    
206
function chalkTag(chalk, strings) {
207
	if (!Array.isArray(strings)) {
208
		// If chalk() was called by itself or with a string,
209
		// return the string itself as a string.
210
		return [].slice.call(arguments, 1).join(' ');
211
	}
212

    
213
	const args = [].slice.call(arguments, 2);
214
	const parts = [strings.raw[0]];
215

    
216
	for (let i = 1; i < strings.length; i++) {
217
		parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&'));
218
		parts.push(String(strings.raw[i]));
219
	}
220

    
221
	return template(chalk, parts.join(''));
222
}
223

    
224
Object.defineProperties(Chalk.prototype, styles);
225

    
226
module.exports = Chalk(); // eslint-disable-line new-cap
227
module.exports.supportsColor = stdoutColor;
228
module.exports.default = module.exports; // For TypeScript
(1-1/6)