feat: slash builde

This commit is contained in:
DjDeveloperr 2020-12-21 19:18:46 +05:30
parent cac3c5c9e3
commit da0bfc12c7
6 changed files with 220 additions and 49 deletions

View file

@ -247,6 +247,7 @@ export function event(name?: string) {
}
}
/** Decorator to create a Slash Command handler */
export function slash(name?: string, guild?: string) {
return function (client: Client | SlashModule, prop: string) {
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) {
return function (client: Client | SlashModule, prop: string) {
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(
parent: string,
group: string,
@ -303,6 +306,7 @@ export function groupslash(
}
}
/** Decorator to add a Slash Module to Client */
export function slashModule() {
return function (client: Client, prop: string) {
if (client._decoratedSlashModules === undefined)

View file

@ -97,6 +97,7 @@ export interface RESTOptions {
token?: string
headers?: { [name: string]: string | undefined }
canary?: boolean
version?: 6 | 7 | 8
}
export class RESTManager {
@ -111,6 +112,7 @@ export class RESTManager {
constructor(client?: RESTOptions) {
this.client = client
this.api = builder(this)
if (client?.version !== undefined) this.version = client.version
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.handleRateLimits()
}

View file

@ -1,14 +1,10 @@
import { Guild } from '../structures/guild.ts'
import { Interaction } from '../structures/slash.ts'
import {
APPLICATION_COMMAND,
APPLICATION_COMMANDS,
APPLICATION_GUILD_COMMAND,
APPLICATION_GUILD_COMMANDS
} from '../types/endpoint.ts'
import {
InteractionType,
SlashCommandChoice,
SlashCommandOption,
SlashCommandOptionType,
SlashCommandPartial,
SlashCommandPayload
} 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 {
slash: SlashClient
@ -58,9 +195,9 @@ export class SlashCommandsManager {
async all(): Promise<Collection<string, SlashCommand>> {
const col = new Collection<string, SlashCommand>()
const res = (await this.rest.get(
APPLICATION_COMMANDS(this.slash.getID())
)) as SlashCommandPayload[]
const res = (await this.rest.api.applications[
this.slash.getID()
].commands.get()) as SlashCommandPayload[]
if (!Array.isArray(res)) return col
for (const raw of res) {
@ -77,12 +214,9 @@ export class SlashCommandsManager {
): Promise<Collection<string, SlashCommand>> {
const col = new Collection<string, SlashCommand>()
const res = (await this.rest.get(
APPLICATION_GUILD_COMMANDS(
this.slash.getID(),
const res = (await this.rest.api.applications[this.slash.getID()].guilds[
typeof guild === 'string' ? guild : guild.id
)
)) as SlashCommandPayload[]
].commands.get()) as SlashCommandPayload[]
if (!Array.isArray(res)) return col
for (const raw of res) {
@ -99,15 +233,14 @@ export class SlashCommandsManager {
data: SlashCommandPartial,
guild?: Guild | string
): Promise<SlashCommand> {
const payload = await this.rest.post(
const route =
guild === undefined
? APPLICATION_COMMANDS(this.slash.getID())
: APPLICATION_GUILD_COMMANDS(
this.slash.getID(),
? this.rest.api.applications[this.slash.getID()].commands
: this.rest.api.applications[this.slash.getID()].guilds[
typeof guild === 'string' ? guild : guild.id
),
data
)
].commands
const payload = await route.post(data)
const cmd = new SlashCommand(this, payload)
cmd._guild =
@ -122,16 +255,14 @@ export class SlashCommandsManager {
data: SlashCommandPartial,
guild?: Guild | string
): Promise<SlashCommandsManager> {
await this.rest.patch(
const route =
guild === undefined
? APPLICATION_COMMAND(this.slash.getID(), id)
: APPLICATION_GUILD_COMMAND(
this.slash.getID(),
typeof guild === 'string' ? guild : guild.id,
id
),
data
)
? this.rest.api.applications[this.slash.getID()].commands[id]
: this.rest.api.applications[this.slash.getID()].guilds[
typeof guild === 'string' ? guild : guild.id
].commands[id]
await route.patch(data)
return this
}
@ -140,29 +271,28 @@ export class SlashCommandsManager {
id: string,
guild?: Guild | string
): Promise<SlashCommandsManager> {
await this.rest.delete(
const route =
guild === undefined
? APPLICATION_COMMAND(this.slash.getID(), id)
: APPLICATION_GUILD_COMMAND(
this.slash.getID(),
typeof guild === 'string' ? guild : guild.id,
id
)
)
? this.rest.api.applications[this.slash.getID()].commands[id]
: this.rest.api.applications[this.slash.getID()].guilds[
typeof guild === 'string' ? guild : guild.id
].commands[id]
await route.delete()
return this
}
/** Get a Slash Command (global or Guild) */
async get(id: string, guild?: Guild | string): Promise<SlashCommand> {
const data = await this.rest.get(
const route =
guild === undefined
? APPLICATION_COMMAND(this.slash.getID(), id)
: APPLICATION_GUILD_COMMAND(
this.slash.getID(),
typeof guild === 'string' ? guild : guild.id,
id
)
)
? this.rest.api.applications[this.slash.getID()].commands[id]
: this.rest.api.applications[this.slash.getID()].guilds[
typeof guild === 'string' ? guild : guild.id
].commands[id]
const data = await route.get()
return new SlashCommand(this, data)
}
}

View file

@ -205,6 +205,10 @@ class VCExtension extends Extension {
const client = new MyClient()
client.on('raw', (e, d) => {
if (e === 'READY') console.log(d)
})
client.extensions.load(VCExtension)
client.connect(TOKEN, Intents.None)

View file

@ -1,6 +1,36 @@
import { SlashClient } from '../models/slashClient.ts'
import { SlashClient, SlashBuilder } from '../models/slashClient.ts'
import { TOKEN } from './config.ts'
const slash = new SlashClient({ token: TOKEN })
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()))

View file

@ -66,7 +66,8 @@ export enum SlashCommandOptionType {
export interface SlashCommandOption {
name: string
description: string
/** Description not required in Sub-Command or Sub-Command-Group */
description?: string
type: SlashCommandOptionType
required?: boolean
default?: boolean