import type { ChatInputCommandInteraction, CommandInteraction, UserContextMenuCommandInteraction, MessageContextMenuCommandInteraction, } from "discord.js"; import type { Option, InferOptions } from "./options"; export const INTEGRATION_TYPES = { GUILD_INSTALL: 0, USER_INSTALL: 1, } as const; export const INTERACTION_CONTEXTS = { GUILD: 0, BOT_DM: 1, PRIVATE_CHANNEL: 2, } as const; export const INTEGRATION_TYPE_PRESETS = { ALL: Object.values(INTEGRATION_TYPES), GUILD_ONLY: [INTEGRATION_TYPES.GUILD_INSTALL], USER_ONLY: [INTEGRATION_TYPES.USER_INSTALL], }; export const INTEGRATION_CONTEXT_PRESETS = { EVERYWHERE: Object.values(INTERACTION_CONTEXTS), GUILDS_ONLY: [INTERACTION_CONTEXTS.GUILD], DMS_ONLY: [INTERACTION_CONTEXTS.BOT_DM, INTERACTION_CONTEXTS.PRIVATE_CHANNEL], }; export type IntegrationType = (typeof INTEGRATION_TYPES)[keyof typeof INTEGRATION_TYPES]; export type InteractionContextType = (typeof INTERACTION_CONTEXTS)[keyof typeof INTERACTION_CONTEXTS]; export class Subcommand { constructor( public name: string, public config: { description: string; options?: Record>; run: Function; }, ) {} } export class SubcommandGroup { public subcommands: Record = {}; constructor( public name: string, public description: string, ) {} subcommand>>( name: string, config: { description: string; options?: O; run: ( interaction: ChatInputCommandInteraction, args: InferOptions, ctx: Ctx, ) => Promise | void; }, ): this { this.subcommands[name] = new Subcommand(name, config); return this; } } export class SubcommandGroupBuilder { public subcommands: Record = {}; public groups: Record> = {}; constructor( public name: string, public description: string, public middlewares: Function[] = [], public config?: { integrationTypes?: IntegrationType[]; contexts?: InteractionContextType[]; }, ) {} subcommand>>( name: string, config: { description: string; options?: O; run: ( interaction: ChatInputCommandInteraction, args: InferOptions, ctx: Ctx, ) => Promise | void; }, ): this { this.subcommands[name] = new Subcommand(name, config); return this; } group( name: string, config: { description: string }, setup: (group: SubcommandGroup) => void, ): this { const group = new SubcommandGroup(name, config.description); setup(group); this.groups[name] = group; return this; } } export class Command { constructor( public name: string, public config: { description: string; options?: Record>; integrationTypes?: IntegrationType[]; contexts?: InteractionContextType[]; run: Function; }, public middlewares: Function[] = [], ) {} } export class ContextMenuCommand { constructor( public name: string, public type: "user" | "message", public run: Function, public middlewares: Function[] = [], public config?: { integrationTypes?: IntegrationType[]; contexts?: InteractionContextType[]; }, ) {} } export class CommandBuilder { constructor(private middlewares: Function[] = []) {} use>( mw: (interaction: CommandInteraction, ctx: Ctx) => Promise | NewCtx | void, ): CommandBuilder { return new CommandBuilder([...this.middlewares, mw]); } command>>( name: string, config: { description: string; options?: O; integrationTypes?: IntegrationType[]; contexts?: InteractionContextType[]; run: ( interaction: ChatInputCommandInteraction, args: InferOptions, ctx: Ctx, ) => Promise | void; }, ): Command; command( name: string, config: { description: string; integrationTypes?: IntegrationType[]; contexts?: InteractionContextType[]; }, ): SubcommandGroupBuilder; command(name: string, config: any): any { if (config.run) { return new Command(name, config, this.middlewares); } return new SubcommandGroupBuilder(name, config.description, this.middlewares, { integrationTypes: config.integrationTypes, contexts: config.contexts, }); } userContextMenu( name: string, runOrConfig: | ((interaction: UserContextMenuCommandInteraction, ctx: Ctx) => Promise | void) | { integrationTypes?: IntegrationType[]; contexts?: InteractionContextType[]; run: (interaction: UserContextMenuCommandInteraction, ctx: Ctx) => Promise | void; }, ): ContextMenuCommand { if (typeof runOrConfig === "function") return new ContextMenuCommand(name, "user", runOrConfig, this.middlewares); return new ContextMenuCommand(name, "user", runOrConfig.run, this.middlewares, { integrationTypes: runOrConfig.integrationTypes, contexts: runOrConfig.contexts, }); } messageContextMenu( name: string, runOrConfig: | ((interaction: MessageContextMenuCommandInteraction, ctx: Ctx) => Promise | void) | { integrationTypes?: IntegrationType[]; contexts?: InteractionContextType[]; run: ( interaction: MessageContextMenuCommandInteraction, ctx: Ctx, ) => Promise | void; }, ): ContextMenuCommand { if (typeof runOrConfig === "function") return new ContextMenuCommand(name, "message", runOrConfig, this.middlewares); return new ContextMenuCommand(name, "message", runOrConfig.run, this.middlewares, { integrationTypes: runOrConfig.integrationTypes, contexts: runOrConfig.contexts, }); } }