Source

core/commander/command.ts

import { ConfigureError } from '../errors';
import { ICommand, IContext, Context, THandlerCommand } from '../../types';

/**
 * @description Класс команды
 * @class
 * @param {ICommand} data
 *
 * @example
 * new Command({
 *
 *  name: 'test',
 *  description: 'test command',
 *  categories: ['test'],
 *
 *  params: {
 *      emoji: '📄'
 * },
 *
 *  handler(context) {
 *      context.send('test');
 *  }
 * })
 *  pattern: /test/i,
 */
export class Command {
  /**
   * паттерн команды
   * @property {RegExp | string}
   * @memberof Command
   */
  public pattern: RegExp | string;

  /**
   * название
   * @property {string}
   */
  public name: string;

  /**
   * @description описание
   * @property {string} description
   */
  public description: string;

  /**
   * @type {string[]}
   */
  public categories: string[];

  /**
   * @description дополнительные параметры
   * @type {Record<string, unknown>}
   */
  public params: Record<string, unknown>;

  /**
   * массив подкоманд
   * @property {Command[]} commands
   */
  public commands: Command[];

  /**
   * обработчик комманды
   * @property {THandlerCommand} handler
   */
  public handler: THandlerCommand;

  constructor(data: ICommand) {
    if (!data.pattern) {
      throw new ConfigureError(
        'Не указан pattern команды (регулярное выражение)',
      );
    }

    if (!(data.pattern instanceof RegExp)) {
      data.pattern = new RegExp(data.pattern);
    }

    if (!data.handler) {
      throw new ConfigureError('Не указан обработчик команды');
    }

    if (typeof data.handler !== 'function') {
      throw new ConfigureError('Обработчик команды не является функцией');
    }

    const {
      pattern,
      name,
      description,
      categories,
      params,
      commands,
      handler,
    } = data;

    this.pattern = pattern;
    this.name = name;
    this.description = description || '';
    this.categories = categories || [];
    this.params = params || {};
    this.commands = <Command[] | []>commands || [];
    this.handler = handler;
  }

  get [Symbol.toStringTag](): string {
    return 'Command';
  }

  /**
   * @description поиск подкоманд
   * @param {Record<string, unknown>} context
   * @return {Command}
   */
  findSubCommand<c extends Context>(context: c & IContext): Command {
    let command: Command;

    for (const subCommand of this.commands) {
      if ((<RegExp>subCommand.pattern).test(context.body[1])) {
        command = subCommand;
      }
    }

    if (!command) {
      return this;
    }

    context.body = context.body[1].match(command.pattern);

    if (command.commands.length) {
      command = (<Command>command).findSubCommand<c>(context);
    }

    return command;
  }
}