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(
|
typeof guild === 'string' ? guild : guild.id
|
||||||
this.slash.getID(),
|
].commands.get()) as SlashCommandPayload[]
|
||||||
typeof guild === 'string' ? guild : guild.id
|
|
||||||
)
|
|
||||||
)) 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…
Reference in a new issue