diff --git a/src/structures/MessageMentions.js b/src/structures/MessageMentions.js index 9d0baebbeb17..8c9c71007619 100644 --- a/src/structures/MessageMentions.js +++ b/src/structures/MessageMentions.js @@ -93,6 +93,13 @@ class MessageMentions { */ this._channels = null; + /** + * Cached users for {@link MessageMentions#parsedUsers} + * @type {?Collection} + * @private + */ + this._parsedUsers = null; + /** * Crossposted channel data. * @typedef {Object} CrosspostedChannel @@ -168,6 +175,23 @@ class MessageMentions { return this._channels; } + /** + * Any user mentions that were included in the message content + * Order as they appear first in the message content + * @type {Collection} + * @readonly + */ + get parsedUsers() { + if (this._parsedUsers) return this._parsedUsers; + this._parsedUsers = new Collection(); + let matches; + while ((matches = this.constructor.USERS_PATTERN.exec(this._content)) !== null) { + const user = this.client.users.cache.get(matches[1]); + if (user) this._parsedUsers.set(user.id, user); + } + return this._parsedUsers; + } + /** * Options used to check for a mention. * @typedef {Object} MessageMentionsHasOptions @@ -187,16 +211,23 @@ class MessageMentions { */ has(data, { ignoreDirect = false, ignoreRoles = false, ignoreRepliedUser = false, ignoreEveryone = false } = {}) { const user = this.client.users.resolve(data); - const role = this.guild?.roles.resolve(data); - const channel = this.client.channels.resolve(data); - if (!ignoreRepliedUser && this.users.has(this.repliedUser?.id) && this.repliedUser?.id === user?.id) return true; + if (!ignoreEveryone && user && this.everyone) return true; + + const userWasRepliedTo = user && this.repliedUser?.id === user.id; + + if (!ignoreRepliedUser && userWasRepliedTo && this.users.has(user.id)) return true; + if (!ignoreDirect) { - if (this.users.has(user?.id)) return true; - if (this.roles.has(role?.id)) return true; - if (this.channels.has(channel?.id)) return true; + if (user && (!ignoreRepliedUser || this.parsedUsers.has(user.id)) && this.users.has(user.id)) return true; + + const role = this.guild?.roles.resolve(data); + if (role && this.roles.has(role.id)) return true; + + const channel = this.client.channels.resolve(data); + if (channel && this.channels.has(channel.id)) return true; } - if (user && !ignoreEveryone && this.everyone) return true; + if (!ignoreRoles) { const member = this.guild?.members.resolve(data); if (member) { diff --git a/typings/index.d.ts b/typings/index.d.ts index 1aebe7dbec81..5da6855a783f 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -1806,6 +1806,7 @@ export class MessageMentions { private _channels: Collection | null; private readonly _content: string; private _members: Collection | null; + private _parsedUsers: Collection | null; public readonly channels: Collection; public readonly client: Client; @@ -1813,6 +1814,7 @@ export class MessageMentions { public readonly guild: Guild; public has(data: UserResolvable | RoleResolvable | ChannelResolvable, options?: MessageMentionsHasOptions): boolean; public readonly members: Collection | null; + public readonly parsedUsers: Collection; public repliedUser: User | null; public roles: Collection; public users: Collection;