mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-03-06 12:31:33 +01:00
feat: remove colors in favour of chalk (#10142)
* feat: remove colors in favour of chalk * fix: bad conversion from colors to chalk in src/cli/index.js * fix: padWidth calculation to account for control characters * fix: termWidth calculation, but swapped one problem for another * fix: formatItem, implement my own padRight to take control characters into account
This commit is contained in:
@@ -4,7 +4,8 @@
|
||||
// to include color styling in the output
|
||||
// so the CLI looks nice
|
||||
|
||||
const { Command, Help } = require('commander');
|
||||
const { Command } = require('commander');
|
||||
const chalk = require('chalk');
|
||||
|
||||
const colors = [
|
||||
// depth = 0, top-level command
|
||||
@@ -23,6 +24,11 @@ function humanReadableArgName(arg) {
|
||||
return arg.required ? `<${nameOutput}>` : `[${nameOutput}]`;
|
||||
}
|
||||
|
||||
function getControlCharacterSpaces(term) {
|
||||
const matches = term.match(/.\[\d+m/g);
|
||||
return matches ? matches.length * 5 : 0;
|
||||
}
|
||||
|
||||
// get depth of command
|
||||
// 0 = top, 1 = subcommand of top, etc
|
||||
Command.prototype.depth = function () {
|
||||
@@ -49,38 +55,50 @@ module.exports = {
|
||||
let parentCmd = cmd.parent;
|
||||
let parentDepth = depth - 1;
|
||||
while (parentCmd) {
|
||||
parentCmdNames = `${parentCmd.name()[colors[parentDepth].command]} ${parentCmdNames}`;
|
||||
parentCmdNames = `${chalk[colors[parentDepth].command](parentCmd.name())} ${parentCmdNames}`;
|
||||
|
||||
parentCmd = parentCmd.parent;
|
||||
parentDepth -= 1;
|
||||
}
|
||||
|
||||
// from Command.prototype.usage()
|
||||
const args = cmd._args.map(arg => humanReadableArgName(arg)[colors[depth].arg]);
|
||||
const args = cmd._args.map(arg => chalk[colors[depth].arg](humanReadableArgName(arg)));
|
||||
const cmdUsage = [].concat(
|
||||
(cmd.options.length || cmd._hasHelpOption ? '[options]'[colors[depth].option] : []),
|
||||
(cmd.commands.length ? '[command]'[colors[depth + 1].command] : []),
|
||||
(cmd.options.length || cmd._hasHelpOption ? chalk[colors[depth].option]('[options]') : []),
|
||||
(cmd.commands.length ? chalk[colors[depth + 1].command]('[command]') : []),
|
||||
(cmd._args.length ? args : [])
|
||||
).join(' ');
|
||||
|
||||
return `${parentCmdNames}${cmdName[colors[depth].command]} ${cmdUsage}`;
|
||||
return `${parentCmdNames}${chalk[colors[depth].command](cmdName)} ${cmdUsage}`;
|
||||
},
|
||||
subcommandTerm(cmd) {
|
||||
const depth = cmd.depth();
|
||||
|
||||
// Legacy. Ignores custom usage string, and nested commands.
|
||||
const args = cmd._args.map(arg => humanReadableArgName(arg)).join(' ');
|
||||
return (cmd._name + (
|
||||
return chalk[colors[depth].command](cmd._name + (
|
||||
cmd._aliases[0] ? `|${cmd._aliases[0]}` : ''
|
||||
))[colors[depth].command] +
|
||||
(cmd.options.length ? ' [options]' : '')[colors[depth].option] + // simplistic check for non-help option
|
||||
(args ? ` ${args}` : '')[colors[depth].arg];
|
||||
)) +
|
||||
chalk[colors[depth].option](cmd.options.length ? ' [options]' : '') + // simplistic check for non-help option
|
||||
chalk[colors[depth].arg](args ? ` ${args}` : '');
|
||||
},
|
||||
longestOptionTermLength(cmd, helper) {
|
||||
return Help.prototype.longestOptionTermLength.call(this, cmd, helper) + ''.red.length;
|
||||
return helper.visibleOptions(cmd).reduce((max, option) => Math.max(
|
||||
max,
|
||||
helper.optionTerm(option).length - getControlCharacterSpaces(helper.optionTerm(option))
|
||||
), 0);
|
||||
},
|
||||
longestSubcommandTermLength(cmd, helper) {
|
||||
return helper.visibleCommands(cmd).reduce((max, command) => Math.max(
|
||||
max,
|
||||
helper.subcommandTerm(command).length - getControlCharacterSpaces(helper.subcommandTerm(command))
|
||||
), 0);
|
||||
},
|
||||
longestArgumentTermLength(cmd, helper) {
|
||||
return Help.prototype.longestArgumentTermLength.call(this, cmd, helper) + ''.red.length;
|
||||
return helper.visibleArguments(cmd).reduce((max, argument) => Math.max(
|
||||
max,
|
||||
helper.argumentTerm(argument).length - getControlCharacterSpaces(helper.argumentTerm(argument))
|
||||
), 0);
|
||||
},
|
||||
formatHelp(cmd, helper) {
|
||||
const depth = cmd.depth();
|
||||
@@ -90,8 +108,9 @@ module.exports = {
|
||||
const itemIndentWidth = 2;
|
||||
const itemSeparatorWidth = 2; // between term and description
|
||||
function formatItem(term, description) {
|
||||
const padding = ' '.repeat((termWidth + itemSeparatorWidth) - (term.length - getControlCharacterSpaces(term)));
|
||||
if (description) {
|
||||
const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;
|
||||
const fullText = `${term}${padding}${description}`;
|
||||
return helper.wrap(fullText, helpWidth - itemIndentWidth, termWidth + itemSeparatorWidth);
|
||||
}
|
||||
return term;
|
||||
@@ -111,7 +130,7 @@ module.exports = {
|
||||
|
||||
// Arguments
|
||||
const argumentList = helper.visibleArguments(cmd).map(argument => formatItem(
|
||||
argument.term[colors[depth].arg],
|
||||
chalk[colors[depth].arg](argument.term),
|
||||
argument.description
|
||||
));
|
||||
if (argumentList.length > 0) {
|
||||
@@ -120,7 +139,7 @@ module.exports = {
|
||||
|
||||
// Options
|
||||
const optionList = helper.visibleOptions(cmd).map(option => formatItem(
|
||||
helper.optionTerm(option)[colors[depth].option],
|
||||
chalk[colors[depth].option](helper.optionTerm(option)),
|
||||
helper.optionDescription(option)
|
||||
));
|
||||
if (optionList.length > 0) {
|
||||
|
||||
@@ -22,10 +22,10 @@ try {
|
||||
packageInstall.preserveExtraneousPlugins();
|
||||
|
||||
try {
|
||||
fs.accessSync(path.join(paths.nodeModules, 'colors/package.json'), fs.constants.R_OK);
|
||||
fs.accessSync(path.join(paths.nodeModules, 'chalk/package.json'), fs.constants.R_OK);
|
||||
|
||||
require('colors');
|
||||
console.log('OK'.green);
|
||||
const chalk = require('chalk');
|
||||
console.log(chalk.green('OK'));
|
||||
} catch (e) {
|
||||
console.log('OK');
|
||||
}
|
||||
@@ -52,7 +52,7 @@ try {
|
||||
checkVersion('nconf');
|
||||
checkVersion('async');
|
||||
checkVersion('commander');
|
||||
checkVersion('colors');
|
||||
checkVersion('chalk');
|
||||
} catch (e) {
|
||||
if (['ENOENT', 'DEP_WRONG_VERSION', 'MODULE_NOT_FOUND'].includes(e.code)) {
|
||||
console.warn('Dependencies outdated or not yet installed.');
|
||||
@@ -61,14 +61,14 @@ try {
|
||||
packageInstall.updatePackageFile();
|
||||
packageInstall.installAll();
|
||||
|
||||
require('colors');
|
||||
console.log('OK'.green + '\n'.reset);
|
||||
const chalk = require('chalk');
|
||||
console.log(`${chalk.green('OK')}\n`);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
require('colors');
|
||||
const chalk = require('chalk');
|
||||
const nconf = require('nconf');
|
||||
const { program } = require('commander');
|
||||
const yargs = require('yargs');
|
||||
@@ -173,7 +173,7 @@ program
|
||||
try {
|
||||
initConfig = JSON.parse(initConfig);
|
||||
} catch (e) {
|
||||
console.warn('Invalid JSON passed as initial config value.'.red);
|
||||
console.warn(chalk.red('Invalid JSON passed as initial config value.'));
|
||||
console.log('If you meant to pass in an initial config value, please try again.\n');
|
||||
|
||||
throw e;
|
||||
@@ -190,7 +190,7 @@ program
|
||||
});
|
||||
program
|
||||
.command('build [targets...]')
|
||||
.description(`Compile static assets ${'(JS, CSS, templates, languages)'.red}`)
|
||||
.description(`Compile static assets ${chalk.red('(JS, CSS, templates, languages)')}`)
|
||||
.option('-s, --series', 'Run builds in series without extra processes')
|
||||
.action((targets, options) => {
|
||||
if (program.opts().dev) {
|
||||
@@ -240,7 +240,7 @@ resetCommand
|
||||
.action((options) => {
|
||||
const valid = ['theme', 'plugin', 'widgets', 'settings', 'all'].some(x => options[x]);
|
||||
if (!valid) {
|
||||
console.warn('\n No valid options passed in, so nothing was reset.'.red);
|
||||
console.warn(`\n${chalk.red('No valid options passed in, so nothing was reset.')}`);
|
||||
resetCommand.help();
|
||||
}
|
||||
|
||||
@@ -270,8 +270,8 @@ program
|
||||
console.log(`\n${[
|
||||
'When running particular upgrade scripts, options are ignored.',
|
||||
'By default all options are enabled. Passing any options disables that default.',
|
||||
`Only package and dependency updates: ${'./nodebb upgrade -mi'.yellow}`,
|
||||
`Only database update: ${'./nodebb upgrade -s'.yellow}`,
|
||||
`Only package and dependency updates: ${chalk.yellow('./nodebb upgrade -mi')}`,
|
||||
`Only database update: ${chalk.yellow('./nodebb upgrade -s')}`,
|
||||
].join('\n')}`);
|
||||
})
|
||||
.action((scripts, options) => {
|
||||
@@ -289,7 +289,7 @@ program
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
console.log('OK'.green);
|
||||
console.log(chalk.green('OK'));
|
||||
process.exit();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
const winston = require('winston');
|
||||
const childProcess = require('child_process');
|
||||
const CliGraph = require('cli-graph');
|
||||
const chalk = require('chalk');
|
||||
|
||||
const build = require('../meta/build');
|
||||
const db = require('../database');
|
||||
@@ -76,9 +77,9 @@ async function listPlugins() {
|
||||
process.stdout.write('Active plugins:\n');
|
||||
combined.forEach((plugin) => {
|
||||
process.stdout.write(`\t* ${plugin.id}${plugin.version ? `@${plugin.version}` : ''} (`);
|
||||
process.stdout.write(plugin.installed ? 'installed'.green : 'not installed'.red);
|
||||
process.stdout.write(plugin.installed ? chalk.green('installed') : chalk.red('not installed'));
|
||||
process.stdout.write(', ');
|
||||
process.stdout.write(plugin.active ? 'enabled'.green : 'disabled'.yellow);
|
||||
process.stdout.write(plugin.active ? chalk.green('enabled') : chalk.yellow('disabled'));
|
||||
process.stdout.write(')\n');
|
||||
});
|
||||
|
||||
@@ -88,9 +89,9 @@ async function listPlugins() {
|
||||
async function listEvents(count = 10) {
|
||||
await db.init();
|
||||
const eventData = await events.getEvents('', 0, count - 1);
|
||||
console.log((`\nDisplaying last ${count} administrative events...`).bold);
|
||||
console.log(chalk.bold(`\nDisplaying last ${count} administrative events...`));
|
||||
eventData.forEach((event) => {
|
||||
console.log(` * ${String(event.timestampISO).green} ${String(event.type).yellow}${event.text ? ` ${event.text}` : ''}${' (uid: '.reset}${event.uid ? event.uid : 0})`);
|
||||
console.log(` * ${chalk.green(String(event.timestampISO))} ${chalk.yellow(String(event.type))}${event.text ? ` ${event.text}` : ''} (uid: ${event.uid ? event.uid : 0})`);
|
||||
});
|
||||
process.exit();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
require('colors');
|
||||
const path = require('path');
|
||||
const winston = require('winston');
|
||||
const fs = require('fs');
|
||||
const chalk = require('chalk');
|
||||
|
||||
const db = require('../database');
|
||||
const events = require('../events');
|
||||
@@ -57,8 +57,8 @@ exports.reset = async function (options) {
|
||||
|
||||
if (!tasks.length) {
|
||||
console.log([
|
||||
'No arguments passed in, so nothing was reset.\n'.yellow,
|
||||
`Use ./nodebb reset ${'{-t|-p|-w|-s|-a}'.red}`,
|
||||
chalk.yellow('No arguments passed in, so nothing was reset.\n'),
|
||||
`Use ./nodebb reset ${chalk.red('{-t|-p|-w|-s|-a}')}`,
|
||||
' -t\tthemes',
|
||||
' -p\tplugins',
|
||||
' -w\twidgets',
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
const fs = require('fs');
|
||||
const childProcess = require('child_process');
|
||||
const chalk = require('chalk');
|
||||
|
||||
const fork = require('../meta/debugFork');
|
||||
const { paths } = require('../constants');
|
||||
@@ -39,17 +40,17 @@ function start(options) {
|
||||
}
|
||||
if (options.log) {
|
||||
console.log(`\n${[
|
||||
'Starting NodeBB with logging output'.bold,
|
||||
'Hit '.red + 'Ctrl-C '.bold + 'to exit'.red,
|
||||
chalk.bold('Starting NodeBB with logging output'),
|
||||
chalk.red('Hit ') + chalk.bold('Ctrl-C ') + chalk.red('to exit'),
|
||||
'The NodeBB process will continue to run in the background',
|
||||
`Use "${'./nodebb stop'.yellow}" to stop the NodeBB server`,
|
||||
`Use "${chalk.yellow('./nodebb stop')}" to stop the NodeBB server`,
|
||||
].join('\n')}`);
|
||||
} else if (!options.silent) {
|
||||
console.log(`\n${[
|
||||
'Starting NodeBB'.bold,
|
||||
` "${'./nodebb stop'.yellow}" to stop the NodeBB server`,
|
||||
` "${'./nodebb log'.yellow}" to view server output`,
|
||||
` "${'./nodebb help'.yellow}${'" for more commands\n'.reset}`,
|
||||
chalk.bold('Starting NodeBB'),
|
||||
` "${chalk.yellow('./nodebb stop')}" to stop the NodeBB server`,
|
||||
` "${chalk.yellow('./nodebb log')}" to view server output`,
|
||||
` "${chalk.yellow('./nodebb help')}" for more commands\n`,
|
||||
].join('\n')}`);
|
||||
}
|
||||
|
||||
@@ -82,7 +83,7 @@ function stop() {
|
||||
function restart(options) {
|
||||
getRunningPid((err, pid) => {
|
||||
if (!err) {
|
||||
console.log('\nRestarting NodeBB'.bold);
|
||||
console.log(chalk.bold('\nRestarting NodeBB'));
|
||||
process.kill(pid, 'SIGTERM');
|
||||
|
||||
options.silent = true;
|
||||
@@ -97,20 +98,20 @@ function status() {
|
||||
getRunningPid((err, pid) => {
|
||||
if (!err) {
|
||||
console.log(`\n${[
|
||||
'NodeBB Running '.bold + (`(pid ${pid.toString()})`).cyan,
|
||||
`\t"${'./nodebb stop'.yellow}" to stop the NodeBB server`,
|
||||
`\t"${'./nodebb log'.yellow}" to view server output`,
|
||||
`\t"${'./nodebb restart'.yellow}" to restart NodeBB\n`,
|
||||
chalk.bold('NodeBB Running ') + chalk.cyan(`(pid ${pid.toString()})`),
|
||||
`\t"${chalk.yellow('./nodebb stop')}" to stop the NodeBB server`,
|
||||
`\t"${chalk.yellow('./nodebb log')}" to view server output`,
|
||||
`\t"${chalk.yellow('./nodebb restart')}" to restart NodeBB\n`,
|
||||
].join('\n')}`);
|
||||
} else {
|
||||
console.log('\nNodeBB is not running'.bold);
|
||||
console.log(`\t"${'./nodebb start'.yellow}${'" to launch the NodeBB server\n'.reset}`);
|
||||
console.log(chalk.bold('\nNodeBB is not running'));
|
||||
console.log(`\t"${chalk.yellow('./nodebb start')}" to launch the NodeBB server\n`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function log() {
|
||||
console.log('\nHit '.red + 'Ctrl-C '.bold + 'to exit\n'.red + '\n'.reset);
|
||||
console.log(`${chalk.red('\nHit ') + chalk.bold('Ctrl-C ') + chalk.red('to exit\n')}\n`);
|
||||
childProcess.spawn('tail', ['-F', './logs/output.log'], {
|
||||
stdio: 'inherit',
|
||||
cwd,
|
||||
|
||||
@@ -7,6 +7,7 @@ const semver = require('semver');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const nconf = require('nconf');
|
||||
const chalk = require('chalk');
|
||||
|
||||
const { paths, pluginNamePattern } = require('../constants');
|
||||
|
||||
@@ -96,11 +97,11 @@ async function checkPlugins() {
|
||||
|
||||
const toCheck = Object.keys(plugins);
|
||||
if (!toCheck.length) {
|
||||
process.stdout.write(' OK'.green + ''.reset);
|
||||
process.stdout.write(chalk.green(' OK'));
|
||||
return []; // no extraneous plugins installed
|
||||
}
|
||||
const suggestedModules = await getSuggestedModules(nbbVersion, toCheck);
|
||||
process.stdout.write(' OK'.green + ''.reset);
|
||||
process.stdout.write(chalk.green(' OK'));
|
||||
|
||||
let current;
|
||||
let suggested;
|
||||
@@ -125,12 +126,12 @@ async function upgradePlugins() {
|
||||
try {
|
||||
const found = await checkPlugins();
|
||||
if (found && found.length) {
|
||||
process.stdout.write(`\n\nA total of ${String(found.length).bold} package(s) can be upgraded:\n\n`);
|
||||
process.stdout.write(`\n\nA total of ${chalk.bold(String(found.length))} package(s) can be upgraded:\n\n`);
|
||||
found.forEach((suggestObj) => {
|
||||
process.stdout.write(`${' * '.yellow + suggestObj.name.reset} (${suggestObj.current.yellow}${' -> '.reset}${suggestObj.suggested.green}${')\n'.reset}`);
|
||||
process.stdout.write(`${chalk.yellow(' * ') + suggestObj.name} (${chalk.yellow(suggestObj.current)}' -> '${chalk.green(suggestObj.suggested)}')\n'`);
|
||||
});
|
||||
} else {
|
||||
console.log('\nAll packages up-to-date!'.green + ''.reset);
|
||||
console.log(chalk.green('\nAll packages up-to-date!'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -140,7 +141,7 @@ async function upgradePlugins() {
|
||||
prompt.start();
|
||||
const result = await prompt.get({
|
||||
name: 'upgrade',
|
||||
description: '\nProceed with upgrade (y|n)?'.reset,
|
||||
description: '\nProceed with upgrade (y|n)?',
|
||||
type: 'string',
|
||||
});
|
||||
|
||||
@@ -150,10 +151,10 @@ async function upgradePlugins() {
|
||||
|
||||
cproc.execFileSync(packageManagerExecutable, args, { stdio: 'ignore' });
|
||||
} else {
|
||||
console.log('Package upgrades skipped'.yellow + '. Check for upgrades at any time by running "'.reset + './nodebb upgrade -p'.green + '".'.reset);
|
||||
console.log(`${chalk.yellow('Package upgrades skipped')}. Check for upgrades at any time by running "${chalk.green('./nodebb upgrade -p')}".`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Warning'.yellow + ': An unexpected error occured when attempting to verify plugin upgradability'.reset);
|
||||
console.log(`${chalk.yellow('Warning')}: An unexpected error occured when attempting to verify plugin upgradability`);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const nconf = require('nconf');
|
||||
const chalk = require('chalk');
|
||||
|
||||
const packageInstall = require('./package-install');
|
||||
const { upgradePlugins } = require('./upgrade-plugins');
|
||||
@@ -11,13 +12,13 @@ const steps = {
|
||||
handler: function () {
|
||||
packageInstall.updatePackageFile();
|
||||
packageInstall.preserveExtraneousPlugins();
|
||||
process.stdout.write(' OK\n'.green);
|
||||
process.stdout.write(chalk.green(' OK\n'));
|
||||
},
|
||||
},
|
||||
install: {
|
||||
message: 'Bringing base dependencies up to date...',
|
||||
handler: function () {
|
||||
process.stdout.write(' started\n'.green);
|
||||
process.stdout.write(chalk.green(' started\n'));
|
||||
packageInstall.installAll();
|
||||
},
|
||||
},
|
||||
@@ -49,7 +50,7 @@ async function runSteps(tasks) {
|
||||
for (let i = 0; i < tasks.length; i++) {
|
||||
const step = steps[tasks[i]];
|
||||
if (step && step.message && step.handler) {
|
||||
process.stdout.write(`\n${(`${i + 1}. `).bold}${step.message.yellow}`);
|
||||
process.stdout.write(`\n${chalk.bold(`${i + 1}. `)}${chalk.yellow(step.message)}`);
|
||||
/* eslint-disable-next-line */
|
||||
await step.handler();
|
||||
}
|
||||
@@ -60,7 +61,7 @@ async function runSteps(tasks) {
|
||||
const { columns } = process.stdout;
|
||||
const spaces = columns ? new Array(Math.floor(columns / 2) - (message.length / 2) + 1).join(' ') : ' ';
|
||||
|
||||
console.log(`\n\n${spaces}${message.green.bold}${'\n'.reset}`);
|
||||
console.log(`\n\n${spaces}${chalk.green.bold(message)}\n`);
|
||||
|
||||
process.exit();
|
||||
} catch (err) {
|
||||
@@ -70,7 +71,7 @@ async function runSteps(tasks) {
|
||||
}
|
||||
|
||||
async function runUpgrade(upgrades, options) {
|
||||
console.log('\nUpdating NodeBB...'.cyan);
|
||||
console.log(chalk.cyan('\nUpdating NodeBB...'));
|
||||
options = options || {};
|
||||
// disable mongo timeouts during upgrade
|
||||
nconf.set('mongo:options:socketTimeoutMS', 0);
|
||||
|
||||
Reference in New Issue
Block a user