subcli
Version:
helpers for creating command-line interfaces that support subcommands
96 lines (82 loc) • 3.67 kB
JavaScript
import cliclopts from 'cliclopts'
import wordwrap from 'wordwrap'
import {sprintf} from 'sprintf-js'
import addHelpOption from './addHelpOption'
import findSubcommandDescriptor from './findSubcommandDescriptor'
import {DEFAULT_OPTIONS} from './index'
export function usageInfo(usage, parentCommand = null, commandPrefix = '') {
if (!usage) {
return ''
}
const usageString = parentCommand ? `${parentCommand} ${usage}` : `${commandPrefix}${usage}`
return `\nUsage:\n ${usageString}`
}
export function commandList(commands, maxWidth = Number.MAX_SAFE_INTEGER) {
if (!commands || commands.length === 0) {
return ''
}
const maxCommandWidth = commands.reduce((maxWidth, currCmd) => {
return (currCmd.name.length > maxWidth) ? currCmd.name.length : maxWidth
}, 0)
const wrap = wordwrap(7 + maxCommandWidth, maxWidth)
const commandDescs = commands.map(cmd => {
const desc = `${wrap(cmd.description).replace(/^\s+/, '')}\n`
return sprintf(` %-${maxCommandWidth}s - %s`, cmd.name, desc)
})
return `\nCommands:\n${commandDescs.join('\n')}`
}
export function optionList(options, maxWidth = Number.MAX_SAFE_INTEGER) {
if (!options || options.length === 0) {
return ''
}
const wrap = wordwrap(26, maxWidth)
const wrappedOptions = options.map(opt => {
return Object.assign({}, opt, {help: `${wrap(opt.help).replace(/^\s+/, '')}\n`})
})
const cliOpts = cliclopts(wrappedOptions)
return `\nOptions:\n${cliOpts.usage()}`
}
export function exampleList(examples, maxWidth = Number.MAX_SAFE_INTEGER, commandPrefix = '') {
if (!examples || examples.length === 0) {
return ''
}
const descPrefix = ' # '
const wrap = wordwrap(0, maxWidth - descPrefix.length)
const exampleDescs = examples.map(expl => {
const desc = wrap(expl.description).split('\n').join(`\n${descPrefix}`)
return sprintf(`%s%s\n %s%s\n`, descPrefix, desc, commandPrefix, expl.example)
})
return `Examples:\n${exampleDescs.join('\n')}`
}
function commandDescriptorIncludesDefaultHelp(commandDescriptor) {
if (!commandDescriptor.options) {
return false
}
const defaultHelpOptions = commandDescriptor.options.filter(opt => opt.__DEFAULT_HELP_OPTION__)
return defaultHelpOptions.length > 0
}
export function usageMessage(commandDescriptor, parentCommand = null, commandPrefix = '', maxWidth = Number.MAX_SAFE_INTEGER) {
const prefix = parentCommand ? '' : commandPrefix
const fullCommandName = parentCommand ? `${parentCommand} ${commandDescriptor.name}` : commandDescriptor.name
return `${prefix}${fullCommandName} - ${commandDescriptor.description}
${usageInfo(commandDescriptor.usage || commandDescriptor.name, parentCommand, prefix)}
${commandList(commandDescriptor.commands, maxWidth)}
${optionList(commandDescriptor.options, maxWidth)}
${exampleList(commandDescriptor.examples, maxWidth, prefix)}`
}
export default function usage(cd, args = null, opts = {}) {
const options = Object.assign({}, DEFAULT_OPTIONS, opts)
const commandDescriptor = options.includeHelp ? addHelpOption(cd) : cd
if (options.includeHelp) {
if (!args || (args.help && commandDescriptorIncludesDefaultHelp(commandDescriptor))) {
return usageMessage(commandDescriptor, null, options.commandPrefix, options.maxWidth)
}
if (args.$) {
const subcommand = Object.keys(args.$)[0]
const subcommandDescriptor = findSubcommandDescriptor(commandDescriptor, subcommand)
if (args.$[subcommand].help && commandDescriptorIncludesDefaultHelp(subcommandDescriptor)) {
return usageMessage(subcommandDescriptor, commandDescriptor.name, null, options.maxWidth)
}
}
}
}