@adonisjs/ace
Version:
Commandline apps framework used by AdonisJs
271 lines (270 loc) • 10.1 kB
JavaScript
;
/*
* @adonisjs/ace
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.printHelpFor = exports.printHelp = void 0;
const cliui_1 = require("@poppinss/cliui");
const term_size_1 = __importDefault(require("term-size"));
const sortAndGroupCommands_1 = require("./sortAndGroupCommands");
/**
* Converts a line to rows at a specific width
*/
function lineToRows(text, width) {
const rows = [];
let row = [];
let wordsCount = 0;
text.split(' ').forEach((word) => {
if (wordsCount + (word.length + 1) > width) {
/**
* Push the number of whitespace left after the existing current
* and the terminal space. We need to do this, coz we at times
* have whitespace when the upcoming word may break into next
* lines
*/
row.push(new Array(width - wordsCount + 1).join(' '));
/**
* Push the existing row to the rows
*/
rows.push(row.join(' '));
/**
* Row is empty now
*/
row = [];
/**
* Row has zero words
*/
wordsCount = 0;
}
/**
* Increase the words count + 1. The extra one is for the
* whitspace between the words
*/
wordsCount += word.length + 1;
/**
* Collect word inside the row
*/
row.push(word);
});
/**
* Handle the orphan row
*/
if (row.length) {
rows.push(row.join(' '));
}
return rows;
}
/**
* Converts the description to multiple lines fitting into
* a given column size
*/
function descriptionToRows(description, options) {
return lineToRows(description, options.descriptionColumnsSize)
.map((column, index) => {
return index > 0 ? `${new Array(options.nameColumnSize + 1).join(' ')}${column}` : column;
})
.join('');
}
/**
* Wraps the command arg inside `<>` or `[]` brackets based upon if it's
* required or not.
*/
function wrapArg(arg) {
const displayName = arg.type === 'spread' ? `...${arg.name}` : arg.name;
return arg.required ? `<${displayName}>` : `[${displayName}]`;
}
/**
* Returns an array of flags for displaying the help screen
*/
function getFlagsForDisplay(flags) {
return flags.map(({ name, type, alias, description }) => {
/**
* Display name is the way we want to display a single flag in the
* list of flags
*/
const displayName = alias ? `-${alias}, --${name}` : `--${name}`;
/**
* The type hints the user about the expectation on the flag type. We only
* print the type, when flag is not a boolean.
*/
let displayType = '';
switch (type) {
case 'array':
displayType = 'string[]';
break;
case 'numArray':
displayType = 'number[]';
break;
case 'string':
displayType = 'string';
break;
case 'boolean':
displayType = 'boolean';
break;
case 'number':
displayType = 'number';
break;
}
return {
displayName,
displayType,
description,
width: displayName.length + displayType.length,
};
});
}
/**
* Returns an array of args for displaying the help screen
*/
function getArgsForDisplay(args) {
return args.map(({ name, description }) => {
return {
displayName: name,
description: description,
width: name.length,
};
});
}
/**
* Returns an array of commands for display
*/
function getCommandsForDisplay(commands, aliases) {
return commands.map(({ commandName, description }) => {
const commandAliases = getCommandAliases(commandName, aliases);
const aliasesString = commandAliases.length ? ` [${commandAliases.join(', ')}]` : '';
return {
displayName: `${commandName}${aliasesString}`,
description,
width: commandName.length + aliasesString.length,
};
});
}
/**
* Returns the aliases for a given command
*/
function getCommandAliases(commandName, aliases) {
return Object.keys(aliases).reduce((commandAliases, alias) => {
if (aliases[alias] === commandName) {
commandAliases.push(alias);
}
return commandAliases;
}, []);
}
/**
* Prints help for all the commands by sorting them in alphabetical order
* and grouping them as per their namespace.
*/
function printHelp(commands, flags, aliases) {
const flagsList = getFlagsForDisplay(flags);
const commandsList = getCommandsForDisplay(commands, aliases);
/**
* Get width of longest command name.
*/
const maxWidth = Math.max.apply(Math, flagsList.concat(commandsList).map(({ width }) => width));
/**
* Size of the terminal columns. Max width is the width of the command
* name and the extra four is whitespace around the command name.
*
* This gives the columns size for the description section
*/
const descriptionColumnsSize = (0, term_size_1.default)().columns - (maxWidth + 4);
/**
* Sort commands and group them, so that we can print them as per
* the namespace they belongs to
*/
(0, sortAndGroupCommands_1.sortAndGroupCommands)(commands).forEach(({ group, commands: groupCommands }) => {
console.log('');
if (group === 'root') {
console.log(cliui_1.logger.colors.bold(cliui_1.logger.colors.yellow('Available commands')));
}
else {
console.log(cliui_1.logger.colors.bold(cliui_1.logger.colors.yellow(group)));
}
groupCommands.forEach(({ commandName, description }) => {
const commandAliases = getCommandAliases(commandName, aliases);
const aliasesString = commandAliases.length ? ` [${commandAliases.join(', ')}]` : '';
const displayName = `${commandName}${aliasesString}`;
const whiteSpace = ''.padEnd(maxWidth - displayName.length, ' ');
const descriptionRows = descriptionToRows(description, {
nameColumnSize: maxWidth + 4,
descriptionColumnsSize,
});
console.log(` ${cliui_1.logger.colors.green(displayName)} ${whiteSpace} ${cliui_1.logger.colors.dim(descriptionRows)}`);
});
});
if (flagsList.length) {
console.log('');
console.log(cliui_1.logger.colors.bold(cliui_1.logger.colors.yellow('Global Flags')));
flagsList.forEach(({ displayName, displayType, description = '', width }) => {
const whiteSpace = ''.padEnd(maxWidth - width, ' ');
const descriptionRows = descriptionToRows(description, {
nameColumnSize: maxWidth + 4,
descriptionColumnsSize,
});
console.log(` ${cliui_1.logger.colors.green(displayName)} ${cliui_1.logger.colors.dim(displayType)}${whiteSpace} ${cliui_1.logger.colors.dim(descriptionRows)}`);
});
}
}
exports.printHelp = printHelp;
/**
* Prints help for a single command
*/
function printHelpFor(command, aliases) {
if (command.description) {
console.log('');
console.log(command.description);
}
console.log('');
console.log(`${cliui_1.logger.colors.yellow('Usage:')} ${command.commandName} ${cliui_1.logger.colors.dim(command.args.map(wrapArg).join(' '))}`);
const flags = getFlagsForDisplay(command.flags);
const args = getArgsForDisplay(command.args);
/**
* Getting max width to keep flags and args symmetric
*/
const maxWidth = Math.max.apply(Math, flags.concat(args).map(({ width }) => width));
/**
* Size of the terminal columns. Max width is the width of the command
* name and the extra four is whitespace around the command name.
*
* This gives the columns size for the description section
*/
const descriptionColumnsSize = (0, term_size_1.default)().columns - (maxWidth + 5);
const commandAliases = getCommandAliases(command.commandName, aliases);
if (commandAliases.length) {
console.log('');
console.log(`${cliui_1.logger.colors.yellow('Aliases:')} ${cliui_1.logger.colors.green(commandAliases.join(', '))}`);
}
if (args.length) {
console.log('');
console.log(cliui_1.logger.colors.bold(cliui_1.logger.colors.yellow('Arguments')));
args.forEach(({ displayName, description = '', width }) => {
const whiteSpace = ''.padEnd(maxWidth - width, ' ');
const descriptionRow = descriptionToRows(description, {
nameColumnSize: maxWidth + 5,
descriptionColumnsSize,
});
console.log(` ${cliui_1.logger.colors.green(displayName)} ${whiteSpace} ${cliui_1.logger.colors.dim(descriptionRow)}`);
});
}
if (flags.length) {
console.log('');
console.log(cliui_1.logger.colors.bold(cliui_1.logger.colors.yellow('Flags')));
flags.forEach(({ displayName, displayType, description = '', width }) => {
const whiteSpace = ''.padEnd(maxWidth - width, ' ');
const descriptionRow = descriptionToRows(description, {
nameColumnSize: maxWidth + 5,
descriptionColumnsSize,
});
console.log(` ${cliui_1.logger.colors.green(displayName)} ${cliui_1.logger.colors.dim(displayType)}${whiteSpace} ${cliui_1.logger.colors.dim(descriptionRow)}`);
});
}
}
exports.printHelpFor = printHelpFor;