148 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			148 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
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;
 |