UNPKG

argparse-ts

Version:

Modern CLI arguments parser for node.js

423 lines 17.9 kB
"use strict"; 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