forked from public/fvtt-cthulhu-eternal
Initial import with skill sheet working
This commit is contained in:
329
node_modules/commander/lib/option.js
generated
vendored
Normal file
329
node_modules/commander/lib/option.js
generated
vendored
Normal file
@ -0,0 +1,329 @@
|
||||
const { InvalidArgumentError } = require('./error.js');
|
||||
|
||||
class Option {
|
||||
/**
|
||||
* Initialize a new `Option` with the given `flags` and `description`.
|
||||
*
|
||||
* @param {string} flags
|
||||
* @param {string} [description]
|
||||
*/
|
||||
|
||||
constructor(flags, description) {
|
||||
this.flags = flags;
|
||||
this.description = description || '';
|
||||
|
||||
this.required = flags.includes('<'); // A value must be supplied when the option is specified.
|
||||
this.optional = flags.includes('['); // A value is optional when the option is specified.
|
||||
// variadic test ignores <value,...> et al which might be used to describe custom splitting of single argument
|
||||
this.variadic = /\w\.\.\.[>\]]$/.test(flags); // The option can take multiple values.
|
||||
this.mandatory = false; // The option must have a value after parsing, which usually means it must be specified on command line.
|
||||
const optionFlags = splitOptionFlags(flags);
|
||||
this.short = optionFlags.shortFlag;
|
||||
this.long = optionFlags.longFlag;
|
||||
this.negate = false;
|
||||
if (this.long) {
|
||||
this.negate = this.long.startsWith('--no-');
|
||||
}
|
||||
this.defaultValue = undefined;
|
||||
this.defaultValueDescription = undefined;
|
||||
this.presetArg = undefined;
|
||||
this.envVar = undefined;
|
||||
this.parseArg = undefined;
|
||||
this.hidden = false;
|
||||
this.argChoices = undefined;
|
||||
this.conflictsWith = [];
|
||||
this.implied = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default value, and optionally supply the description to be displayed in the help.
|
||||
*
|
||||
* @param {*} value
|
||||
* @param {string} [description]
|
||||
* @return {Option}
|
||||
*/
|
||||
|
||||
default(value, description) {
|
||||
this.defaultValue = value;
|
||||
this.defaultValueDescription = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preset to use when option used without option-argument, especially optional but also boolean and negated.
|
||||
* The custom processing (parseArg) is called.
|
||||
*
|
||||
* @example
|
||||
* new Option('--color').default('GREYSCALE').preset('RGB');
|
||||
* new Option('--donate [amount]').preset('20').argParser(parseFloat);
|
||||
*
|
||||
* @param {*} arg
|
||||
* @return {Option}
|
||||
*/
|
||||
|
||||
preset(arg) {
|
||||
this.presetArg = arg;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add option name(s) that conflict with this option.
|
||||
* An error will be displayed if conflicting options are found during parsing.
|
||||
*
|
||||
* @example
|
||||
* new Option('--rgb').conflicts('cmyk');
|
||||
* new Option('--js').conflicts(['ts', 'jsx']);
|
||||
*
|
||||
* @param {string | string[]} names
|
||||
* @return {Option}
|
||||
*/
|
||||
|
||||
conflicts(names) {
|
||||
this.conflictsWith = this.conflictsWith.concat(names);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify implied option values for when this option is set and the implied options are not.
|
||||
*
|
||||
* The custom processing (parseArg) is not called on the implied values.
|
||||
*
|
||||
* @example
|
||||
* program
|
||||
* .addOption(new Option('--log', 'write logging information to file'))
|
||||
* .addOption(new Option('--trace', 'log extra details').implies({ log: 'trace.txt' }));
|
||||
*
|
||||
* @param {Object} impliedOptionValues
|
||||
* @return {Option}
|
||||
*/
|
||||
implies(impliedOptionValues) {
|
||||
let newImplied = impliedOptionValues;
|
||||
if (typeof impliedOptionValues === 'string') {
|
||||
// string is not documented, but easy mistake and we can do what user probably intended.
|
||||
newImplied = { [impliedOptionValues]: true };
|
||||
}
|
||||
this.implied = Object.assign(this.implied || {}, newImplied);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set environment variable to check for option value.
|
||||
*
|
||||
* An environment variable is only used if when processed the current option value is
|
||||
* undefined, or the source of the current value is 'default' or 'config' or 'env'.
|
||||
*
|
||||
* @param {string} name
|
||||
* @return {Option}
|
||||
*/
|
||||
|
||||
env(name) {
|
||||
this.envVar = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the custom handler for processing CLI option arguments into option values.
|
||||
*
|
||||
* @param {Function} [fn]
|
||||
* @return {Option}
|
||||
*/
|
||||
|
||||
argParser(fn) {
|
||||
this.parseArg = fn;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the option is mandatory and must have a value after parsing.
|
||||
*
|
||||
* @param {boolean} [mandatory=true]
|
||||
* @return {Option}
|
||||
*/
|
||||
|
||||
makeOptionMandatory(mandatory = true) {
|
||||
this.mandatory = !!mandatory;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide option in help.
|
||||
*
|
||||
* @param {boolean} [hide=true]
|
||||
* @return {Option}
|
||||
*/
|
||||
|
||||
hideHelp(hide = true) {
|
||||
this.hidden = !!hide;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @api private
|
||||
*/
|
||||
|
||||
_concatValue(value, previous) {
|
||||
if (previous === this.defaultValue || !Array.isArray(previous)) {
|
||||
return [value];
|
||||
}
|
||||
|
||||
return previous.concat(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only allow option value to be one of choices.
|
||||
*
|
||||
* @param {string[]} values
|
||||
* @return {Option}
|
||||
*/
|
||||
|
||||
choices(values) {
|
||||
this.argChoices = values.slice();
|
||||
this.parseArg = (arg, previous) => {
|
||||
if (!this.argChoices.includes(arg)) {
|
||||
throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(', ')}.`);
|
||||
}
|
||||
if (this.variadic) {
|
||||
return this._concatValue(arg, previous);
|
||||
}
|
||||
return arg;
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return option name.
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
|
||||
name() {
|
||||
if (this.long) {
|
||||
return this.long.replace(/^--/, '');
|
||||
}
|
||||
return this.short.replace(/^-/, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return option name, in a camelcase format that can be used
|
||||
* as a object attribute key.
|
||||
*
|
||||
* @return {string}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
attributeName() {
|
||||
return camelcase(this.name().replace(/^no-/, ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if `arg` matches the short or long flag.
|
||||
*
|
||||
* @param {string} arg
|
||||
* @return {boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
is(arg) {
|
||||
return this.short === arg || this.long === arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether a boolean option.
|
||||
*
|
||||
* Options are one of boolean, negated, required argument, or optional argument.
|
||||
*
|
||||
* @return {boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
isBoolean() {
|
||||
return !this.required && !this.optional && !this.negate;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is to make it easier to work with dual options, without changing the existing
|
||||
* implementation. We support separate dual options for separate positive and negative options,
|
||||
* like `--build` and `--no-build`, which share a single option value. This works nicely for some
|
||||
* use cases, but is tricky for others where we want separate behaviours despite
|
||||
* the single shared option value.
|
||||
*/
|
||||
class DualOptions {
|
||||
/**
|
||||
* @param {Option[]} options
|
||||
*/
|
||||
constructor(options) {
|
||||
this.positiveOptions = new Map();
|
||||
this.negativeOptions = new Map();
|
||||
this.dualOptions = new Set();
|
||||
options.forEach(option => {
|
||||
if (option.negate) {
|
||||
this.negativeOptions.set(option.attributeName(), option);
|
||||
} else {
|
||||
this.positiveOptions.set(option.attributeName(), option);
|
||||
}
|
||||
});
|
||||
this.negativeOptions.forEach((value, key) => {
|
||||
if (this.positiveOptions.has(key)) {
|
||||
this.dualOptions.add(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Did the value come from the option, and not from possible matching dual option?
|
||||
*
|
||||
* @param {*} value
|
||||
* @param {Option} option
|
||||
* @returns {boolean}
|
||||
*/
|
||||
valueFromOption(value, option) {
|
||||
const optionKey = option.attributeName();
|
||||
if (!this.dualOptions.has(optionKey)) return true;
|
||||
|
||||
// Use the value to deduce if (probably) came from the option.
|
||||
const preset = this.negativeOptions.get(optionKey).presetArg;
|
||||
const negativeValue = (preset !== undefined) ? preset : false;
|
||||
return option.negate === (negativeValue === value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert string from kebab-case to camelCase.
|
||||
*
|
||||
* @param {string} str
|
||||
* @return {string}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function camelcase(str) {
|
||||
return str.split('-').reduce((str, word) => {
|
||||
return str + word[0].toUpperCase() + word.slice(1);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the short and long flag out of something like '-m,--mixed <value>'
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function splitOptionFlags(flags) {
|
||||
let shortFlag;
|
||||
let longFlag;
|
||||
// Use original very loose parsing to maintain backwards compatibility for now,
|
||||
// which allowed for example unintended `-sw, --short-word` [sic].
|
||||
const flagParts = flags.split(/[ |,]+/);
|
||||
if (flagParts.length > 1 && !/^[[<]/.test(flagParts[1])) shortFlag = flagParts.shift();
|
||||
longFlag = flagParts.shift();
|
||||
// Add support for lone short flag without significantly changing parsing!
|
||||
if (!shortFlag && /^-[^-]$/.test(longFlag)) {
|
||||
shortFlag = longFlag;
|
||||
longFlag = undefined;
|
||||
}
|
||||
return { shortFlag, longFlag };
|
||||
}
|
||||
|
||||
exports.Option = Option;
|
||||
exports.splitOptionFlags = splitOptionFlags;
|
||||
exports.DualOptions = DualOptions;
|
Reference in New Issue
Block a user