mirror of
				https://github.com/keanuplayz/TravBot-v3.git
				synced 2024-08-15 02:33:12 +00:00 
			
		
		
		
	Tried experimental porting of command types from CrossExchange
This commit is contained in:
		
							parent
							
								
									df3e4e8e6e
								
							
						
					
					
						commit
						0d0d134415
					
				
					 3 changed files with 175 additions and 57 deletions
				
			
		|  | @ -1,4 +1,4 @@ | ||||||
| import Command from "../../core/command"; | import Command, {TYPES} from "../../core/command"; | ||||||
| import {toTitleCase} from "../../core/lib"; | import {toTitleCase} from "../../core/lib"; | ||||||
| import {loadableCommands, categories} from "../../core/command"; | import {loadableCommands, categories} from "../../core/command"; | ||||||
| import {getPermissionName} from "../../core/permissions"; | import {getPermissionName} from "../../core/permissions"; | ||||||
|  | @ -68,16 +68,16 @@ export default new Command({ | ||||||
|                 if (permLevel === -1) permLevel = command.permission; |                 if (permLevel === -1) permLevel = command.permission; | ||||||
| 
 | 
 | ||||||
|                 switch (type) { |                 switch (type) { | ||||||
|                     case Command.TYPES.SUBCOMMAND: |                     case TYPES.SUBCOMMAND: | ||||||
|                         header += ` ${command.originalCommandName}`; |                         header += ` ${command.originalCommandName}`; | ||||||
|                         break; |                         break; | ||||||
|                     case Command.TYPES.USER: |                     case TYPES.USER: | ||||||
|                         header += " <user>"; |                         header += " <user>"; | ||||||
|                         break; |                         break; | ||||||
|                     case Command.TYPES.NUMBER: |                     case TYPES.NUMBER: | ||||||
|                         header += " <number>"; |                         header += " <number>"; | ||||||
|                         break; |                         break; | ||||||
|                     case Command.TYPES.ANY: |                     case TYPES.ANY: | ||||||
|                         header += " <any>"; |                         header += " <any>"; | ||||||
|                         break; |                         break; | ||||||
|                     default: |                     default: | ||||||
|  | @ -85,7 +85,7 @@ export default new Command({ | ||||||
|                         break; |                         break; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (type === Command.TYPES.NONE) { |                 if (type === TYPES.NONE) { | ||||||
|                     invalid = true; |                     invalid = true; | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,5 @@ | ||||||
| import {parseVars} from "./lib"; | import {parseVars} from "./lib"; | ||||||
| import {Collection} from "discord.js"; | import {Collection, Client, Message, TextChannel, DMChannel, NewsChannel, Guild, User, GuildMember} from "discord.js"; | ||||||
| import {Client, Message, TextChannel, DMChannel, NewsChannel, Guild, User, GuildMember} from "discord.js"; |  | ||||||
| import {getPrefix} from "../core/structures"; | import {getPrefix} from "../core/structures"; | ||||||
| import glob from "glob"; | import glob from "glob"; | ||||||
| 
 | 
 | ||||||
|  | @ -22,17 +21,27 @@ interface CommandOptions { | ||||||
|     aliases?: string[]; |     aliases?: string[]; | ||||||
|     run?: (($: CommandMenu) => Promise<any>) | string; |     run?: (($: CommandMenu) => Promise<any>) | string; | ||||||
|     subcommands?: {[key: string]: Command}; |     subcommands?: {[key: string]: Command}; | ||||||
|  |     channel?: Command; | ||||||
|  |     role?: Command; | ||||||
|  |     emote?: Command; | ||||||
|  |     message?: Command; | ||||||
|     user?: Command; |     user?: Command; | ||||||
|  |     id?: "channel" | "role" | "emote" | "message" | "user"; | ||||||
|     number?: Command; |     number?: Command; | ||||||
|     any?: Command; |     any?: Command; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export enum TYPES { | export enum TYPES { | ||||||
|     SUBCOMMAND, |     SUBCOMMAND, // Any specifically-defined keywords / string literals.
 | ||||||
|     USER, |     CHANNEL, // <#...>
 | ||||||
|     NUMBER, |     ROLE, // <@&...>
 | ||||||
|     ANY, |     EMOTE, // <::ID> (The previous two values, animated and emote name respectively, do not matter at all for finding the emote.)
 | ||||||
|     NONE |     MESSAGE, // Available by using the built-in "Copy Message Link" or "Copy ID" buttons. https://discordapp.com/channels/<Guild ID>/<Channel ID>/<Message ID> or <Channel ID>-<Message ID> (automatically searches all guilds for the channel ID).
 | ||||||
|  |     USER, // <@...> and <@!...>
 | ||||||
|  |     ID, // Any number with 17-19 digits. Only used as a redirect to another subcommand type.
 | ||||||
|  |     NUMBER, // Any valid number via the Number() function, except for NaN and Infinity (because those can really mess with the program).
 | ||||||
|  |     ANY, // Generic argument case.
 | ||||||
|  |     NONE // No subcommands exist.
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export default class Command { | export default class Command { | ||||||
|  | @ -44,10 +53,14 @@ export default class Command { | ||||||
|     public originalCommandName: string | null; // If the command is an alias, what's the original name?
 |     public originalCommandName: string | null; // If the command is an alias, what's the original name?
 | ||||||
|     public run: (($: CommandMenu) => Promise<any>) | string; |     public run: (($: CommandMenu) => Promise<any>) | string; | ||||||
|     public readonly subcommands: Collection<string, Command>; // This is the final data structure you'll actually use to work with the commands the aliases point to.
 |     public readonly subcommands: Collection<string, Command>; // This is the final data structure you'll actually use to work with the commands the aliases point to.
 | ||||||
|  |     public channel: Command | null; | ||||||
|  |     public role: Command | null; | ||||||
|  |     public emote: Command | null; | ||||||
|  |     public message: Command | null; | ||||||
|     public user: Command | null; |     public user: Command | null; | ||||||
|  |     public id: Command | null; | ||||||
|     public number: Command | null; |     public number: Command | null; | ||||||
|     public any: Command | null; |     public any: Command | null; | ||||||
|     public static readonly TYPES = TYPES; |  | ||||||
| 
 | 
 | ||||||
|     constructor(options?: CommandOptions) { |     constructor(options?: CommandOptions) { | ||||||
|         this.description = options?.description || "No description."; |         this.description = options?.description || "No description."; | ||||||
|  | @ -58,10 +71,35 @@ export default class Command { | ||||||
|         this.originalCommandName = null; |         this.originalCommandName = null; | ||||||
|         this.run = options?.run || "No action was set on this command!"; |         this.run = options?.run || "No action was set on this command!"; | ||||||
|         this.subcommands = new Collection(); // Populate this collection after setting subcommands.
 |         this.subcommands = new Collection(); // Populate this collection after setting subcommands.
 | ||||||
|  |         this.channel = options?.channel || null; | ||||||
|  |         this.role = options?.role || null; | ||||||
|  |         this.emote = options?.emote || null; | ||||||
|  |         this.message = options?.message || null; | ||||||
|         this.user = options?.user || null; |         this.user = options?.user || null; | ||||||
|         this.number = options?.number || null; |         this.number = options?.number || null; | ||||||
|         this.any = options?.any || null; |         this.any = options?.any || null; | ||||||
| 
 | 
 | ||||||
|  |         switch (options?.id) { | ||||||
|  |             case "channel": | ||||||
|  |                 this.id = this.channel; | ||||||
|  |                 break; | ||||||
|  |             case "role": | ||||||
|  |                 this.id = this.role; | ||||||
|  |                 break; | ||||||
|  |             case "emote": | ||||||
|  |                 this.id = this.emote; | ||||||
|  |                 break; | ||||||
|  |             case "message": | ||||||
|  |                 this.id = this.message; | ||||||
|  |                 break; | ||||||
|  |             case "user": | ||||||
|  |                 this.id = this.user; | ||||||
|  |                 break; | ||||||
|  |             default: | ||||||
|  |                 this.id = null; | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         if (options?.subcommands) { |         if (options?.subcommands) { | ||||||
|             const baseSubcommands = Object.keys(options.subcommands); |             const baseSubcommands = Object.keys(options.subcommands); | ||||||
| 
 | 
 | ||||||
|  | @ -89,20 +127,28 @@ export default class Command { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (this.user && this.user.aliases.length > 0) |         // Because command aliases don't actually do anything except for subcommands, let the user know that this won't do anything.
 | ||||||
|             console.warn( |         warnCommandAliases(this.channel, "channel"); | ||||||
|                 `There are aliases defined for a "user"-type subcommand, but those aliases won't be used. (Look at the next "Loading Command" line to see which command is affected.)` |         warnCommandAliases(this.role, "role"); | ||||||
|             ); |         warnCommandAliases(this.emote, "emote"); | ||||||
|  |         warnCommandAliases(this.message, "message"); | ||||||
|  |         warnCommandAliases(this.user, "user"); | ||||||
|  |         warnCommandAliases(this.number, "number"); | ||||||
|  |         warnCommandAliases(this.any, "any"); | ||||||
| 
 | 
 | ||||||
|         if (this.number && this.number.aliases.length > 0) |         // Warn on unused endpoints too.
 | ||||||
|             console.warn( |         if ( | ||||||
|                 `There are aliases defined for a "number"-type subcommand, but those aliases won't be used. (Look at the next "Loading Command" line to see which command is affected.)` |             this.endpoint && | ||||||
|             ); |             (this.subcommands.size > 0 || | ||||||
| 
 |                 this.channel || | ||||||
|         if (this.any && this.any.aliases.length > 0) |                 this.role || | ||||||
|             console.warn( |                 this.emote || | ||||||
|                 `There are aliases defined for an "any"-type subcommand, but those aliases won't be used. (Look at the next "Loading Command" line to see which command is affected.)` |                 this.message || | ||||||
|             ); |                 this.user || | ||||||
|  |                 this.number || | ||||||
|  |                 this.any) | ||||||
|  |         ) | ||||||
|  |             console.warn(`An endpoint cannot have subcommands!`); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public execute($: CommandMenu) { |     public execute($: CommandMenu) { | ||||||
|  | @ -121,39 +167,59 @@ export default class Command { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public resolve(param: string): TYPES { |     public resolve(param: string): TYPES { | ||||||
|  |         if (this.id && /^\d{17,19}$/.test(param)) { | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         if (this.subcommands.has(param)) return TYPES.SUBCOMMAND; |         if (this.subcommands.has(param)) return TYPES.SUBCOMMAND; | ||||||
|         // Any Discord ID format will automatically format to a user ID.
 |         else if (this.channel && /^<#\d{17,19}>$/.test(param)) return TYPES.CHANNEL; | ||||||
|         else if (this.user && /\d{17,19}/.test(param)) return TYPES.USER; |         else if (this.role && /^<@&\d{17,19}>$/.test(param)) return TYPES.ROLE; | ||||||
|  |         else if (this.emote && /^<a?:.*?:\d{17,19}>$/.test(param)) return TYPES.EMOTE; | ||||||
|  |         else if (this.message && /(\d{17,19}\/\d{17,19}\/\d{17,19}$)|(^\d{17,19}-\d{17,19}$)/.test(param)) | ||||||
|  |             return TYPES.MESSAGE; | ||||||
|  |         else if (this.user && /^<@!?\d{17,19}>$/.test(param)) return TYPES.USER; | ||||||
|         // Disallow infinity and allow for 0.
 |         // Disallow infinity and allow for 0.
 | ||||||
|         else if (this.number && (Number(param) || param === "0") && !param.includes("Infinity")) return TYPES.NUMBER; |         else if (this.number && !Number.isNaN(Number(param)) && param !== "Infinity" && param !== "-Infinity") | ||||||
|  |             return TYPES.NUMBER; | ||||||
|         else if (this.any) return TYPES.ANY; |         else if (this.any) return TYPES.ANY; | ||||||
|         else return TYPES.NONE; |         else return TYPES.NONE; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public get(param: string): Command { |     // You can also optionally send in a pre-calculated value if you already called Command.resolve so you don't call it again.
 | ||||||
|         const type = this.resolve(param); |     public get(param: string, type?: TYPES): Command { | ||||||
|         let command: Command; |         // This expression only runs once, don't worry.
 | ||||||
| 
 |         switch (type ?? this.resolve(param)) { | ||||||
|         switch (type) { |  | ||||||
|             case TYPES.SUBCOMMAND: |             case TYPES.SUBCOMMAND: | ||||||
|                 command = this.subcommands.get(param) as Command; |                 return checkResolvedCommand(this.subcommands.get(param)); | ||||||
|                 break; |             case TYPES.CHANNEL: | ||||||
|  |                 return checkResolvedCommand(this.channel); | ||||||
|  |             case TYPES.ROLE: | ||||||
|  |                 return checkResolvedCommand(this.role); | ||||||
|  |             case TYPES.EMOTE: | ||||||
|  |                 return checkResolvedCommand(this.emote); | ||||||
|  |             case TYPES.MESSAGE: | ||||||
|  |                 return checkResolvedCommand(this.message); | ||||||
|             case TYPES.USER: |             case TYPES.USER: | ||||||
|                 command = this.user as Command; |                 return checkResolvedCommand(this.user); | ||||||
|                 break; |  | ||||||
|             case TYPES.NUMBER: |             case TYPES.NUMBER: | ||||||
|                 command = this.number as Command; |                 return checkResolvedCommand(this.number); | ||||||
|                 break; |  | ||||||
|             case TYPES.ANY: |             case TYPES.ANY: | ||||||
|                 command = this.any as Command; |                 return checkResolvedCommand(this.any); | ||||||
|                 break; |  | ||||||
|             default: |             default: | ||||||
|                 command = this; |                 return this; | ||||||
|                 break; |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|         return command; | function warnCommandAliases(command: Command | null, type: string) { | ||||||
|  |     if (command && command.aliases.length > 0) | ||||||
|  |         console.warn( | ||||||
|  |             `There are aliases defined for an "${type}"-type subcommand, but those aliases won't be used. (Look at the next "Loading Command" line to see which command is affected.)` | ||||||
|  |         ); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | function checkResolvedCommand(command: Command | null | undefined): Command { | ||||||
|  |     if (!command) throw new Error("FATAL: Command type mismatch while calling Command.get!"); | ||||||
|  |     return command; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Internally, it'll keep its original capitalization. It's up to you to convert it to title case when you make a help command.
 | // Internally, it'll keep its original capitalization. It's up to you to convert it to title case when you make a help command.
 | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import {client} from "../index"; | import {client} from "../index"; | ||||||
| import Command, {loadableCommands} from "../core/command"; | import Command, {loadableCommands, TYPES} from "../core/command"; | ||||||
| import {hasPermission, getPermissionLevel, getPermissionName} from "../core/permissions"; | import {hasPermission, getPermissionLevel, getPermissionName} from "../core/permissions"; | ||||||
| import {Permissions} from "discord.js"; | import {Permissions} from "discord.js"; | ||||||
| import {getPrefix} from "../core/structures"; | import {getPrefix} from "../core/structures"; | ||||||
|  | @ -102,18 +102,70 @@ client.on("message", async (message) => { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const type = command.resolve(param); |         const type = command.resolve(param); | ||||||
|         command = command.get(param); |         command = command.get(param, type); | ||||||
|         permLevel = command.permission ?? permLevel; |         permLevel = command.permission ?? permLevel; | ||||||
| 
 | 
 | ||||||
|         if (type === Command.TYPES.USER) { |         // Add argument to parameter list, do different stuff depending on the subcommand type.
 | ||||||
|             const id = param.match(/\d+/g)![0]; |         switch (type) { | ||||||
|  |             case TYPES.SUBCOMMAND: | ||||||
|  |                 break; | ||||||
|  |             case TYPES.CHANNEL: { | ||||||
|  |                 const id = param.match(/^<#(\d{17,19})>$/)![1]; | ||||||
|  |                 console.debug(id); | ||||||
|  |                 try { | ||||||
|  |                     params.push(message.guild!.channels.cache.get(id)); | ||||||
|  |                 } catch (error) { | ||||||
|  |                     return message.channel.send(`No channel found by the ID \`${id}\` in this guild!`); | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             case TYPES.ROLE: { | ||||||
|  |                 const id = param.match(/^<@&(\d{17,19})>$/)![1]; | ||||||
|  |                 console.debug(id); | ||||||
|  |                 try { | ||||||
|  |                     params.push(await message.guild!.roles.fetch(id)); | ||||||
|  |                 } catch (error) { | ||||||
|  |                     return message.channel.send(`No role found by the ID \`${id}\` in this guild!`); | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             case TYPES.EMOTE: { | ||||||
|  |                 const id = param.match(/^<a?:.*?:(\d{17,19})>$/)![1]; | ||||||
|  |                 console.debug(id); | ||||||
|  |                 try { | ||||||
|  |                     params.push(message.client.emojis.cache.get(id)); | ||||||
|  |                 } catch (error) { | ||||||
|  |                     return message.channel.send(`No emote found by the ID \`${id}\`!`); | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             case TYPES.MESSAGE: { | ||||||
|  |                 const id = param.match(/(\d{17,19}\/\d{17,19}\/\d{17,19}$)|(^\d{17,19}-\d{17,19}$)/); | ||||||
|  |                 console.log(id); | ||||||
|  |                 /*try { | ||||||
|  |                     params.push(await message.client.users.fetch(id)); | ||||||
|  |                 } catch (error) { | ||||||
|  |                     return message.channel.send(`No user found by the ID \`${id}\`!`); | ||||||
|  |                 }*/ | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             case TYPES.USER: { | ||||||
|  |                 const id = param.match(/^<@!?(\d{17,19})>$/)![1]; | ||||||
|  |                 console.debug(param, id); | ||||||
|                 try { |                 try { | ||||||
|                     params.push(await message.client.users.fetch(id)); |                     params.push(await message.client.users.fetch(id)); | ||||||
|                 } catch (error) { |                 } catch (error) { | ||||||
|                     return message.channel.send(`No user found by the ID \`${id}\`!`); |                     return message.channel.send(`No user found by the ID \`${id}\`!`); | ||||||
|                 } |                 } | ||||||
|         } else if (type === Command.TYPES.NUMBER) params.push(Number(param)); |                 break; | ||||||
|         else if (type !== Command.TYPES.SUBCOMMAND) params.push(param); |             } | ||||||
|  |             case TYPES.NUMBER: | ||||||
|  |                 params.push(Number(param)); | ||||||
|  |                 break; | ||||||
|  |             case TYPES.ANY: | ||||||
|  |                 params.push(param); | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!message.member) |     if (!message.member) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue