From 346fa57f95a99d5b4e1169bb85706c4c25bf71d0 Mon Sep 17 00:00:00 2001 From: ckohen Date: Sat, 12 Aug 2023 00:08:47 -0700 Subject: [PATCH] fix(CachedManager): allow overriding constructor for makeCache (#9763) * fix(CachedManager): allow overriding constructor for makeCache * feat: allow determining makeCache based on non-overriden constructor * types: cleanup leftovers --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- packages/discord.js/src/managers/CachedManager.js | 9 ++++++++- .../discord.js/src/managers/MessageManager.js | 3 +++ packages/discord.js/src/managers/ThreadManager.js | 3 +++ packages/discord.js/src/util/Options.js | 8 +++++--- packages/discord.js/src/util/Symbols.js | 3 +++ packages/discord.js/typings/index.d.ts | 15 ++++++++++++--- 6 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 packages/discord.js/src/util/Symbols.js diff --git a/packages/discord.js/src/managers/CachedManager.js b/packages/discord.js/src/managers/CachedManager.js index e0ce0f8a52ca..b4c50b1b324d 100644 --- a/packages/discord.js/src/managers/CachedManager.js +++ b/packages/discord.js/src/managers/CachedManager.js @@ -1,6 +1,7 @@ 'use strict'; const DataManager = require('./DataManager'); +const { MakeCacheOverrideSymbol } = require('../util/Symbols'); /** * Manages the API methods of a data model with a mutable cache of instances. @@ -18,7 +19,13 @@ class CachedManager extends DataManager { * @readonly * @name CachedManager#_cache */ - Object.defineProperty(this, '_cache', { value: this.client.options.makeCache(this.constructor, this.holds) }); + Object.defineProperty(this, '_cache', { + value: this.client.options.makeCache( + this.constructor[MakeCacheOverrideSymbol] ?? this.constructor, + this.holds, + this.constructor, + ), + }); if (iterable) { for (const item of iterable) { diff --git a/packages/discord.js/src/managers/MessageManager.js b/packages/discord.js/src/managers/MessageManager.js index ea05b1d19418..6fb95eb66ac5 100644 --- a/packages/discord.js/src/managers/MessageManager.js +++ b/packages/discord.js/src/managers/MessageManager.js @@ -7,6 +7,7 @@ const CachedManager = require('./CachedManager'); const { DiscordjsTypeError, ErrorCodes } = require('../errors'); const { Message } = require('../structures/Message'); const MessagePayload = require('../structures/MessagePayload'); +const { MakeCacheOverrideSymbol } = require('../util/Symbols'); const { resolvePartialEmoji } = require('../util/Util'); /** @@ -15,6 +16,8 @@ const { resolvePartialEmoji } = require('../util/Util'); * @abstract */ class MessageManager extends CachedManager { + static [MakeCacheOverrideSymbol] = MessageManager; + constructor(channel, iterable) { super(channel.client, Message, iterable); diff --git a/packages/discord.js/src/managers/ThreadManager.js b/packages/discord.js/src/managers/ThreadManager.js index 005e02c45392..17569f5b97fe 100644 --- a/packages/discord.js/src/managers/ThreadManager.js +++ b/packages/discord.js/src/managers/ThreadManager.js @@ -6,12 +6,15 @@ const { Routes } = require('discord-api-types/v10'); const CachedManager = require('./CachedManager'); const { DiscordjsTypeError, ErrorCodes } = require('../errors'); const ThreadChannel = require('../structures/ThreadChannel'); +const { MakeCacheOverrideSymbol } = require('../util/Symbols'); /** * Manages API methods for thread-based channels and stores their cache. * @extends {CachedManager} */ class ThreadManager extends CachedManager { + static [MakeCacheOverrideSymbol] = ThreadManager; + constructor(channel, iterable) { super(channel.client, ThreadChannel, iterable); diff --git a/packages/discord.js/src/util/Options.js b/packages/discord.js/src/util/Options.js index 429354622e22..9d1ce50ec2b0 100644 --- a/packages/discord.js/src/util/Options.js +++ b/packages/discord.js/src/util/Options.js @@ -4,10 +4,12 @@ const { DefaultRestOptions, DefaultUserAgentAppendix } = require('@discordjs/res const { toSnakeCase } = require('./Transformers'); const { version } = require('../../package.json'); +// TODO(ckohen): switch order of params so full manager is first and "type" is optional /** * @typedef {Function} CacheFactory - * @param {Function} manager The manager class the cache is being requested from. + * @param {Function} managerType The base manager class the cache is being requested from. * @param {Function} holds The class that the cache will hold. + * @param {Function} manager The fully extended manager class the cache is being requested from. * @returns {Collection} A Collection used to store the cache of the manager. */ @@ -150,8 +152,8 @@ class Options extends null { const { Collection } = require('@discordjs/collection'); const LimitedCollection = require('./LimitedCollection'); - return manager => { - const setting = settings[manager.name]; + return (managerType, _, manager) => { + const setting = settings[manager.name] ?? settings[managerType.name]; /* eslint-disable-next-line eqeqeq */ if (setting == null) { return new Collection(); diff --git a/packages/discord.js/src/util/Symbols.js b/packages/discord.js/src/util/Symbols.js new file mode 100644 index 000000000000..36d4ed8162d0 --- /dev/null +++ b/packages/discord.js/src/util/Symbols.js @@ -0,0 +1,3 @@ +'use strict'; + +exports.MakeCacheOverrideSymbol = Symbol('djs.managers.makeCacheOverride'); diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index d6f3b27d6481..2504625c7f14 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -4720,17 +4720,19 @@ export interface Caches { AutoModerationRuleManager: [manager: typeof AutoModerationRuleManager, holds: typeof AutoModerationRule]; ApplicationCommandManager: [manager: typeof ApplicationCommandManager, holds: typeof ApplicationCommand]; BaseGuildEmojiManager: [manager: typeof BaseGuildEmojiManager, holds: typeof GuildEmoji]; + DMMessageManager: [manager: typeof MessageManager, holds: typeof Message]; GuildEmojiManager: [manager: typeof GuildEmojiManager, holds: typeof GuildEmoji]; // TODO: ChannelManager: [manager: typeof ChannelManager, holds: typeof Channel]; // TODO: GuildChannelManager: [manager: typeof GuildChannelManager, holds: typeof GuildChannel]; // TODO: GuildManager: [manager: typeof GuildManager, holds: typeof Guild]; GuildMemberManager: [manager: typeof GuildMemberManager, holds: typeof GuildMember]; GuildBanManager: [manager: typeof GuildBanManager, holds: typeof GuildBan]; - GuildForumThreadManager: [manager: typeof GuildForumThreadManager, holds: typeof ThreadChannel]; + GuildForumThreadManager: [manager: typeof GuildForumThreadManager, holds: typeof ThreadChannel]; GuildInviteManager: [manager: typeof GuildInviteManager, holds: typeof Invite]; + GuildMessageManager: [manager: typeof GuildMessageManager, holds: typeof Message]; GuildScheduledEventManager: [manager: typeof GuildScheduledEventManager, holds: typeof GuildScheduledEvent]; GuildStickerManager: [manager: typeof GuildStickerManager, holds: typeof Sticker]; - GuildTextThreadManager: [manager: typeof GuildTextThreadManager, holds: typeof ThreadChannel]; + GuildTextThreadManager: [manager: typeof GuildTextThreadManager, holds: typeof ThreadChannel]; MessageManager: [manager: typeof MessageManager, holds: typeof Message]; // TODO: PermissionOverwriteManager: [manager: typeof PermissionOverwriteManager, holds: typeof PermissionOverwrites]; PresenceManager: [manager: typeof PresenceManager, holds: typeof Presence]; @@ -4748,11 +4750,18 @@ export type CacheConstructors = { [K in keyof Caches]: Caches[K][0] & { name: K }; }; +type OverriddenCaches = + | 'DMMessageManager' + | 'GuildForumThreadManager' + | 'GuildMessageManager' + | 'GuildTextThreadManager'; + // This doesn't actually work the way it looks 😢. // Narrowing the type of `manager.name` doesn't propagate type information to `holds` and the return type. export type CacheFactory = ( - manager: CacheConstructors[keyof Caches], + managerType: CacheConstructors[Exclude], holds: Caches[(typeof manager)['name']][1], + manager: CacheConstructors[keyof Caches], ) => (typeof manager)['prototype'] extends DataManager ? Collection : never; export type CacheWithLimitsOptions = {