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 getChannelByType from '../../utils/getChannelByType.ts'
|
||||
import { ChannelPayload } from '../../types/channel.ts'
|
||||
import { Guild } from "../../structures/guild.ts"
|
||||
|
||||
export const channelCreate: GatewayEventHandler = async (
|
||||
gateway: Gateway,
|
||||
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) {
|
||||
await gateway.client.channels.set(d.id, d)
|
||||
gateway.client.emit('channelCreate', channel)
|
||||
|
|
|
@ -4,6 +4,7 @@ import { TextChannel } from '../structures/textChannel.ts'
|
|||
import { User } from '../structures/user.ts'
|
||||
import { Collection } from '../utils/collection.ts'
|
||||
import { CommandClient } from './commandClient.ts'
|
||||
import { Extension } from "./extensions.ts"
|
||||
|
||||
export interface CommandContext {
|
||||
/** The Client object */
|
||||
|
@ -35,8 +36,8 @@ export class Command {
|
|||
description?: string
|
||||
/** Array of Aliases of Command, or only string */
|
||||
aliases?: string | string[]
|
||||
/** Category of the Command */
|
||||
category?: string
|
||||
/** Extension (Parent) of the Command */
|
||||
extension?: Extension
|
||||
/** Usage of Command, only Argument Names */
|
||||
usage?: string | string[]
|
||||
/** Usage Example of Command, only Arguments (without Prefix and Name) */
|
||||
|
@ -58,13 +59,16 @@ export class Command {
|
|||
execute(ctx: CommandContext): any { }
|
||||
/** Method executed after executing command, passes on CommandContext and the value returned by execute too. (optional) */
|
||||
afterExecute(ctx: CommandContext, executeResult: any): any { }
|
||||
|
||||
toString(): string {
|
||||
return `Command: ${this.name}${this.extension !== undefined ? ` [${this.extension.name}]` : ''}`
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandsManager {
|
||||
client: CommandClient
|
||||
list: Collection<string, Command> = new Collection()
|
||||
disabled: Set<string> = new Set()
|
||||
disabledCategories: Set<string> = new Set()
|
||||
|
||||
constructor(client: CommandClient) {
|
||||
this.client = client
|
||||
|
@ -96,7 +100,6 @@ export class CommandsManager {
|
|||
const cmd = this.find(name)
|
||||
if (cmd === undefined) return
|
||||
if (this.isDisabled(cmd) && bypassDisable !== true) return
|
||||
if (cmd.category !== undefined && this.isCategoryDisabled(cmd.category) && bypassDisable !== true) return
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
@ -121,7 +124,7 @@ export class CommandsManager {
|
|||
add(cmd: Command | typeof Command): boolean {
|
||||
// eslint-disable-next-line new-cap
|
||||
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)
|
||||
return true
|
||||
}
|
||||
|
@ -133,11 +136,6 @@ export class CommandsManager {
|
|||
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 */
|
||||
isDisabled(name: string | Command): boolean {
|
||||
const cmd = typeof name === "string" ? this.find(name) : name
|
||||
|
@ -155,18 +153,6 @@ export class CommandsManager {
|
|||
this.disabled.add(cmd.name)
|
||||
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 {
|
||||
|
|
|
@ -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 { Client, ClientOptions } from './client.ts'
|
||||
import { CommandContext, CommandsManager, parseCommand } from './command.ts'
|
||||
import { ExtensionsManager } from "./extensions.ts"
|
||||
|
||||
type PrefixReturnType = string | string[] | Promise<string | string[]>
|
||||
|
||||
|
@ -62,6 +64,7 @@ export class CommandClient extends Client implements CommandClientOptions {
|
|||
allowBots: boolean
|
||||
allowDMs: boolean
|
||||
caseSensitive: boolean
|
||||
extensions: ExtensionsManager = new ExtensionsManager(this)
|
||||
commands: CommandsManager = new CommandsManager(this)
|
||||
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'
|
||||
|
||||
const client = new CommandClient({
|
||||
|
@ -17,6 +20,29 @@ client.on('ready', () => {
|
|||
|
||||
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
|
||||
;(async() => {
|
||||
const files = Deno.readDirSync('./src/test/cmds')
|
||||
|
|
Loading…
Reference in a new issue