From 89df6dffa32e519a88804a2aef92025a1bc2ee2a Mon Sep 17 00:00:00 2001 From: xhyrom Date: Sat, 12 Feb 2022 15:02:38 +0100 Subject: [PATCH] feat: mentionable argument --- src/handlers/MessageCommandHandler.ts | 8 +++--- src/lib/structures/arguments/Channel.ts | 26 +++++++++++++++++- src/lib/structures/arguments/Mentionable.ts | 30 ++++++++++++++++++++- src/lib/structures/arguments/Role.ts | 26 +++++++++++++++++- src/lib/structures/arguments/User.ts | 24 +++++++++++------ src/lib/structures/arguments/base.ts | 13 ++++----- src/lib/util/regexes.ts | 4 +++ 7 files changed, 111 insertions(+), 20 deletions(-) create mode 100644 src/lib/util/regexes.ts diff --git a/src/handlers/MessageCommandHandler.ts b/src/handlers/MessageCommandHandler.ts index 1d7f5f708..e08277825 100644 --- a/src/handlers/MessageCommandHandler.ts +++ b/src/handlers/MessageCommandHandler.ts @@ -48,7 +48,9 @@ const checkValidation = async(arg: MessageArgumentTypes, content: string | Messa channel.send(text); const message = await channel.awaitMessages({ filter: (m) => m.author.id === user.id && m.channelId === channel.id, time: 60000, max: 1 }); - // @ts-expect-error TODO: Use ArgumentType.ATTACHMENT | Need wait for https://github.com/Garlic-Team/gcommands/pull/314 to be merged (: + /** + * TODO: Use ArgumentType.ATTACHMENT | Need wait for https://github.com/Garlic-Team/gcommands/pull/314 to be merged (: + * @ts-expect-error */ if (argument.type == 11) { const attachments = [...message.values()]?.[0]?.attachments; content = attachments ? [...attachments.values()][0] : null; @@ -60,7 +62,7 @@ const checkValidation = async(arg: MessageArgumentTypes, content: string | Messa const validate = arg instanceof AttachmentType ? arg.validate(content) : arg.validate(content as string); if (!validate) return checkValidation(arg, null, client, guild, argument, channel, user); - return arg.resolve(argument, client, guild); + return arg.resolve(argument); }; export async function MessageCommandHandler( @@ -111,7 +113,7 @@ export async function MessageCommandHandler( args[0].options[0].options = args[0].options.splice(1);*/ for (const argument in command.arguments) { - const arg = await MessageArgumentTypeBase.createArgument(command.arguments[argument].type); + const arg = await MessageArgumentTypeBase.createArgument(command.arguments[argument].type, message.guild); args[argument] = await checkValidation(arg, args[argument] as string, client, message.guild, command.arguments[argument], message.channel as TextChannel, message.author); } diff --git a/src/lib/structures/arguments/Channel.ts b/src/lib/structures/arguments/Channel.ts index 9d6abbc4f..6da0e83db 100644 --- a/src/lib/structures/arguments/Channel.ts +++ b/src/lib/structures/arguments/Channel.ts @@ -1,7 +1,31 @@ +import type { Guild } from 'discord.js'; +import { channelRegexp } from '../../util/regexes'; +import { Argument, ArgumentType } from '../Argument'; import { MessageArgumentTypeBase } from './base'; export class ChannelType extends MessageArgumentTypeBase { - validate() { + value; + guild: Guild; + constructor(guild: Guild) { + super(); + + this.guild = guild; + } + + validate(content: string): boolean { + const matches = channelRegexp.exec(content); + if (!matches || !this.guild.channels.cache.get(matches?.[1])) return false; + + this.value = matches[1]; + return true; } + + resolve(argument: Argument) { + return { + ...argument.toJSON(), + type: ArgumentType[argument.type], + channel: this.guild.channels.cache.get(this.value) + }; + } } \ No newline at end of file diff --git a/src/lib/structures/arguments/Mentionable.ts b/src/lib/structures/arguments/Mentionable.ts index c7b896528..9962695c5 100644 --- a/src/lib/structures/arguments/Mentionable.ts +++ b/src/lib/structures/arguments/Mentionable.ts @@ -1,7 +1,35 @@ +import type { Client, Guild } from 'discord.js'; +import { channelRegexp, mentionableRegexp } from '../../util/regexes'; +import { Argument, ArgumentType } from '../Argument'; import { MessageArgumentTypeBase } from './base'; export class MentionableType extends MessageArgumentTypeBase { - validate() { + value; + guild: Guild; + client: Client; + constructor(guild: Guild) { + super(); + + this.client = guild.client; + this.guild = guild; + } + + validate(content: string): boolean { + const matches = mentionableRegexp.exec(content); + if (!matches || (this.guild.roles.cache.get(matches?.[1]) || this.client.users.cache.get(matches?.[1]))) return false; + + this.value = matches[1]; + return true; } + + resolve(argument: Argument) { + return { + ...argument.toJSON(), + type: ArgumentType[argument.type], + user: this.client.users.cache.get(this.value), + member: this.guild.members.cache.get(this.value), + roles: this.guild.roles.cache.get(this.value), + }; + } } \ No newline at end of file diff --git a/src/lib/structures/arguments/Role.ts b/src/lib/structures/arguments/Role.ts index e3d210586..c443127d9 100644 --- a/src/lib/structures/arguments/Role.ts +++ b/src/lib/structures/arguments/Role.ts @@ -1,7 +1,31 @@ +import type { Guild } from 'discord.js'; +import { roleRegexp } from '../../util/regexes'; +import { Argument, ArgumentType } from '../Argument'; import { MessageArgumentTypeBase } from './base'; export class RoleType extends MessageArgumentTypeBase { - validate() { + value; + guild: Guild; + constructor(guild: Guild) { + super(); + + this.guild = guild; + } + + validate(content: string): boolean { + const matches = roleRegexp.exec(content); + if (!matches || !this.guild.roles.cache.get(matches?.[1])) return false; + + this.value = matches[1]; + return true; } + + resolve(argument: Argument) { + return { + ...argument.toJSON(), + type: ArgumentType[argument.type], + channel: this.guild.roles.cache.get(this.value) + }; + } } \ No newline at end of file diff --git a/src/lib/structures/arguments/User.ts b/src/lib/structures/arguments/User.ts index b4bd949e1..7284a9e4a 100644 --- a/src/lib/structures/arguments/User.ts +++ b/src/lib/structures/arguments/User.ts @@ -1,26 +1,34 @@ import type { Client, Guild } from 'discord.js'; +import { userRegexp } from '../../util/regexes'; import { Argument, ArgumentType } from '../Argument'; import { MessageArgumentTypeBase } from './base'; export class UserType extends MessageArgumentTypeBase { - matches; + value; + guild: Guild; + client: Client; + constructor(guild: Guild) { + super(); - validate(content: string): boolean { - const matches = content?.match(/([0-9]+)/); + this.client = guild.client; + this.guild = guild; + } - if (!matches) return false; + validate(content: string): boolean { + const matches = userRegexp.exec(content); + if (!matches || !this.client.users.cache.get(matches?.[1])) return false; - this.matches = matches; + this.value = matches[1]; return true; } - resolve(argument: Argument, client: Client, guild: Guild) { + resolve(argument: Argument) { return { ...argument.toJSON(), type: ArgumentType[argument.type], - user: client.users.cache.get(this.matches[1]), - member: guild.members?.cache?.get(this.matches[1]) + user: this.client.users.cache.get(this.value), + member: this.guild.members.cache.get(this.value) }; } } \ No newline at end of file diff --git a/src/lib/structures/arguments/base.ts b/src/lib/structures/arguments/base.ts index 2dde3e5b8..1b4ba46ad 100644 --- a/src/lib/structures/arguments/base.ts +++ b/src/lib/structures/arguments/base.ts @@ -1,3 +1,4 @@ +import type { Guild } from 'discord.js'; import { Util } from '../../util/Util'; import { Argument, ArgumentType } from '../Argument'; import type { AttachmentType } from './Attachment'; @@ -20,11 +21,11 @@ export class MessageArgumentTypeBase { } // eslint-disable-next-line @typescript-eslint/no-unused-vars - resolve(argument: Argument, ...args) { + resolve(argument: Argument) { Util.throwError('Resolve method is not implemented!', this.constructor.name); } - static async createArgument(type: ArgumentType | keyof typeof ArgumentType) { + static async createArgument(type: ArgumentType | keyof typeof ArgumentType, guild: Guild) { switch(type) { case ArgumentType.BOOLEAN: { const { BooleanType } = await import('./Boolean'); @@ -32,7 +33,7 @@ export class MessageArgumentTypeBase { } case ArgumentType.CHANNEL: { const { ChannelType } = await import('./Channel'); - return new ChannelType(); + return new ChannelType(guild); } case ArgumentType.INTEGER: { const { IntegerType } = await import('./Integer'); @@ -40,7 +41,7 @@ export class MessageArgumentTypeBase { } case ArgumentType.MENTIONABLE: { const { MentionableType } = await import('./Mentionable'); - return new MentionableType(); + return new MentionableType(guild); } case ArgumentType.NUMBER: { const { NumberType } = await import('./Number'); @@ -48,7 +49,7 @@ export class MessageArgumentTypeBase { } case ArgumentType.ROLE: { const { RoleType } = await import('./Role'); - return new RoleType(); + return new RoleType(guild); } case ArgumentType.STRING: { const { StringType } = await import('./String'); @@ -56,7 +57,7 @@ export class MessageArgumentTypeBase { } case ArgumentType.USER: { const { UserType } = await import('./User'); - return new UserType(); + return new UserType(guild); } // @ts-expect-error TODO: Use ArgumentType.ATTACHMENT | Need wait for https://github.com/Garlic-Team/gcommands/pull/314 to be merged (: case 11: { diff --git a/src/lib/util/regexes.ts b/src/lib/util/regexes.ts new file mode 100644 index 000000000..b43935354 --- /dev/null +++ b/src/lib/util/regexes.ts @@ -0,0 +1,4 @@ +export const userRegexp = /^(?:<@!?)?([0-9]+)>?$/; +export const roleRegexp = /^(?:<@&)?([0-9]+)>?$/; +export const channelRegexp = /^(?:<#)?([0-9]+)>?$/; +export const mentionableRegexp = /^(?:<@!?)?(?:<@&?)?([0-9]+)>?$/; \ No newline at end of file