/** * A CLI option. Supports basic comparative, and set-based validation. * @class */ export abstract class CLIOption { /** * Do we use the whitelist? * @type {boolean} * @private */ protected useWhitelist = false /** * Do we use the blacklist? * @type {boolean} * @private */ protected useBlacklist = false /** * Do we use the less-than comparison? * @type {boolean} * @private */ protected useLessThan = false /** * Do we use the greater-than comparison? * @type {boolean} * @private */ protected useGreaterThan = false /** * Do we use the equality operator? * @type {boolean} * @private */ protected useEquality = false /** * Is this option optional? * @type {boolean} * @private */ protected isOptional = false /** * Whitelisted values. * @type {Array<*>} * @private */ protected whitelistItems: T[] = [] /** * Blacklisted values. * @type {Array<*>} * @private */ protected blacklistItems: T[] = [] /** * Value to be compared in less than. * @type {*} * @private */ protected lessThanValue?: T /** * If true, the less than will be less than or equal to. * @type {boolean} * @private */ protected lessThanBit = false /** * Value to be compared in greater than. * @type {*} * @private */ protected greaterThanValue?: T /** * If true, the greater than will be greater than or equal to. * @type {boolean} * @private */ protected greaterThanBit = false /** * The value to be used to check equality. * @type {*} * @private */ protected equalityValue?: T /** * Whitelist the specified item or items and enable the whitelist. * @param {...*} items - the items to whitelist */ whitelist(...items: T[]): this { this.useWhitelist = true items.forEach(item => this.whitelistItems.push(item)) return this } /** * Blacklist the specified item or items and enable the blacklist. * @param {...*} items - the items to blacklist */ blacklist(...items: T[]): this { this.useBlacklist = true items.forEach(item => this.blacklistItems.push(item)) return this } /** * Specifies the value to be used in less-than comparison and enables less-than comparison. * @param {*} value */ lessThan(value: T): this { this.useLessThan = true this.lessThanValue = value return this } /** * Specifies the value to be used in less-than or equal-to comparison and enables that comparison. * @param {*} value */ lessThanOrEqualTo(value: T): this { this.lessThanBit = true this.lessThan(value) return this } /** * Specifies the value to be used in greater-than comparison and enables that comparison. * @param {*} value */ greaterThan(value: T): this { this.useGreaterThan = true this.greaterThanValue = value return this } /** * Specifies the value to be used in greater-than or equal-to comparison and enables that comparison. * @param {*} value */ greaterThanOrEqualTo(value: T): this { this.greaterThanBit = true this.greaterThan(value) return this } /** * Specifies the value to be used in equality comparison and enables that comparison. * @param {*} value */ equals(value: T): this { this.useEquality = true this.equalityValue = value return this } /** * Checks if the specified value passes the configured comparisons. * @param value * @returns {boolean} */ validate(value: T): boolean { let isValid = true if ( this.useEquality ) { isValid = isValid && (this.equalityValue === value) } if ( this.useLessThan && typeof this.lessThanValue !== 'undefined' ) { if ( this.lessThanBit ) { isValid = isValid && (value <= this.lessThanValue) } else { isValid = isValid && (value < this.lessThanValue) } } if ( this.useGreaterThan && typeof this.greaterThanValue !== 'undefined' ) { if ( this.greaterThanBit ) { isValid = isValid && (value >= this.greaterThanValue) } else { isValid = isValid && (value > this.greaterThanValue) } } if ( this.useWhitelist ) { isValid = isValid && this.whitelistItems.some(x => { return x === value }) } if ( this.useBlacklist ) { isValid = isValid && !(this.blacklistItems.some(x => x === value)) } return isValid } /** * Sets the Option as optional. */ optional(): this { this.isOptional = true return this } /** * Get the argument name. Should be overridden by child classes. * @returns {string} */ abstract getArgumentName(): string /** * Get an array of strings denoting the human-readable requirements for this option to be valid. * @returns {Array} */ getRequirementDisplays(): string[] { const clauses = [] if ( this.useBlacklist ) { clauses.push(`must not be one of: ${this.blacklistItems.map(x => String(x)).join(', ')}`) } if ( this.useWhitelist ) { clauses.push(`must be one of: ${this.whitelistItems.map(x => String(x)).join(', ')}`) } if ( this.useGreaterThan ) { clauses.push(`must be greater than${this.greaterThanBit ? ' or equal to' : ''}: ${String(this.greaterThanValue)}`) } if ( this.useLessThan ) { clauses.push(`must be less than${this.lessThanBit ? ' or equal to' : ''}: ${String(this.lessThanValue)}`) } if ( this.useEquality ) { clauses.push(`must be equal to: ${String(this.equalityValue)}`) } return clauses } }