UNPKG

appcenter-cli

Version:

Command line tool for Visual Studio App Center

189 lines (188 loc) 8.35 kB
"use strict"; // Help system - displays help for categories and commands Object.defineProperty(exports, "__esModule", { value: true }); exports.runHelp = void 0; const _ = require("lodash"); const os = require("os"); const tty_1 = require("tty"); const chalk = require("chalk"); const debug = require("debug")("appcenter-cli:util:commandline:help"); const Table = require("cli-table3"); const option_decorators_1 = require("./option-decorators"); const interaction_1 = require("../interaction"); const misc_1 = require("../misc"); const usageConst = "Usage: "; function runHelp(commandPrototype, commandObj) { const commandExample = getCommandExample(commandPrototype, commandObj); const commandHelp = getCommandHelp(commandObj); const optionsHelpTable = getOptionsHelpTable(commandPrototype); const commonSwitchOptionsHelpTable = getCommonSwitchOptionsHelpTable(commandPrototype); interaction_1.out.help(); interaction_1.out.help(commandHelp); interaction_1.out.help(); interaction_1.out.help(usageConst + chalk.bold(commandExample)); if (optionsHelpTable.length > 0) { interaction_1.out.help(); interaction_1.out.help("Options:"); interaction_1.out.help(optionsHelpTable.toString()); } if (commonSwitchOptionsHelpTable.length > 0) { interaction_1.out.help(); interaction_1.out.help("Common Options (works on all commands):"); interaction_1.out.help(commonSwitchOptionsHelpTable.toString()); } } exports.runHelp = runHelp; function getCommandHelp(commandObj) { const helpString = option_decorators_1.getClassHelpText(commandObj.constructor); return !!helpString ? helpString : "No help text for command. Dev, fix it!"; } function toSwitchOptionHelp(option) { return { shortName: option.shortName ? `-${option.shortName}` : "", longName: option.longName ? `--${option.longName}` : "", helpText: option.helpText || "", argName: option.hasArg ? "<arg>" : "", }; } function getOptionsHelpTable(commandPrototype) { const nonCommonSwitchOpts = getSwitchOptionsHelp(commandPrototype, false); const posOpts = getPositionalOptionsHelp(commandPrototype); return getStyledOptionsHelpTable(nonCommonSwitchOpts.concat(posOpts)); } function getCommonSwitchOptionsHelpTable(commandPrototype) { const commonSwitchOpts = getSwitchOptionsHelp(commandPrototype, true); return getStyledOptionsHelpTable(commonSwitchOpts); } function getStyledOptionsHelpTable(options) { const opts = styleOptsTable(options); // Calculate max length of the strings from the first column (switches/positional parameters) - it will be a width for the first column; const firstColumnWidth = opts.reduce((contenderMaxWidth, optRow) => Math.max(optRow[0].length, contenderMaxWidth), 0); // Creating a help table object const helpTableObject = new Table(interaction_1.out.getOptionsForTwoColumnTableWithNoBorders(firstColumnWidth)); opts.forEach((opt) => helpTableObject.push(opt)); return helpTableObject; } function getSwitchOptionsHelp(commandPrototype, isCommon) { const switchOptions = option_decorators_1.getOptionsDescription(commandPrototype); const filteredSwitchOptions = filterOptionDescriptions(_.values(switchOptions), isCommon); const options = sortOptionDescriptions(filteredSwitchOptions).map(toSwitchOptionHelp); debug(`Command has ${options.length} switch options:`); debug(options.map((o) => `${o.shortName}|${o.longName}`).join("/")); return options.map((optionHelp) => [` ${switchText(optionHelp)} `, optionHelp.helpText]); } function toPositionalOptionHelp(option) { return { name: option.name, helpText: option.helpText, }; } function getPositionalOptionsHelp(commandPrototype) { const options = option_decorators_1.getPositionalOptionsDescription(commandPrototype).map(toPositionalOptionHelp); debug(`Command has ${options.length} positional options:`); debug(options.map((o) => o.name).join("/")); return options.map((optionsHelp) => [` ${optionsHelp.name} `, optionsHelp.helpText]); } function switchText(switchOption) { // Desired formats look like: // // -x // -x|--xopt // --xopt // -y <arg> // -y|--yopt <arg> // --yopt <arg> const start = switchOption.shortName ? [switchOption.shortName] : [" "]; const sep = switchOption.shortName && switchOption.longName ? ["|"] : [" "]; const long = switchOption.longName ? [switchOption.longName] : []; const arg = switchOption.argName ? [" " + switchOption.argName] : []; return start.concat(sep).concat(long).concat(arg).join(""); } function terminalWidth() { // If stdout is a terminal, return the width if (tty_1.isatty(1)) { return process.stdout.columns; } // Otherwise return something useful. return 80; } function getCommandExample(commandPrototype, commandObj) { const commandName = getCommandName(commandObj); const lines = []; const lastLinesLeftMargin = " "; // 2 spaces const linesSeparator = os.EOL + lastLinesLeftMargin; let currentLine = `${misc_1.scriptName} ${commandName}`; const maxWidth = terminalWidth(); const separatorLength = os.EOL.length; const firstLineFreeSpace = maxWidth - usageConst.length - separatorLength; const freeSpace = firstLineFreeSpace - lastLinesLeftMargin.length; const leftMargin = _.repeat(" ", usageConst.length); getAllOptionExamples(commandPrototype).forEach((example) => { if (currentLine.length + example.length + 1 > (lines.length ? freeSpace : firstLineFreeSpace)) { lines.push(currentLine); currentLine = leftMargin + example; } else { currentLine += ` ${example}`; } }); lines.push(currentLine); return lines.join(linesSeparator); } function getCommandName(commandObj) { const commandParts = commandObj.command; let script = commandParts[commandParts.length - 1]; const extIndex = script.lastIndexOf("."); if (extIndex > -1) { script = script.slice(0, extIndex); } commandParts[commandParts.length - 1] = script; return commandParts.join(" "); } function getAllOptionExamples(commandPrototype) { return getSwitchOptionExamples(commandPrototype, false).concat(getPositionalOptionExamples(commandPrototype)); } function getSwitchOptionExamples(commandPrototype, includeCommon = true) { const switchOptions = option_decorators_1.getOptionsDescription(commandPrototype); const switchOptionDescriptions = includeCommon ? _.values(switchOptions) : filterOptionDescriptions(_.values(switchOptions), false); return sortOptionDescriptions(switchOptionDescriptions).map((description) => { const result = []; result.push(description.shortName ? `-${description.shortName}` : ""); result.push(description.shortName && description.longName ? "|" : ""); result.push(description.longName ? `--${description.longName}` : ""); result.push(description.hasArg ? " <arg>" : ""); if (!description.required) { result.unshift("["); result.push("]"); } return result.join(""); }); } function getPositionalOptionExamples(commandPrototype) { const positionalOptions = option_decorators_1.getPositionalOptionsDescription(commandPrototype); return _.sortBy(positionalOptions, "position").map((description) => { if (description.position !== null) { return `<${description.name}>`; } // Output for "rest" parameter. sortBy will push it to the end. return `<${description.name}...>`; }); } function styleOptsTable(table) { return table.map((row) => [chalk.bold(row[0])].concat(row.slice(1))); } function sortOptionDescriptions(options) { return _(options) .reverse() // options from a top prototype are added first, reversing order .sortBy([(opt) => (opt.required ? 0 : 1)]) // required options should be shown first .value(); } function filterOptionDescriptions(options, isCommon) { return isCommon ? options.filter((option) => { return option.common; }) : options.filter((option) => { return !option.common; }); }