import { ApplicationCommandHandler, ApplicationCommandHandlerCallback, AutocompleteHandler, AutocompleteHandlerCallback, InteractionsClient} from './client.ts'import type { Client } from '../client/mod.ts'import { ApplicationCommandsModule } from './commandModule.ts'import { ApplicationCommandInteraction } from '../structures/applicationCommand.ts'import { GatewayIntents } from '../types/gateway.ts'import { ApplicationCommandType } from '../types/applicationCommand.ts'
interface DecoratedAppExt { _decoratedAppCmd?: ApplicationCommandHandler[] _decoratedAutocomplete?: AutocompleteHandler[]}
type ApplicationCommandClient = | Client | InteractionsClient | ApplicationCommandsModule
type ApplicationCommandClientExt = ApplicationCommandClient & DecoratedAppExt
type CommandValidationCondition = ( i: ApplicationCommandInteraction) => boolean | Promise<boolean>
interface CommandValidation { condition: CommandValidationCondition action?: string | ApplicationCommandHandlerCallback}
type ApplicationCommandDecorator = ( client: ApplicationCommandClientExt, prop: string, desc: TypedPropertyDescriptor<ApplicationCommandHandlerCallback>) => void
type AutocompleteDecorator = ( client: ApplicationCommandClientExt, prop: string, desc: TypedPropertyDescriptor<AutocompleteHandlerCallback>) => void
function wrapConditionApplicationCommandHandler( desc: TypedPropertyDescriptor<ApplicationCommandHandlerCallback>, validation: CommandValidation): ApplicationCommandHandlerCallback { if (typeof desc.value !== 'function') { throw new Error('The decorator requires a function') } const { condition, action } = validation
const original = desc.value return async function ( this: ApplicationCommandClient, i: ApplicationCommandInteraction ) { if (!(await condition(i))) { if (typeof action === 'string') { i.reply(action) } else if (typeof action === 'function') { action(i) } return } return original.call(this, i) }}
export function autocomplete( command: string, option: string): AutocompleteDecorator { return function ( client: ApplicationCommandClientExt, _prop: string, desc: TypedPropertyDescriptor<AutocompleteHandlerCallback> ) { if (client._decoratedAutocomplete === undefined) client._decoratedAutocomplete = [] if (typeof desc.value !== 'function') { throw new Error('@autocomplete decorator requires a function') } else client._decoratedAutocomplete.push({ cmd: command, option, handler: desc.value }) }}
export function slash( name?: string, guild?: string): ApplicationCommandDecorator { return function ( client: ApplicationCommandClientExt, prop: string, desc: TypedPropertyDescriptor<ApplicationCommandHandlerCallback> ) { if (client._decoratedAppCmd === undefined) client._decoratedAppCmd = [] if (typeof desc.value !== 'function') { throw new Error('@slash decorator requires a function') } else client._decoratedAppCmd.push({ name: name ?? prop, guild, handler: desc.value }) }}
export function subslash( parent: string, name?: string, guild?: string): ApplicationCommandDecorator { return function ( client: ApplicationCommandClientExt, prop: string, desc: TypedPropertyDescriptor<ApplicationCommandHandlerCallback> ) { if (client._decoratedAppCmd === undefined) client._decoratedAppCmd = [] if (typeof desc.value !== 'function') { throw new Error('@subslash decorator requires a function') } else client._decoratedAppCmd.push({ parent, name: name ?? prop, guild, handler: desc.value }) }}
export function groupslash( parent: string, group: string, name?: string, guild?: string): ApplicationCommandDecorator { return function ( client: ApplicationCommandClientExt, prop: string, desc: TypedPropertyDescriptor<ApplicationCommandHandlerCallback> ) { if (client._decoratedAppCmd === undefined) client._decoratedAppCmd = [] if (typeof desc.value !== 'function') { throw new Error('@groupslash decorator requires a function') } else client._decoratedAppCmd.push({ group, parent, name: name ?? prop, guild, handler: desc.value }) }}
export function messageContextMenu(name?: string): ApplicationCommandDecorator { return function ( client: ApplicationCommandClientExt, prop: string, desc: TypedPropertyDescriptor<ApplicationCommandHandlerCallback> ) { if (client._decoratedAppCmd === undefined) client._decoratedAppCmd = [] if (typeof desc.value !== 'function') { throw new Error('@messageContextMenu decorator requires a function') } else client._decoratedAppCmd.push({ name: name ?? prop, type: ApplicationCommandType.MESSAGE, handler: desc.value }) }}
export function userContextMenu(name?: string): ApplicationCommandDecorator { return function ( client: ApplicationCommandClientExt, prop: string, desc: TypedPropertyDescriptor<ApplicationCommandHandlerCallback> ) { if (client._decoratedAppCmd === undefined) client._decoratedAppCmd = [] if (typeof desc.value !== 'function') { throw new Error('@userContextMenu decorator requires a function') } else client._decoratedAppCmd.push({ name: name ?? prop, type: ApplicationCommandType.USER, handler: desc.value }) }}
export function isInGuild(message: string): ApplicationCommandDecoratorexport function isInGuild( callback: ApplicationCommandHandlerCallback): ApplicationCommandDecoratorexport function isInGuild( action: string | ApplicationCommandHandlerCallback): ApplicationCommandDecorator { return function ( _client: ApplicationCommandClient, _prop: string, desc: TypedPropertyDescriptor<ApplicationCommandHandlerCallback> ) { const validation: CommandValidation = { condition: (i: ApplicationCommandInteraction) => { return Boolean(i.guild) }, action } desc.value = wrapConditionApplicationCommandHandler(desc, validation) }}
export function isBotInVoiceChannel( message: string): ApplicationCommandDecoratorexport function isBotInVoiceChannel( callback: ApplicationCommandHandlerCallback): ApplicationCommandDecoratorexport function isBotInVoiceChannel( action: string | ApplicationCommandHandlerCallback): ApplicationCommandDecorator { return function ( _client: ApplicationCommandClient, _prop: string, desc: TypedPropertyDescriptor<ApplicationCommandHandlerCallback> ) { const validation: CommandValidation = { condition: async (i: ApplicationCommandInteraction) => { if (!i.client.intents?.includes(GatewayIntents.GUILD_VOICE_STATES)) { const err = '@isBotInVoiceChannel: GatewayIntents.GUILD_VOICE_STATES needs to be set.' console.error(err) throw new Error(err) } return Boolean(await i.guild?.voiceStates.get(i.client.user!.id)) }, action } desc.value = wrapConditionApplicationCommandHandler(desc, validation) }}
export function isUserInVoiceChannel( message: string): ApplicationCommandDecoratorexport function isUserInVoiceChannel( callback: ApplicationCommandHandlerCallback): ApplicationCommandDecoratorexport function isUserInVoiceChannel( action: string | ApplicationCommandHandlerCallback): ApplicationCommandDecorator { return function ( _client: ApplicationCommandClient, _prop: string, desc: TypedPropertyDescriptor<ApplicationCommandHandlerCallback> ) { const validation: CommandValidation = { condition: async (i: ApplicationCommandInteraction): Promise<boolean> => { if (!i.client.intents?.includes(GatewayIntents.GUILD_VOICE_STATES)) { const err = '@isUserInVoiceChannel: GatewayIntents.GUILD_VOICE_STATES needs to be set.' console.error(err) throw new Error(err) } return Boolean(await i.guild?.voiceStates.get(i.user.id)) }, action } desc.value = wrapConditionApplicationCommandHandler(desc, validation) }}
export function customValidation( condition: CommandValidationCondition, message: string): ApplicationCommandDecoratorexport function customValidation( condition: CommandValidationCondition, callback: ApplicationCommandHandlerCallback): ApplicationCommandDecoratorexport function customValidation( condition: CommandValidationCondition, action: string | ApplicationCommandHandlerCallback): ApplicationCommandDecorator { return function ( _client: ApplicationCommandClient, _prop: string, desc: TypedPropertyDescriptor<ApplicationCommandHandlerCallback> ) { desc.value = wrapConditionApplicationCommandHandler(desc, { condition, action }) }}