argparse-ts
Version:
Modern CLI arguments parser for node.js
423 lines • 17.9 kB
JavaScript
;
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateArgConfig = validateArgConfig;
exports.validatePositionalArgConfig = validatePositionalArgConfig;
exports.validateOptionalArgConfig = validateOptionalArgConfig;
exports.checkEnoughPositionalValues = checkEnoughPositionalValues;
exports.checkAllPositionalValuesUsed = checkAllPositionalValuesUsed;
exports.checkAllOptionsRecognized = checkAllOptionsRecognized;
exports.createValueValidator = createValueValidator;
var exceptions_1 = require("../exceptions");
var utils_1 = require("./utils");
/**
* Validates an argument configuration.
*
* @param config - The argument configuration.
* @param usedArgs - A set of used argument names and aliases.
*
* @throws {ArgumentConfigError} - If the argument configuration is invalid.
*
* @category Utils
* @category Validation
*/
function validateArgConfig(config, usedArgs) {
if (!config.name.startsWith('-')) {
validatePositionalArgConfig(config);
}
else {
validateOptionalArgConfig(config);
}
// Check if the argument name is already used
if (usedArgs.has(config.name)) {
throw new exceptions_1.ArgumentConfigError("Argument with such name already exists: ".concat(config.name, "."));
}
// Check if the argument alias is defined and already used
if (config.alias !== undefined && usedArgs.has(config.alias)) {
throw new exceptions_1.ArgumentConfigError("Argument with such alias already exists: ".concat(config.alias, "."));
}
}
/**
* Validates a positional argument configuration.
*
* @param config - The positional argument configuration.
*
* @throws {ArgumentConfigError} - If the positional argument configuration is invalid.
*
* @category Utils
* @category Validation
*/
function validatePositionalArgConfig(config) {
// Positional argument cannot be required
if (config.required !== undefined) {
throw new exceptions_1.ArgumentConfigError("Positional argument cannot be required: ".concat(config.name, "."));
}
// Positional argument cannot have alias
if (config.alias !== undefined) {
throw new exceptions_1.ArgumentConfigError("Positional argument cannot have alias: ".concat(config.name, "."));
}
}
/**
* Validates an optional argument configuration.
*
* @param config - The optional argument configuration.
*
* @throws {ArgumentConfigError} - If the optional argument configuration is invalid.
*
* @category Utils
* @category Validation
*/
function validateOptionalArgConfig(config) {
// Optional argument must start with '--'
if (!config.name.startsWith('--')) {
throw new exceptions_1.ArgumentConfigError("Argument name is invalid: ".concat(config.name, "."));
}
if (config.alias !== undefined) {
// Optional argument alias must start with '-' and not with '--'
if (!config.alias.startsWith('-') || config.alias.startsWith('--')) {
throw new exceptions_1.ArgumentConfigError("Argument alias is invalid: ".concat(config.alias, "."));
}
// Optional argument alias cannot be a number
if (!isNaN(Number(config.alias))) {
throw new exceptions_1.ArgumentConfigError("Argument alias cannot be a number: ".concat(config.alias, "."));
}
}
}
/**
* Checks if there are enough positional values to satisfy the given argument
* configuration and the remaining argument configurations.
*
* @param valuesStack - The remaining positional values.
* @param argConfig - The current argument configuration.
* @param remainingArgConfigs - The remaining argument configurations.
*
* @throws {ArgumentValueError} - If there are not enough positional values.
*
* @category Utils
* @category Validation
*/
function checkEnoughPositionalValues(valuesStack, argConfig, remainingArgConfigs) {
// Collect all argument names from the current and remaining configurations
var allArgNames = __spreadArray([argConfig], __read(remainingArgConfigs), false).map(function (x) { return x.name; });
var errorMessage = "The following arguments are required: ".concat(__spreadArray([], __read(allArgNames), false).reverse().join(', '));
// If the argument is not multiple
if (!argConfig.multiple) {
// Throw an error if the argument does not allow empty values and no values are provided
if (!argConfig.allowEmpty && valuesStack.length === 0) {
throw new exceptions_1.ArgumentValueError(errorMessage);
}
return;
}
// For multiple arguments, check if they do not allow empty values
if (!argConfig.allowEmpty && valuesStack.length === 0) {
// Throw an error if no values are provided
throw new exceptions_1.ArgumentValueError(errorMessage);
}
// If a specific number of values is required, check if enough values are provided
if (!argConfig.allowEmpty && argConfig.valuesCount !== undefined && argConfig.valuesCount > valuesStack.length) {
// Throw an error if not enough values are provided
throw new exceptions_1.ArgumentValueError(errorMessage);
}
}
/**
* Checks if all positional values are used.
*
* @param valuesStack - The remaining positional values.
*
* @throws {ArgumentValueError} - If there are any remaining positional values.
*
* @category Utils
* @category Validation
*/
function checkAllPositionalValuesUsed(valuesStack) {
// Check if there are any remaining positional values
if (valuesStack.length > 0) {
// Throw an error for unrecognized positional arguments
throw new exceptions_1.ArgumentValueError("Unrecognized positional arguments: ".concat(__spreadArray([], __read(valuesStack), false).reverse().join(' '), "."));
}
}
/**
* Checks if all options in the parsed options are recognized according to the provided argument configurations.
*
* @param parsedOptions - A record of options that have been parsed.
* @param argConfigs - A record of argument configurations against which the options are validated.
*
* @throws {ArgumentValueError} - If there are any unrecognized options.
*
* @category Utils
* @category Validation
*/
function checkAllOptionsRecognized(parsedOptions, argConfigs) {
// Check if there are any unrecognized options
var unrecognizedOptions = Object.keys(parsedOptions).filter(function (key) { return argConfigs[key] === undefined; });
if (unrecognizedOptions.length > 0) {
// Throw an error for unrecognized options
throw new exceptions_1.ArgumentValueError("Unrecognized options: ".concat(unrecognizedOptions.join(', '), "."));
}
}
/**
* Creates a value validator based on the provided argument configuration.
*
* @param argConfig - The argument configuration to generate a value validator for.
*
* @returns A value validator that can be used to validate the argument value.
*
* @category Utils
* @category Validation
*/
function createValueValidator(argConfig) {
if (argConfig.multiple) {
return new ArrayValueValidator(argConfig);
}
return createSingleValueValidator(argConfig);
}
/**
* Creates a value validator for a single value argument based on the provided argument configuration.
*
* @param argConfig - The argument configuration to generate a value validator for.
*
* @returns A value validator that can be used to validate the argument value.
*
* @category Utils
* @category Validation
*/
function createSingleValueValidator(argConfig) {
switch (argConfig.type) {
case 'string':
return new StringValueValidator(argConfig);
case 'number':
return new NumberValueValidator(argConfig);
case 'boolean':
return new BooleanValueValidator(argConfig);
}
}
/**
* BaseValueValidator is an abstract class that implements the ValueValidatorInterface.
* It provides basic validation functionalities for argument values.
*
* @category Validation
*/
var BaseValueValidator = /** @class */ (function () {
/**
* Constructs a BaseValueValidator with the provided argument configuration.
*
* @param argConfig - The extended configuration for the argument to validate.
*/
function BaseValueValidator(argConfig) {
this.argConfig = argConfig;
}
/**
* Validates the argument value before it is cast.
*
* @param value - The array of string values to validate.
* @param isset - Whether the value is set.
*
* @throws ArgumentValueError - If the value is required but not set, or if empty values are not allowed.
*/
BaseValueValidator.prototype.validateBeforeCast = function (value, isset) {
if (!isset && this.argConfig.required && value.length === 0) {
throw new exceptions_1.ArgumentValueError("Argument ".concat((0, utils_1.formatArgNameWithAlias)(this.argConfig), " is required."));
}
if (isset && !this.argConfig.allowEmpty && value.length === 0) {
throw new exceptions_1.ArgumentValueError("Argument ".concat((0, utils_1.formatArgNameWithAlias)(this.argConfig), " cannot be empty."));
}
};
/**
* Validates the argument value after it has been cast.
*
* @param value - The casted value to validate.
*
* @throws ArgumentValueError - If the value is invalid according to the custom validator.
*/
BaseValueValidator.prototype.validateAfterCast = function (value) {
if (this.argConfig.validator !== undefined && !this.argConfig.validator(value)) {
throw new exceptions_1.ArgumentValueError("Argument ".concat((0, utils_1.formatArgNameWithAlias)(this.argConfig), " value is invalid."));
}
};
return BaseValueValidator;
}());
/**
* A value validator for a single argument value.
*
* @category Validation
*/
var SingleValueValidator = /** @class */ (function (_super) {
__extends(SingleValueValidator, _super);
function SingleValueValidator() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* Validates the argument value before it is cast.
*
* @param value - The array of string values to validate.
* @param isset - Whether the value is set.
*
* @throws ArgumentValueError - If the value is required but not set, or if empty values are not allowed.
* @throws ArgumentValueError - If the value is not a single value.
* @throws ArgumentValueError - If the value is not one of the allowed choices.
*/
SingleValueValidator.prototype.validateBeforeCast = function (value, isset) {
_super.prototype.validateBeforeCast.call(this, value, isset);
if (value.length > 1) {
throw new exceptions_1.ArgumentValueError("Argument ".concat((0, utils_1.formatArgNameWithAlias)(this.argConfig), " expects a single value."));
}
if (this.argConfig.choices !== undefined && !this.argConfig.choices.includes(value[0])) {
throw new exceptions_1.ArgumentValueError("Argument ".concat((0, utils_1.formatArgNameWithAlias)(this.argConfig), " value must be one of ").concat(this.argConfig.choices.join(', '), "."));
}
};
return SingleValueValidator;
}(BaseValueValidator));
/**
* A value validator for a single string argument value.
*
* @category Validation
*/
var StringValueValidator = /** @class */ (function (_super) {
__extends(StringValueValidator, _super);
function StringValueValidator() {
return _super !== null && _super.apply(this, arguments) || this;
}
return StringValueValidator;
}(SingleValueValidator));
/**
* A value validator for a single number argument value.
*
* @category Validation
*/
var NumberValueValidator = /** @class */ (function (_super) {
__extends(NumberValueValidator, _super);
function NumberValueValidator() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* Validates the argument value before it is cast.
*
* @param value - The array of string values to validate.
* @param isset - Whether the value is set.
*
* @throws ArgumentValueError - If the value is required but not set, or if empty values are not allowed.
* @throws ArgumentValueError - If the value is not a single numeric value.
*/
NumberValueValidator.prototype.validateBeforeCast = function (value, isset) {
_super.prototype.validateBeforeCast.call(this, value, isset);
if (value.length > 0 && isNaN(parseFloat(value[0]))) {
throw new exceptions_1.ArgumentValueError("Argument ".concat((0, utils_1.formatArgNameWithAlias)(this.argConfig), " value is not a number."));
}
};
return NumberValueValidator;
}(SingleValueValidator));
/**
* A value validator for a single boolean argument value.
*
* @category Validation
*/
var BooleanValueValidator = /** @class */ (function (_super) {
__extends(BooleanValueValidator, _super);
function BooleanValueValidator() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* Validates the argument value before it is cast.
*
* @param value - The array of string values to validate.
* @param isset - Whether the value is set.
*
* @throws ArgumentValueError - If the value is required but not set, if empty values are not allowed.
* @throws ArgumentValueError - if the value is not a boolean representation.
*/
BooleanValueValidator.prototype.validateBeforeCast = function (value, isset) {
_super.prototype.validateBeforeCast.call(this, value, isset);
if (value.length > 0 && !['true', 'false', '1', '0'].includes(value[0].toLowerCase())) {
throw new exceptions_1.ArgumentValueError("Argument ".concat((0, utils_1.formatArgNameWithAlias)(this.argConfig), " value is not a boolean."));
}
};
return BooleanValueValidator;
}(SingleValueValidator));
/**
* A value validator for an array of argument values.
*
* @category Validation
*/
var ArrayValueValidator = /** @class */ (function (_super) {
__extends(ArrayValueValidator, _super);
/**
* Constructs an ArrayValueValidator with the provided argument configuration.
*
* @param argConfig - The extended configuration for the argument to validate.
*/
function ArrayValueValidator(argConfig) {
var _this = _super.call(this, argConfig) || this;
_this.itemValidator = createSingleValueValidator(_this.argConfig);
return _this;
}
/**
* Validates the argument value before it is cast.
*
* @param value - The array of string values to validate.
* @param isset - Whether the value is set.
*
* @throws ArgumentValueError - If the value is required but not set, or if empty values are not allowed.
* @throws ArgumentValueError - If any of the item values are invalid.
*/
ArrayValueValidator.prototype.validateBeforeCast = function (value, isset) {
var _this = this;
if (isset && this.argConfig.valuesCount !== undefined && value.length !== this.argConfig.valuesCount) {
throw new exceptions_1.ArgumentValueError("Argument ".concat((0, utils_1.formatArgNameWithAlias)(this.argConfig), " expects ").concat(this.argConfig.valuesCount, " values, but ").concat(value.length, " given"));
}
_super.prototype.validateBeforeCast.call(this, value, isset);
(value !== null && value !== void 0 ? value : []).forEach(function (v) { return _this.itemValidator.validateBeforeCast([v], isset); });
};
/**
* Validates the argument value after it has been cast.
*
* @param value - The casted value to validate.
*
* @throws ArgumentValueError - If any of the item values are invalid according to the custom validator.
*/
ArrayValueValidator.prototype.validateAfterCast = function (value) {
var _this = this;
_super.prototype.validateAfterCast.call(this, value);
(value !== null && value !== void 0 ? value : []).forEach(function (v) { return _this.itemValidator.validateAfterCast([v]); });
};
return ArrayValueValidator;
}(BaseValueValidator));
//# sourceMappingURL=validation.js.map