diff --git a/packages/discord.js/src/client/Client.js b/packages/discord.js/src/client/Client.js index 828a492319cb..0290c5daba74 100644 --- a/packages/discord.js/src/client/Client.js +++ b/packages/discord.js/src/client/Client.js @@ -11,7 +11,6 @@ const { ActionsManager } = require('./actions/ActionsManager.js'); const { ClientVoiceManager } = require('./voice/ClientVoiceManager.js'); const { PacketHandlers } = require('./websocket/handlers/index.js'); const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js'); -const { BaseGuildEmojiManager } = require('../managers/BaseGuildEmojiManager.js'); const { ChannelManager } = require('../managers/ChannelManager.js'); const { GuildManager } = require('../managers/GuildManager.js'); const { UserManager } = require('../managers/UserManager.js'); @@ -217,19 +216,6 @@ class Client extends BaseClient { this._attachEvents(); } - /** - * A manager of all the custom emojis that the client has access to - * @type {BaseGuildEmojiManager} - * @readonly - */ - get emojis() { - const emojis = new BaseGuildEmojiManager(this); - for (const guild of this.guilds.cache.values()) { - if (guild.available) for (const emoji of guild.emojis.cache.values()) emojis.cache.set(emoji.id, emoji); - } - return emojis; - } - /** * Time at which the client was last regarded as being in the {@link Status.Ready} state * (each time the client disconnects and successfully reconnects, this will be overwritten) diff --git a/packages/discord.js/src/index.js b/packages/discord.js/src/index.js index 20e7cd157208..87a0c662e8ac 100644 --- a/packages/discord.js/src/index.js +++ b/packages/discord.js/src/index.js @@ -58,7 +58,6 @@ exports.ApplicationCommandPermissionsManager = require('./managers/ApplicationCommandPermissionsManager.js').ApplicationCommandPermissionsManager; exports.ApplicationEmojiManager = require('./managers/ApplicationEmojiManager.js').ApplicationEmojiManager; exports.AutoModerationRuleManager = require('./managers/AutoModerationRuleManager.js').AutoModerationRuleManager; -exports.BaseGuildEmojiManager = require('./managers/BaseGuildEmojiManager.js').BaseGuildEmojiManager; exports.CachedManager = require('./managers/CachedManager.js').CachedManager; exports.ChannelManager = require('./managers/ChannelManager.js').ChannelManager; exports.ClientVoiceManager = require('./client/voice/ClientVoiceManager.js').ClientVoiceManager; diff --git a/packages/discord.js/src/managers/BaseGuildEmojiManager.js b/packages/discord.js/src/managers/BaseGuildEmojiManager.js deleted file mode 100644 index 9efc116da707..000000000000 --- a/packages/discord.js/src/managers/BaseGuildEmojiManager.js +++ /dev/null @@ -1,85 +0,0 @@ -'use strict'; - -const { CachedManager } = require('./CachedManager.js'); -const { ApplicationEmoji } = require('../structures/ApplicationEmoji.js'); -const { GuildEmoji } = require('../structures/GuildEmoji.js'); -const { ReactionEmoji } = require('../structures/ReactionEmoji.js'); -const { parseEmoji } = require('../util/Util.js'); - -/** - * Holds methods to resolve GuildEmojis and stores their cache. - * @extends {CachedManager} - */ -class BaseGuildEmojiManager extends CachedManager { - constructor(client, iterable) { - super(client, GuildEmoji, iterable); - } - - /** - * The cache of GuildEmojis - * @type {Collection} - * @name BaseGuildEmojiManager#cache - */ - - /** - * Data that can be resolved into a GuildEmoji object. This can be: - * * A Snowflake - * * A GuildEmoji object - * * A ReactionEmoji object - * * An ApplicationEmoji object - * @typedef {Snowflake|GuildEmoji|ReactionEmoji|ApplicationEmoji} EmojiResolvable - */ - - /** - * Resolves an EmojiResolvable to an Emoji object. - * @param {EmojiResolvable} emoji The Emoji resolvable to identify - * @returns {?GuildEmoji} - */ - resolve(emoji) { - if (emoji instanceof ReactionEmoji) return super.cache.get(emoji.id) ?? null; - if (emoji instanceof ApplicationEmoji) return super.cache.get(emoji.id) ?? null; - return super.resolve(emoji); - } - - /** - * Resolves an EmojiResolvable to an Emoji id string. - * @param {EmojiResolvable} emoji The Emoji resolvable to identify - * @returns {?Snowflake} - */ - resolveId(emoji) { - if (emoji instanceof ReactionEmoji) return emoji.id; - if (emoji instanceof ApplicationEmoji) return emoji.id; - return super.resolveId(emoji); - } - - /** - * Data that can be resolved to give an emoji identifier. This can be: - * * An EmojiResolvable - * * The ``, `<:name:id>`, `a:name:id` or `name:id` emoji identifier string of an emoji - * * The Unicode representation of an emoji - * @typedef {string|EmojiResolvable} EmojiIdentifierResolvable - */ - - /** - * Resolves an EmojiResolvable to an emoji identifier. - * @param {EmojiIdentifierResolvable} emoji The emoji resolvable to resolve - * @returns {?string} - */ - resolveIdentifier(emoji) { - const emojiResolvable = this.resolve(emoji); - if (emojiResolvable) return emojiResolvable.identifier; - if (emoji instanceof ReactionEmoji) return emoji.identifier; - if (emoji instanceof ApplicationEmoji) return emoji.identifier; - if (typeof emoji === 'string') { - const res = parseEmoji(emoji); - if (res?.name.length) { - emoji = `${res.animated ? 'a:' : ''}${res.name}${res.id ? `:${res.id}` : ''}`; - } - if (!emoji.includes('%')) return encodeURIComponent(emoji); - return emoji; - } - return null; - } -} - -exports.BaseGuildEmojiManager = BaseGuildEmojiManager; diff --git a/packages/discord.js/src/managers/GuildEmojiManager.js b/packages/discord.js/src/managers/GuildEmojiManager.js index 695faa2c68af..0ca7d26677e3 100644 --- a/packages/discord.js/src/managers/GuildEmojiManager.js +++ b/packages/discord.js/src/managers/GuildEmojiManager.js @@ -1,18 +1,21 @@ 'use strict'; - const { Collection } = require('@discordjs/collection'); const { Routes, PermissionFlagsBits } = require('discord-api-types/v10'); -const { BaseGuildEmojiManager } = require('./BaseGuildEmojiManager.js'); +const { CachedManager } = require('./CachedManager.js'); const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js'); +const { ApplicationEmoji } = require('../structures/ApplicationEmoji.js'); +const { GuildEmoji } = require('../structures/GuildEmoji.js'); +const { ReactionEmoji } = require('../structures/ReactionEmoji.js'); const { resolveImage } = require('../util/DataResolver.js'); +const { parseEmoji } = require('../util/Util.js'); /** * Manages API methods for GuildEmojis and stores their cache. - * @extends {BaseGuildEmojiManager} + * @extends {CachedManager} */ -class GuildEmojiManager extends BaseGuildEmojiManager { +class GuildEmojiManager extends CachedManager { constructor(guild, iterable) { - super(guild.client, iterable); + super(guild.client, GuildEmoji, iterable); /** * The guild this manager belongs to @@ -25,6 +28,72 @@ class GuildEmojiManager extends BaseGuildEmojiManager { return super._add(data, cache, { extras: [this.guild] }); } + /** + * The cache of GuildEmojis + * @type {Collection} + * @name GuildEmojiManager#cache + */ + + /** + * Data that can be resolved into a GuildEmoji object. This can be: + * * A Snowflake + * * A GuildEmoji object + * * A ReactionEmoji object + * * An ApplicationEmoji object + * @typedef {Snowflake|GuildEmoji|ReactionEmoji|ApplicationEmoji} EmojiResolvable + */ + + /** + * Resolves an EmojiResolvable to an Emoji object. + * @param {EmojiResolvable} emoji The Emoji resolvable to identify + * @returns {?GuildEmoji} + */ + resolve(emoji) { + if (emoji instanceof ReactionEmoji) return super.cache.get(emoji.id) ?? null; + if (emoji instanceof ApplicationEmoji) return super.cache.get(emoji.id) ?? null; + return super.resolve(emoji); + } + + /** + * Resolves an EmojiResolvable to an Emoji id string. + * @param {EmojiResolvable} emoji The Emoji resolvable to identify + * @returns {?Snowflake} + */ + resolveId(emoji) { + if (emoji instanceof ReactionEmoji) return emoji.id; + if (emoji instanceof ApplicationEmoji) return emoji.id; + return super.resolveId(emoji); + } + + /** + * Data that can be resolved to give an emoji identifier. This can be: + * * An EmojiResolvable + * * The ``, `<:name:id>`, `a:name:id` or `name:id` emoji identifier string of an emoji + * * The Unicode representation of an emoji + * @typedef {string|EmojiResolvable} EmojiIdentifierResolvable + */ + + /** + * Resolves an EmojiResolvable to an emoji identifier. + * @param {EmojiIdentifierResolvable} emoji The emoji resolvable to resolve + * @returns {?string} + */ + resolveIdentifier(emoji) { + const emojiResolvable = this.resolve(emoji); + if (emojiResolvable) return emojiResolvable.identifier; + if (emoji instanceof ReactionEmoji) return emoji.identifier; + if (emoji instanceof ApplicationEmoji) return emoji.identifier; + if (typeof emoji === 'string') { + const res = parseEmoji(emoji); + if (res?.name.length) { + emoji = `${res.animated ? 'a:' : ''}${res.name}${res.id ? `:${res.id}` : ''}`; + } + if (!emoji.includes('%')) return encodeURIComponent(emoji); + return emoji; + } + return null; + } + /** * Options used for creating an emoji in a guild. * @typedef {Object} GuildEmojiCreateOptions diff --git a/packages/discord.js/src/structures/GuildOnboardingPromptOption.js b/packages/discord.js/src/structures/GuildOnboardingPromptOption.js index b5dca0025bcb..503c1d9a7461 100644 --- a/packages/discord.js/src/structures/GuildOnboardingPromptOption.js +++ b/packages/discord.js/src/structures/GuildOnboardingPromptOption.js @@ -79,7 +79,7 @@ class GuildOnboardingPromptOption extends Base { */ get emoji() { if (!this._emoji.id && !this._emoji.name) return null; - return this.client.emojis.cache.get(this._emoji.id) ?? new Emoji(this.client, this._emoji); + return this.guild.emojis.cache.get(this._emoji.id) ?? new Emoji(this.client, this._emoji); } } diff --git a/packages/discord.js/src/structures/MessageReaction.js b/packages/discord.js/src/structures/MessageReaction.js index f59efa60efd7..334b0dffa42f 100644 --- a/packages/discord.js/src/structures/MessageReaction.js +++ b/packages/discord.js/src/structures/MessageReaction.js @@ -5,7 +5,7 @@ const { ApplicationEmoji } = require('./ApplicationEmoji.js'); const { GuildEmoji } = require('./GuildEmoji.js'); const { ReactionEmoji } = require('./ReactionEmoji.js'); const { ReactionUserManager } = require('../managers/ReactionUserManager.js'); -const { flatten } = require('../util/Util.js'); +const { flatten, resolveGuildEmoji } = require('../util/Util.js'); /** * Represents a reaction to a message. @@ -127,14 +127,9 @@ class MessageReaction { this._emoji = emoji; return emoji; } - const emojis = this.message.client.emojis.cache; - if (emojis.has(this._emoji.id)) { - const emoji = emojis.get(this._emoji.id); - this._emoji = emoji; - return emoji; - } } - return this._emoji; + const emoji = resolveGuildEmoji(this.client, this._emoji.id); + return emoji ?? this._emoji; } /** diff --git a/packages/discord.js/src/structures/PollAnswer.js b/packages/discord.js/src/structures/PollAnswer.js index b37794b628ed..19a83a21daa2 100644 --- a/packages/discord.js/src/structures/PollAnswer.js +++ b/packages/discord.js/src/structures/PollAnswer.js @@ -2,6 +2,7 @@ const { Base } = require('./Base.js'); const { Emoji } = require('./Emoji.js'); +const { resolveGuildEmoji } = require('../util/Util.js'); /** * Represents an answer to a {@link Poll} @@ -61,7 +62,7 @@ class PollAnswer extends Base { */ get emoji() { if (!this._emoji || (!this._emoji.id && !this._emoji.name)) return null; - return this.client.emojis.cache.get(this._emoji.id) ?? new Emoji(this.client, this._emoji); + return resolveGuildEmoji(this.client, this._emoji.id) ?? new Emoji(this.client, this._emoji); } /** diff --git a/packages/discord.js/src/structures/WelcomeChannel.js b/packages/discord.js/src/structures/WelcomeChannel.js index 72a87e237f23..86701dec8003 100644 --- a/packages/discord.js/src/structures/WelcomeChannel.js +++ b/packages/discord.js/src/structures/WelcomeChannel.js @@ -53,7 +53,7 @@ class WelcomeChannel extends Base { * @type {GuildEmoji|Emoji} */ get emoji() { - return this.client.emojis.cache.get(this._emoji.id) ?? new Emoji(this.client, this._emoji); + return this.guild.emojis.cache.get(this._emoji.id) ?? new Emoji(this.client, this._emoji); } } diff --git a/packages/discord.js/src/util/Util.js b/packages/discord.js/src/util/Util.js index a76b3bb23519..ae8126dd43cf 100644 --- a/packages/discord.js/src/util/Util.js +++ b/packages/discord.js/src/util/Util.js @@ -122,6 +122,29 @@ function resolvePartialEmoji(emoji) { return { id, name, animated: Boolean(animated) }; } +/** + * Resolves a {@link GuildEmoji} from an emoji id. + * @param {Client} client The client to use to resolve the emoji + * @param {Snowflake} emojiId The emoji id to resolve + * @returns {?GuildEmoji} + * @private + */ +function resolveGuildEmoji(client, emojiId) { + for (const guild of client.guilds.cache.values()) { + if (!guild.available) { + continue; + } + + const emoji = guild.emojis.cache.get(emojiId); + + if (emoji) { + return emoji; + } + } + + return null; +} + /** * Options used to make an error object. * @typedef {Object} MakeErrorOptions @@ -503,6 +526,7 @@ exports.flatten = flatten; exports.fetchRecommendedShardCount = fetchRecommendedShardCount; exports.parseEmoji = parseEmoji; exports.resolvePartialEmoji = resolvePartialEmoji; +exports.resolveGuildEmoji = resolveGuildEmoji; exports.makeError = makeError; exports.makePlainError = makePlainError; exports.getSortableGroupTypes = getSortableGroupTypes; diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 39a30b453a58..7f42f57338c0 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -976,7 +976,6 @@ export class Client extends BaseClient; public channels: ChannelManager; - public get emojis(): BaseGuildEmojiManager; public guilds: GuildManager; public lastPingTimestamps: ReadonlyCollection; public options: Omit & { intents: IntentsBitField }; @@ -3456,6 +3455,7 @@ export function discordSort; export function flatten(obj: unknown, ...props: Record[]): unknown; + /** @internal */ export function makeError(obj: MakeErrorOptions): Error; /** @internal */ @@ -3474,6 +3474,8 @@ export function resolveColor(color: ColorResolvable): number; export function resolvePartialEmoji(emoji: Snowflake): PartialEmojiOnlyId; /** @internal */ export function resolvePartialEmoji(emoji: Emoji | EmojiIdentifierResolvable): PartialEmoji | null; +/** @internal */ +export function resolveGuildEmoji(client: Client, emojiId: Snowflake): GuildEmoji | null; export function verifyString(data: string, error?: typeof Error, errorMessage?: string, allowEmpty?: boolean): string; /** @internal */ export function setPosition( @@ -3997,11 +3999,6 @@ export class AutoModerationRuleManager extends CachedManager< public delete(autoModerationRule: AutoModerationRuleResolvable, reason?: string): Promise; } -export class BaseGuildEmojiManager extends CachedManager { - protected constructor(client: Client, iterable?: Iterable); - public resolveIdentifier(emoji: EmojiIdentifierResolvable): string | null; -} - export class CategoryChannelChildManager extends DataManager { private constructor(channel: CategoryChannel); @@ -4142,7 +4139,7 @@ export class GuildChannelManager extends CachedManager; } -export class GuildEmojiManager extends BaseGuildEmojiManager { +export class GuildEmojiManager extends CachedManager { private constructor(guild: Guild, iterable?: Iterable); public guild: Guild; public create(options: GuildEmojiCreateOptions): Promise; @@ -4151,6 +4148,7 @@ export class GuildEmojiManager extends BaseGuildEmojiManager { public fetchAuthor(emoji: EmojiResolvable): Promise; public delete(emoji: EmojiResolvable, reason?: string): Promise; public edit(emoji: EmojiResolvable, options: GuildEmojiEditOptions): Promise; + public resolveIdentifier(emoji: EmojiIdentifierResolvable): string | null; } export class GuildEmojiRoleManager extends DataManager { @@ -4969,7 +4967,6 @@ export interface Caches { ApplicationCommandManager: [manager: typeof ApplicationCommandManager, holds: typeof ApplicationCommand]; ApplicationEmojiManager: [manager: typeof ApplicationEmojiManager, holds: typeof ApplicationEmoji]; AutoModerationRuleManager: [manager: typeof AutoModerationRuleManager, holds: typeof AutoModerationRule]; - BaseGuildEmojiManager: [manager: typeof BaseGuildEmojiManager, holds: typeof GuildEmoji]; // TODO: ChannelManager: [manager: typeof ChannelManager, holds: typeof Channel]; DMMessageManager: [manager: typeof MessageManager, holds: typeof Message]; EntitlementManager: [manager: typeof EntitlementManager, holds: typeof Entitlement];