feat(extensions): the beginning

This commit is contained in:
DjDeveloperr 2020-11-11 14:34:49 +05:30
parent 9c9726259b
commit f6393c8226
5 changed files with 154 additions and 25 deletions

View file

@ -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)

View file

@ -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 {

View file

@ -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
View 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)
}
}

View file

@ -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')