UNPKG

@adonisjs/ace

Version:

Commandline apps framework used by AdonisJs

271 lines (270 loc) 10.1 kB
"use strict"; /* * @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;