import { OptionType } from "../interfaces/CommandOption.js"; import { ICommand, CommandDefinition } from "../interfaces/Command.js"; import SubcommandOption from "./SubcommandOption.js"; import SubcommandGroupOption from "./SubcommandGroupOption.js"; import CommandOption from "./CommandOption.js"; import { ArgsResult } from "../Parser.js"; abstract class Command implements ICommand { name: string; aliases: string[]; options: CommandOption[]; help?: string; constructor (def: CommandDefinition) { if (typeof def !== 'object') throw new Error('Missing command definition'); if (!def.name) throw new Error('Missing name for command'); this.name = def.name; this.aliases = def.aliases || []; this.help = def.help; // Add a built-in help flag to any non-subcommand option this.options = [ new CommandOption({ name: 'help', type: OptionType.BOOLEAN, flag: true, valueOptional: true, defaultValue: true }) ]; for (const opt of def.options || []) { if (opt instanceof CommandOption) this.options.push(opt); else this.options.push(new CommandOption(opt)); } if (this.options.some(opt => [ OptionType.SUB_COMMAND, OptionType.SUB_COMMAND_GROUP ].includes(opt.type)) && this.options.some(opt => ![ OptionType.SUB_COMMAND, OptionType.SUB_COMMAND_GROUP ].includes(opt.type) && opt.name !== 'help')) throw new Error('Cannot have subcommand(group)s on the same level as an option'); } abstract execute(message: unknown, args?: ArgsResult): Promise; get subcommands (): SubcommandOption[] { return this._subcommands(this.options); } get subcommandGroups (): SubcommandGroupOption[] { return this.options.filter((opt) => opt.type === OptionType.SUB_COMMAND_GROUP); } subcommand (name: string): SubcommandOption | null { name = name.toLowerCase(); return this.subcommands.find((cmd) => cmd.name === name || cmd.aliases.includes(name)) || null; } subcommandGroup (name: string): SubcommandGroupOption | null { name = name.toLowerCase(); return this.subcommandGroups.find((grp) => grp.name === name || grp.aliases.includes(name)) || null; } private _subcommands (options: CommandOption[]): SubcommandOption[] { const subcommands: SubcommandOption[] = []; for (const opt of options) { if (opt.type === OptionType.SUB_COMMAND) subcommands.push(opt); else if (opt.type === OptionType.SUB_COMMAND_GROUP) subcommands.push(...this._subcommands(opt.options)); } return subcommands; } } export { Command }; export default Command;