You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

190 lines
6.3 KiB

import {
ApplicationCommand,
ApplicationCommandSubCommandData,
ApplicationCommandSubGroupData,
AutocompleteInteraction,
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 autocompleteNotImplementedError = "An autocomplete implementation was not provided."
export abstract class CommandData {
private _cachedGlobal: ApplicationCommand | null = null
private _cacheByGuild: Record<string, ApplicationCommand> = {}
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<void>
autocomplete?(b: AutocompleteInteraction): Promise<void>
}
export type BaseChatInputCommandData = Omit<ChatInputApplicationCommandData, "options">
export abstract class CommandWithSubcommandsData extends CommandData {
private _subcommandGroupsCache: Record<string, SubcommandGroupData> | null = null
private _subcommandsCache: Record<string, SubcommandData> | 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): Promise<void> {
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
}
}
async autocomplete?(b: AutocompleteInteraction): Promise<void> {
const group = b.options.getSubcommandGroup()
const subcommand = b.options.getSubcommand()
if (group !== null) {
const groupObject = this.resolveSubcommandGroup(group)
if (groupObject.autocomplete) {
await groupObject.autocomplete(b)
return
}
}
if (subcommand !== null) {
const subcommandObject = this.resolveSubcommand(subcommand)
if (subcommandObject.autocomplete) {
await subcommandObject.autocomplete(b)
return
}
}
throw autocompleteNotImplementedError
}
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<ApplicationCommandSubGroupData, "options">
export abstract class SubcommandGroupData {
private _subcommandsCache: Record<string, SubcommandData> | 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<void> {
const subcommand = b.options.getSubcommand()
if (subcommand !== null) {
await this.resolveSubcommand(subcommand).execute(b)
} else {
throw noSubcommandError
}
}
async autocomplete?(b: AutocompleteInteraction): Promise<void> {
const subcommand = b.options.getSubcommand()
if (subcommand !== null) {
const subcommandObject = this.resolveSubcommand(subcommand)
if (subcommandObject.autocomplete) {
await subcommandObject.autocomplete(b)
return
}
}
throw autocompleteNotImplementedError
}
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<void>
autocomplete?(b: AutocompleteInteraction): Promise<void>
}