appcenter-cli
Version:
Command line tool for Visual Studio App Center
120 lines (119 loc) • 4.43 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseOptions = void 0;
const minimist = require("minimist");
const util = require("util");
const debug = require("debug")("appcenter-cli:util:commandline:option-parser");
function optionKey(option) {
return option.shortName || option.longName;
}
function optionDisplayName(options) {
const short = options.shortName ? "-" + options.shortName : null;
const long = options.longName ? "--" + options.longName : null;
return [short, long].filter((x) => !!x).join(" / ");
}
function descriptionToMinimistOpts(options) {
const parseOpts = {
boolean: [],
string: [],
alias: {},
default: {},
unknown: (arg) => {
if (arg.charAt(0) === "-") {
throw new Error(`Unknown argument ${arg}`);
}
return true;
},
};
Object.keys(options)
.map((key) => options[key])
.forEach((option) => {
const key = optionKey(option);
// Is option a boolean or has a value?
if (option.hasArg) {
parseOpts.string.push(key);
}
else {
parseOpts.boolean.push(key);
}
// If both names are given, set up alias
if (option.shortName && option.longName) {
parseOpts.alias[option.shortName] = option.longName;
}
if (option.defaultValue !== undefined) {
parseOpts.default[key] = option.defaultValue;
}
});
return parseOpts;
}
function parseOptions(...params) {
let flagOptions;
let positionalOptions;
let target;
let args;
if (params.length === 4) {
debug(`Parser called with 4 args: ${util.inspect(params)}`);
[flagOptions, positionalOptions, target, args] = params;
}
else {
debug(`Parser called with 3 args: ${util.inspect(params)}`);
[flagOptions, target, args] = params;
positionalOptions = [];
}
debug(`Parsing command line ${args.join(" ")}`);
const minimistOptions = descriptionToMinimistOpts(flagOptions);
const parsed = minimist(args, minimistOptions);
debug(`Raw parsed command line = ${util.inspect(parsed)}`);
// handle flag args
Object.keys(flagOptions).forEach((targetPropertyName) => {
const option = flagOptions[targetPropertyName];
const optKey = optionKey(option);
// Skip required args if help or version have been invoked
if (!parsed["help"] && !parsed["version"] && option.required && !parsed[optKey]) {
// TODO: Replace this with auto-prompting
throw new Error(`Missing required option ${optionDisplayName(option)}`);
}
target[targetPropertyName] = parsed[optKey];
});
// Handle positional args
const positionalArgs = parsed["_"] || [];
positionalOptions.sort((a, b) => {
if (a.position === null) {
return +1;
}
if (b.position === null) {
return -1;
}
return b.position - a.position;
});
// Check for leftover positional parameters, fail if found
const hasRestOption = positionalOptions.some((o) => o.position === null);
if (!hasRestOption && positionalArgs.length > positionalOptions.length) {
const unknownArgs = positionalArgs.slice(positionalOptions.length);
throw new Error(`Unknown arguments: ${unknownArgs.join(" ")}`);
}
positionalOptions.forEach((opt, index) => {
debug(`Checking for ${opt.required ? "required" : "optional"} option ${opt.name} at position ${opt.position}`);
if (positionalArgs.length - 1 < opt.position) {
if (!parsed["help"] && opt.required) {
throw new Error(`Missing required positional argument ${opt.name}`);
}
else if (opt.defaultValue) {
target[opt.propertyName] = opt.defaultValue;
return;
}
else {
return;
}
}
if (opt.position !== null) {
target[opt.propertyName] = positionalArgs[opt.position];
positionalArgs[opt.position] = null;
}
else {
// This is the rest argument, pick up whatever's left
target[opt.propertyName] = positionalArgs.filter((opt) => opt !== null);
}
});
}
exports.parseOptions = parseOptions;