nx
Version:
254 lines (253 loc) • 8.35 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.output = void 0;
exports.orange = orange;
const pc = require("picocolors");
const os_1 = require("os");
const readline = require("readline");
const GH_GROUP_PREFIX = '::group::';
const GH_GROUP_SUFFIX = '::endgroup::';
/**
* Custom orange color using ANSI 256-color code 214.
* picocolors does not support keyword-based colors like chalk,
* so orange is implemented manually.
*/
function orange(text) {
return pc.isColorSupported ? `\x1b[38;5;214m${text}\x1b[39m` : String(text);
}
/**
* Map of color names to picocolors functions, used for dynamic color access.
*/
const pcColors = {
cyan: pc.cyan,
red: pc.red,
yellow: pc.yellow,
green: pc.green,
gray: pc.gray,
white: pc.white,
blue: pc.blue,
magenta: pc.magenta,
orange,
};
class CLIOutput {
constructor() {
this.cliName = 'NX';
this.formatCommand = (taskId) => `${pc.dim('nx run')} ${taskId}`;
/**
* Expose some color and other utility functions so that other parts of the codebase that need
* more fine-grained control of message bodies are still using a centralized
* implementation.
*/
this.colors = {
gray: pc.gray,
green: pc.green,
red: pc.red,
cyan: pc.cyan,
white: pc.white,
orange,
};
this.bold = pc.bold;
this.underline = pc.underline;
this.dim = pc.dim;
}
/**
* Longer dash character which forms more of a continuous line when place side to side
* with itself, unlike the standard dash character
*/
get VERTICAL_SEPARATOR() {
let divider = '';
for (let i = 0; i < process.stdout.columns - 1; i++) {
divider += '\u2014';
}
return divider;
}
writeToStdOut(str) {
process.stdout.write(str);
}
overwriteLine(lineText = '') {
// this replaces the existing text up to the new line length
process.stdout.write(lineText);
// clear whatever text might be left to the right of the cursor (happens
// when existing text was longer than new one)
readline.clearLine(process.stdout, 1);
process.stdout.write(os_1.EOL);
}
writeOutputTitle({ color, title, }) {
this.writeToStdOut(`${this.applyNxPrefix(color, title)}${os_1.EOL}`);
}
writeOptionalOutputBody(bodyLines) {
if (!bodyLines) {
return;
}
this.addNewline();
bodyLines.forEach((bodyLine) => this.writeToStdOut(`${bodyLine}${os_1.EOL}`));
}
applyNxPrefix(color = 'cyan', text) {
const colorFn = pcColors[color] || ((t) => t);
const nxPrefix = pc.inverse(pc.bold(colorFn(` ${this.cliName} `)));
return `${nxPrefix} ${text}`;
}
addNewline() {
this.writeToStdOut(os_1.EOL);
}
addVerticalSeparator(color = 'gray') {
this.addNewline();
this.addVerticalSeparatorWithoutNewLines(color);
this.addNewline();
}
addVerticalSeparatorWithoutNewLines(color = 'gray') {
this.writeToStdOut(`${this.getVerticalSeparator(color)}${os_1.EOL}`);
}
getVerticalSeparatorLines(color = 'gray') {
return ['', this.getVerticalSeparator(color), ''];
}
getVerticalSeparator(color) {
const colorFn = pcColors[color] || ((t) => t);
return pc.dim(colorFn(this.VERTICAL_SEPARATOR));
}
error({ title, slug, bodyLines }) {
this.addNewline();
this.writeOutputTitle({
color: 'red',
title: pc.red(title),
});
this.writeOptionalOutputBody(bodyLines);
/**
* Optional slug to be used in an Nx error message redirect URL
*/
if (slug && typeof slug === 'string') {
this.addNewline();
this.writeToStdOut(`${pc.gray(' Learn more about this error: ')}https://errors.nx.dev/${slug}${os_1.EOL}`);
}
this.addNewline();
}
warn({ title, slug, bodyLines }) {
this.addNewline();
this.writeOutputTitle({
color: 'yellow',
title: pc.yellow(title),
});
this.writeOptionalOutputBody(bodyLines);
/**
* Optional slug to be used in an Nx warning message redirect URL
*/
if (slug && typeof slug === 'string') {
this.addNewline();
this.writeToStdOut(`${pc.gray(' Learn more about this warning: ')}https://errors.nx.dev/${slug}${os_1.EOL}`);
}
this.addNewline();
}
note({ title, bodyLines }) {
this.addNewline();
this.writeOutputTitle({
color: 'orange',
title: orange(title),
});
this.writeOptionalOutputBody(bodyLines);
this.addNewline();
}
success({ title, bodyLines }) {
this.addNewline();
this.writeOutputTitle({
color: 'green',
title: pc.green(title),
});
this.writeOptionalOutputBody(bodyLines);
this.addNewline();
}
logSingleLine(message) {
this.addNewline();
this.writeOutputTitle({
color: 'gray',
title: message,
});
this.addNewline();
}
logCommand(message, taskStatus) {
this.addNewline();
this.writeToStdOut(this.getCommandWithStatus(message, taskStatus));
this.addNewline();
this.addNewline();
}
logCommandOutput(message, taskStatus, output) {
let commandOutputWithStatus = this.getCommandWithStatus(message, taskStatus);
if (process.env.NX_SKIP_LOG_GROUPING !== 'true' &&
process.env.GITHUB_ACTIONS) {
const icon = this.getStatusIcon(taskStatus);
commandOutputWithStatus = `${GH_GROUP_PREFIX}${icon} ${commandOutputWithStatus}`;
}
this.addNewline();
this.writeToStdOut(commandOutputWithStatus);
this.addNewline();
this.addNewline();
this.writeToStdOut(output);
if (process.env.NX_SKIP_LOG_GROUPING !== 'true' &&
process.env.GITHUB_ACTIONS) {
this.writeToStdOut(GH_GROUP_SUFFIX);
}
}
getCommandWithStatus(message, taskStatus) {
const commandOutput = pc.dim('> ') + this.formatCommand(this.normalizeMessage(message));
return this.addTaskStatus(taskStatus, commandOutput);
}
getStatusIcon(taskStatus) {
switch (taskStatus) {
case 'success':
return '✅';
case 'failure':
return '❌';
case 'skipped':
case 'local-cache-kept-existing':
return '⏩';
case 'local-cache':
case 'remote-cache':
return '🔁';
}
}
normalizeMessage(message) {
if (message.startsWith('nx run ')) {
return message.substring('nx run '.length);
}
else if (message.startsWith('run ')) {
return message.substring('run '.length);
}
else {
return message;
}
}
addTaskStatus(taskStatus, commandOutput) {
if (taskStatus === 'local-cache') {
return `${commandOutput} ${pc.dim('[local cache]')}`;
}
else if (taskStatus === 'remote-cache') {
return `${commandOutput} ${pc.dim('[remote cache]')}`;
}
else if (taskStatus === 'local-cache-kept-existing') {
return `${commandOutput} ${pc.dim('[existing outputs match the cache, left as is]')}`;
}
else {
return commandOutput;
}
}
log({ title, bodyLines, color }) {
this.addNewline();
const colorFn = color ? pcColors[color] : undefined;
this.writeOutputTitle({
color: 'cyan',
title: colorFn ? colorFn(title) : title,
});
this.writeOptionalOutputBody(bodyLines);
this.addNewline();
}
drain() {
return new Promise((resolve) => {
if (process.stdout.writableNeedDrain) {
process.stdout.once('drain', resolve);
}
else {
resolve();
}
});
}
}
exports.output = new CLIOutput();