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…
	
	Add table
		Add a link
		
	
		Reference in a new issue