feat: slash builde
This commit is contained in:
		
							parent
							
								
									cac3c5c9e3
								
							
						
					
					
						commit
						da0bfc12c7
					
				
					 6 changed files with 220 additions and 49 deletions
				
			
		|  | @ -247,6 +247,7 @@ export function event(name?: string) { | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** Decorator to create a Slash Command handler */ | ||||||
| export function slash(name?: string, guild?: string) { | export function slash(name?: string, guild?: string) { | ||||||
|   return function (client: Client | SlashModule, prop: string) { |   return function (client: Client | SlashModule, prop: string) { | ||||||
|     if (client._decoratedSlash === undefined) client._decoratedSlash = [] |     if (client._decoratedSlash === undefined) client._decoratedSlash = [] | ||||||
|  | @ -262,6 +263,7 @@ export function slash(name?: string, guild?: string) { | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** Decorator to create a Sub-Slash Command handler */ | ||||||
| export function subslash(parent: string, name?: string, guild?: string) { | export function subslash(parent: string, name?: string, guild?: string) { | ||||||
|   return function (client: Client | SlashModule, prop: string) { |   return function (client: Client | SlashModule, prop: string) { | ||||||
|     if (client._decoratedSlash === undefined) client._decoratedSlash = [] |     if (client._decoratedSlash === undefined) client._decoratedSlash = [] | ||||||
|  | @ -279,6 +281,7 @@ export function subslash(parent: string, name?: string, guild?: string) { | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** Decorator to create a Grouped Slash Command handler */ | ||||||
| export function groupslash( | export function groupslash( | ||||||
|   parent: string, |   parent: string, | ||||||
|   group: string, |   group: string, | ||||||
|  | @ -303,6 +306,7 @@ export function groupslash( | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** Decorator to add a Slash Module to Client */ | ||||||
| export function slashModule() { | export function slashModule() { | ||||||
|   return function (client: Client, prop: string) { |   return function (client: Client, prop: string) { | ||||||
|     if (client._decoratedSlashModules === undefined) |     if (client._decoratedSlashModules === undefined) | ||||||
|  |  | ||||||
|  | @ -97,6 +97,7 @@ export interface RESTOptions { | ||||||
|   token?: string |   token?: string | ||||||
|   headers?: { [name: string]: string | undefined } |   headers?: { [name: string]: string | undefined } | ||||||
|   canary?: boolean |   canary?: boolean | ||||||
|  |   version?: 6 | 7 | 8 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class RESTManager { | export class RESTManager { | ||||||
|  | @ -111,6 +112,7 @@ export class RESTManager { | ||||||
|   constructor(client?: RESTOptions) { |   constructor(client?: RESTOptions) { | ||||||
|     this.client = client |     this.client = client | ||||||
|     this.api = builder(this) |     this.api = builder(this) | ||||||
|  |     if (client?.version !== undefined) this.version = client.version | ||||||
|     // eslint-disable-next-line @typescript-eslint/no-floating-promises
 |     // eslint-disable-next-line @typescript-eslint/no-floating-promises
 | ||||||
|     this.handleRateLimits() |     this.handleRateLimits() | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -1,14 +1,10 @@ | ||||||
| import { Guild } from '../structures/guild.ts' | import { Guild } from '../structures/guild.ts' | ||||||
| import { Interaction } from '../structures/slash.ts' | import { Interaction } from '../structures/slash.ts' | ||||||
| import { |  | ||||||
|   APPLICATION_COMMAND, |  | ||||||
|   APPLICATION_COMMANDS, |  | ||||||
|   APPLICATION_GUILD_COMMAND, |  | ||||||
|   APPLICATION_GUILD_COMMANDS |  | ||||||
| } from '../types/endpoint.ts' |  | ||||||
| import { | import { | ||||||
|   InteractionType, |   InteractionType, | ||||||
|  |   SlashCommandChoice, | ||||||
|   SlashCommandOption, |   SlashCommandOption, | ||||||
|  |   SlashCommandOptionType, | ||||||
|   SlashCommandPartial, |   SlashCommandPartial, | ||||||
|   SlashCommandPayload |   SlashCommandPayload | ||||||
| } from '../types/slash.ts' | } from '../types/slash.ts' | ||||||
|  | @ -43,6 +39,147 @@ export class SlashCommand { | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export interface CreateOptions { | ||||||
|  |   name: string | ||||||
|  |   description?: string | ||||||
|  |   options?: Array<SlashCommandOption | SlashOptionCallable> | ||||||
|  |   choices?: Array<SlashCommandChoice | string> | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function createSlashOption( | ||||||
|  |   type: SlashCommandOptionType, | ||||||
|  |   data: CreateOptions | ||||||
|  | ): SlashCommandOption { | ||||||
|  |   return { | ||||||
|  |     name: data.name, | ||||||
|  |     type, | ||||||
|  |     description: | ||||||
|  |       type === 0 || type === 1 | ||||||
|  |         ? undefined | ||||||
|  |         : data.description ?? 'No description.', | ||||||
|  |     options: data.options?.map((e) => | ||||||
|  |       typeof e === 'function' ? e(SlashOptionCallableBuilder) : e | ||||||
|  |     ), | ||||||
|  |     choices: | ||||||
|  |       data.choices === undefined | ||||||
|  |         ? undefined | ||||||
|  |         : data.choices.map((e) => | ||||||
|  |             typeof e === 'string' ? { name: e, value: e } : e | ||||||
|  |           ) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // eslint-disable-next-line @typescript-eslint/no-extraneous-class
 | ||||||
|  | export class SlashOptionCallableBuilder { | ||||||
|  |   static string(data: CreateOptions): SlashCommandOption { | ||||||
|  |     return createSlashOption(SlashCommandOptionType.STRING, data) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static bool(data: CreateOptions): SlashCommandOption { | ||||||
|  |     return createSlashOption(SlashCommandOptionType.BOOLEAN, data) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static subCommand(data: CreateOptions): SlashCommandOption { | ||||||
|  |     return createSlashOption(SlashCommandOptionType.SUB_COMMAND, data) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static subCommandGroup(data: CreateOptions): SlashCommandOption { | ||||||
|  |     return createSlashOption(SlashCommandOptionType.SUB_COMMAND_GROUP, data) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static role(data: CreateOptions): SlashCommandOption { | ||||||
|  |     return createSlashOption(SlashCommandOptionType.ROLE, data) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static channel(data: CreateOptions): SlashCommandOption { | ||||||
|  |     return createSlashOption(SlashCommandOptionType.CHANNEL, data) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static user(data: CreateOptions): SlashCommandOption { | ||||||
|  |     return createSlashOption(SlashCommandOptionType.USER, data) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static number(data: CreateOptions): SlashCommandOption { | ||||||
|  |     return createSlashOption(SlashCommandOptionType.INTEGER, data) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export type SlashOptionCallable = ( | ||||||
|  |   o: typeof SlashOptionCallableBuilder | ||||||
|  | ) => SlashCommandOption | ||||||
|  | 
 | ||||||
|  | export type SlashBuilderOptionsData = | ||||||
|  |   | Array<SlashCommandOption | SlashOptionCallable> | ||||||
|  |   | { | ||||||
|  |       [name: string]: | ||||||
|  |         | { | ||||||
|  |             description: string | ||||||
|  |             type: SlashCommandOptionType | ||||||
|  |             options?: SlashCommandOption[] | ||||||
|  |             choices?: SlashCommandChoice[] | ||||||
|  |           } | ||||||
|  |         | SlashOptionCallable | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | function buildOptionsArray( | ||||||
|  |   options: SlashBuilderOptionsData | ||||||
|  | ): SlashCommandOption[] { | ||||||
|  |   return Array.isArray(options) | ||||||
|  |     ? options.map((op) => | ||||||
|  |         typeof op === 'function' ? op(SlashOptionCallableBuilder) : op | ||||||
|  |       ) | ||||||
|  |     : Object.entries(options).map((entry) => | ||||||
|  |         typeof entry[1] === 'function' | ||||||
|  |           ? entry[1](SlashOptionCallableBuilder) | ||||||
|  |           : Object.assign(entry[1], { name: entry[0] }) | ||||||
|  |       ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class SlashBuilder { | ||||||
|  |   data: SlashCommandPartial | ||||||
|  | 
 | ||||||
|  |   constructor( | ||||||
|  |     name?: string, | ||||||
|  |     description?: string, | ||||||
|  |     options?: SlashBuilderOptionsData | ||||||
|  |   ) { | ||||||
|  |     this.data = { | ||||||
|  |       name: name ?? '', | ||||||
|  |       description: description ?? 'No description.', | ||||||
|  |       options: options === undefined ? [] : buildOptionsArray(options) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   name(name: string): SlashBuilder { | ||||||
|  |     this.data.name = name | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   description(desc: string): SlashBuilder { | ||||||
|  |     this.data.description = desc | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   option(option: SlashOptionCallable | SlashCommandOption): SlashBuilder { | ||||||
|  |     if (this.data.options === undefined) this.data.options = [] | ||||||
|  |     this.data.options.push( | ||||||
|  |       typeof option === 'function' ? option(SlashOptionCallableBuilder) : option | ||||||
|  |     ) | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   options(options: SlashBuilderOptionsData): SlashBuilder { | ||||||
|  |     this.data.options = buildOptionsArray(options) | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   export(): SlashCommandPartial { | ||||||
|  |     if (this.data.name === '') | ||||||
|  |       throw new Error('Name was not provided in Slash Builder') | ||||||
|  |     return this.data | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export class SlashCommandsManager { | export class SlashCommandsManager { | ||||||
|   slash: SlashClient |   slash: SlashClient | ||||||
| 
 | 
 | ||||||
|  | @ -58,9 +195,9 @@ export class SlashCommandsManager { | ||||||
|   async all(): Promise<Collection<string, SlashCommand>> { |   async all(): Promise<Collection<string, SlashCommand>> { | ||||||
|     const col = new Collection<string, SlashCommand>() |     const col = new Collection<string, SlashCommand>() | ||||||
| 
 | 
 | ||||||
|     const res = (await this.rest.get( |     const res = (await this.rest.api.applications[ | ||||||
|       APPLICATION_COMMANDS(this.slash.getID()) |       this.slash.getID() | ||||||
|     )) as SlashCommandPayload[] |     ].commands.get()) as SlashCommandPayload[] | ||||||
|     if (!Array.isArray(res)) return col |     if (!Array.isArray(res)) return col | ||||||
| 
 | 
 | ||||||
|     for (const raw of res) { |     for (const raw of res) { | ||||||
|  | @ -77,12 +214,9 @@ export class SlashCommandsManager { | ||||||
|   ): Promise<Collection<string, SlashCommand>> { |   ): Promise<Collection<string, SlashCommand>> { | ||||||
|     const col = new Collection<string, SlashCommand>() |     const col = new Collection<string, SlashCommand>() | ||||||
| 
 | 
 | ||||||
|     const res = (await this.rest.get( |     const res = (await this.rest.api.applications[this.slash.getID()].guilds[ | ||||||
|       APPLICATION_GUILD_COMMANDS( |  | ||||||
|         this.slash.getID(), |  | ||||||
|       typeof guild === 'string' ? guild : guild.id |       typeof guild === 'string' ? guild : guild.id | ||||||
|       ) |     ].commands.get()) as SlashCommandPayload[] | ||||||
|     )) as SlashCommandPayload[] |  | ||||||
|     if (!Array.isArray(res)) return col |     if (!Array.isArray(res)) return col | ||||||
| 
 | 
 | ||||||
|     for (const raw of res) { |     for (const raw of res) { | ||||||
|  | @ -99,15 +233,14 @@ export class SlashCommandsManager { | ||||||
|     data: SlashCommandPartial, |     data: SlashCommandPartial, | ||||||
|     guild?: Guild | string |     guild?: Guild | string | ||||||
|   ): Promise<SlashCommand> { |   ): Promise<SlashCommand> { | ||||||
|     const payload = await this.rest.post( |     const route = | ||||||
|       guild === undefined |       guild === undefined | ||||||
|         ? APPLICATION_COMMANDS(this.slash.getID()) |         ? this.rest.api.applications[this.slash.getID()].commands | ||||||
|         : APPLICATION_GUILD_COMMANDS( |         : this.rest.api.applications[this.slash.getID()].guilds[ | ||||||
|             this.slash.getID(), |  | ||||||
|             typeof guild === 'string' ? guild : guild.id |             typeof guild === 'string' ? guild : guild.id | ||||||
|           ), |           ].commands | ||||||
|       data | 
 | ||||||
|     ) |     const payload = await route.post(data) | ||||||
| 
 | 
 | ||||||
|     const cmd = new SlashCommand(this, payload) |     const cmd = new SlashCommand(this, payload) | ||||||
|     cmd._guild = |     cmd._guild = | ||||||
|  | @ -122,16 +255,14 @@ export class SlashCommandsManager { | ||||||
|     data: SlashCommandPartial, |     data: SlashCommandPartial, | ||||||
|     guild?: Guild | string |     guild?: Guild | string | ||||||
|   ): Promise<SlashCommandsManager> { |   ): Promise<SlashCommandsManager> { | ||||||
|     await this.rest.patch( |     const route = | ||||||
|       guild === undefined |       guild === undefined | ||||||
|         ? APPLICATION_COMMAND(this.slash.getID(), id) |         ? this.rest.api.applications[this.slash.getID()].commands[id] | ||||||
|         : APPLICATION_GUILD_COMMAND( |         : this.rest.api.applications[this.slash.getID()].guilds[ | ||||||
|             this.slash.getID(), |             typeof guild === 'string' ? guild : guild.id | ||||||
|             typeof guild === 'string' ? guild : guild.id, |           ].commands[id] | ||||||
|             id | 
 | ||||||
|           ), |     await route.patch(data) | ||||||
|       data |  | ||||||
|     ) |  | ||||||
|     return this |     return this | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -140,29 +271,28 @@ export class SlashCommandsManager { | ||||||
|     id: string, |     id: string, | ||||||
|     guild?: Guild | string |     guild?: Guild | string | ||||||
|   ): Promise<SlashCommandsManager> { |   ): Promise<SlashCommandsManager> { | ||||||
|     await this.rest.delete( |     const route = | ||||||
|       guild === undefined |       guild === undefined | ||||||
|         ? APPLICATION_COMMAND(this.slash.getID(), id) |         ? this.rest.api.applications[this.slash.getID()].commands[id] | ||||||
|         : APPLICATION_GUILD_COMMAND( |         : this.rest.api.applications[this.slash.getID()].guilds[ | ||||||
|             this.slash.getID(), |             typeof guild === 'string' ? guild : guild.id | ||||||
|             typeof guild === 'string' ? guild : guild.id, |           ].commands[id] | ||||||
|             id | 
 | ||||||
|           ) |     await route.delete() | ||||||
|     ) |  | ||||||
|     return this |     return this | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Get a Slash Command (global or Guild) */ |   /** Get a Slash Command (global or Guild) */ | ||||||
|   async get(id: string, guild?: Guild | string): Promise<SlashCommand> { |   async get(id: string, guild?: Guild | string): Promise<SlashCommand> { | ||||||
|     const data = await this.rest.get( |     const route = | ||||||
|       guild === undefined |       guild === undefined | ||||||
|         ? APPLICATION_COMMAND(this.slash.getID(), id) |         ? this.rest.api.applications[this.slash.getID()].commands[id] | ||||||
|         : APPLICATION_GUILD_COMMAND( |         : this.rest.api.applications[this.slash.getID()].guilds[ | ||||||
|             this.slash.getID(), |             typeof guild === 'string' ? guild : guild.id | ||||||
|             typeof guild === 'string' ? guild : guild.id, |           ].commands[id] | ||||||
|             id | 
 | ||||||
|           ) |     const data = await route.get() | ||||||
|     ) | 
 | ||||||
|     return new SlashCommand(this, data) |     return new SlashCommand(this, data) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -205,6 +205,10 @@ class VCExtension extends Extension { | ||||||
| 
 | 
 | ||||||
| const client = new MyClient() | const client = new MyClient() | ||||||
| 
 | 
 | ||||||
|  | client.on('raw', (e, d) => { | ||||||
|  |   if (e === 'READY') console.log(d) | ||||||
|  | }) | ||||||
|  | 
 | ||||||
| client.extensions.load(VCExtension) | client.extensions.load(VCExtension) | ||||||
| 
 | 
 | ||||||
| client.connect(TOKEN, Intents.None) | client.connect(TOKEN, Intents.None) | ||||||
|  |  | ||||||
|  | @ -1,6 +1,36 @@ | ||||||
| import { SlashClient } from '../models/slashClient.ts' | import { SlashClient, SlashBuilder } from '../models/slashClient.ts' | ||||||
| import { TOKEN } from './config.ts' | import { TOKEN } from './config.ts' | ||||||
| 
 | 
 | ||||||
| const slash = new SlashClient({ token: TOKEN }) | const slash = new SlashClient({ token: TOKEN }) | ||||||
| 
 | 
 | ||||||
| slash.commands.all().then(console.log) | slash.commands.all().then(console.log) | ||||||
|  | 
 | ||||||
|  | const cmd = new SlashBuilder() | ||||||
|  |   .name('searchmusic') | ||||||
|  |   .description('Search for music.') | ||||||
|  |   .option((o) => | ||||||
|  |     o.string({ name: 'query', description: 'Query to search with.' }) | ||||||
|  |   ) | ||||||
|  |   .option((o) => | ||||||
|  |     o.string({ | ||||||
|  |       name: 'engine', | ||||||
|  |       description: 'Search engine to use.', | ||||||
|  |       choices: [{ name: 'YouTube', value: 'youtube' }, 'Spotify'] | ||||||
|  |     }) | ||||||
|  |   ) | ||||||
|  |   .options({ | ||||||
|  |     query: { | ||||||
|  |       description: 'Query UWU', | ||||||
|  |       type: 3 | ||||||
|  |     }, | ||||||
|  |     engine: { | ||||||
|  |       description: 'Engine UWU', | ||||||
|  |       type: 3, | ||||||
|  |       choices: [ | ||||||
|  |         { name: 'YouTube', value: 'youtube' }, | ||||||
|  |         { name: 'Spotify', value: 'spotify' } | ||||||
|  |       ] | ||||||
|  |     } | ||||||
|  |   }) | ||||||
|  | 
 | ||||||
|  | console.log(JSON.stringify(cmd.export())) | ||||||
|  |  | ||||||
|  | @ -66,7 +66,8 @@ export enum SlashCommandOptionType { | ||||||
| 
 | 
 | ||||||
| export interface SlashCommandOption { | export interface SlashCommandOption { | ||||||
|   name: string |   name: string | ||||||
|   description: string |   /** Description not required in Sub-Command or Sub-Command-Group */ | ||||||
|  |   description?: string | ||||||
|   type: SlashCommandOptionType |   type: SlashCommandOptionType | ||||||
|   required?: boolean |   required?: boolean | ||||||
|   default?: boolean |   default?: boolean | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue