import { ApplicationCommand, ApplicationCommandSubCommandData, ApplicationCommandSubGroupData, ChatInputApplicationCommandData, ChatInputCommandInteraction, } from "discord.js" export const noSubcommandError = "No subcommand was provided, but one is required." export const invalidSubcommandGroupError = "The subcommand group provided does not exist." export const invalidSubcommandError = "The subcommand provided does not exist." export const adminId = "126936953789743104" export abstract class CommandData { private _cachedGlobal: ApplicationCommand | null = null private _cacheByGuild: Record = {} abstract get definition(): ChatInputApplicationCommandData getCached(guildId: string | null): ApplicationCommand { if (guildId === null) { if (this._cachedGlobal === null) { throw Error("Not yet cached") } return this._cachedGlobal } else if (this._cacheByGuild.hasOwnProperty(guildId)) { return this._cacheByGuild[guildId] } else { throw Error("Not yet cached") } } setCached(command: ApplicationCommand) { if (command.guildId === null) { this._cachedGlobal = command } else { this._cacheByGuild[command.guildId] = command } } abstract execute(b: ChatInputCommandInteraction): Promise } export type BaseChatInputCommandData = Omit export abstract class CommandWithSubcommandsData extends CommandData { private _subcommandGroupsCache: Record | null = null private _subcommandsCache: Record | null = null get definition(): ChatInputApplicationCommandData { return { options: this.subcommands.map((s) => s.definition), ...this.baseDefinition, } } protected abstract get baseDefinition(): BaseChatInputCommandData protected abstract get subcommands(): (SubcommandData | SubcommandGroupData)[] async execute(b: ChatInputCommandInteraction) { const group = b.options.getSubcommandGroup() const subcommand = b.options.getSubcommand() if (group !== null) { await this.resolveSubcommandGroup(group).execute(b) } else if (subcommand !== null) { await this.resolveSubcommand(subcommand).execute(b) } else { throw noSubcommandError } } protected resolveSubcommandGroup(name: string): SubcommandGroupData { let cache = this._subcommandGroupsCache if (cache === null) { cache = {} for (const item of this.subcommands) { if (item instanceof SubcommandGroupData) { cache[item.definition.name] = item } } this._subcommandGroupsCache = cache } if (!cache.hasOwnProperty(name)) { throw invalidSubcommandGroupError } return cache[name] } protected resolveSubcommand(name: string): SubcommandData { let cache = this._subcommandsCache if (cache === null) { cache = {} for (const item of this.subcommands) { if (item instanceof SubcommandData) { cache[item.definition.name] = item } } this._subcommandsCache = cache } if (!cache.hasOwnProperty(name)) { throw invalidSubcommandGroupError } return cache[name] } } export type BaseSubcommandGroupData = Omit export abstract class SubcommandGroupData { private _subcommandsCache: Record | null = null get definition(): ApplicationCommandSubGroupData { return { ...this.baseDefinition, options: this.subcommands.map((s) => s.definition), } } protected abstract get baseDefinition(): BaseSubcommandGroupData protected abstract get subcommands(): SubcommandData[] async execute(b: ChatInputCommandInteraction): Promise { const subcommand = b.options.getSubcommand() if (subcommand !== null) { await this.resolveSubcommand(subcommand).execute(b) } else { throw noSubcommandError } } protected resolveSubcommand(name: string): SubcommandData { let cache = this._subcommandsCache if (cache === null) { cache = {} for (const item of this.subcommands) { cache[item.definition.name] = item } this._subcommandsCache = cache } if (!cache.hasOwnProperty(name)) { throw invalidSubcommandError } return cache[name] } } export abstract class SubcommandData { abstract get definition(): ApplicationCommandSubCommandData abstract execute(b: ChatInputCommandInteraction): Promise }