Merge pull request #54 from DjDeveloperr/decorators
feat(decorators): added support for decorated events and commands
This commit is contained in:
		
						commit
						e403a62a0b
					
				
					 9 changed files with 304 additions and 48 deletions
				
			
		
							
								
								
									
										4
									
								
								mod.ts
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								mod.ts
									
										
									
									
									
								
							|  | @ -12,13 +12,13 @@ export { | ||||||
|   CommandsManager, |   CommandsManager, | ||||||
|   CategoriesManager |   CategoriesManager | ||||||
| } from './src/models/command.ts' | } from './src/models/command.ts' | ||||||
| export type { CommandContext } from './src/models/command.ts' | export type { CommandContext, CommandOptions } from './src/models/command.ts' | ||||||
| export { | export { | ||||||
|   Extension, |   Extension, | ||||||
|   ExtensionCommands, |   ExtensionCommands, | ||||||
|   ExtensionsManager |   ExtensionsManager | ||||||
| } from './src/models/extensions.ts' | } from './src/models/extensions.ts' | ||||||
| export { CommandClient } from './src/models/commandClient.ts' | export { CommandClient, command } from './src/models/commandClient.ts' | ||||||
| export type { CommandClientOptions } from './src/models/commandClient.ts' | export type { CommandClientOptions } from './src/models/commandClient.ts' | ||||||
| export { BaseManager } from './src/managers/base.ts' | export { BaseManager } from './src/managers/base.ts' | ||||||
| export { BaseChildManager } from './src/managers/baseChild.ts' | export { BaseChildManager } from './src/managers/baseChild.ts' | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ export const ready: GatewayEventHandler = async ( | ||||||
| ) => { | ) => { | ||||||
|   await gateway.client.guilds.flush() |   await gateway.client.guilds.flush() | ||||||
| 
 | 
 | ||||||
|  |   await gateway.client.users.set(d.user.id, d.user) | ||||||
|   gateway.client.user = new User(gateway.client, d.user) |   gateway.client.user = new User(gateway.client, d.user) | ||||||
|   gateway.sessionID = d.session_id |   gateway.sessionID = d.session_id | ||||||
|   gateway.debug(`Received READY. Session: ${gateway.sessionID}`) |   gateway.debug(`Received READY. Session: ${gateway.sessionID}`) | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ import { ClientPresence } from '../structures/presence.ts' | ||||||
| import { EmojisManager } from '../managers/emojis.ts' | import { EmojisManager } from '../managers/emojis.ts' | ||||||
| import { ActivityGame, ClientActivity } from '../types/presence.ts' | 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' | ||||||
| 
 | 
 | ||||||
| /** Some Client Options to modify behaviour */ | /** Some Client Options to modify behaviour */ | ||||||
| export interface ClientOptions { | export interface ClientOptions { | ||||||
|  | @ -70,6 +71,7 @@ export class Client extends EventEmitter { | ||||||
|   canary: boolean = false |   canary: boolean = false | ||||||
|   /** 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 } | ||||||
| 
 | 
 | ||||||
|   private readonly _untypedOn = this.on |   private readonly _untypedOn = this.on | ||||||
| 
 | 
 | ||||||
|  | @ -101,6 +103,16 @@ export class Client extends EventEmitter { | ||||||
|       this.reactionCacheLifetime = options.reactionCacheLifetime |       this.reactionCacheLifetime = options.reactionCacheLifetime | ||||||
|     if (options.fetchUncachedReactions === true) |     if (options.fetchUncachedReactions === true) | ||||||
|       this.fetchUncachedReactions = true |       this.fetchUncachedReactions = true | ||||||
|  | 
 | ||||||
|  |     if ( | ||||||
|  |       this._decoratedEvents !== undefined && | ||||||
|  |       Object.keys(this._decoratedEvents).length !== 0 | ||||||
|  |     ) { | ||||||
|  |       Object.entries(this._decoratedEvents).forEach((entry) => { | ||||||
|  |         this.on(entry[0], entry[1]) | ||||||
|  |       }) | ||||||
|  |       this._decoratedEvents = undefined | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|  | @ -153,3 +165,13 @@ export class Client extends EventEmitter { | ||||||
|     this.gateway = new Gateway(this, token, intents) |     this.gateway = new Gateway(this, token, intents) | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | export function event(name?: string) { | ||||||
|  |   return function (client: Client | Extension, prop: string) { | ||||||
|  |     const listener = ((client as unknown) as { | ||||||
|  |       [name: string]: (...args: any[]) => any | ||||||
|  |     })[prop] | ||||||
|  |     if (client._decoratedEvents === undefined) client._decoratedEvents = {} | ||||||
|  |     client._decoratedEvents[name === undefined ? prop : name] = listener | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ 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' | import { Extension } from './extensions.ts' | ||||||
|  | import { parse } from 'https://deno.land/x/mutil@0.1.2/mod.ts' | ||||||
| 
 | 
 | ||||||
| export interface CommandContext { | export interface CommandContext { | ||||||
|   /** The Client object */ |   /** The Client object */ | ||||||
|  | @ -29,9 +30,9 @@ export interface CommandContext { | ||||||
|   guild?: Guild |   guild?: Guild | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class Command { | export interface CommandOptions { | ||||||
|   /** Name of the Command */ |   /** Name of the Command */ | ||||||
|   name: string = '' |   name?: string | ||||||
|   /** Description of the Command */ |   /** Description of the Command */ | ||||||
|   description?: string |   description?: string | ||||||
|   /** Category of the Command */ |   /** Category of the Command */ | ||||||
|  | @ -60,12 +61,36 @@ export class Command { | ||||||
|   whitelistedChannels?: string | string[] |   whitelistedChannels?: string | string[] | ||||||
|   /** Whitelisted Users. Command can be executed only by these Users (List or one of IDs) */ |   /** Whitelisted Users. Command can be executed only by these Users (List or one of IDs) */ | ||||||
|   whitelistedUsers?: string | string[] |   whitelistedUsers?: string | string[] | ||||||
|  |   /** Whether the Command can only be used in NSFW channel or not */ | ||||||
|  |   nsfw?: boolean | ||||||
|   /** Whether the Command can only be used in Guild (if allowed in DMs) */ |   /** Whether the Command can only be used in Guild (if allowed in DMs) */ | ||||||
|   guildOnly?: boolean |   guildOnly?: boolean | ||||||
|   /** Whether the Command can only be used in Bot's DMs (if allowed) */ |   /** Whether the Command can only be used in Bot's DMs (if allowed) */ | ||||||
|   dmOnly?: boolean |   dmOnly?: boolean | ||||||
|   /** Whether the Command can only be used by Bot Owners */ |   /** Whether the Command can only be used by Bot Owners */ | ||||||
|   ownerOnly?: boolean |   ownerOnly?: boolean | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export class Command implements CommandOptions { | ||||||
|  |   name: string = '' | ||||||
|  |   description?: string | ||||||
|  |   category?: string | ||||||
|  |   aliases?: string | string[] | ||||||
|  |   extension?: Extension | ||||||
|  |   usage?: string | string[] | ||||||
|  |   examples?: string | string[] | ||||||
|  |   args?: number | boolean | string[] | ||||||
|  |   permissions?: string | string[] | ||||||
|  |   userPermissions?: string | string[] | ||||||
|  |   botPermissions?: string | string[] | ||||||
|  |   roles?: string | string[] | ||||||
|  |   whitelistedGuilds?: string | string[] | ||||||
|  |   whitelistedChannels?: string | string[] | ||||||
|  |   whitelistedUsers?: string | string[] | ||||||
|  |   nsfw?: boolean | ||||||
|  |   guildOnly?: boolean | ||||||
|  |   dmOnly?: boolean | ||||||
|  |   ownerOnly?: boolean | ||||||
| 
 | 
 | ||||||
|   /** Method executed before executing actual command. Returns bool value - whether to continue or not (optional) */ |   /** Method executed before executing actual command. Returns bool value - whether to continue or not (optional) */ | ||||||
|   beforeExecute(ctx: CommandContext): boolean | Promise<boolean> { |   beforeExecute(ctx: CommandContext): boolean | Promise<boolean> { | ||||||
|  | @ -79,7 +104,7 @@ export class Command { | ||||||
| 
 | 
 | ||||||
|   toString(): string { |   toString(): string { | ||||||
|     return `Command: ${this.name}${ |     return `Command: ${this.name}${ | ||||||
|       this.extension !== undefined |       this.extension !== undefined && this.extension.name !== '' | ||||||
|         ? ` [${this.extension.name}]` |         ? ` [${this.extension.name}]` | ||||||
|         : this.category !== undefined |         : this.category !== undefined | ||||||
|         ? ` [${this.category}]` |         ? ` [${this.category}]` | ||||||
|  | @ -231,6 +256,11 @@ export class CommandBuilder extends Command { | ||||||
|     return this |     return this | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   setNSFW(value: boolean = true): CommandBuilder { | ||||||
|  |     this.nsfw = value | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   setOwnerOnly(value: boolean = true): CommandBuilder { |   setOwnerOnly(value: boolean = true): CommandBuilder { | ||||||
|     this.ownerOnly = value |     this.ownerOnly = value | ||||||
|     return this |     return this | ||||||
|  | @ -268,38 +298,86 @@ export class CommandsManager { | ||||||
|     return this.list.size |     return this.list.size | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Find a Command by name/alias */ |   /** Filter out Commands by name/alias */ | ||||||
|   find(search: string): Command | undefined { |   filter(search: string, subPrefix?: string): Collection<string, Command> { | ||||||
|     if (this.client.caseSensitive === false) search = search.toLowerCase() |     if (this.client.caseSensitive === false) search = search.toLowerCase() | ||||||
|     return this.list.find((cmd: Command): boolean => { |     return this.list.filter((cmd: Command): boolean => { | ||||||
|  |       if (subPrefix !== undefined) { | ||||||
|  |         if ( | ||||||
|  |           this.client.caseSensitive === true | ||||||
|  |             ? subPrefix !== cmd.extension?.subPrefix | ||||||
|  |             : subPrefix.toLowerCase() !== | ||||||
|  |               cmd.extension?.subPrefix?.toLowerCase() | ||||||
|  |         ) { | ||||||
|  |           return false | ||||||
|  |         } | ||||||
|  |       } else if ( | ||||||
|  |         subPrefix === undefined && | ||||||
|  |         cmd.extension?.subPrefix !== undefined | ||||||
|  |       ) { | ||||||
|  |         return false | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|       const name = |       const name = | ||||||
|         this.client.caseSensitive === true ? cmd.name : cmd.name.toLowerCase() |         this.client.caseSensitive === true ? cmd.name : cmd.name.toLowerCase() | ||||||
|       if (name === search) return true |       if (name === search) { | ||||||
|       else if (cmd.aliases !== undefined) { |         return true | ||||||
|  |       } else if (cmd.aliases !== undefined) { | ||||||
|         let aliases: string[] |         let aliases: string[] | ||||||
|         if (typeof cmd.aliases === 'string') aliases = [cmd.aliases] |         if (typeof cmd.aliases === 'string') aliases = [cmd.aliases] | ||||||
|         else aliases = cmd.aliases |         else aliases = cmd.aliases | ||||||
|         if (this.client.caseSensitive === false) |         if (this.client.caseSensitive === false) | ||||||
|           aliases = aliases.map((e) => e.toLowerCase()) |           aliases = aliases.map((e) => e.toLowerCase()) | ||||||
|  | 
 | ||||||
|         return aliases.includes(search) |         return aliases.includes(search) | ||||||
|       } else return false |       } else { | ||||||
|  |         return false | ||||||
|  |       } | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Fetch a Command including disable checks */ |   /** Find a Command by name/alias */ | ||||||
|   fetch(name: string, bypassDisable?: boolean): Command | undefined { |   find(search: string, subPrefix?: string): Command | undefined { | ||||||
|     const cmd = this.find(name) |     const filtered = this.filter(search, subPrefix) | ||||||
|  |     return filtered.first() | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** Fetch a Command including disable checks and subPrefix implementation */ | ||||||
|  |   fetch(parsed: ParsedCommand, bypassDisable?: boolean): Command | undefined { | ||||||
|  |     let cmd = this.find(parsed.name) | ||||||
|  |     if (cmd?.extension?.subPrefix !== undefined) cmd = undefined | ||||||
|  | 
 | ||||||
|  |     if (cmd === undefined && parsed.args.length > 0) { | ||||||
|  |       cmd = this.find(parsed.args[0], parsed.name) | ||||||
|  |       if (cmd === undefined || cmd.extension?.subPrefix === undefined) return | ||||||
|  |       if ( | ||||||
|  |         this.client.caseSensitive === true | ||||||
|  |           ? cmd.extension.subPrefix !== parsed.name | ||||||
|  |           : cmd.extension.subPrefix.toLowerCase() !== parsed.name.toLowerCase() | ||||||
|  |       ) | ||||||
|  |         return | ||||||
|  | 
 | ||||||
|  |       parsed.args.shift() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     if (cmd === undefined) return |     if (cmd === undefined) return | ||||||
|     if (this.isDisabled(cmd) && bypassDisable !== true) return |     if (this.isDisabled(cmd) && bypassDisable !== true) return | ||||||
|     return cmd |     return cmd | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Check whether a Command exists or not */ |   /** Check whether a Command exists or not */ | ||||||
|   exists(search: Command | string): boolean { |   exists(search: Command | string, subPrefix?: string): boolean { | ||||||
|     let exists = false |     let exists = false | ||||||
|     if (typeof search === 'string') return this.find(search) !== undefined | 
 | ||||||
|  |     if (typeof search === 'string') | ||||||
|  |       return this.find(search, subPrefix) !== undefined | ||||||
|     else { |     else { | ||||||
|       exists = this.find(search.name) !== undefined |       exists = | ||||||
|  |         this.find( | ||||||
|  |           search.name, | ||||||
|  |           subPrefix === undefined ? search.extension?.subPrefix : subPrefix | ||||||
|  |         ) !== undefined | ||||||
|  | 
 | ||||||
|       if (search.aliases !== undefined) { |       if (search.aliases !== undefined) { | ||||||
|         const aliases: string[] = |         const aliases: string[] = | ||||||
|           typeof search.aliases === 'string' ? [search.aliases] : search.aliases |           typeof search.aliases === 'string' ? [search.aliases] : search.aliases | ||||||
|  | @ -308,6 +386,7 @@ export class CommandsManager { | ||||||
|             .map((alias) => this.find(alias) !== undefined) |             .map((alias) => this.find(alias) !== undefined) | ||||||
|             .find((e) => e) ?? false |             .find((e) => e) ?? false | ||||||
|       } |       } | ||||||
|  | 
 | ||||||
|       return exists |       return exists | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | @ -316,11 +395,20 @@ 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)) |     if (this.exists(cmd, cmd.extension?.subPrefix)) | ||||||
|       throw new Error( |       throw new Error( | ||||||
|         `Failed to add Command '${cmd.toString()}' with name/alias already exists.` |         `Failed to add Command '${cmd.toString()}' with name/alias already exists.` | ||||||
|       ) |       ) | ||||||
|     this.list.set(cmd.name, cmd) |     this.list.set( | ||||||
|  |       `${cmd.name}-${ | ||||||
|  |         this.list.filter((e) => | ||||||
|  |           this.client.caseSensitive === true | ||||||
|  |             ? e.name === cmd.name | ||||||
|  |             : e.name.toLowerCase() === cmd.name.toLowerCase() | ||||||
|  |         ).size | ||||||
|  |       }`,
 | ||||||
|  |       cmd | ||||||
|  |     ) | ||||||
|     return true |     return true | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -418,7 +506,8 @@ export const parseCommand = ( | ||||||
| ): ParsedCommand => { | ): ParsedCommand => { | ||||||
|   let content = msg.content.slice(prefix.length) |   let content = msg.content.slice(prefix.length) | ||||||
|   if (client.spacesAfterPrefix === true) content = content.trim() |   if (client.spacesAfterPrefix === true) content = content.trim() | ||||||
|   const args = content.split(client.betterArgs === true ? /[\S\s]*/ : / +/) |   const args = parse(content)._.map((e) => e.toString()) | ||||||
|  | 
 | ||||||
|   const name = args.shift() as string |   const name = args.shift() as string | ||||||
|   const argString = content.slice(name.length).trim() |   const argString = content.slice(name.length).trim() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,13 +1,16 @@ | ||||||
| import { Message } from '../structures/message.ts' | import { Message } from '../structures/message.ts' | ||||||
|  | import { GuildTextChannel } from '../structures/textChannel.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 { | import { | ||||||
|   CategoriesManager, |   CategoriesManager, | ||||||
|  |   Command, | ||||||
|   CommandContext, |   CommandContext, | ||||||
|  |   CommandOptions, | ||||||
|   CommandsManager, |   CommandsManager, | ||||||
|   parseCommand |   parseCommand | ||||||
| } from './command.ts' | } from './command.ts' | ||||||
| import { ExtensionsManager } from './extensions.ts' | import { Extension, ExtensionsManager } from './extensions.ts' | ||||||
| 
 | 
 | ||||||
| type PrefixReturnType = string | string[] | Promise<string | string[]> | type PrefixReturnType = string | string[] | Promise<string | string[]> | ||||||
| 
 | 
 | ||||||
|  | @ -21,6 +24,8 @@ export interface CommandClientOptions extends ClientOptions { | ||||||
|   getGuildPrefix?: (guildID: string) => PrefixReturnType |   getGuildPrefix?: (guildID: string) => PrefixReturnType | ||||||
|   /** Method to get a User's custom prefix(s). */ |   /** Method to get a User's custom prefix(s). */ | ||||||
|   getUserPrefix?: (userID: string) => PrefixReturnType |   getUserPrefix?: (userID: string) => PrefixReturnType | ||||||
|  |   /** Method to get a Channel's custom prefix(s). */ | ||||||
|  |   getChannelPrefix?: (channelID: string) => PrefixReturnType | ||||||
|   /** Method to check if certain Guild is blacklisted from using Commands. */ |   /** Method to check if certain Guild is blacklisted from using Commands. */ | ||||||
|   isGuildBlacklisted?: (guildID: string) => boolean | Promise<boolean> |   isGuildBlacklisted?: (guildID: string) => boolean | Promise<boolean> | ||||||
|   /** Method to check if certain User is blacklisted from using Commands. */ |   /** Method to check if certain User is blacklisted from using Commands. */ | ||||||
|  | @ -29,8 +34,6 @@ export interface CommandClientOptions extends ClientOptions { | ||||||
|   isChannelBlacklisted?: (guildID: string) => boolean | Promise<boolean> |   isChannelBlacklisted?: (guildID: string) => boolean | Promise<boolean> | ||||||
|   /** Allow spaces after prefix? Recommended with Mention Prefix ON. */ |   /** Allow spaces after prefix? Recommended with Mention Prefix ON. */ | ||||||
|   spacesAfterPrefix?: boolean |   spacesAfterPrefix?: boolean | ||||||
|   /** Better Arguments regex to split at every whitespace. */ |  | ||||||
|   betterArgs?: boolean |  | ||||||
|   /** List of Bot's Owner IDs whom can access `ownerOnly` commands. */ |   /** List of Bot's Owner IDs whom can access `ownerOnly` commands. */ | ||||||
|   owners?: string[] |   owners?: string[] | ||||||
|   /** Whether to allow Bots to use Commands or not, not allowed by default. */ |   /** Whether to allow Bots to use Commands or not, not allowed by default. */ | ||||||
|  | @ -44,26 +47,33 @@ export interface CommandClientOptions extends ClientOptions { | ||||||
| export class CommandClient extends Client implements CommandClientOptions { | export class CommandClient extends Client implements CommandClientOptions { | ||||||
|   prefix: string | string[] |   prefix: string | string[] | ||||||
|   mentionPrefix: boolean |   mentionPrefix: boolean | ||||||
|  | 
 | ||||||
|   getGuildPrefix: (guildID: string) => PrefixReturnType |   getGuildPrefix: (guildID: string) => PrefixReturnType | ||||||
|   getUserPrefix: (userID: string) => PrefixReturnType |   getUserPrefix: (userID: string) => PrefixReturnType | ||||||
|  |   getChannelPrefix: (channelID: string) => PrefixReturnType | ||||||
|  | 
 | ||||||
|   isGuildBlacklisted: (guildID: string) => boolean | Promise<boolean> |   isGuildBlacklisted: (guildID: string) => boolean | Promise<boolean> | ||||||
|   isUserBlacklisted: (guildID: string) => boolean | Promise<boolean> |   isUserBlacklisted: (guildID: string) => boolean | Promise<boolean> | ||||||
|   isChannelBlacklisted: (guildID: string) => boolean | Promise<boolean> |   isChannelBlacklisted: (guildID: string) => boolean | Promise<boolean> | ||||||
|  | 
 | ||||||
|   spacesAfterPrefix: boolean |   spacesAfterPrefix: boolean | ||||||
|   betterArgs: boolean |  | ||||||
|   owners: string[] |   owners: string[] | ||||||
|   allowBots: boolean |   allowBots: boolean | ||||||
|   allowDMs: boolean |   allowDMs: boolean | ||||||
|   caseSensitive: boolean |   caseSensitive: boolean | ||||||
|  | 
 | ||||||
|   extensions: ExtensionsManager = new ExtensionsManager(this) |   extensions: ExtensionsManager = new ExtensionsManager(this) | ||||||
|   commands: CommandsManager = new CommandsManager(this) |   commands: CommandsManager = new CommandsManager(this) | ||||||
|   categories: CategoriesManager = new CategoriesManager(this) |   categories: CategoriesManager = new CategoriesManager(this) | ||||||
| 
 | 
 | ||||||
|  |   _decoratedCommands?: { [name: string]: Command } | ||||||
|  | 
 | ||||||
|   constructor(options: CommandClientOptions) { |   constructor(options: CommandClientOptions) { | ||||||
|     super(options) |     super(options) | ||||||
|     this.prefix = options.prefix |     this.prefix = options.prefix | ||||||
|     this.mentionPrefix = |     this.mentionPrefix = | ||||||
|       options.mentionPrefix === undefined ? false : options.mentionPrefix |       options.mentionPrefix === undefined ? false : options.mentionPrefix | ||||||
|  | 
 | ||||||
|     this.getGuildPrefix = |     this.getGuildPrefix = | ||||||
|       options.getGuildPrefix === undefined |       options.getGuildPrefix === undefined | ||||||
|         ? (id: string) => this.prefix |         ? (id: string) => this.prefix | ||||||
|  | @ -72,6 +82,12 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|       options.getUserPrefix === undefined |       options.getUserPrefix === undefined | ||||||
|         ? (id: string) => this.prefix |         ? (id: string) => this.prefix | ||||||
|         : options.getUserPrefix |         : options.getUserPrefix | ||||||
|  | 
 | ||||||
|  |     this.getChannelPrefix = | ||||||
|  |       options.getChannelPrefix === undefined | ||||||
|  |         ? (id: string) => this.prefix | ||||||
|  |         : options.getChannelPrefix | ||||||
|  | 
 | ||||||
|     this.isUserBlacklisted = |     this.isUserBlacklisted = | ||||||
|       options.isUserBlacklisted === undefined |       options.isUserBlacklisted === undefined | ||||||
|         ? (id: string) => false |         ? (id: string) => false | ||||||
|  | @ -84,18 +100,25 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|       options.isChannelBlacklisted === undefined |       options.isChannelBlacklisted === undefined | ||||||
|         ? (id: string) => false |         ? (id: string) => false | ||||||
|         : options.isChannelBlacklisted |         : options.isChannelBlacklisted | ||||||
|  | 
 | ||||||
|     this.spacesAfterPrefix = |     this.spacesAfterPrefix = | ||||||
|       options.spacesAfterPrefix === undefined |       options.spacesAfterPrefix === undefined | ||||||
|         ? false |         ? false | ||||||
|         : options.spacesAfterPrefix |         : options.spacesAfterPrefix | ||||||
|     this.betterArgs = | 
 | ||||||
|       options.betterArgs === undefined ? false : options.betterArgs |  | ||||||
|     this.owners = options.owners === undefined ? [] : options.owners |     this.owners = options.owners === undefined ? [] : options.owners | ||||||
|     this.allowBots = options.allowBots === undefined ? false : options.allowBots |     this.allowBots = options.allowBots === undefined ? false : options.allowBots | ||||||
|     this.allowDMs = options.allowDMs === undefined ? true : options.allowDMs |     this.allowDMs = options.allowDMs === undefined ? true : options.allowDMs | ||||||
|     this.caseSensitive = |     this.caseSensitive = | ||||||
|       options.caseSensitive === undefined ? false : options.caseSensitive |       options.caseSensitive === undefined ? false : options.caseSensitive | ||||||
| 
 | 
 | ||||||
|  |     if (this._decoratedCommands !== undefined) { | ||||||
|  |       Object.values(this._decoratedCommands).forEach((entry) => { | ||||||
|  |         this.commands.add(entry) | ||||||
|  |       }) | ||||||
|  |       this._decoratedCommands = undefined | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     this.on( |     this.on( | ||||||
|       'messageCreate', |       'messageCreate', | ||||||
|       async (msg: Message) => await this.processMessage(msg) |       async (msg: Message) => await this.processMessage(msg) | ||||||
|  | @ -123,43 +146,48 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|       if (isGuildBlacklisted === true) return |       if (isGuildBlacklisted === true) return | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     let prefix: string | string[] = await awaitSync( |     let prefix: string | string[] = [] | ||||||
|       this.getUserPrefix(msg.author.id) |     if (typeof this.prefix === 'string') prefix = [...prefix, this.prefix] | ||||||
|     ) |     else prefix = [...prefix, ...this.prefix] | ||||||
|  | 
 | ||||||
|  |     const userPrefix = await awaitSync(this.getUserPrefix(msg.author.id)) | ||||||
|  |     if (userPrefix !== undefined) { | ||||||
|  |       if (typeof userPrefix === 'string') prefix = [...prefix, userPrefix] | ||||||
|  |       else prefix = [...prefix, ...userPrefix] | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     if (msg.guild !== undefined) { |     if (msg.guild !== undefined) { | ||||||
|       prefix = await awaitSync(this.getGuildPrefix(msg.guild.id)) |       const guildPrefix = await awaitSync(this.getGuildPrefix(msg.guild.id)) | ||||||
|  |       if (guildPrefix !== undefined) { | ||||||
|  |         if (typeof guildPrefix === 'string') prefix = [...prefix, guildPrefix] | ||||||
|  |         else prefix = [...prefix, ...guildPrefix] | ||||||
|  |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     prefix = [...new Set(prefix)] | ||||||
|  | 
 | ||||||
|     let mentionPrefix = false |     let mentionPrefix = false | ||||||
| 
 | 
 | ||||||
|     if (typeof prefix === 'string') { |     let usedPrefix = prefix | ||||||
|       if (msg.content.startsWith(prefix) === false) { |       .filter((v) => msg.content.startsWith(v)) | ||||||
|         if (this.mentionPrefix) mentionPrefix = true |       .sort((b, a) => a.length - b.length)[0] | ||||||
|         else return |     if (usedPrefix === undefined && this.mentionPrefix) mentionPrefix = true | ||||||
|       } |  | ||||||
|     } else { |  | ||||||
|       const usedPrefix = prefix.find((v) => msg.content.startsWith(v)) |  | ||||||
|       if (usedPrefix === undefined) { |  | ||||||
|         if (this.mentionPrefix) mentionPrefix = true |  | ||||||
|         else return |  | ||||||
|       } else prefix = usedPrefix |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     if (mentionPrefix) { |     if (mentionPrefix) { | ||||||
|       if (msg.content.startsWith(this.user?.mention as string) === true) |       if (msg.content.startsWith(this.user?.mention as string) === true) | ||||||
|         prefix = this.user?.mention as string |         usedPrefix = this.user?.mention as string | ||||||
|       else if ( |       else if ( | ||||||
|         msg.content.startsWith(this.user?.nickMention as string) === true |         msg.content.startsWith(this.user?.nickMention as string) === true | ||||||
|       ) |       ) | ||||||
|         prefix = this.user?.nickMention as string |         usedPrefix = this.user?.nickMention as string | ||||||
|       else return |       else return | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (typeof prefix !== 'string') return |     if (typeof usedPrefix !== 'string') return | ||||||
|  |     prefix = usedPrefix | ||||||
| 
 | 
 | ||||||
|     const parsed = parseCommand(this, msg, prefix) |     const parsed = parseCommand(this, msg, prefix) | ||||||
|     const command = this.commands.find(parsed.name) |     const command = this.commands.fetch(parsed) | ||||||
| 
 | 
 | ||||||
|     if (command === undefined) return |     if (command === undefined) return | ||||||
|     const category = |     const category = | ||||||
|  | @ -250,6 +278,13 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|     ) |     ) | ||||||
|       return this.emit('commandDmOnly', ctx, command) |       return this.emit('commandDmOnly', ctx, command) | ||||||
| 
 | 
 | ||||||
|  |     if ( | ||||||
|  |       command.nsfw === true && | ||||||
|  |       (msg.guild === undefined || | ||||||
|  |         ((msg.channel as unknown) as GuildTextChannel).nsfw !== true) | ||||||
|  |     ) | ||||||
|  |       return this.emit('commandNSFW', ctx, command) | ||||||
|  | 
 | ||||||
|     const allPermissions = |     const allPermissions = | ||||||
|       command.permissions !== undefined |       command.permissions !== undefined | ||||||
|         ? command.permissions |         ? command.permissions | ||||||
|  | @ -345,3 +380,21 @@ export class CommandClient extends Client implements CommandClientOptions { | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | export function command(options?: CommandOptions) { | ||||||
|  |   return function (target: CommandClient | Extension, name: string) { | ||||||
|  |     const command = new Command() | ||||||
|  | 
 | ||||||
|  |     command.name = name | ||||||
|  |     command.execute = ((target as unknown) as { | ||||||
|  |       [name: string]: (ctx: CommandContext) => any | ||||||
|  |     })[name] | ||||||
|  | 
 | ||||||
|  |     if (options !== undefined) Object.assign(command, options) | ||||||
|  | 
 | ||||||
|  |     if (target instanceof Extension) command.extension = target | ||||||
|  | 
 | ||||||
|  |     if (target._decoratedCommands === undefined) target._decoratedCommands = {} | ||||||
|  |     target._decoratedCommands[command.name] = command | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -67,11 +67,33 @@ export class Extension { | ||||||
|   description?: string |   description?: string | ||||||
|   /** Extensions's Commands Manager */ |   /** Extensions's Commands Manager */ | ||||||
|   commands: ExtensionCommands = new ExtensionCommands(this) |   commands: ExtensionCommands = new ExtensionCommands(this) | ||||||
|  |   /** Sub-Prefix to be used for ALL of Extenion's Commands. */ | ||||||
|  |   subPrefix?: string | ||||||
|   /** Events registered by this Extension */ |   /** Events registered by this Extension */ | ||||||
|   events: { [name: string]: (...args: any[]) => {} } = {} |   events: { [name: string]: (...args: any[]) => {} } = {} | ||||||
| 
 | 
 | ||||||
|  |   _decoratedCommands?: { [name: string]: Command } | ||||||
|  |   _decoratedEvents?: { [name: string]: (...args: any[]) => any } | ||||||
|  | 
 | ||||||
|   constructor(client: CommandClient) { |   constructor(client: CommandClient) { | ||||||
|     this.client = client |     this.client = client | ||||||
|  |     if (this._decoratedCommands !== undefined) { | ||||||
|  |       Object.entries(this._decoratedCommands).forEach((entry) => { | ||||||
|  |         entry[1].extension = this | ||||||
|  |         this.commands.add(entry[1]) | ||||||
|  |       }) | ||||||
|  |       this._decoratedCommands = undefined | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if ( | ||||||
|  |       this._decoratedEvents !== undefined && | ||||||
|  |       Object.keys(this._decoratedEvents).length !== 0 | ||||||
|  |     ) { | ||||||
|  |       Object.entries(this._decoratedEvents).forEach((entry) => { | ||||||
|  |         this.listen(entry[0], entry[1]) | ||||||
|  |       }) | ||||||
|  |       this._decoratedEvents = undefined | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Listens for an Event through Extension. */ |   /** Listens for an Event through Extension. */ | ||||||
|  |  | ||||||
|  | @ -42,7 +42,7 @@ export class VoiceChannel extends Channel { | ||||||
|         if (state.channel?.id !== this.id) return |         if (state.channel?.id !== this.id) return | ||||||
|         this.client.removeListener('voiceStateAdd', onVoiceStateAdd) |         this.client.removeListener('voiceStateAdd', onVoiceStateAdd) | ||||||
|         done++ |         done++ | ||||||
|         if (done >= 2) resolve(vcdata) |         if (done >= 2) resolve((vcdata as unknown) as VoiceServerUpdateData) | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       const onVoiceServerUpdate = (data: VoiceServerUpdateData): void => { |       const onVoiceServerUpdate = (data: VoiceServerUpdateData): void => { | ||||||
|  |  | ||||||
|  | @ -1,7 +1,6 @@ | ||||||
| import { Base } from './base.ts' | import { Base } from './base.ts' | ||||||
| import { | import { | ||||||
|   Attachment, |   Attachment, | ||||||
|   ChannelMention, |  | ||||||
|   MessageActivity, |   MessageActivity, | ||||||
|   MessageApplication, |   MessageApplication, | ||||||
|   MessageOption, |   MessageOption, | ||||||
|  |  | ||||||
							
								
								
									
										70
									
								
								src/test/class.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/test/class.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | ||||||
|  | import { | ||||||
|  |   CommandClient, | ||||||
|  |   event, | ||||||
|  |   Intents, | ||||||
|  |   command, | ||||||
|  |   CommandContext, | ||||||
|  |   Extension, | ||||||
|  |   CommandBuilder | ||||||
|  | } from '../../mod.ts' | ||||||
|  | import { TOKEN } from './config.ts' | ||||||
|  | 
 | ||||||
|  | class MyClient extends CommandClient { | ||||||
|  |   constructor() { | ||||||
|  |     super({ | ||||||
|  |       prefix: ['!', '!!'], | ||||||
|  |       caseSensitive: false | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @event() | ||||||
|  |   ready(): void { | ||||||
|  |     console.log(`Logged in as ${this.user?.tag}!`) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @command({ aliases: 'pong' }) | ||||||
|  |   Ping(ctx: CommandContext): void { | ||||||
|  |     ctx.message.reply('Pong!') | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class VCExtension extends Extension { | ||||||
|  |   name = 'VC' | ||||||
|  |   subPrefix = 'vc' | ||||||
|  | 
 | ||||||
|  |   @command() | ||||||
|  |   async join(ctx: CommandContext): Promise<void> { | ||||||
|  |     const userVS = await ctx.guild?.voiceStates.get(ctx.author.id) | ||||||
|  |     if (userVS === undefined) { | ||||||
|  |       ctx.message.reply("You're not in VC.") | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  |     await userVS.channel?.join() | ||||||
|  |     ctx.message.reply(`Joined VC channel - ${userVS.channel?.name}!`) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @command() | ||||||
|  |   async leave(ctx: CommandContext): Promise<void> { | ||||||
|  |     const userVS = await ctx.guild?.voiceStates.get( | ||||||
|  |       (ctx.client.user?.id as unknown) as string | ||||||
|  |     ) | ||||||
|  |     if (userVS === undefined) { | ||||||
|  |       ctx.message.reply("I'm not in VC.") | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  |     userVS.channel?.leave() | ||||||
|  |     ctx.message.reply(`Left VC channel - ${userVS.channel?.name}!`) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const client = new MyClient() | ||||||
|  | 
 | ||||||
|  | client.extensions.load(VCExtension) | ||||||
|  | 
 | ||||||
|  | client.commands.add( | ||||||
|  |   new CommandBuilder() | ||||||
|  |     .setName('join') | ||||||
|  |     .onExecute((ctx) => ctx.message.reply('haha')) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | client.connect(TOKEN, Intents.All) | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue