feat(extensions): the beginning
This commit is contained in:
parent
9c9726259b
commit
f6393c8226
5 changed files with 154 additions and 25 deletions
|
@ -1,12 +1,14 @@
|
||||||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||||
import getChannelByType from '../../utils/getChannelByType.ts'
|
import getChannelByType from '../../utils/getChannelByType.ts'
|
||||||
import { ChannelPayload } from '../../types/channel.ts'
|
import { ChannelPayload } from '../../types/channel.ts'
|
||||||
|
import { Guild } from "../../structures/guild.ts"
|
||||||
|
|
||||||
export const channelCreate: GatewayEventHandler = async (
|
export const channelCreate: GatewayEventHandler = async (
|
||||||
gateway: Gateway,
|
gateway: Gateway,
|
||||||
d: ChannelPayload
|
d: ChannelPayload
|
||||||
) => {
|
) => {
|
||||||
const channel = getChannelByType(gateway.client, d)
|
const guild: undefined | Guild = (d as any).guild_id !== undefined ? await gateway.client.guilds.get((d as any).guild_id) : undefined
|
||||||
|
const channel = getChannelByType(gateway.client, d, guild)
|
||||||
if (channel !== undefined) {
|
if (channel !== undefined) {
|
||||||
await gateway.client.channels.set(d.id, d)
|
await gateway.client.channels.set(d.id, d)
|
||||||
gateway.client.emit('channelCreate', channel)
|
gateway.client.emit('channelCreate', channel)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { TextChannel } from '../structures/textChannel.ts'
|
||||||
import { User } from '../structures/user.ts'
|
import { User } from '../structures/user.ts'
|
||||||
import { Collection } from '../utils/collection.ts'
|
import { Collection } from '../utils/collection.ts'
|
||||||
import { CommandClient } from './commandClient.ts'
|
import { CommandClient } from './commandClient.ts'
|
||||||
|
import { Extension } from "./extensions.ts"
|
||||||
|
|
||||||
export interface CommandContext {
|
export interface CommandContext {
|
||||||
/** The Client object */
|
/** The Client object */
|
||||||
|
@ -35,8 +36,8 @@ export class Command {
|
||||||
description?: string
|
description?: string
|
||||||
/** Array of Aliases of Command, or only string */
|
/** Array of Aliases of Command, or only string */
|
||||||
aliases?: string | string[]
|
aliases?: string | string[]
|
||||||
/** Category of the Command */
|
/** Extension (Parent) of the Command */
|
||||||
category?: string
|
extension?: Extension
|
||||||
/** Usage of Command, only Argument Names */
|
/** Usage of Command, only Argument Names */
|
||||||
usage?: string | string[]
|
usage?: string | string[]
|
||||||
/** Usage Example of Command, only Arguments (without Prefix and Name) */
|
/** Usage Example of Command, only Arguments (without Prefix and Name) */
|
||||||
|
@ -58,13 +59,16 @@ export class Command {
|
||||||
execute(ctx: CommandContext): any { }
|
execute(ctx: CommandContext): any { }
|
||||||
/** Method executed after executing command, passes on CommandContext and the value returned by execute too. (optional) */
|
/** Method executed after executing command, passes on CommandContext and the value returned by execute too. (optional) */
|
||||||
afterExecute(ctx: CommandContext, executeResult: any): any { }
|
afterExecute(ctx: CommandContext, executeResult: any): any { }
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
return `Command: ${this.name}${this.extension !== undefined ? ` [${this.extension.name}]` : ''}`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CommandsManager {
|
export class CommandsManager {
|
||||||
client: CommandClient
|
client: CommandClient
|
||||||
list: Collection<string, Command> = new Collection()
|
list: Collection<string, Command> = new Collection()
|
||||||
disabled: Set<string> = new Set()
|
disabled: Set<string> = new Set()
|
||||||
disabledCategories: Set<string> = new Set()
|
|
||||||
|
|
||||||
constructor(client: CommandClient) {
|
constructor(client: CommandClient) {
|
||||||
this.client = client
|
this.client = client
|
||||||
|
@ -96,7 +100,6 @@ export class CommandsManager {
|
||||||
const cmd = this.find(name)
|
const cmd = this.find(name)
|
||||||
if (cmd === undefined) return
|
if (cmd === undefined) return
|
||||||
if (this.isDisabled(cmd) && bypassDisable !== true) return
|
if (this.isDisabled(cmd) && bypassDisable !== true) return
|
||||||
if (cmd.category !== undefined && this.isCategoryDisabled(cmd.category) && bypassDisable !== true) return
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +124,7 @@ export class CommandsManager {
|
||||||
add(cmd: Command | typeof Command): boolean {
|
add(cmd: Command | typeof Command): boolean {
|
||||||
// eslint-disable-next-line new-cap
|
// eslint-disable-next-line new-cap
|
||||||
if (!(cmd instanceof Command)) cmd = new cmd()
|
if (!(cmd instanceof Command)) cmd = new cmd()
|
||||||
if (this.exists(cmd)) return false
|
if (this.exists(cmd)) throw new Error(`Failed to add Command '${cmd.toString()}' with name/alias already exists.`)
|
||||||
this.list.set(cmd.name, cmd)
|
this.list.set(cmd.name, cmd)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -133,11 +136,6 @@ export class CommandsManager {
|
||||||
else return this.list.delete(find.name)
|
else return this.list.delete(find.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get all Commands of given Category */
|
|
||||||
category(name: string): Collection<string, Command> {
|
|
||||||
return this.list.filter(c => c.category === name)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check whether a Command is disabled or not */
|
/** Check whether a Command is disabled or not */
|
||||||
isDisabled(name: string | Command): boolean {
|
isDisabled(name: string | Command): boolean {
|
||||||
const cmd = typeof name === "string" ? this.find(name) : name
|
const cmd = typeof name === "string" ? this.find(name) : name
|
||||||
|
@ -155,18 +153,6 @@ export class CommandsManager {
|
||||||
this.disabled.add(cmd.name)
|
this.disabled.add(cmd.name)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check whether a Category is disabled */
|
|
||||||
isCategoryDisabled(name: string): boolean {
|
|
||||||
return this.disabledCategories.has(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Disable a Category of Commands */
|
|
||||||
disableCategory(name: string): boolean {
|
|
||||||
if (this.isCategoryDisabled(name)) return false
|
|
||||||
this.disabledCategories.add(name)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ParsedCommand {
|
export interface ParsedCommand {
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import { Embed, Message } from '../../mod.ts'
|
import { Message } from "../../mod.ts"
|
||||||
|
import { Embed } from "../structures/embed.ts"
|
||||||
import { awaitSync } from "../utils/mixedPromise.ts"
|
import { awaitSync } from "../utils/mixedPromise.ts"
|
||||||
import { Client, ClientOptions } from './client.ts'
|
import { Client, ClientOptions } from './client.ts'
|
||||||
import { CommandContext, CommandsManager, parseCommand } from './command.ts'
|
import { CommandContext, CommandsManager, parseCommand } from './command.ts'
|
||||||
|
import { ExtensionsManager } from "./extensions.ts"
|
||||||
|
|
||||||
type PrefixReturnType = string | string[] | Promise<string | string[]>
|
type PrefixReturnType = string | string[] | Promise<string | string[]>
|
||||||
|
|
||||||
|
@ -62,6 +64,7 @@ export class CommandClient extends Client implements CommandClientOptions {
|
||||||
allowBots: boolean
|
allowBots: boolean
|
||||||
allowDMs: boolean
|
allowDMs: boolean
|
||||||
caseSensitive: boolean
|
caseSensitive: boolean
|
||||||
|
extensions: ExtensionsManager = new ExtensionsManager(this)
|
||||||
commands: CommandsManager = new CommandsManager(this)
|
commands: CommandsManager = new CommandsManager(this)
|
||||||
texts: CommandTexts = DefaultCommandTexts
|
texts: CommandTexts = DefaultCommandTexts
|
||||||
|
|
||||||
|
|
112
src/models/extensions.ts
Normal file
112
src/models/extensions.ts
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
import { Collection } from "../utils/collection.ts";
|
||||||
|
import { Command } from "./command.ts";
|
||||||
|
import { CommandClient } from "./commandClient.ts";
|
||||||
|
|
||||||
|
export type ExtensionEventCallback = (ext: Extension, ...args: any[]) => any
|
||||||
|
|
||||||
|
export class ExtensionCommands {
|
||||||
|
extension: Extension
|
||||||
|
|
||||||
|
constructor(ext: Extension) {
|
||||||
|
this.extension = ext
|
||||||
|
}
|
||||||
|
|
||||||
|
get list(): Collection<string, Command> {
|
||||||
|
return this.extension.client.commands.list.filter(c => c.extension?.name === this.extension.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
get(cmd: string): Command | undefined {
|
||||||
|
const find = this.extension.client.commands.find(cmd)
|
||||||
|
// linter sucks
|
||||||
|
if (find === undefined) return undefined
|
||||||
|
else if (find.extension === undefined) return undefined
|
||||||
|
else if (find.extension.name !== this.extension.name) return undefined
|
||||||
|
else return find
|
||||||
|
}
|
||||||
|
|
||||||
|
add(Cmd: Command | typeof Command): boolean {
|
||||||
|
const cmd = Cmd instanceof Command ? Cmd : new Cmd()
|
||||||
|
cmd.extension = this.extension
|
||||||
|
return this.extension.client.commands.add(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(cmd: Command | string): boolean {
|
||||||
|
const find = this.extension.client.commands.find(typeof cmd === 'string' ? cmd : cmd.name)
|
||||||
|
if (find === undefined) return false
|
||||||
|
if (find.extension !== undefined && find.extension.name !== this.extension.name) return false
|
||||||
|
else return this.extension.client.commands.delete(find)
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteAll(): void {
|
||||||
|
for (const [cmd] of this.list) {
|
||||||
|
this.delete(cmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Extension {
|
||||||
|
client: CommandClient
|
||||||
|
name: string = ''
|
||||||
|
description?: string
|
||||||
|
commands: ExtensionCommands = new ExtensionCommands(this)
|
||||||
|
events: { [name: string]: (...args: any[]) => {} } = {}
|
||||||
|
|
||||||
|
constructor(client: CommandClient) {
|
||||||
|
this.client = client
|
||||||
|
}
|
||||||
|
|
||||||
|
listen(event: string, cb: ExtensionEventCallback): boolean {
|
||||||
|
if (this.events[event] !== undefined) return false
|
||||||
|
else {
|
||||||
|
const fn = (...args: any[]): any => {
|
||||||
|
// eslint-disable-next-line standard/no-callback-literal
|
||||||
|
cb(this, ...args)
|
||||||
|
};
|
||||||
|
this.client.on(event, fn)
|
||||||
|
this.events[event] = fn
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
load(): any {}
|
||||||
|
unload(): any {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ExtensionsManager {
|
||||||
|
client: CommandClient
|
||||||
|
list: Collection<string, Extension> = new Collection()
|
||||||
|
|
||||||
|
constructor(client: CommandClient) {
|
||||||
|
this.client = client
|
||||||
|
}
|
||||||
|
|
||||||
|
get(ext: string): Extension | undefined {
|
||||||
|
return this.list.get(ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
exists(ext: string): boolean {
|
||||||
|
return this.get(ext) !== undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
load(ext: Extension | typeof Extension): void {
|
||||||
|
// eslint-disable-next-line new-cap
|
||||||
|
if (!(ext instanceof Extension)) ext = new ext(this.client)
|
||||||
|
if (this.exists(ext.name)) throw new Error(`Extension with name '${ext.name}' already exists`)
|
||||||
|
this.list.set(ext.name, ext)
|
||||||
|
ext.load()
|
||||||
|
}
|
||||||
|
|
||||||
|
unload(ext: Extension | string): boolean {
|
||||||
|
const name = typeof ext === 'string' ? ext : ext.name
|
||||||
|
const extension = this.get(name)
|
||||||
|
if (extension === undefined) return false
|
||||||
|
extension.commands.deleteAll()
|
||||||
|
for (const [k, v] of Object.entries(extension.events)) {
|
||||||
|
this.client.removeListener(k, v)
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||||
|
delete extension.events[k]
|
||||||
|
}
|
||||||
|
extension.unload()
|
||||||
|
return this.list.delete(name)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,7 @@
|
||||||
import { CommandClient, Intents } from '../../mod.ts'
|
import { Command, CommandClient, Intents } from '../../mod.ts'
|
||||||
|
import { GuildChannel } from "../managers/guildChannels.ts"
|
||||||
|
import { CommandContext } from "../models/command.ts"
|
||||||
|
import { Extension } from "../models/extensions.ts"
|
||||||
import { TOKEN } from './config.ts'
|
import { TOKEN } from './config.ts'
|
||||||
|
|
||||||
const client = new CommandClient({
|
const client = new CommandClient({
|
||||||
|
@ -17,6 +20,29 @@ client.on('ready', () => {
|
||||||
|
|
||||||
client.on("commandError", console.error)
|
client.on("commandError", console.error)
|
||||||
|
|
||||||
|
class ChannelLog extends Extension {
|
||||||
|
|
||||||
|
onChannelCreate(ext: Extension, channel: GuildChannel): void {
|
||||||
|
console.log(`Channel Created: ${channel.name}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
load(): void {
|
||||||
|
this.listen('channelCreate', this.onChannelCreate)
|
||||||
|
|
||||||
|
class Pong extends Command {
|
||||||
|
name = 'Pong'
|
||||||
|
|
||||||
|
execute(ctx: CommandContext): any {
|
||||||
|
ctx.message.reply('Ping!')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.commands.add(Pong)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client.extensions.load(ChannelLog)
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
;(async() => {
|
;(async() => {
|
||||||
const files = Deno.readDirSync('./src/test/cmds')
|
const files = Deno.readDirSync('./src/test/cmds')
|
||||||
|
|
Loading…
Reference in a new issue