/** * SAMPLE CODE * Reference for how to extend a command option and implement a custom * command that inherits a custom superclass while being compatible with the parser by implementing the interface */ /* eslint-disable max-classes-per-file */ import { ICommand, OptionType, CommandOpts, SubcommandOption, SubcommandGroupOption } from '@navy.gif/commandparser'; import ExtendedCommandOption from './ExtendedCommandOption.js'; type Snowflake = string type DiscordClient = { // } type ComponentOptions = { // } type CommandDefinition = { aliases: never[]; help: string | undefined; restricted: boolean; disabled: boolean; guildOnly: boolean; dmOnly: boolean; limited: null; options: ExtendedCommandOption[]; } type User = { // } class Component { // eslint-disable-next-line no-useless-constructor constructor (_client: DiscordClient, _options: ComponentOptions) { // } get name () { return ''; } } class CommandError extends Error { constructor (_command: Command, _options: object) { super(); } } abstract class Command extends Component implements ICommand { #aliases: string[]; #options: ExtendedCommandOption[]; #help?: string | undefined; #restricted: boolean; // Developer only #disabled: boolean; #guildOnly: boolean; #dmOnly: boolean; #limited: Snowflake[] | null; // Limited to specific roles constructor (client: DiscordClient, def: CommandDefinition) { super(client, { ...def, type: 'command' }); this.#aliases = def.aliases ?? []; this.#help = def.help; this.#restricted = def.restricted ?? false; this.#disabled = def.disabled ?? false; this.#guildOnly = def.guildOnly ?? false; this.#dmOnly = def.dmOnly ?? false; this.#limited = def.limited ?? null; this.#options = []; if (def.options) { for (const opt of def.options) { if (opt instanceof ExtendedCommandOption) this.#options.push(opt); else this.#options.push(new ExtendedCommandOption(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: CommandOpts): Promise; protected timeout (user?: User) { throw new CommandError(this, { reason: 'Command timed out', user }); } get restricted () { return this.#restricted; } get limited () { return this.#limited; } get disabled () { return this.#disabled; } get guildOnly () { return this.#guildOnly; } get dmOnly () { return this.#dmOnly; } get aliases () { return this.#aliases; } get options () { return this.#options; } get help () { return this.#help; } 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: ExtendedCommandOption[]): 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 default Command;