subcli
Version:
helpers for creating command-line interfaces that support subcommands
66 lines (59 loc) • 2.1 kB
JavaScript
import parseArgs from 'minimist'
import addHelpOption from './addHelpOption'
import findSubcommandDescriptor from './findSubcommandDescriptor'
import {DEFAULT_OPTIONS} from './index'
function getParseOptions(commandDescriptor) {
const options = {
string: [],
boolean: [],
alias: {},
default: {},
stopEarly: commandDescriptor.commands && commandDescriptor.commands.length > 0,
unknown(opt) {
if (opt[0] === '-') {
throw new Error(`Unknown option: ${opt}`)
}
},
}
commandDescriptor.options.forEach(opt => {
if (opt.abbr) {
if (!options.alias[opt.name]) {
options.alias[opt.name] = []
}
options.alias[opt.name].push(opt.abbr)
}
if (opt.alias) {
if (!options.alias[opt.name]) {
options.alias[opt.name] = []
}
options.alias[opt.name] = options.alias[opt.name].concat(opt.alias)
}
if (opt.boolean) {
options.boolean.push(opt.name)
} else {
options.string.push(opt.name)
}
if (opt.default) {
options.default[opt.name] = opt.default
}
})
return options
}
export default function parse(cd, rawArgv, opts = {}) {
const options = Object.assign({}, DEFAULT_OPTIONS, opts)
const argv = rawArgv.filter(arg => arg.trim().length > 0)
const commandDescriptor = options.includeHelp ? addHelpOption(cd) : cd
const parseOptions = getParseOptions(commandDescriptor)
let args = parseArgs(argv, parseOptions)
// if we have subcommands and the subcommand was provided, we'll recurse into
// the subcommand options and parse the subcommand options into a nested
// object (named after the subcommand)
if (parseOptions.stopEarly && args._.length > 0) {
const [subcommand, ...subcommandArgv] = args._
const subcommandDescriptor = findSubcommandDescriptor(commandDescriptor, subcommand)
const subcommandParseOptions = getParseOptions(subcommandDescriptor)
const subcommandArgs = parseArgs(subcommandArgv, subcommandParseOptions)
args = Object.assign({}, args, {$: {[subcommand]: subcommandArgs}})
}
return args
}