You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
3.1 KiB
147 lines
3.1 KiB
const { InvalidArgumentError } = require('./error.js'); |
|
|
|
// @ts-check |
|
|
|
class Argument { |
|
/** |
|
* Initialize a new command argument with the given name and description. |
|
* The default is that the argument is required, and you can explicitly |
|
* indicate this with <> around the name. Put [] around the name for an optional argument. |
|
* |
|
* @param {string} name |
|
* @param {string} [description] |
|
*/ |
|
|
|
constructor(name, description) { |
|
this.description = description || ''; |
|
this.variadic = false; |
|
this.parseArg = undefined; |
|
this.defaultValue = undefined; |
|
this.defaultValueDescription = undefined; |
|
this.argChoices = undefined; |
|
|
|
switch (name[0]) { |
|
case '<': // e.g. <required> |
|
this.required = true; |
|
this._name = name.slice(1, -1); |
|
break; |
|
case '[': // e.g. [optional] |
|
this.required = false; |
|
this._name = name.slice(1, -1); |
|
break; |
|
default: |
|
this.required = true; |
|
this._name = name; |
|
break; |
|
} |
|
|
|
if (this._name.length > 3 && this._name.slice(-3) === '...') { |
|
this.variadic = true; |
|
this._name = this._name.slice(0, -3); |
|
} |
|
} |
|
|
|
/** |
|
* Return argument name. |
|
* |
|
* @return {string} |
|
*/ |
|
|
|
name() { |
|
return this._name; |
|
}; |
|
|
|
/** |
|
* @api private |
|
*/ |
|
|
|
_concatValue(value, previous) { |
|
if (previous === this.defaultValue || !Array.isArray(previous)) { |
|
return [value]; |
|
} |
|
|
|
return previous.concat(value); |
|
} |
|
|
|
/** |
|
* Set the default value, and optionally supply the description to be displayed in the help. |
|
* |
|
* @param {any} value |
|
* @param {string} [description] |
|
* @return {Argument} |
|
*/ |
|
|
|
default(value, description) { |
|
this.defaultValue = value; |
|
this.defaultValueDescription = description; |
|
return this; |
|
}; |
|
|
|
/** |
|
* Set the custom handler for processing CLI command arguments into argument values. |
|
* |
|
* @param {Function} [fn] |
|
* @return {Argument} |
|
*/ |
|
|
|
argParser(fn) { |
|
this.parseArg = fn; |
|
return this; |
|
}; |
|
|
|
/** |
|
* Only allow option value to be one of choices. |
|
* |
|
* @param {string[]} values |
|
* @return {Argument} |
|
*/ |
|
|
|
choices(values) { |
|
this.argChoices = values; |
|
this.parseArg = (arg, previous) => { |
|
if (!values.includes(arg)) { |
|
throw new InvalidArgumentError(`Allowed choices are ${values.join(', ')}.`); |
|
} |
|
if (this.variadic) { |
|
return this._concatValue(arg, previous); |
|
} |
|
return arg; |
|
}; |
|
return this; |
|
}; |
|
|
|
/** |
|
* Make option-argument required. |
|
*/ |
|
argRequired() { |
|
this.required = true; |
|
return this; |
|
} |
|
|
|
/** |
|
* Make option-argument optional. |
|
*/ |
|
argOptional() { |
|
this.required = false; |
|
return this; |
|
} |
|
} |
|
|
|
/** |
|
* Takes an argument and returns its human readable equivalent for help usage. |
|
* |
|
* @param {Argument} arg |
|
* @return {string} |
|
* @api private |
|
*/ |
|
|
|
function humanReadableArgName(arg) { |
|
const nameOutput = arg.name() + (arg.variadic === true ? '...' : ''); |
|
|
|
return arg.required |
|
? '<' + nameOutput + '>' |
|
: '[' + nameOutput + ']'; |
|
} |
|
|
|
exports.Argument = Argument; |
|
exports.humanReadableArgName = humanReadableArgName;
|
|
|