feat(slash): add @slash decorator support

This commit is contained in:
DjDeveloperr 2020-12-10 14:40:00 +05:30
parent b0d6092c25
commit e1281736ec
4 changed files with 134 additions and 52 deletions

3
mod.ts
View File

@ -4,6 +4,7 @@ export { Base } from './src/structures/base.ts'
export { Gateway } from './src/gateway/index.ts' export { Gateway } from './src/gateway/index.ts'
export type { ClientEvents } from './src/gateway/handlers/index.ts' export type { ClientEvents } from './src/gateway/handlers/index.ts'
export * from './src/models/client.ts' export * from './src/models/client.ts'
export * from './src/models/slashClient.ts'
export { RESTManager } from './src/models/rest.ts' export { RESTManager } from './src/models/rest.ts'
export * from './src/models/cacheAdapter.ts' export * from './src/models/cacheAdapter.ts'
export { export {
@ -29,6 +30,8 @@ export { GatewayCache } from './src/managers/gatewayCache.ts'
export { GuildChannelsManager } from './src/managers/guildChannels.ts' export { GuildChannelsManager } from './src/managers/guildChannels.ts'
export type { GuildChannel } from './src/managers/guildChannels.ts' export type { GuildChannel } from './src/managers/guildChannels.ts'
export { GuildManager } from './src/managers/guilds.ts' export { GuildManager } from './src/managers/guilds.ts'
export * from './src/structures/slash.ts'
export * from './src/types/slash.ts'
export { GuildEmojisManager } from './src/managers/guildEmojis.ts' export { GuildEmojisManager } from './src/managers/guildEmojis.ts'
export { MembersManager } from './src/managers/members.ts' export { MembersManager } from './src/managers/members.ts'
export { MessageReactionsManager } from './src/managers/messageReactions.ts' export { MessageReactionsManager } from './src/managers/messageReactions.ts'

View File

@ -13,6 +13,7 @@ import { ActivityGame, ClientActivity } from '../types/presence.ts'
import { ClientEvents } from '../gateway/handlers/index.ts' import { ClientEvents } from '../gateway/handlers/index.ts'
import { Extension } from './extensions.ts' import { Extension } from './extensions.ts'
import { SlashClient } from './slashClient.ts' import { SlashClient } from './slashClient.ts'
import { Interaction } from '../structures/slash.ts'
/** OS related properties sent with Gateway Identify */ /** OS related properties sent with Gateway Identify */
export interface ClientProperties { export interface ClientProperties {
@ -43,6 +44,8 @@ export interface ClientOptions {
fetchUncachedReactions?: boolean fetchUncachedReactions?: boolean
/** Client Properties */ /** Client Properties */
clientProperties?: ClientProperties clientProperties?: ClientProperties
/** Enable/Disable Slash Commands Integration (enabled by default) */
enableSlash?: boolean
} }
/** /**
@ -86,6 +89,11 @@ export class Client extends EventEmitter {
/** Client's presence. Startup one if set before connecting */ /** Client's presence. Startup one if set before connecting */
presence: ClientPresence = new ClientPresence() presence: ClientPresence = new ClientPresence()
_decoratedEvents?: { [name: string]: (...args: any[]) => any } _decoratedEvents?: { [name: string]: (...args: any[]) => any }
_decoratedSlash?: Array<{
name: string
guild?: string
handler: (interaction: Interaction) => any
}>
private readonly _untypedOn = this.on private readonly _untypedOn = this.on
@ -137,7 +145,9 @@ export class Client extends EventEmitter {
} }
: options.clientProperties : options.clientProperties
this.slash = new SlashClient(this) this.slash = new SlashClient(this, {
enabled: options.enableSlash
})
} }
/** /**
@ -200,3 +210,14 @@ export function event(name?: string) {
client._decoratedEvents[name === undefined ? prop : name] = listener client._decoratedEvents[name === undefined ? prop : name] = listener
} }
} }
export function slash(name?: string, guild?: string) {
return function (client: Client, prop: string) {
if (client._decoratedSlash === undefined) client._decoratedSlash = []
client._decoratedSlash.push({
name: name ?? prop,
guild,
handler: (client as { [name: string]: any })[prop]
})
}
}

View File

@ -19,22 +19,33 @@ export interface SlashOptions {
} }
export class SlashCommand { export class SlashCommand {
slash: SlashCommandsManager
id: string id: string
applicationID: string applicationID: string
name: string name: string
description: string description: string
options: SlashCommandOption[] options: SlashCommandOption[]
_guild?: string
constructor(data: SlashCommandPayload) { constructor(manager: SlashCommandsManager, data: SlashCommandPayload) {
this.slash = manager
this.id = data.id this.id = data.id
this.applicationID = data.application_id this.applicationID = data.application_id
this.name = data.name this.name = data.name
this.description = data.description this.description = data.description
this.options = data.options this.options = data.options
} }
async delete(): Promise<void> {
await this.slash.delete(this.id, this._guild)
}
async edit(data: SlashCommandPartial): Promise<void> {
await this.slash.edit(this.id, data, this._guild)
}
} }
export class SlashCommands { export class SlashCommandsManager {
client: Client client: Client
slash: SlashClient slash: SlashClient
@ -53,7 +64,8 @@ export class SlashCommands {
if (!Array.isArray(res)) return col if (!Array.isArray(res)) return col
for (const raw of res) { for (const raw of res) {
col.set(raw.id, new SlashCommand(raw)) const cmd = new SlashCommand(this, raw)
col.set(raw.id, cmd)
} }
return col return col
@ -74,7 +86,9 @@ export class SlashCommands {
if (!Array.isArray(res)) return col if (!Array.isArray(res)) return col
for (const raw of res) { for (const raw of res) {
col.set(raw.id, new SlashCommand(raw)) const cmd = new SlashCommand(this, raw)
cmd._guild = typeof guild === 'string' ? guild : guild.id
col.set(raw.id, cmd)
} }
return col return col
@ -95,14 +109,19 @@ export class SlashCommands {
data data
) )
return new SlashCommand(payload) const cmd = new SlashCommand(this, payload)
cmd._guild =
typeof guild === 'string' || guild === undefined ? guild : guild.id
return cmd
} }
/** Edit a Slash Command (global or Guild) */
async edit( async edit(
id: string, id: string,
data: SlashCommandPayload, data: SlashCommandPartial,
guild?: Guild guild?: Guild | string
): Promise<SlashCommands> { ): Promise<SlashCommandsManager> {
await this.client.rest.patch( await this.client.rest.patch(
guild === undefined guild === undefined
? APPLICATION_COMMAND(this.client.user?.id as string, id) ? APPLICATION_COMMAND(this.client.user?.id as string, id)
@ -115,30 +134,85 @@ export class SlashCommands {
) )
return this return this
} }
/** Delete a Slash Command (global or Guild) */
async delete(
id: string,
guild?: Guild | string
): Promise<SlashCommandsManager> {
await this.client.rest.delete(
guild === undefined
? APPLICATION_COMMAND(this.client.user?.id as string, id)
: APPLICATION_GUILD_COMMAND(
this.client.user?.id as string,
typeof guild === 'string' ? guild : guild.id,
id
)
)
return this
}
}
export type SlashCommandHandlerCallback = (interaction: Interaction) => any
export interface SlashCommandHandler {
name: string
guild?: string
handler: SlashCommandHandlerCallback
} }
export class SlashClient { export class SlashClient {
client: Client client: Client
enabled: boolean = true enabled: boolean = true
commands: SlashCommands commands: SlashCommandsManager
handlers: SlashCommandHandler[] = []
constructor(client: Client, options?: SlashOptions) { constructor(client: Client, options?: SlashOptions) {
this.client = client this.client = client
this.commands = new SlashCommands(client) this.commands = new SlashCommandsManager(client)
if (options !== undefined) { if (options !== undefined) {
this.enabled = options.enabled ?? true this.enabled = options.enabled ?? true
} }
if (this.client._decoratedSlash !== undefined) {
this.client._decoratedSlash.forEach((e) => {
this.handlers.push(e)
})
}
this.client.on('interactionCreate', (interaction) => this.client.on('interactionCreate', (interaction) =>
this.process(interaction) this.process(interaction)
) )
} }
process(interaction: Interaction): any {} /** Adds a new Slash Command Handler */
handle(
handle(fn: (interaction: Interaction) => any): SlashClient { name: string,
this.process = fn handler: SlashCommandHandlerCallback,
guild?: string
): SlashClient {
this.handlers.push({
name,
guild,
handler
})
return this return this
} }
process(interaction: Interaction): any {
if (!this.enabled) return
let cmd
if (interaction.guild !== undefined)
cmd =
this.handlers.find(
(e) => e.guild !== undefined && e.name === interaction.name
) ?? this.handlers.find((e) => e.name === interaction.name)
else cmd = this.handlers.find((e) => e.name === interaction.name)
if (cmd === undefined) return
cmd.handler(interaction)
}
} }

View File

@ -1,33 +1,23 @@
import { Client, Intents } from '../../mod.ts' import { Client, Intents, event, slash } from '../../mod.ts'
import { Embed } from '../structures/embed.ts' import { Embed } from '../structures/embed.ts'
import { SlashCommandOptionType } from '../types/slash.ts' import { Interaction } from '../structures/slash.ts'
import { TOKEN } from './config.ts' import { TOKEN } from './config.ts'
const client = new Client() export class MyClient extends Client {
@event()
ready(): void {
console.log(`Logged in as ${this.user?.tag}!`)
}
client.on('ready', () => { @slash()
console.log('Logged in!') send(d: Interaction): void {
client.slash.commands d.respond({
.create( content: d.data.options.find((e) => e.name === 'content')?.value
{ })
name: 'send', }
description: 'Send a Message through Bot!',
options: [
{
name: 'content',
description: 'Message to send',
type: SlashCommandOptionType.STRING,
required: true
}
]
},
'783319033205751809'
)
.then(console.log)
})
client.on('interactionCreate', async (d) => { @slash()
if (d.name === 'eval') { async eval(d: Interaction): Promise<void> {
if (d.user.id !== '422957901716652033') { if (d.user.id !== '422957901716652033') {
d.respond({ d.respond({
content: 'This command can only be used by owner!' content: 'This command can only be used by owner!'
@ -53,8 +43,10 @@ client.on('interactionCreate', async (d) => {
}) })
} }
} }
return }
} else if (d.name === 'hug') {
@slash()
async hug(d: Interaction): Promise<void> {
const id = d.data.options.find((e) => e.name === 'user')?.value as string const id = d.data.options.find((e) => e.name === 'user')?.value as string
const user = (await client.users.get(id)) ?? (await client.users.fetch(id)) const user = (await client.users.get(id)) ?? (await client.users.fetch(id))
const url = await fetch('https://nekos.life/api/v2/img/hug') const url = await fetch('https://nekos.life/api/v2/img/hug')
@ -69,16 +61,8 @@ client.on('interactionCreate', async (d) => {
.setColor(0x2f3136) .setColor(0x2f3136)
] ]
}) })
return
} else if (d.name === 'send') {
d.respond({
content: d.data.options.find((e) => e.name === 'content')?.value as string
})
return
} }
await d.respond({ }
content: `Hi, ${d.member.user.username}! You used /${d.name}`
})
})
const client = new MyClient()
client.connect(TOKEN, Intents.None) client.connect(TOKEN, Intents.None)