UNPKG

commandbot

Version:

A framework that helps you create your own Discord bot easier.

187 lines (186 loc) 7.32 kB
import { generateUsageFromArguments } from "../utils/generateUsageFromArguments.js"; import { DefaultParameter, Parameter } from "../structures/Parameter.js"; import { PermissionCommand } from "./base/PermissionCommand.js"; import { SubCommandGroup } from "./SubCommandGroup.js"; import { CommandRegExps } from "./commandsTypes.js"; /** * Representation of SUB_COMMAND Discord interaction * @class */ export class SubCommand extends PermissionCommand { /** * Command parent * @type {SubCommand | ChatCommand} * @public * @readonly */ parent; /** * Command description displayed in the help message or in slash commands menu (Default description: "No description") * @type {string} * @public * @readonly */ description; /** * List of parameters that can passed to this command * @type {Array<Parameter>} * @public * @readonly */ parameters; /** * List of different names that can be used to invoke a command (when using prefix interactions) * @type {?Array<string>} * @public * @readonly */ aliases; /** * Command usage displayed in the help message * @type {?string} * @public * @readonly */ usage; /** * Subcommand constructor (SUB_COMMAND parameter in Discord API) * @constructor * @param {SubCommandGroup | ChatCommand} parent - command parent * @param {SubCommandInit} options - initialization options */ constructor(parent, options) { super(parent instanceof SubCommandGroup ? parent.parent.manager : parent.manager, "CHAT", { name: options.name, announceSuccess: options.announceSuccess, permissions: options.permissions, function: options.function, ephemeral: options.ephemeral, }); this.parent = parent; this.description = options.description ?? "No description"; if (options.parameters == "no_input" || !options.parameters) { this.parameters = []; } else if (options.parameters == "simple") { this.parameters = [new DefaultParameter(this)]; } else { this.parameters = options.parameters.map((ps) => new Parameter(this, ps)); } this.aliases = options.aliases ? (Array.isArray(options.aliases) ? options.aliases : [options.aliases]) : undefined; this.usage = options.usage ?? generateUsageFromArguments(this); if (this.parent.children.find((ch) => ch.name === this.name)) { throw new Error(`Parent "${this.parent.name}" already has a subcommand or group named "${this.name}"`); } if (!CommandRegExps.chatName.test(this.name)) { throw new Error(`"${this.name}" is not a valid command name (regexp: ${CommandRegExps.chatName})`); } if (this.description && !CommandRegExps.chatDescription.test(this.description)) { throw new Error(`The description of "${this.name}" doesn't match a regular expression ${CommandRegExps.chatDescription}`); } if (this.aliases) { if (Array.isArray(this.aliases)) { this.aliases.map((a) => { if (!CommandRegExps.chatName.test(a)) { throw new Error(`"${a}" is not a valid alias name (regexp: ${CommandRegExps.chatName})`); } }); } else { if (!CommandRegExps.chatName.test(this.aliases)) { throw new Error(`"${this.aliases}" is not a valid alias name (regexp: ${CommandRegExps.chatName})`); } } } if (this.aliases && this.aliases.length > 0 && this.aliases.find((a) => this.manager.get(a, this.type))) { throw new Error(`One of aliases from "${this.name}" command is already a registered name in the manager and cannot be reused.`); } } /** * Invoke the command * @param {InputManager} input - input data * @returns {Promise<void>} * @async */ async start(input) { if (this.parent instanceof SubCommandGroup ? !this.parent.parent.dm && !input.interaction.guild : !this.parent.dm && !input.interaction.guild) throw new Error(`Command "${this.name}" is only available inside a guild.`); if (this.parent instanceof SubCommandGroup ? this.parent.parent.guilds && this.parent.parent.guilds.length > 0 && !this.parent.parent.guilds.find((id) => id === input.interaction.guild?.id) : this.parent.guilds && this.parent.guilds.length > 0 && !this.parent.guilds.find((id) => id === input.interaction.guild?.id)) throw new Error(`Command "${this.name}" is not available.`); await super.start(input); } /** * @returns {ChatCommandObject} Discord API object * @public */ toObject() { const obj = { ...super.toObject(), type: 1, description: this.description, }; let options = []; if (this.parameters) { options = this.parameters .map((p) => { let type = 3; switch (p.type) { case "boolean": type = 5; break; case "user": type = 6; break; case "channel": type = 7; break; case "role": type = 8; break; case "mentionable": type = 9; break; case "number": type = 10; break; case "target": throw new Error(`"target" parameter cannot be used in chat commands`); default: type = 3; break; } const choices = []; if (p.choices) { p.choices.map((c) => { choices.push({ name: c, value: c }); }); } const optionObj = { name: p.name, description: p.description, required: !p.optional, type: p.choices ? 3 : type, choices: choices.length > 0 ? choices : undefined, }; return optionObj; }) .sort((a, b) => { if (a.required && !b.required) { return -1; } else if (a.required && b.required) { return 0; } else if (!a.required && b.required) { return 1; } return 0; }); obj.options = options; } return obj; } }