in src/util/commandline/option-parser.ts [90:166]
export function parseOptions(...params: any[]): void {
let flagOptions: OptionsDescription;
let positionalOptions: PositionalOptionsDescription;
let target: any;
let args: string[];
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);
}
});
}