feat: remove datastores and implement Managers (#3696)

* Initial commit: add 5 initial managers

- Base manager
- GuildChannelManager
- MessageManager
- PresenceManager
- Reaction Manager
- Added LimitedCollection

* Add GuildEmojiManager, various fixes

* Modify some managers and add guildmembermanager

* Initial integration

* Delete old stores

* Integration part two, removed LRUCollection

- Most of the integration has been finished
- TODO typings
- Removed LRUCollection, needless sweeping

* Typings + stuff i somehow missed in ChannelManager

* LimitedCollection typings/ final changes

* Various jsdoc and syntactical fixes, Removed Util.mixin()

* tslint fix

* Grammatical and logical changes

* Delete temporary file placed by mistake

* Grammatical changes

* Add missing type

* Update jsdoc examples

* fix: ChannelManager#remove should call cache#delete not cache#remove

* fix recursive require

* Fix missed cache in util

* fix: more missed cache

* Remove accidental _fetchMany change from #3645

* fix: use .cache.delete() over .remove()

* fix: missing cache in ReactionCollector

* fix: missed cache in client

* fix: members is a collection not a manager

Co-Authored-By: Sugden <28943913+NotSugden@users.noreply.github.com>

* fix: various docs and cache fixes

* fix: missed cache

* fix: missing _roles

* Final testing and debugging

* LimitedCollection: return the Collection instead of undefined on .set

* Add cache to BaseManager in typings

* Commit fixes i forgot to stage yesterday

* Update invite events

* Account for new commit

* fix: MessageReactionRemoveAll should call .cache.clear()

* fix: add .cache at various places, correct return type

* docs: remove mentions of 'store'

* Add extra documented properties to typings

Co-authored-by: Sugden <28943913+NotSugden@users.noreply.github.com>
Co-authored-by: SpaceEEC <spaceeec@yahoo.com>
This commit is contained in:
BorgerKing
2020-02-11 14:21:07 -05:00
committed by GitHub
parent fe7df708e4
commit bbdbc4cfa7
87 changed files with 804 additions and 705 deletions

View File

@@ -19,7 +19,7 @@ client.on('ready', () => {
// Create an event listener for new guild members
client.on('guildMemberAdd', member => {
// Send the message to a designated channel on a server:
const channel = member.guild.channels.find(ch => ch.name === 'member-log');
const channel = member.guild.channels.cache.find(ch => ch.name === 'member-log');
// Do nothing if the channel wasn't found on this server
if (!channel) return;
// Send the message, mentioning the member

View File

@@ -11,10 +11,10 @@ const Webhook = require('../structures/Webhook');
const Invite = require('../structures/Invite');
const ClientApplication = require('../structures/ClientApplication');
const ShardClientUtil = require('../sharding/ShardClientUtil');
const UserStore = require('../stores/UserStore');
const ChannelStore = require('../stores/ChannelStore');
const GuildStore = require('../stores/GuildStore');
const GuildEmojiStore = require('../stores/GuildEmojiStore');
const UserManager = require('../managers/UserManager');
const ChannelManager = require('../managers/ChannelManager');
const GuildManager = require('../managers/GuildManager');
const GuildEmojiManager = require('../managers/GuildEmojiManager');
const { Events, browser, DefaultOptions } = require('../util/Constants');
const DataResolver = require('../util/DataResolver');
const Structures = require('../util/Structures');
@@ -99,25 +99,25 @@ class Client extends BaseClient {
/**
* All of the {@link User} objects that have been cached at any point, mapped by their IDs
* @type {UserStore<Snowflake, User>}
* @type {UserManager}
*/
this.users = new UserStore(this);
this.users = new UserManager(this);
/**
* All of the guilds the client is currently handling, mapped by their IDs -
* as long as sharding isn't being used, this will be *every* guild the bot is a member of
* @type {GuildStore<Snowflake, Guild>}
* @type {GuildManager}
*/
this.guilds = new GuildStore(this);
this.guilds = new GuildManager(this);
/**
* All of the {@link Channel}s that the client is currently handling, mapped by their IDs -
* as long as sharding isn't being used, this will be *every* channel in *every* guild the bot
* is a member of. Note that DM channels will not be initially cached, and thus not be present
* in the store without their explicit fetching or use.
* @type {ChannelStore<Snowflake, Channel>}
* in the Manager without their explicit fetching or use.
* @type {ChannelManager}
*/
this.channels = new ChannelStore(this);
this.channels = new ChannelManager(this);
const ClientPresence = Structures.get('ClientPresence');
/**
@@ -159,13 +159,13 @@ class Client extends BaseClient {
/**
* All custom emojis that the client has access to, mapped by their IDs
* @type {GuildEmojiStore<Snowflake, GuildEmoji>}
* @type {GuildEmojiManager}
* @readonly
*/
get emojis() {
const emojis = new GuildEmojiStore({ client: this });
for (const guild of this.guilds.values()) {
if (guild.available) for (const emoji of guild.emojis.values()) emojis.set(emoji.id, emoji);
const emojis = new GuildEmojiManager({ client: 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;
}
@@ -298,11 +298,11 @@ class Client extends BaseClient {
let channels = 0;
let messages = 0;
for (const channel of this.channels.values()) {
for (const channel of this.channels.cache.values()) {
if (!channel.messages) continue;
channels++;
messages += channel.messages.sweep(
messages += channel.messages.cache.sweep(
message => now - (message.editedTimestamp || message.createdTimestamp) > lifetimeMs
);
}

View File

@@ -23,10 +23,10 @@ class GenericAction {
return data;
}
getPayload(data, store, id, partialType, cache) {
const existing = store.get(id);
getPayload(data, manager, id, partialType, cache) {
const existing = manager.cache.get(id);
if (!existing && this.client.options.partials.includes(partialType)) {
return store.add(data, cache);
return manager.add(data, cache);
}
return existing;
}

View File

@@ -6,7 +6,7 @@ const { Events } = require('../../util/Constants');
class ChannelCreateAction extends Action {
handle(data) {
const client = this.client;
const existing = client.channels.has(data.id);
const existing = client.channels.cache.has(data.id);
const channel = client.channels.add(data);
if (!existing && channel) {
/**

View File

@@ -12,13 +12,13 @@ class ChannelDeleteAction extends Action {
handle(data) {
const client = this.client;
let channel = client.channels.get(data.id);
let channel = client.channels.cache.get(data.id);
if (channel) {
client.channels.remove(channel.id);
channel.deleted = true;
if (channel.messages && !(channel instanceof DMChannel)) {
for (const message of channel.messages.values()) {
for (const message of channel.messages.cache.values()) {
message.deleted = true;
}
}

View File

@@ -8,16 +8,16 @@ class ChannelUpdateAction extends Action {
handle(data) {
const client = this.client;
let channel = client.channels.get(data.id);
let channel = client.channels.cache.get(data.id);
if (channel) {
const old = channel._update(data);
if (ChannelTypes[channel.type.toUpperCase()] !== data.type) {
const newChannel = Channel.create(this.client, data, channel.guild);
for (const [id, message] of channel.messages) newChannel.messages.set(id, message);
for (const [id, message] of channel.messages.cache) newChannel.messages.cache.set(id, message);
newChannel._typing = new Map(channel._typing);
channel = newChannel;
this.client.channels.set(channel.id, channel);
this.client.channels.cache.set(channel.id, channel);
}
return {

View File

@@ -6,7 +6,7 @@ const { Events } = require('../../util/Constants');
class GuildBanRemove extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
const user = client.users.add(data.user);
/**
* Emitted whenever a member is unbanned from a guild.

View File

@@ -6,10 +6,10 @@ class GuildChannelsPositionUpdate extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
for (const partialChannel of data.channels) {
const channel = guild.channels.get(partialChannel.id);
const channel = guild.channels.cache.get(partialChannel.id);
if (channel) channel.rawPosition = partialChannel.position;
}
}

View File

@@ -12,9 +12,9 @@ class GuildDeleteAction extends Action {
handle(data) {
const client = this.client;
let guild = client.guilds.get(data.id);
let guild = client.guilds.cache.get(data.id);
if (guild) {
for (const channel of guild.channels.values()) {
for (const channel of guild.channels.cache.values()) {
if (channel.type === 'text') channel.stopTyping(true);
}
@@ -36,11 +36,11 @@ class GuildDeleteAction extends Action {
};
}
for (const channel of guild.channels.values()) this.client.channels.remove(channel.id);
for (const channel of guild.channels.cache.values()) this.client.channels.remove(channel.id);
if (guild.voice && guild.voice.connection) guild.voice.connection.disconnect();
// Delete guild
client.guilds.remove(guild.id);
client.guilds.cache.delete(guild.id);
guild.deleted = true;
/**

View File

@@ -5,7 +5,7 @@ const { Events } = require('../../util/Constants');
class GuildEmojiDeleteAction extends Action {
handle(emoji) {
emoji.guild.emojis.remove(emoji.id);
emoji.guild.emojis.cache.delete(emoji.id);
emoji.deleted = true;
/**
* Emitted whenever a custom emoji is deleted in a guild.

View File

@@ -4,14 +4,14 @@ const Action = require('./Action');
class GuildEmojisUpdateAction extends Action {
handle(data) {
const guild = this.client.guilds.get(data.guild_id);
const guild = this.client.guilds.cache.get(data.guild_id);
if (!guild || !guild.emojis) return;
const deletions = new Map(guild.emojis);
const deletions = new Map(guild.emojis.cache);
for (const emoji of data.emojis) {
// Determine type of emoji event
const cachedEmoji = guild.emojis.get(emoji.id);
const cachedEmoji = guild.emojis.cache.get(emoji.id);
if (cachedEmoji) {
deletions.delete(emoji.id);
if (!cachedEmoji.equals(emoji)) {

View File

@@ -6,7 +6,7 @@ const { Events } = require('../../util/Constants');
class GuildIntegrationsUpdate extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
/**
* Emitted whenever a guild integration is updated
* @event Client#guildIntegrationsUpdate

View File

@@ -6,14 +6,14 @@ const { Events, Status } = require('../../util/Constants');
class GuildMemberRemoveAction extends Action {
handle(data, shard) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
let member = null;
if (guild) {
member = this.getMember(data, guild);
guild.memberCount--;
if (member) {
member.deleted = true;
guild.members.remove(member.id);
guild.members.cache.delete(member.id);
/**
* Emitted whenever a member leaves a guild, or is kicked.
* @event Client#guildMemberRemove
@@ -21,7 +21,7 @@ class GuildMemberRemoveAction extends Action {
*/
if (shard.status === Status.READY) client.emit(Events.GUILD_MEMBER_REMOVE, member);
}
guild.voiceStates.delete(data.user.id);
guild.voiceStates.cache.delete(data.user.id);
}
return { guild, member };
}

View File

@@ -6,10 +6,10 @@ const { Events } = require('../../util/Constants');
class GuildRoleCreate extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
let role;
if (guild) {
const already = guild.roles.has(data.role.id);
const already = guild.roles.cache.has(data.role.id);
role = guild.roles.add(data.role);
/**
* Emitted whenever a role is created.

View File

@@ -6,13 +6,13 @@ const { Events } = require('../../util/Constants');
class GuildRoleDeleteAction extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
let role;
if (guild) {
role = guild.roles.get(data.role_id);
role = guild.roles.cache.get(data.role_id);
if (role) {
guild.roles.remove(data.role_id);
guild.roles.cache.delete(data.role_id);
role.deleted = true;
/**
* Emitted whenever a guild role is deleted.

View File

@@ -6,12 +6,12 @@ const { Events } = require('../../util/Constants');
class GuildRoleUpdateAction extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
let old = null;
const role = guild.roles.get(data.role.id);
const role = guild.roles.cache.get(data.role.id);
if (role) {
old = role._update(data.role);
/**

View File

@@ -6,10 +6,10 @@ class GuildRolesPositionUpdate extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
for (const partialRole of data.roles) {
const role = guild.roles.get(partialRole.id);
const role = guild.roles.cache.get(partialRole.id);
if (role) role.rawPosition = partialRole.position;
}
}

View File

@@ -7,7 +7,7 @@ class GuildUpdateAction extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.id);
const guild = client.guilds.cache.get(data.id);
if (guild) {
const old = guild._update(data);
/**

View File

@@ -7,8 +7,8 @@ const { Events } = require('../../util/Constants');
class InviteCreateAction extends Action {
handle(data) {
const client = this.client;
const channel = client.channels.get(data.channel_id);
const guild = client.guilds.get(data.guild_id);
const channel = client.channels.cache.get(data.channel_id);
const guild = client.guilds.cache.get(data.guild_id);
if (!channel && !guild) return false;
const inviteData = Object.assign(data, { channel, guild });

View File

@@ -7,8 +7,8 @@ const { Events } = require('../../util/Constants');
class InviteDeleteAction extends Action {
handle(data) {
const client = this.client;
const channel = client.channels.get(data.channel_id);
const guild = client.guilds.get(data.guild_id);
const channel = client.channels.cache.get(data.channel_id);
const guild = client.guilds.cache.get(data.guild_id);
if (!channel && !guild) return false;
const inviteData = Object.assign(data, { channel, guild });

View File

@@ -6,9 +6,9 @@ const { Events } = require('../../util/Constants');
class MessageCreateAction extends Action {
handle(data) {
const client = this.client;
const channel = client.channels.get(data.channel_id);
const channel = client.channels.cache.get(data.channel_id);
if (channel) {
const existing = channel.messages.get(data.id);
const existing = channel.messages.cache.get(data.id);
if (existing) return { message: existing };
const message = channel.messages.add(data);
const user = message.author;

View File

@@ -11,7 +11,7 @@ class MessageDeleteAction extends Action {
if (channel) {
message = this.getMessage(data, channel);
if (message) {
channel.messages.delete(message.id);
channel.messages.cache.delete(message.id);
message.deleted = true;
/**
* Emitted whenever a message is deleted.

View File

@@ -7,7 +7,7 @@ const { Events } = require('../../util/Constants');
class MessageDeleteBulkAction extends Action {
handle(data) {
const client = this.client;
const channel = client.channels.get(data.channel_id);
const channel = client.channels.cache.get(data.channel_id);
if (channel) {
const ids = data.ids;
@@ -20,7 +20,7 @@ class MessageDeleteBulkAction extends Action {
if (message) {
message.deleted = true;
messages.set(message.id, message);
channel.messages.delete(id);
channel.messages.cache.delete(id);
}
}

View File

@@ -13,7 +13,7 @@ class MessageReactionRemoveAll extends Action {
const message = this.getMessage(data, channel);
if (!message) return false;
message.reactions.clear();
message.reactions.cache.clear();
this.client.emit(Events.MESSAGE_REACTION_REMOVE_ALL, message);
return { message };

View File

@@ -13,7 +13,7 @@ class MessageReactionRemoveEmoji extends Action {
const reaction = this.getReaction(data, message);
if (!reaction) return false;
if (!message.partial) message.reactions.delete(reaction.emoji.id || reaction.emoji.name);
if (!message.partial) message.reactions.cache.delete(reaction.emoji.id || reaction.emoji.name);
/**
* Emitted when a bot removes an emoji reaction from a cached message.

View File

@@ -5,7 +5,7 @@ const { Events } = require('../../util/Constants');
class PresenceUpdateAction extends Action {
handle(data) {
let user = this.client.users.get(data.user.id);
let user = this.client.users.cache.get(data.user.id);
if (!user && data.user.username) user = this.client.users.add(data.user);
if (!user) return;
@@ -13,12 +13,12 @@ class PresenceUpdateAction extends Action {
if (!user.equals(data.user)) this.client.actions.UserUpdate.handle(data.user);
}
const guild = this.client.guilds.get(data.guild_id);
const guild = this.client.guilds.cache.get(data.guild_id);
if (!guild) return;
let oldPresence = guild.presences.get(user.id);
let oldPresence = guild.presences.cache.get(user.id);
if (oldPresence) oldPresence = oldPresence._clone();
let member = guild.members.get(user.id);
let member = guild.members.cache.get(user.id);
if (!member && data.status !== 'offline') {
member = guild.members.add({
user,

View File

@@ -7,7 +7,7 @@ class UserUpdateAction extends Action {
handle(data) {
const client = this.client;
const newUser = client.users.get(data.id);
const newUser = client.users.cache.get(data.id);
const oldUser = newUser._update(data);
if (!oldUser.equals(newUser)) {

View File

@@ -7,17 +7,17 @@ const VoiceState = require('../../structures/VoiceState');
class VoiceStateUpdate extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
// Update the state
const oldState = guild.voiceStates.has(data.user_id) ?
guild.voiceStates.get(data.user_id)._clone() :
const oldState = guild.voiceStates.cache.has(data.user_id) ?
guild.voiceStates.cache.get(data.user_id)._clone() :
new VoiceState(guild, { user_id: data.user_id });
const newState = guild.voiceStates.add(data);
// Get the member
let member = guild.members.get(data.user_id);
let member = guild.members.cache.get(data.user_id);
if (member && data.member) {
member._patch(data.member);
} else if (data.member && data.member.user && data.member.joined_at) {

View File

@@ -6,7 +6,7 @@ const { Events } = require('../../util/Constants');
class WebhooksUpdate extends Action {
handle(data) {
const client = this.client;
const channel = client.channels.get(data.channel_id);
const channel = client.channels.cache.get(data.channel_id);
/**
* Emitted whenever a guild text channel has its webhooks changed.
* @event Client#webhookUpdate

View File

@@ -56,7 +56,7 @@ class ClientVoiceManager {
this.connections.delete(guild_id);
return;
}
connection.channel = this.client.channels.get(channel_id);
connection.channel = this.client.channels.cache.get(channel_id);
connection.setSessionID(session_id);
}

View File

@@ -483,7 +483,7 @@ class VoiceConnection extends EventEmitter {
onSpeaking({ user_id, speaking }) {
speaking = new Speaking(speaking).freeze();
const guild = this.channel.guild;
const user = this.client.users.get(user_id);
const user = this.client.users.cache.get(user_id);
const old = this._speaking.get(user_id);
this._speaking.set(user_id, speaking);
/**

View File

@@ -408,7 +408,7 @@ class WebSocketManager extends EventEmitter {
if (this.client.options.fetchAllMembers) {
try {
const promises = this.client.guilds.map(guild => {
const promises = this.client.guilds.cache.map(guild => {
if (guild.available) return guild.members.fetch();
// Return empty promise if guild is unavailable
return Promise.resolve();

View File

@@ -3,7 +3,7 @@
const { Events } = require('../../../util/Constants');
module.exports = (client, { d: data }) => {
const channel = client.channels.get(data.channel_id);
const channel = client.channels.cache.get(data.channel_id);
const time = new Date(data.last_pin_timestamp);
if (channel && !Number.isNaN(time.getTime())) {

View File

@@ -3,7 +3,7 @@
const { Events } = require('../../../util/Constants');
module.exports = (client, { d: data }) => {
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
const user = client.users.add(data.user);
/**

View File

@@ -3,7 +3,7 @@
const { Events, Status } = require('../../../util/Constants');
module.exports = async (client, { d: data }, shard) => {
let guild = client.guilds.get(data.id);
let guild = client.guilds.cache.get(data.id);
if (guild) {
if (!guild.available && !data.unavailable) {
// A newly available guild

View File

@@ -4,7 +4,7 @@ const { Events } = require('../../../util/Constants');
const Collection = require('../../../util/Collection');
module.exports = (client, { d: data }) => {
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
if (!guild) return;
const members = new Collection();

View File

@@ -3,7 +3,7 @@
const { Events, Status } = require('../../../util/Constants');
module.exports = (client, { d: data }, shard) => {
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
guild.memberCount++;
const member = guild.members.add(data);

View File

@@ -3,9 +3,9 @@
const { Status, Events } = require('../../../util/Constants');
module.exports = (client, { d: data }, shard) => {
const guild = client.guilds.get(data.guild_id);
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
const member = guild.members.get(data.user.id);
const member = guild.members.cache.get(data.user.id);
if (member) {
const old = member._update(data);
if (shard.status === Status.READY) {

View File

@@ -9,7 +9,7 @@ module.exports = (client, { d: data }, shard) => {
if (!ClientUser) ClientUser = require('../../../structures/ClientUser');
const clientUser = new ClientUser(client, data.user);
client.user = clientUser;
client.users.set(clientUser.id, clientUser);
client.users.cache.set(clientUser.id, clientUser);
}
for (const guild of data.guilds) {

View File

@@ -3,8 +3,8 @@
const { Events } = require('../../../util/Constants');
module.exports = (client, { d: data }) => {
const channel = client.channels.get(data.channel_id);
const user = client.users.get(data.user_id);
const channel = client.channels.cache.get(data.channel_id);
const user = client.users.cache.get(data.user_id);
if (channel && user) {
/**

View File

@@ -17,7 +17,8 @@ module.exports = {
Collection: require('./util/Collection'),
Constants: require('./util/Constants'),
DataResolver: require('./util/DataResolver'),
DataStore: require('./stores/DataStore'),
LimitedCollection: require('./util/LimitedCollection'),
BaseManager: require('./managers/BaseManager'),
DiscordAPIError: require('./rest/DiscordAPIError'),
HTTPError: require('./rest/HTTPError'),
MessageFlags: require('./util/MessageFlags'),
@@ -30,19 +31,19 @@ module.exports = {
Util: Util,
version: require('../package.json').version,
// Stores
ChannelStore: require('./stores/ChannelStore'),
GuildChannelStore: require('./stores/GuildChannelStore'),
GuildEmojiStore: require('./stores/GuildEmojiStore'),
GuildEmojiRoleStore: require('./stores/GuildEmojiRoleStore'),
GuildMemberStore: require('./stores/GuildMemberStore'),
GuildMemberRoleStore: require('./stores/GuildMemberRoleStore'),
GuildStore: require('./stores/GuildStore'),
ReactionUserStore: require('./stores/ReactionUserStore'),
MessageStore: require('./stores/MessageStore'),
PresenceStore: require('./stores/PresenceStore'),
RoleStore: require('./stores/RoleStore'),
UserStore: require('./stores/UserStore'),
// Managers
ChannelManager: require('./managers/ChannelManager'),
GuildChannelManager: require('./managers/GuildChannelManager'),
GuildEmojiManager: require('./managers/GuildEmojiManager'),
GuildEmojiRoleManager: require('./managers/GuildEmojiRoleManager'),
GuildMemberManager: require('./managers/GuildMemberManager'),
GuildMemberRoleManager: require('./managers/GuildMemberRoleManager'),
GuildManager: require('./managers/GuildManager'),
ReactionUserManager: require('./managers/ReactionUserManager'),
MessageManager: require('./managers/MessageManager'),
PresenceManager: require('./managers/PresenceManager'),
RoleManager: require('./managers/RoleManager'),
UserManager: require('./managers/UserManager'),
// Shortcuts to Util methods
discordSort: Util.discordSort,

View File

@@ -4,44 +4,67 @@ const Collection = require('../util/Collection');
let Structures;
/**
* Manages the creation, retrieval and deletion of a specific data model.
* @extends {Collection}
* Manages the API methods of a data model and holds its cache.
* @abstract
*/
class DataStore extends Collection {
constructor(client, iterable, holds) {
super();
class BaseManager {
constructor(client, iterable, holds, cacheType = Collection, ...cacheOptions) {
if (!Structures) Structures = require('../util/Structures');
Object.defineProperty(this, 'client', { value: client });
/**
* The data structure belonging to this manager
* @name BaseManager#holds
* @type {Function}
* @private
* @readonly
*/
Object.defineProperty(this, 'holds', { value: Structures.get(holds.name) || holds });
if (iterable) for (const item of iterable) this.add(item);
/**
* The client that instantiated this Manager
* @name BaseManager#client
* @type {Client}
* @readonly
*/
Object.defineProperty(this, 'client', { value: client });
/**
* The type of Collection of the Manager
* @type {Collection}
*/
this.cacheType = cacheType;
/**
* Holds the cache for the data model
* @type {?Collection}
*/
this.cache = new cacheType(...cacheOptions);
if (iterable) for (const i of iterable) this.add(i);
}
add(data, cache = true, { id, extras = [] } = {}) {
const existing = this.get(id || data.id);
const existing = this.cache.get(id || data.id);
if (existing && existing._patch && cache) existing._patch(data);
if (existing) return existing;
const entry = this.holds ? new this.holds(this.client, data, ...extras) : data;
if (cache) this.set(id || entry.id, entry);
if (cache) this.cache.set(id || entry.id, entry);
return entry;
}
remove(key) { return this.delete(key); }
/**
* Resolves a data entry to a data Object.
* @param {string|Object} idOrInstance The id or instance of something in this DataStore
* @returns {?Object} An instance from this DataStore
* @param {string|Object} idOrInstance The id or instance of something in this Manager
* @returns {?Object} An instance from this Manager
*/
resolve(idOrInstance) {
if (idOrInstance instanceof this.holds) return idOrInstance;
if (typeof idOrInstance === 'string') return this.get(idOrInstance) || null;
if (typeof idOrInstance === 'string') return this.cache.get(idOrInstance) || null;
return null;
}
/**
* Resolves a data entry to a instance ID.
* @param {string|Instance} idOrInstance The id or instance of something in this DataStore
* @param {string|Instance} idOrInstance The id or instance of something in this Manager
* @returns {?Snowflake}
*/
resolveID(idOrInstance) {
@@ -49,10 +72,6 @@ class DataStore extends Collection {
if (typeof idOrInstance === 'string') return idOrInstance;
return null;
}
static get [Symbol.species]() {
return Collection;
}
}
module.exports = DataStore;
module.exports = BaseManager;

View File

@@ -1,59 +1,26 @@
'use strict';
const DataStore = require('./DataStore');
const Channel = require('../structures/Channel');
const BaseManager = require('./BaseManager');
const { Events } = require('../util/Constants');
const kLru = Symbol('LRU');
const lruable = ['dm'];
/**
* Stores channels.
* @extends {DataStore}
* A manager of channels belonging to a client
*/
class ChannelStore extends DataStore {
constructor(client, iterableOrOptions = {}, options) {
if (!options && typeof iterableOrOptions[Symbol.iterator] !== 'function') {
options = iterableOrOptions;
iterableOrOptions = undefined;
}
super(client, iterableOrOptions, Channel);
if (options.lru) {
const lru = this[kLru] = [];
lru.add = item => {
lru.remove(item);
lru.unshift(item);
while (lru.length > options.lru) this.remove(lru[lru.length - 1]);
};
lru.remove = item => {
const index = lru.indexOf(item);
if (index > -1) lru.splice(index, 1);
};
}
class ChannelManager extends BaseManager {
constructor(client, iterable) {
super(client, iterable, Channel);
}
get(key, peek = false) {
const item = super.get(key);
if (!item || !lruable.includes(item.type)) return item;
if (!peek && this[kLru]) this[kLru].add(key);
return item;
}
set(key, val) {
if (this[kLru] && lruable.includes(val.type)) this[kLru].add(key);
return super.set(key, val);
}
delete(key) {
const item = this.get(key, true);
if (!item) return false;
if (this[kLru] && lruable.includes(item.type)) this[kLru].remove(key);
return super.delete(key);
}
/**
* The cache of Channels
* @property {Collection<Snowflake, Channel>} cache
* @memberof ChannelManager
* @instance
*/
add(data, guild, cache = true) {
const existing = this.get(data.id);
const existing = this.cache.get(data.id);
if (existing) {
if (existing._patch && cache) existing._patch(data);
if (guild) guild.channels.add(existing);
@@ -67,15 +34,15 @@ class ChannelStore extends DataStore {
return null;
}
if (cache) this.set(channel.id, channel);
if (cache) this.cache.set(channel.id, channel);
return channel;
}
remove(id) {
const channel = this.get(id);
if (channel.guild) channel.guild.channels.remove(id);
super.remove(id);
const channel = this.cache.get(id);
if (channel.guild) channel.guild.channels.cache.delete(id);
this.cache.delete(id);
}
/**
@@ -88,7 +55,7 @@ class ChannelStore extends DataStore {
/**
* Resolves a ChannelResolvable to a Channel object.
* @method resolve
* @memberof ChannelStore
* @memberof ChannelManager
* @instance
* @param {ChannelResolvable} channel The channel resolvable to resolve
* @returns {?Channel}
@@ -97,7 +64,7 @@ class ChannelStore extends DataStore {
/**
* Resolves a ChannelResolvable to a channel ID string.
* @method resolveID
* @memberof ChannelStore
* @memberof ChannelManager
* @instance
* @param {ChannelResolvable} channel The channel resolvable to resolve
* @returns {?Snowflake}
@@ -115,7 +82,7 @@ class ChannelStore extends DataStore {
* .catch(console.error);
*/
async fetch(id, cache = true) {
const existing = this.get(id);
const existing = this.cache.get(id);
if (existing && !existing.partial) return existing;
const data = await this.client.api.channels(id).get();
@@ -123,4 +90,4 @@ class ChannelStore extends DataStore {
}
}
module.exports = ChannelStore;
module.exports = ChannelManager;

View File

@@ -1,24 +1,36 @@
'use strict';
const { ChannelTypes } = require('../util/Constants');
const DataStore = require('./DataStore');
const BaseManager = require('./BaseManager');
const GuildChannel = require('../structures/GuildChannel');
const PermissionOverwrites = require('../structures/PermissionOverwrites');
/**
* Stores guild channels.
* @extends {DataStore}
* Manages API methods for GuildChannels and stores their cache.
* @extends {BaseManager}
*/
class GuildChannelStore extends DataStore {
class GuildChannelManager extends BaseManager {
constructor(guild, iterable) {
super(guild.client, iterable, GuildChannel);
/**
* The guild this Manager belongs to
* @type {Guild}
*/
this.guild = guild;
}
/**
* The cache of this Manager
* @property {Collection<Snowflake, GuildChannel>} cache
* @memberof GuildChannelManager
* @instance
*/
add(channel) {
const existing = this.get(channel.id);
const existing = this.cache.get(channel.id);
if (existing) return existing;
this.set(channel.id, channel);
this.cache.set(channel.id, channel);
return channel;
}
@@ -32,7 +44,7 @@ class GuildChannelStore extends DataStore {
/**
* Resolves a GuildChannelResolvable to a Channel object.
* @method resolve
* @memberof GuildChannelStore
* @memberof GuildChannelManager
* @instance
* @param {GuildChannelResolvable} channel The GuildChannel resolvable to resolve
* @returns {?Channel}
@@ -41,7 +53,7 @@ class GuildChannelStore extends DataStore {
/**
* Resolves a GuildChannelResolvable to a channel ID string.
* @method resolveID
* @memberof GuildChannelStore
* @memberof GuildChannelManager
* @instance
* @param {GuildChannelResolvable} channel The GuildChannel resolvable to resolve
* @returns {?Snowflake}
@@ -117,4 +129,4 @@ class GuildChannelStore extends DataStore {
}
}
module.exports = GuildChannelStore;
module.exports = GuildChannelManager;

View File

@@ -1,22 +1,33 @@
'use strict';
const Collection = require('../util/Collection');
const DataStore = require('./DataStore');
const BaseManager = require('./BaseManager');
const GuildEmoji = require('../structures/GuildEmoji');
const ReactionEmoji = require('../structures/ReactionEmoji');
const DataResolver = require('../util/DataResolver');
const { TypeError } = require('../errors');
/**
* Stores guild emojis.
* @extends {DataStore}
* Manages API methods for GuildEmojis and stores their cache.
* @extends {BaseManager}
*/
class GuildEmojiStore extends DataStore {
class GuildEmojiManager extends BaseManager {
constructor(guild, iterable) {
super(guild.client, iterable, GuildEmoji);
/**
* The guild this manager belongs to
* @type {Guild}
*/
this.guild = guild;
}
/**
* The cache of GuildEmojis
* @property {Collection<Snowflake, GuildEmoji>} cache
* @memberof GuildEmojiManager
* @instance
*/
add(data, cache) {
return super.add(data, cache, { extras: [this.guild] });
}
@@ -114,4 +125,4 @@ class GuildEmojiStore extends DataStore {
}
}
module.exports = GuildEmojiStore;
module.exports = GuildEmojiManager;

View File

@@ -1,18 +1,28 @@
'use strict';
const Collection = require('../util/Collection');
const Util = require('../util/Util');
const { TypeError } = require('../errors');
/**
* Stores emoji roles
* @extends {Collection}
* Manages API methods for roles belonging to emojis and stores their cache.
*/
class GuildEmojiRoleStore extends Collection {
class GuildEmojiRoleManager {
constructor(emoji) {
super();
/**
* The emoji belonging to this manager
* @type {GuildEmoji}
*/
this.emoji = emoji;
/**
* The guild belonging to this manager
* @type {Guild}
*/
this.guild = emoji.guild;
/**
* The client belonging to this manager
* @type {Client}
* @readonly
*/
Object.defineProperty(this, 'client', { value: emoji.client });
}
@@ -22,8 +32,17 @@ class GuildEmojiRoleStore extends Collection {
* @private
* @readonly
*/
get _filtered() {
return this.guild.roles.filter(role => this.emoji._roles.includes(role.id));
get _roles() {
return this.guild.roles.cache.filter(role => this.emoji._roles.includes(role.id));
}
/**
* The cache of roles belonging to this emoji
* @type {Collection<Snowflake, Role>}
* @readonly
*/
get cache() {
return this._roles;
}
/**
@@ -41,7 +60,7 @@ class GuildEmojiRoleStore extends Collection {
'Array or Collection of Roles or Snowflakes', true));
}
const newRoles = [...new Set(roleOrRoles.concat(...this.values()))];
const newRoles = [...new Set(roleOrRoles.concat(...this._roles.values()))];
return this.set(newRoles);
}
@@ -60,7 +79,7 @@ class GuildEmojiRoleStore extends Collection {
'Array or Collection of Roles or Snowflakes', true));
}
const newRoles = this.keyArray().filter(role => !roleOrRoles.includes(role));
const newRoles = this._roles.keyArray().filter(role => !roleOrRoles.includes(role));
return this.set(newRoles);
}
@@ -85,32 +104,18 @@ class GuildEmojiRoleStore extends Collection {
clone() {
const clone = new this.constructor(this.emoji);
clone._patch(this.keyArray().slice());
clone._patch(this._roles.keyArray().slice());
return clone;
}
/**
* Patches the roles for this store
* Patches the roles for this manager's cache
* @param {Snowflake[]} roles The new roles
* @private
*/
_patch(roles) {
this.emoji._roles = roles;
}
*[Symbol.iterator]() {
yield* this._filtered.entries();
}
valueOf() {
return this._filtered;
}
static get [Symbol.species]() {
return Collection;
}
}
Util.mixin(GuildEmojiRoleStore, ['set']);
module.exports = GuildEmojiRoleStore;
module.exports = GuildEmojiRoleManager;

View File

@@ -1,6 +1,6 @@
'use strict';
const DataStore = require('./DataStore');
const BaseManager = require('./BaseManager');
const DataResolver = require('../util/DataResolver');
const { Events } = require('../util/Constants');
const Guild = require('../structures/Guild');
@@ -9,14 +9,21 @@ const GuildMember = require('../structures/GuildMember');
const Role = require('../structures/Role');
/**
* Stores guilds.
* @extends {DataStore}
* Manages API methods for Guilds and stores their cache.
* @extends {BaseManager}
*/
class GuildStore extends DataStore {
class GuildManager extends BaseManager {
constructor(client, iterable) {
super(client, iterable, Guild);
}
/**
* The cache of this Manager
* @property {Collection<Snowflake, Guild>} cache
* @memberof GuildManager
* @instance
*/
/**
* Data that resolves to give a Guild object. This can be:
* * A Guild object
@@ -29,7 +36,7 @@ class GuildStore extends DataStore {
/**
* Resolves a GuildResolvable to a Guild object.
* @method resolve
* @memberof GuildStore
* @memberof GuildManager
* @instance
* @param {GuildResolvable} guild The guild resolvable to identify
* @returns {?Guild}
@@ -44,7 +51,7 @@ class GuildStore extends DataStore {
/**
* Resolves a GuildResolvable to a Guild ID string.
* @method resolveID
* @memberof GuildStore
* @memberof GuildManager
* @instance
* @param {GuildResolvable} guild The guild resolvable to identify
* @returns {?Snowflake}
@@ -70,7 +77,7 @@ class GuildStore extends DataStore {
return new Promise((resolve, reject) =>
this.client.api.guilds.post({ data: { name, region, icon } })
.then(data => {
if (this.client.guilds.has(data.id)) return resolve(this.client.guilds.get(data.id));
if (this.client.guilds.cache.has(data.id)) return resolve(this.client.guilds.cache.get(data.id));
const handleGuild = guild => {
if (guild.id === data.id) {
@@ -95,4 +102,4 @@ class GuildStore extends DataStore {
}
}
module.exports = GuildStore;
module.exports = GuildManager;

View File

@@ -1,21 +1,32 @@
'use strict';
const DataStore = require('./DataStore');
const BaseManager = require('./BaseManager');
const GuildMember = require('../structures/GuildMember');
const { Events, OPCodes } = require('../util/Constants');
const Collection = require('../util/Collection');
const { Error, TypeError } = require('../errors');
/**
* Stores guild members.
* @extends {DataStore}
* Manages API methods for GuildMembers and stores their cache.
* @extends {BaseManager}
*/
class GuildMemberStore extends DataStore {
class GuildMemberManager extends BaseManager {
constructor(guild, iterable) {
super(guild.client, iterable, GuildMember);
/**
* The guild this manager belongs to
* @type {Guild}
*/
this.guild = guild;
}
/**
* The cache of this Manager
* @property {Collection<Snowflake, GuildMember>} cache
* @memberof GuildMemberManager
* @instance
*/
add(data, cache = true) {
return super.add(data, cache, { id: data.user.id, extras: [this.guild] });
}
@@ -49,7 +60,7 @@ class GuildMemberStore extends DataStore {
const memberResolvable = super.resolveID(member);
if (memberResolvable) return memberResolvable;
const userResolvable = this.client.users.resolveID(member);
return this.has(userResolvable) ? userResolvable : null;
return this.cache.has(userResolvable) ? userResolvable : null;
}
/**
@@ -184,7 +195,7 @@ class GuildMemberStore extends DataStore {
_fetchSingle({ user, cache }) {
const existing = this.get(user);
const existing = this.cache.get(user);
if (existing && !existing.partial) return Promise.resolve(existing);
return this.client.api.guilds(this.guild.id).members(user).get()
.then(data => this.add(data, cache));
@@ -192,8 +203,8 @@ class GuildMemberStore extends DataStore {
_fetchMany({ query = '', limit = 0 } = {}) {
return new Promise((resolve, reject) => {
if (this.guild.memberCount === this.size && !query && !limit) {
resolve(this);
if (this.guild.memberCount === this.cache.size && !query && !limit) {
resolve(this.cache);
return;
}
this.guild.shard.send({
@@ -211,11 +222,11 @@ class GuildMemberStore extends DataStore {
for (const member of members.values()) {
if (query || limit) fetchedMembers.set(member.id, member);
}
if (this.guild.memberCount <= this.size ||
if (this.guild.memberCount <= this.cache.size ||
((query || limit) && members.size < 1000) ||
(limit && fetchedMembers.size >= limit)) {
this.guild.client.removeListener(Events.GUILD_MEMBERS_CHUNK, handler);
resolve(query || limit ? fetchedMembers : this);
resolve(query || limit ? fetchedMembers : this.cache);
}
};
const timeout = this.guild.client.setTimeout(() => {
@@ -227,4 +238,4 @@ class GuildMemberStore extends DataStore {
}
}
module.exports = GuildMemberStore;
module.exports = GuildMemberManager;

View File

@@ -1,17 +1,22 @@
'use strict';
const Collection = require('../util/Collection');
const Util = require('../util/Util');
const { TypeError } = require('../errors');
/**
* Stores member roles
* @extends {Collection}
* Manages API methods for roles of a GuildMember and stores their cache.
*/
class GuildMemberRoleStore extends Collection {
class GuildMemberRoleManager {
constructor(member) {
super();
/**
* The GuildMember this manager belongs to
* @type {GuildMember}
*/
this.member = member;
/**
* The Guild this manager belongs to
* @type {Guild}
*/
this.guild = member.guild;
Object.defineProperty(this, 'client', { value: member.client });
}
@@ -22,9 +27,18 @@ class GuildMemberRoleStore extends Collection {
* @private
* @readonly
*/
get _filtered() {
get _roles() {
const everyone = this.guild.roles.everyone;
return this.guild.roles.filter(role => this.member._roles.includes(role.id)).set(everyone.id, everyone);
return this.guild.roles.cache.filter(role => this.member._roles.includes(role.id)).set(everyone.id, everyone);
}
/**
* The roles of this member
* @type {Collection<Snowflake, Role>}
* @readonly
*/
get cache() {
return this._roles;
}
/**
@@ -33,7 +47,7 @@ class GuildMemberRoleStore extends Collection {
* @readonly
*/
get hoist() {
const hoistedRoles = this._filtered.filter(role => role.hoist);
const hoistedRoles = this._roles.filter(role => role.hoist);
if (!hoistedRoles.size) return null;
return hoistedRoles.reduce((prev, role) => !prev || role.comparePositionTo(prev) > 0 ? role : prev);
}
@@ -44,7 +58,7 @@ class GuildMemberRoleStore extends Collection {
* @readonly
*/
get color() {
const coloredRoles = this._filtered.filter(role => role.color);
const coloredRoles = this._roles.filter(role => role.color);
if (!coloredRoles.size) return null;
return coloredRoles.reduce((prev, role) => !prev || role.comparePositionTo(prev) > 0 ? role : prev);
}
@@ -55,7 +69,7 @@ class GuildMemberRoleStore extends Collection {
* @readonly
*/
get highest() {
return this._filtered.reduce((prev, role) => role.comparePositionTo(prev) > 0 ? role : prev, this.first());
return this._roles.reduce((prev, role) => role.comparePositionTo(prev) > 0 ? role : prev, this._roles.first());
}
/**
@@ -72,7 +86,7 @@ class GuildMemberRoleStore extends Collection {
'Array or Collection of Roles or Snowflakes', true);
}
const newRoles = [...new Set(roleOrRoles.concat(...this.values()))];
const newRoles = [...new Set(roleOrRoles.concat(...this._roles.values()))];
return this.set(newRoles, reason);
} else {
roleOrRoles = this.guild.roles.resolve(roleOrRoles);
@@ -84,7 +98,7 @@ class GuildMemberRoleStore extends Collection {
await this.client.api.guilds[this.guild.id].members[this.member.id].roles[roleOrRoles.id].put({ reason });
const clone = this.member._clone();
clone._roles = [...this.keys(), roleOrRoles.id];
clone._roles = [...this._roles.keys(), roleOrRoles.id];
return clone;
}
}
@@ -103,7 +117,7 @@ class GuildMemberRoleStore extends Collection {
'Array or Collection of Roles or Snowflakes', true);
}
const newRoles = this.filter(role => !roleOrRoles.includes(role));
const newRoles = this._roles.filter(role => !roleOrRoles.includes(role));
return this.set(newRoles, reason);
} else {
roleOrRoles = this.guild.roles.resolve(roleOrRoles);
@@ -115,7 +129,7 @@ class GuildMemberRoleStore extends Collection {
await this.client.api.guilds[this.guild.id].members[this.member.id].roles[roleOrRoles.id].delete({ reason });
const clone = this.member._clone();
const newRoles = this.filter(role => role.id !== roleOrRoles.id);
const newRoles = this._roles.filter(role => role.id !== roleOrRoles.id);
clone._roles = [...newRoles.keys()];
return clone;
}
@@ -134,7 +148,7 @@ class GuildMemberRoleStore extends Collection {
* @example
* // Remove all the roles from a member
* guildMember.roles.set([])
* .then(member => console.log(`Member roles is now of ${member.roles.size} size`))
* .then(member => console.log(`Member roles is now of ${member.roles.cache.size} size`))
* .catch(console.error);
*/
set(roles, reason) {
@@ -143,23 +157,9 @@ class GuildMemberRoleStore extends Collection {
clone() {
const clone = new this.constructor(this.member);
clone.member._roles = [...this.keyArray()];
clone.member._roles = [...this._roles.keyArray()];
return clone;
}
*[Symbol.iterator]() {
yield* this._filtered.entries();
}
valueOf() {
return this._filtered;
}
static get [Symbol.species]() {
return Collection;
}
}
Util.mixin(GuildMemberRoleStore, ['set']);
module.exports = GuildMemberRoleStore;
module.exports = GuildMemberRoleManager;

View File

@@ -0,0 +1,141 @@
'use strict';
const BaseManager = require('./BaseManager');
const Message = require('../structures/Message');
const LimitedCollection = require('../util/LimitedCollection');
const Collection = require('../util/Collection');
/**
* Manages API methods for Messages and holds their cache.
* @extends {BaseManager}
*/
class MessageManager extends BaseManager {
constructor(channel, iterable) {
super(channel.client, iterable, Message, LimitedCollection, channel.client.options.messageCacheMaxSize);
/**
* The channel that the messages belong to
* @type {TextBasedChannel}
*/
this.channel = channel;
}
/**
* The cache of Messages
* @property {LimitedCollection<Snowflake, Message>} cache
* @memberof MessageManager
* @instance
*/
add(data, cache) {
return super.add(data, cache, { extras: [this.channel] });
}
/**
* The parameters to pass in when requesting previous messages from a channel. `around`, `before` and
* `after` are mutually exclusive. All the parameters are optional.
* @typedef {Object} ChannelLogsQueryOptions
* @property {number} [limit=50] Number of messages to acquire
* @property {Snowflake} [before] ID of a message to get the messages that were posted before it
* @property {Snowflake} [after] ID of a message to get the messages that were posted after it
* @property {Snowflake} [around] ID of a message to get the messages that were posted around it
*/
/**
* Gets a message, or messages, from this channel.
* <info>The returned Collection does not contain reaction users of the messages if they were not cached.
* Those need to be fetched separately in such a case.</info>
* @param {Snowflake|ChannelLogsQueryOptions} [message] The ID of the message to fetch, or query parameters.
* @param {boolean} [cache=true] Whether to cache the message(s)
* @returns {Promise<Message>|Promise<Collection<Snowflake, Message>>}
* @example
* // Get message
* channel.messages.fetch('99539446449315840')
* .then(message => console.log(message.content))
* .catch(console.error);
* @example
* // Get messages
* channel.messages.fetch({ limit: 10 })
* .then(messages => console.log(`Received ${messages.size} messages`))
* .catch(console.error);
* @example
* // Get messages and filter by user ID
* channel.messages.fetch()
* .then(messages => console.log(`${messages.filter(m => m.author.id === '84484653687267328').size} messages`))
* .catch(console.error);
*/
fetch(message, cache = true) {
return typeof message === 'string' ? this._fetchId(message, cache) : this._fetchMany(message, cache);
}
/**
* Fetches the pinned messages of this channel and returns a collection of them.
* <info>The returned Collection does not contain any reaction data of the messages.
* Those need to be fetched separately.</info>
* @param {boolean} [cache=true] Whether to cache the message(s)
* @returns {Promise<Collection<Snowflake, Message>>}
* @example
* // Get pinned messages
* channel.fetchPinned()
* .then(messages => console.log(`Received ${messages.size} messages`))
* .catch(console.error);
*/
fetchPinned(cache = true) {
return this.client.api.channels[this.channel.id].pins.get().then(data => {
const messages = new Collection();
for (const message of data) messages.set(message.id, this.add(message, cache));
return messages;
});
}
/**
* Data that can be resolved to a Message object. This can be:
* * A Message
* * A Snowflake
* @typedef {Message|Snowflake} MessageResolvable
*/
/**
* Resolves a MessageResolvable to a Message object.
* @method resolve
* @memberof MessageManager
* @instance
* @param {MessageResolvable} message The message resolvable to resolve
* @returns {?Message}
*/
/**
* Resolves a MessageResolvable to a Message ID string.
* @method resolveID
* @memberof MessageManager
* @instance
* @param {MessageResolvable} message The message resolvable to resolve
* @returns {?Snowflake}
*/
/**
* Deletes a message, even if it's not cached.
* @param {MessageResolvable} message The message to delete
* @param {string} [reason] Reason for deleting this message, if it does not belong to the client user
*/
async delete(message, reason) {
message = this.resolveID(message);
if (message) await this.client.api.channels(this.channel.id).messages(message).delete({ reason });
}
async _fetchId(messageID, cache) {
const existing = this.cache.get(messageID);
if (existing && !existing.partial) return existing;
const data = await this.client.api.channels[this.channel.id].messages[messageID].get();
return this.add(data, cache);
}
async _fetchMany(options = {}, cache) {
const data = await this.client.api.channels[this.channel.id].messages.get({ query: options });
const messages = new Collection();
for (const message of data) messages.set(message.id, this.add(message, cache));
return messages;
}
}
module.exports = MessageManager;

View File

@@ -1,19 +1,26 @@
'use strict';
const DataStore = require('./DataStore');
const { Presence } = require('../structures/Presence');
const BaseManager = require('./BaseManager');
/**
* Stores presences.
* @extends {DataStore}
* Manages API methods for Presences and holds their cache.
* @extends {BaseManager}
*/
class PresenceStore extends DataStore {
class PresenceManager extends BaseManager {
constructor(client, iterable) {
super(client, iterable, Presence);
}
/**
* The cache of Presences
* @property {Collection<Snowflake, Presence>} cache
* @memberof PresenceManager
* @instance
*/
add(data, cache) {
const existing = this.get(data.user.id);
const existing = this.cache.get(data.user.id);
return existing ? existing.patch(data) : super.add(data, cache, { id: data.user.id });
}
@@ -46,8 +53,8 @@ class PresenceStore extends DataStore {
const presenceResolvable = super.resolveID(presence);
if (presenceResolvable) return presenceResolvable;
const userResolvable = this.client.users.resolveID(presence);
return this.has(userResolvable) ? userResolvable : null;
return this.cache.has(userResolvable) ? userResolvable : null;
}
}
module.exports = PresenceStore;
module.exports = PresenceManager;

View File

@@ -1,15 +1,20 @@
'use strict';
const DataStore = require('./DataStore');
const MessageReaction = require('../structures/MessageReaction');
const BaseManager = require('./BaseManager');
/**
* Stores reactions.
* @extends {DataStore}
* Manages API methods for reactions and holds their cache.
* @extends {BaseManager}
*/
class ReactionStore extends DataStore {
class ReactionManager extends BaseManager {
constructor(message, iterable) {
super(message.client, iterable, MessageReaction);
/**
* The message that this manager belongs to
* @type {Message}
*/
this.message = message;
}
@@ -17,6 +22,13 @@ class ReactionStore extends DataStore {
return super.add(data, cache, { id: data.emoji.id || data.emoji.name, extras: [this.message] });
}
/**
* The reaction cache of this manager
* @property {Collection<Snowflake, MessageReaction>} cache
* @memberof ReactionManager
* @instance
*/
/**
* Data that can be resolved to a MessageReaction object. This can be:
* * A MessageReaction
@@ -27,7 +39,7 @@ class ReactionStore extends DataStore {
/**
* Resolves a MessageReactionResolvable to a MessageReaction object.
* @method resolve
* @memberof ReactionStore
* @memberof ReactionManager
* @instance
* @param {MessageReactionResolvable} reaction The MessageReaction to resolve
* @returns {?MessageReaction}
@@ -36,7 +48,7 @@ class ReactionStore extends DataStore {
/**
* Resolves a MessageReactionResolvable to a MessageReaction ID string.
* @method resolveID
* @memberof ReactionStore
* @memberof ReactionManager
* @instance
* @param {MessageReactionResolvable} reaction The MessageReaction to resolve
* @returns {?Snowflake}
@@ -53,18 +65,18 @@ class ReactionStore extends DataStore {
_partial(emoji) {
const id = emoji.id || emoji.name;
const existing = this.get(id);
const existing = this.cache.get(id);
return !existing || existing.partial;
}
async _fetchReaction(reactionEmoji, cache) {
const id = reactionEmoji.id || reactionEmoji.name;
const existing = this.get(id);
const existing = this.cache.get(id);
if (!this._partial(reactionEmoji)) return existing;
const data = await this.client.api.channels(this.message.channel.id).messages(this.message.id).get();
if (!data.reactions || !data.reactions.some(r => (r.emoji.id || r.emoji.name) === id)) {
reactionEmoji.reaction._patch({ count: 0 });
this.message.reactions.remove(id);
this.message.reactions.cache.delete(id);
return existing;
}
for (const reaction of data.reactions) {
@@ -74,4 +86,4 @@ class ReactionStore extends DataStore {
}
}
module.exports = ReactionStore;
module.exports = ReactionManager;

View File

@@ -1,19 +1,30 @@
'use strict';
const Collection = require('../util/Collection');
const DataStore = require('./DataStore');
const BaseManager = require('./BaseManager');
const { Error } = require('../errors');
/**
* A data store to store User models who reacted to a MessageReaction.
* @extends {DataStore}
* Manages API methods for users who reacted to a reaction and stores their cache.
* @extends {BaseManager}
*/
class ReactionUserStore extends DataStore {
class ReactionUserManager extends BaseManager {
constructor(client, iterable, reaction) {
super(client, iterable, require('../structures/User'));
super(client, iterable, { name: 'User' });
/**
* The reaction that this manager belongs to
* @type {MessageReaction}
*/
this.reaction = reaction;
}
/**
* The cache of this manager
* @property {Collection<Snowflake, User>} cache
* @memberof GuildManager
* @instance
*/
/**
* Fetches all the users that gave this reaction. Resolves with a collection of users, mapped by their IDs.
* @param {Object} [options] Options for fetching the users
@@ -30,7 +41,7 @@ class ReactionUserStore extends DataStore {
const users = new Collection();
for (const rawUser of data) {
const user = this.client.users.add(rawUser);
this.set(user.id, user);
this.cache.set(user.id, user);
users.set(user.id, user);
}
return users;
@@ -52,4 +63,4 @@ class ReactionUserStore extends DataStore {
}
}
module.exports = ReactionUserStore;
module.exports = ReactionUserManager;

View File

@@ -1,20 +1,31 @@
'use strict';
const DataStore = require('./DataStore');
const BaseManager = require('./BaseManager');
const Role = require('../structures/Role');
const { resolveColor } = require('../util/Util');
const Permissions = require('../util/Permissions');
/**
* Stores roles.
* @extends {DataStore}
* Manages API methods for roles and stores their cache.
* @extends {BaseManager}
*/
class RoleStore extends DataStore {
class RoleManager extends BaseManager {
constructor(guild, iterable) {
super(guild.client, iterable, Role);
/**
* The guild belonging to this manager
* @type {Guild}
*/
this.guild = guild;
}
/**
* The role cache of this manager
* @property {Collection<Snowflake, Role>} cache
* @memberof RoleManager
* @instance
*/
add(data, cache) {
return super.add(data, cache, { extras: [this.guild] });
}
@@ -23,11 +34,11 @@ class RoleStore extends DataStore {
* Obtains one or more roles from Discord, or the role cache if they're already available.
* @param {Snowflake} [id] ID or IDs of the role(s)
* @param {boolean} [cache=true] Whether to cache the new roles objects if it weren't already
* @returns {Promise<Role|Role[]>}
* @returns {Promise<Role|RoleManager>}
* @example
* // Fetch all roles from the guild
* message.guild.roles.fetch()
* .then(roles => console.log(`There are ${roles.size} roles.`))
* .then(roles => console.log(`There are ${roles.cache.size} roles.`))
* .catch(console.error);
* @example
* // Fetch a single role
@@ -37,14 +48,14 @@ class RoleStore extends DataStore {
*/
async fetch(id, cache = true) {
if (id) {
const existing = this.get(id);
const existing = this.cache.get(id);
if (existing) return existing;
}
// We cannot fetch a single role, as of this commit's date, Discord API throws with 405
const roles = await this.client.api.guilds(this.guild.id).roles.get();
for (const role of roles) this.add(role, cache);
return id ? this.get(id) || null : this;
return id ? this.cache.get(id) || null : this;
}
/**
@@ -57,7 +68,7 @@ class RoleStore extends DataStore {
/**
* Resolves a RoleResolvable to a Role object.
* @method resolve
* @memberof RoleStore
* @memberof RoleManager
* @instance
* @param {RoleResolvable} role The role resolvable to resolve
* @returns {?Role}
@@ -66,7 +77,7 @@ class RoleStore extends DataStore {
/**
* Resolves a RoleResolvable to a role ID string.
* @method resolveID
* @memberof RoleStore
* @memberof RoleManager
* @instance
* @param {RoleResolvable} role The role resolvable to resolve
* @returns {?Snowflake}
@@ -116,17 +127,17 @@ class RoleStore extends DataStore {
* @readonly
*/
get everyone() {
return this.get(this.guild.id) || null;
return this.cache.get(this.guild.id) || null;
}
/**
* The role with the highest position in the store
* The role with the highest position in the cache
* @type {Role}
* @readonly
*/
get highest() {
return this.reduce((prev, role) => role.comparePositionTo(prev) > 0 ? role : prev, this.first());
return this.cache.reduce((prev, role) => role.comparePositionTo(prev) > 0 ? role : prev, this.cache.first());
}
}
module.exports = RoleStore;
module.exports = RoleManager;

View File

@@ -1,19 +1,26 @@
'use strict';
const DataStore = require('./DataStore');
const BaseManager = require('./BaseManager');
const User = require('../structures/User');
const GuildMember = require('../structures/GuildMember');
const Message = require('../structures/Message');
/**
* A data store to store User models.
* @extends {DataStore}
* Manages API methods for users and stores their cache.
* @extends {BaseManager}
*/
class UserStore extends DataStore {
class UserManager extends BaseManager {
constructor(client, iterable) {
super(client, iterable, User);
}
/**
* The cache of this manager
* @property {Collection<Snowflake, User>} cache
* @memberof UserManager
* @instance
*/
/**
* Data that resolves to give a User object. This can be:
* * A User object
@@ -52,11 +59,11 @@ class UserStore extends DataStore {
* @returns {Promise<User>}
*/
async fetch(id, cache = true) {
const existing = this.get(id);
const existing = this.cache.get(id);
if (existing && !existing.partial) return existing;
const data = await this.client.api.users(id).get();
return this.add(data, cache);
}
}
module.exports = UserStore;
module.exports = UserManager;

View File

@@ -0,0 +1,37 @@
'use strict';
const BaseManager = require('./BaseManager');
const VoiceState = require('../structures/VoiceState');
/**
* Manages API methods for VoiceStates and stores their cache.
* @extends {BaseManager}
*/
class VoiceStateManager extends BaseManager {
constructor(guild, iterable) {
super(guild.client, iterable, VoiceState);
/**
* The guild this manager belongs to
* @type {Guild}
*/
this.guild = guild;
}
/**
* The cache of this manager
* @property {Collection<Snowflake, VoiceState>} cache
* @memberof VoiceStateManager
* @instance
*/
add(data, cache = true) {
const existing = this.cache.get(data.user_id);
if (existing) return existing._patch(data);
const entry = new VoiceState(this.guild, data);
if (cache) this.cache.set(data.user_id, entry);
return entry;
}
}
module.exports = VoiceStateManager;

View File

@@ -86,7 +86,7 @@ class ShardClientUtil {
* @param {string} prop Name of the client property to get, using periods for nesting
* @returns {Promise<Array<*>>}
* @example
* client.shard.fetchClientValues('guilds.size')
* client.shard.fetchClientValues('guilds.cache.size')
* .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`))
* .catch(console.error);
* @see {@link ShardingManager#fetchClientValues}
@@ -114,7 +114,7 @@ class ShardClientUtil {
* @param {string|Function} script JavaScript to run on each shard
* @returns {Promise<Array<*>>} Results of the script execution
* @example
* client.shard.broadcastEval('this.guilds.size')
* client.shard.broadcastEval('this.guilds.cache.size')
* .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`))
* .catch(console.error);
* @see {@link ShardingManager#broadcastEval}

View File

@@ -229,7 +229,7 @@ class ShardingManager extends EventEmitter {
* @param {string} prop Name of the client property to get, using periods for nesting
* @returns {Promise<Array<*>>}
* @example
* manager.fetchClientValues('guilds.size')
* manager.fetchClientValues('guilds.cache.size')
* .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`))
* .catch(console.error);
*/

View File

@@ -1,135 +0,0 @@
'use strict';
const DataStore = require('./DataStore');
const Collection = require('../util/Collection');
const Message = require('../structures/Message');
/**
* Stores messages for text-based channels.
* @extends {DataStore}
*/
class MessageStore extends DataStore {
constructor(channel, iterable) {
super(channel.client, iterable, Message);
this.channel = channel;
}
add(data, cache) {
return super.add(data, cache, { extras: [this.channel] });
}
set(key, value) {
const maxSize = this.client.options.messageCacheMaxSize;
if (maxSize === 0) return;
if (this.size >= maxSize && maxSize > 0) this.delete(this.firstKey());
super.set(key, value);
}
/**
* The parameters to pass in when requesting previous messages from a channel. `around`, `before` and
* `after` are mutually exclusive. All the parameters are optional.
* @typedef {Object} ChannelLogsQueryOptions
* @property {number} [limit=50] Number of messages to acquire
* @property {Snowflake} [before] ID of a message to get the messages that were posted before it
* @property {Snowflake} [after] ID of a message to get the messages that were posted after it
* @property {Snowflake} [around] ID of a message to get the messages that were posted around it
*/
/**
* Gets a message, or messages, from this channel.
* <info>The returned Collection does not contain reaction users of the messages if they were not cached.
* Those need to be fetched separately in such a case.</info>
* @param {Snowflake|ChannelLogsQueryOptions} [message] The ID of the message to fetch, or query parameters.
* @param {boolean} [cache=true] Whether to cache the message(s)
* @returns {Promise<Message>|Promise<Collection<Snowflake, Message>>}
* @example
* // Get message
* channel.messages.fetch('99539446449315840')
* .then(message => console.log(message.content))
* .catch(console.error);
* @example
* // Get messages
* channel.messages.fetch({ limit: 10 })
* .then(messages => console.log(`Received ${messages.size} messages`))
* .catch(console.error);
* @example
* // Get messages and filter by user ID
* channel.messages.fetch()
* .then(messages => console.log(`${messages.filter(m => m.author.id === '84484653687267328').size} messages`))
* .catch(console.error);
*/
fetch(message, cache = true) {
return typeof message === 'string' ? this._fetchId(message, cache) : this._fetchMany(message, cache);
}
/**
* Fetches the pinned messages of this channel and returns a collection of them.
* <info>The returned Collection does not contain any reaction data of the messages.
* Those need to be fetched separately.</info>
* @param {boolean} [cache=true] Whether to cache the message(s)
* @returns {Promise<Collection<Snowflake, Message>>}
* @example
* // Get pinned messages
* channel.fetchPinned()
* .then(messages => console.log(`Received ${messages.size} messages`))
* .catch(console.error);
*/
fetchPinned(cache = true) {
return this.client.api.channels[this.channel.id].pins.get().then(data => {
const messages = new Collection();
for (const message of data) messages.set(message.id, this.add(message, cache));
return messages;
});
}
/**
* Data that can be resolved to a Message object. This can be:
* * A Message
* * A Snowflake
* @typedef {Message|Snowflake} MessageResolvable
*/
/**
* Resolves a MessageResolvable to a Message object.
* @method resolve
* @memberof MessageStore
* @instance
* @param {MessageResolvable} message The message resolvable to resolve
* @returns {?Message}
*/
/**
* Resolves a MessageResolvable to a Message ID string.
* @method resolveID
* @memberof MessageStore
* @instance
* @param {MessageResolvable} message The message resolvable to resolve
* @returns {?Snowflake}
*/
/**
* Deletes a message, even if it's not cached.
* @param {MessageResolvable} message The message to delete
* @param {string} [reason] Reason for deleting this message, if it does not belong to the client user
*/
async remove(message, reason) {
message = this.resolveID(message);
if (message) await this.client.api.channels(this.channel.id).messages(message).delete({ reason });
}
async _fetchId(messageID, cache) {
const existing = this.get(messageID);
if (existing && !existing.partial) return existing;
const data = await this.client.api.channels[this.channel.id].messages[messageID].get();
return this.add(data, cache);
}
async _fetchMany(options = {}, cache) {
const data = await this.client.api.channels[this.channel.id].messages.get({ query: options });
const messages = new Collection();
for (const message of data) messages.set(message.id, this.add(message, cache));
return messages;
}
}
module.exports = MessageStore;

View File

@@ -1,26 +0,0 @@
'use strict';
const DataStore = require('./DataStore');
const VoiceState = require('../structures/VoiceState');
/**
* Stores voice states.
* @extends {DataStore}
*/
class VoiceStateStore extends DataStore {
constructor(guild, iterable) {
super(guild.client, iterable, VoiceState);
this.guild = guild;
}
add(data, cache = true) {
const existing = this.get(data.user_id);
if (existing) return existing._patch(data);
const entry = new VoiceState(this.guild, data);
if (cache) this.set(data.user_id, entry);
return entry;
}
}
module.exports = VoiceStateStore;

View File

@@ -13,7 +13,7 @@ class CategoryChannel extends GuildChannel {
* @readonly
*/
get children() {
return this.guild.channels.filter(c => c.parentID === this.id);
return this.guild.channels.cache.filter(c => c.parentID === this.id);
}
/**

View File

@@ -100,7 +100,7 @@ class Channel extends Base {
const DMChannel = Structures.get('DMChannel');
channel = new DMChannel(client, data);
} else {
guild = guild || client.guilds.get(data.guild_id);
guild = guild || client.guilds.cache.get(data.guild_id);
if (guild) {
switch (data.type) {
case ChannelTypes.TEXT: {
@@ -129,7 +129,7 @@ class Channel extends Base {
break;
}
}
if (channel) guild.channels.set(channel.id, channel);
if (channel) guild.channels.cache.set(channel.id, channel);
}
}
return channel;

View File

@@ -2,7 +2,7 @@
const Channel = require('./Channel');
const TextBasedChannel = require('./interfaces/TextBasedChannel');
const MessageStore = require('../stores/MessageStore');
const MessageManager = require('../managers/MessageManager');
/**
* Represents a direct message channel between two users.
@@ -19,10 +19,10 @@ class DMChannel extends Channel {
// Override the channel type so partials have a known type
this.type = 'dm';
/**
* A collection containing the messages sent to this channel
* @type {MessageStore<Snowflake, Message>}
* A manager of the messages belonging to this channel
* @type {MessageManager}
*/
this.messages = new MessageStore(this);
this.messages = new MessageManager(this);
this._typing = new Map();
}

View File

@@ -82,7 +82,7 @@ class Emoji extends Base {
* @returns {string}
* @example
* // Send a custom emoji from a guild:
* const emoji = guild.emojis.first();
* const emoji = guild.emojis.cache.first();
* msg.reply(`Hello! ${emoji}`);
* @example
* // Send the emoji used in a reaction to the channel the reaction is part of

View File

@@ -11,12 +11,12 @@ const Util = require('../util/Util');
const DataResolver = require('../util/DataResolver');
const Snowflake = require('../util/Snowflake');
const SystemChannelFlags = require('../util/SystemChannelFlags');
const GuildMemberStore = require('../stores/GuildMemberStore');
const RoleStore = require('../stores/RoleStore');
const GuildEmojiStore = require('../stores/GuildEmojiStore');
const GuildChannelStore = require('../stores/GuildChannelStore');
const PresenceStore = require('../stores/PresenceStore');
const VoiceStateStore = require('../stores/VoiceStateStore');
const GuildMemberManager = require('../managers/GuildMemberManager');
const RoleManager = require('../managers/RoleManager');
const GuildEmojiManager = require('../managers/GuildEmojiManager');
const GuildChannelManager = require('../managers/GuildChannelManager');
const PresenceManager = require('../managers/PresenceManager');
const VoiceStateManager = require('../managers/VoiceStateManager');
const Base = require('./Base');
const { Error, TypeError } = require('../errors');
@@ -35,34 +35,34 @@ class Guild extends Base {
super(client);
/**
* A collection of members that are in this guild. The key is the member's ID, the value is the member
* @type {GuildMemberStore<Snowflake, GuildMember>}
* A manager of the members belonging to this guild
* @type {GuildMemberManager}
*/
this.members = new GuildMemberStore(this);
this.members = new GuildMemberManager(this);
/**
* A collection of channels that are in this guild. The key is the channel's ID, the value is the channel
* @type {GuildChannelStore<Snowflake, GuildChannel>}
* A manager of the members belonging to this guild
* @type {GuildChannelManager}
*/
this.channels = new GuildChannelStore(this);
this.channels = new GuildChannelManager(this);
/**
* A collection of roles that are in this guild. The key is the role's ID, the value is the role
* @type {RoleStore<Snowflake, Role>}
* A manager of the roles belonging to this guild
* @type {RoleManager}
*/
this.roles = new RoleStore(this);
this.roles = new RoleManager(this);
/**
* A collection of presences in this guild
* @type {PresenceStore<Snowflake, Presence>}
* A manager of the presences belonging to this guild
* @type {PresenceManager}
*/
this.presences = new PresenceStore(this.client);
this.presences = new PresenceManager(this.client);
/**
* A collection of voice states in this guild
* @type {VoiceStateStore<Snowflake, VoiceState>}
* A manager of the voice states of this guild
* @type {VoiceStateManager}
*/
this.voiceStates = new VoiceStateStore(this);
this.voiceStates = new VoiceStateManager(this);
/**
* Whether the bot has been removed from the guild
@@ -321,19 +321,19 @@ class Guild extends Base {
this.features = data.features || this.features || [];
if (data.channels) {
this.channels.clear();
this.channels.cache.clear();
for (const rawChannel of data.channels) {
this.client.channels.add(rawChannel, this);
}
}
if (data.roles) {
this.roles.clear();
this.roles.cache.clear();
for (const role of data.roles) this.roles.add(role);
}
if (data.members) {
this.members.clear();
this.members.cache.clear();
for (const guildUser of data.members) this.members.add(guildUser);
}
@@ -352,7 +352,7 @@ class Guild extends Base {
}
if (data.voice_states) {
this.voiceStates.clear();
this.voiceStates.cache.clear();
for (const voiceState of data.voice_states) {
this.voiceStates.add(voiceState);
}
@@ -360,10 +360,10 @@ class Guild extends Base {
if (!this.emojis) {
/**
* A collection of emojis that are in this guild. The key is the emoji's ID, the value is the emoji.
* @type {GuildEmojiStore<Snowflake, GuildEmoji>}
* A manager of the emojis belonging to this guild
* @type {GuildEmojiManager}
*/
this.emojis = new GuildEmojiStore(this);
this.emojis = new GuildEmojiManager(this);
if (data.emojis) for (const emoji of data.emojis) this.emojis.add(emoji);
} else if (data.emojis) {
this.client.actions.GuildEmojisUpdate.handle({
@@ -463,7 +463,7 @@ class Guild extends Base {
* @readonly
*/
get owner() {
return this.members.get(this.ownerID) || (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) ?
return this.members.cache.get(this.ownerID) || (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) ?
this.members.add({ user: { id: this.ownerID } }, true) :
null);
}
@@ -474,7 +474,7 @@ class Guild extends Base {
* @readonly
*/
get afkChannel() {
return this.client.channels.get(this.afkChannelID) || null;
return this.client.channels.cache.get(this.afkChannelID) || null;
}
/**
@@ -483,7 +483,7 @@ class Guild extends Base {
* @readonly
*/
get systemChannel() {
return this.client.channels.get(this.systemChannelID) || null;
return this.client.channels.cache.get(this.systemChannelID) || null;
}
/**
@@ -492,7 +492,7 @@ class Guild extends Base {
* @readonly
*/
get widgetChannel() {
return this.client.channels.get(this.widgetChannelID) || null;
return this.client.channels.cache.get(this.widgetChannelID) || null;
}
/**
@@ -501,7 +501,7 @@ class Guild extends Base {
* @readonly
*/
get embedChannel() {
return this.client.channels.get(this.embedChannelID) || null;
return this.client.channels.cache.get(this.embedChannelID) || null;
}
/**
@@ -510,9 +510,10 @@ class Guild extends Base {
* @readonly
*/
get me() {
return this.members.get(this.client.user.id) || (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) ?
this.members.add({ user: { id: this.client.user.id } }, true) :
null);
return this.members.cache.get(this.client.user.id) ||
(this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) ?
this.members.add({ user: { id: this.client.user.id } }, true) :
null);
}
/**
@@ -521,7 +522,7 @@ class Guild extends Base {
* @readonly
*/
get voice() {
return this.voiceStates.get(this.client.user.id);
return this.voiceStates.cache.get(this.client.user.id);
}
/**
@@ -716,7 +717,7 @@ class Guild extends Base {
fetchEmbed() {
return this.client.api.guilds(this.id).embed.get().then(data => ({
enabled: data.enabled,
channel: data.channel_id ? this.channels.get(data.channel_id) : null,
channel: data.channel_id ? this.channels.cache.get(data.channel_id) : null,
}));
}
@@ -763,7 +764,7 @@ class Guild extends Base {
addMember(user, options) {
user = this.client.users.resolveID(user);
if (!user) return Promise.reject(new TypeError('INVALID_TYPE', 'user', 'UserResolvable'));
if (this.members.has(user)) return Promise.resolve(this.members.get(user));
if (this.members.cache.has(user)) return Promise.resolve(this.members.cache.get(user));
options.access_token = options.accessToken;
if (options.roles) {
const roles = [];
@@ -988,7 +989,7 @@ class Guild extends Base {
* @returns {Promise<Guild>}
* @example
* // Edit the guild owner
* guild.setOwner(guild.members.first())
* guild.setOwner(guild.members.cache.first())
* .then(updated => console.log(`Updated the guild owner to ${updated.owner.displayName}`))
* .catch(console.error);
*/
@@ -1203,7 +1204,7 @@ class Guild extends Base {
* @private
*/
_sortedRoles() {
return Util.discordSort(this.roles);
return Util.discordSort(this.roles.cache);
}
/**
@@ -1214,7 +1215,7 @@ class Guild extends Base {
*/
_sortedChannels(channel) {
const category = channel.type === ChannelTypes.CATEGORY;
return Util.discordSort(this.channels.filter(c =>
return Util.discordSort(this.channels.cache.filter(c =>
c.type === channel.type && (category || c.parent === channel.parent)
));
}

View File

@@ -285,7 +285,7 @@ class GuildAuditLogsEntry {
*/
this.executor = guild.client.options.partials.includes(PartialTypes.USER) ?
guild.client.users.add({ id: data.user_id }) :
guild.client.users.get(data.user_id);
guild.client.users.cache.get(data.user_id);
/**
* An entry in the audit log representing a specific change.
@@ -321,7 +321,7 @@ class GuildAuditLogsEntry {
} else if (data.action_type === Actions.MESSAGE_DELETE) {
this.extra = {
count: data.options.count,
channel: guild.channels.get(data.options.channel_id),
channel: guild.channels.cache.get(data.options.channel_id),
};
} else if (data.action_type === Actions.MESSAGE_BULK_DELETE) {
this.extra = {
@@ -330,11 +330,11 @@ class GuildAuditLogsEntry {
} else {
switch (data.options.type) {
case 'member':
this.extra = guild.members.get(data.options.id);
this.extra = guild.members.cache.get(data.options.id);
if (!this.extra) this.extra = { id: data.options.id };
break;
case 'role':
this.extra = guild.roles.get(data.options.id);
this.extra = guild.roles.cache.get(data.options.id);
if (!this.extra) this.extra = { id: data.options.id, name: data.options.role_name };
break;
default:
@@ -357,9 +357,9 @@ class GuildAuditLogsEntry {
} else if (targetType === Targets.USER) {
this.target = guild.client.options.partials.includes(PartialTypes.USER) ?
guild.client.users.add({ id: data.target_id }) :
guild.client.users.get(data.target_id);
guild.client.users.cache.get(data.target_id);
} else if (targetType === Targets.GUILD) {
this.target = guild.client.guilds.get(data.target_id);
this.target = guild.client.guilds.cache.get(data.target_id);
} else if (targetType === Targets.WEBHOOK) {
this.target = logs.webhooks.get(data.target_id) ||
new Webhook(guild.client,
@@ -386,9 +386,9 @@ class GuildAuditLogsEntry {
}
});
} else if (targetType === Targets.MESSAGE) {
this.target = guild.client.users.get(data.target_id);
this.target = guild.client.users.cache.get(data.target_id);
} else {
this.target = guild[`${targetType.toLowerCase()}s`].get(data.target_id) || { id: data.target_id };
this.target = guild[`${targetType.toLowerCase()}s`].cache.get(data.target_id) || { id: data.target_id };
}
}

View File

@@ -72,7 +72,7 @@ class GuildChannel extends Channel {
* @readonly
*/
get parent() {
return this.guild.channels.get(this.parentID) || null;
return this.guild.channels.cache.get(this.parentID) || null;
}
/**
@@ -118,7 +118,7 @@ class GuildChannel extends Channel {
if (!verified) member = this.guild.members.resolve(member);
if (!member) return [];
roles = roles || member.roles;
roles = roles || member.roles.cache;
const roleOverwrites = [];
let memberOverwrites;
let everyoneOverwrites;
@@ -149,7 +149,7 @@ class GuildChannel extends Channel {
memberPermissions(member) {
if (member.id === this.guild.ownerID) return new Permissions(Permissions.ALL).freeze();
const roles = member.roles;
const roles = member.roles.cache;
const permissions = new Permissions(roles.map(role => role.permissions));
if (permissions.has(Permissions.FLAGS.ADMINISTRATOR)) return new Permissions(Permissions.ALL).freeze();
@@ -274,7 +274,7 @@ class GuildChannel extends Channel {
*/
get members() {
const members = new Collection();
for (const member of this.guild.members.values()) {
for (const member of this.guild.members.cache.values()) {
if (this.permissionsFor(member).has('VIEW_CHANNEL', false)) {
members.set(member.id, member);
}

View File

@@ -1,6 +1,6 @@
'use strict';
const GuildEmojiRoleStore = require('../stores/GuildEmojiRoleStore');
const GuildEmojiRoleManager = require('../managers/GuildEmojiRoleManager');
const Permissions = require('../util/Permissions');
const { Error } = require('../errors');
const Emoji = require('./Emoji');
@@ -79,12 +79,12 @@ class GuildEmoji extends Emoji {
}
/**
* A collection of roles this emoji is active for (empty if all), mapped by role ID
* @type {GuildEmojiRoleStore<Snowflake, Role>}
* A manager for roles this emoji is active for.
* @type {GuildEmojiRoleManager}
* @readonly
*/
get roles() {
return new GuildEmojiRoleStore(this);
return new GuildEmojiRoleManager(this);
}
/**
@@ -168,15 +168,15 @@ class GuildEmoji extends Emoji {
other.name === this.name &&
other.managed === this.managed &&
other.requiresColons === this.requiresColons &&
other.roles.size === this.roles.size &&
other.roles.every(role => this.roles.has(role.id))
other.roles.cache.size === this.roles.cache.size &&
other.roles.cache.every(role => this.roles.cache.has(role.id))
);
} else {
return (
other.id === this.id &&
other.name === this.name &&
other.roles.length === this.roles.size &&
other.roles.every(role => this.roles.has(role))
other.roles.length === this.roles.cache.size &&
other.roles.every(role => this.roles.cache.has(role))
);
}
}

View File

@@ -3,7 +3,7 @@
const TextBasedChannel = require('./interfaces/TextBasedChannel');
const Role = require('./Role');
const Permissions = require('../util/Permissions');
const GuildMemberRoleStore = require('../stores/GuildMemberRoleStore');
const GuildMemberRoleManager = require('../managers/GuildMemberRoleManager');
const Base = require('./Base');
const VoiceState = require('./VoiceState');
const { Presence } = require('./Presence');
@@ -101,12 +101,12 @@ class GuildMember extends Base {
}
/**
* A collection of roles that are applied to this member, mapped by the role ID
* @type {GuildMemberRoleStore<Snowflake, Role>}
* A manager for the roles belonging to this member
* @type {GuildMemberRoleManager}
* @readonly
*/
get roles() {
return new GuildMemberRoleStore(this);
return new GuildMemberRoleManager(this);
}
/**
@@ -115,8 +115,8 @@ class GuildMember extends Base {
* @readonly
*/
get lastMessage() {
const channel = this.guild.channels.get(this.lastMessageChannelID);
return (channel && channel.messages.get(this.lastMessageID)) || null;
const channel = this.guild.channels.cache.get(this.lastMessageChannelID);
return (channel && channel.messages.cache.get(this.lastMessageID)) || null;
}
/**
@@ -125,7 +125,7 @@ class GuildMember extends Base {
* @readonly
*/
get voice() {
return this.guild.voiceStates.get(this.id) || new VoiceState(this.guild, { user_id: this.id });
return this.guild.voiceStates.cache.get(this.id) || new VoiceState(this.guild, { user_id: this.id });
}
/**
@@ -152,7 +152,7 @@ class GuildMember extends Base {
* @readonly
*/
get presence() {
return this.guild.presences.get(this.id) || new Presence(this.client, {
return this.guild.presences.cache.get(this.id) || new Presence(this.client, {
user: {
id: this.id,
},
@@ -205,7 +205,7 @@ class GuildMember extends Base {
*/
get permissions() {
if (this.user.id === this.guild.ownerID) return new Permissions(Permissions.ALL).freeze();
return new Permissions(this.roles.map(role => role.permissions)).freeze();
return new Permissions(this.roles.cache.map(role => role.permissions)).freeze();
}
/**
@@ -261,7 +261,7 @@ class GuildMember extends Base {
*/
hasPermission(permission, { checkAdmin = true, checkOwner = true } = {}) {
if (checkOwner && this.user.id === this.guild.ownerID) return true;
return this.roles.some(r => r.permissions.has(permission, checkAdmin));
return this.roles.cache.some(r => r.permissions.has(permission, checkAdmin));
}
/**

View File

@@ -56,7 +56,7 @@ class Integration extends Base {
* The role that this integration uses for subscribers
* @type {Role}
*/
this.role = this.guild.roles.get(data.role_id);
this.role = this.guild.roles.cache.get(data.role_id);
/**
* The user for this integration

View File

@@ -117,7 +117,7 @@ class Invite extends Base {
*/
get deletable() {
const guild = this.guild;
if (!guild || !this.client.guilds.has(guild.id)) return false;
if (!guild || !this.client.guilds.cache.has(guild.id)) return false;
if (!guild.me) throw new Error('GUILD_UNCACHED_ME');
return this.channel.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_CHANNELS, false) ||
guild.me.permissions.has(Permissions.FLAGS.MANAGE_GUILD);

View File

@@ -7,7 +7,7 @@ const ReactionCollector = require('./ReactionCollector');
const ClientApplication = require('./ClientApplication');
const Util = require('../util/Util');
const Collection = require('../util/Collection');
const ReactionStore = require('../stores/ReactionStore');
const ReactionManager = require('../managers/ReactionManager');
const { MessageTypes } = require('../util/Constants');
const Permissions = require('../util/Permissions');
const Base = require('./Base');
@@ -126,10 +126,10 @@ class Message extends Base {
this.editedTimestamp = data.edited_timestamp ? new Date(data.edited_timestamp).getTime() : null;
/**
* A collection of reactions to this message, mapped by the reaction ID
* @type {ReactionStore<Snowflake, MessageReaction>}
* A manager of the reactions belonging to this message
* @type {ReactionManager}
*/
this.reactions = new ReactionStore(this);
this.reactions = new ReactionManager(this);
if (data.reactions && data.reactions.length > 0) {
for (const reaction of data.reactions) {
this.reactions.add(reaction);
@@ -452,7 +452,7 @@ class Message extends Base {
* .catch(console.error);
* @example
* // React to a message with a custom emoji
* message.react(message.guild.emojis.get('123456789012345678'))
* message.react(message.guild.emojis.cache.get('123456789012345678'))
* .then(console.log)
* .catch(console.error);
*/
@@ -484,7 +484,7 @@ class Message extends Base {
*/
delete({ timeout = 0, reason } = {}) {
if (timeout <= 0) {
return this.channel.messages.remove(this.id, reason).then(() => this);
return this.channel.messages.delete(this.id, reason).then(() => this);
} else {
return new Promise(resolve => {
this.client.setTimeout(() => {

View File

@@ -71,7 +71,7 @@ class MessageMentions {
} else {
this.roles = new Collection();
for (const mention of roles) {
const role = message.channel.guild.roles.get(mention);
const role = message.channel.guild.roles.cache.get(mention);
if (role) this.roles.set(role.id, role);
}
}
@@ -156,7 +156,7 @@ class MessageMentions {
this._channels = new Collection();
let matches;
while ((matches = this.constructor.CHANNELS_PATTERN.exec(this._content)) !== null) {
const chan = this.client.channels.get(matches[1]);
const chan = this.client.channels.cache.get(matches[1]);
if (chan) this._channels.set(chan.id, chan);
}
return this._channels;
@@ -175,7 +175,7 @@ class MessageMentions {
has(data, { ignoreDirect = false, ignoreRoles = false, ignoreEveryone = false } = {}) {
if (!ignoreEveryone && this.everyone) return true;
if (!ignoreRoles && data instanceof GuildMember) {
for (const role of this.roles.values()) if (data.roles.has(role.id)) return true;
for (const role of this.roles.values()) if (data.roles.cache.has(role.id)) return true;
}
if (!ignoreDirect) {

View File

@@ -3,7 +3,7 @@
const GuildEmoji = require('./GuildEmoji');
const Util = require('../util/Util');
const ReactionEmoji = require('./ReactionEmoji');
const ReactionUserStore = require('../stores/ReactionUserStore');
const ReactionUserManager = require('../managers/ReactionUserManager');
/**
* Represents a reaction to a message.
@@ -35,10 +35,10 @@ class MessageReaction {
this.me = data.me;
/**
* The users that have given this reaction, mapped by their ID
* @type {ReactionUserStore<Snowflake, User>}
* A manager of the users that have given this reaction
* @type {ReactionUserManager}
*/
this.users = new ReactionUserStore(client, undefined, this);
this.users = new ReactionUserManager(client, undefined, this);
this._emoji = new ReactionEmoji(this, data.emoji);
@@ -75,7 +75,7 @@ class MessageReaction {
if (this._emoji instanceof GuildEmoji) return this._emoji;
// Check to see if the emoji has become known to the client
if (this._emoji.id) {
const emojis = this.message.client.emojis;
const emojis = this.message.client.emojis.cache;
if (emojis.has(this._emoji.id)) {
const emoji = emojis.get(this._emoji.id);
this._emoji = emoji;
@@ -108,18 +108,18 @@ class MessageReaction {
_add(user) {
if (this.partial) return;
this.users.set(user.id, user);
this.users.cache.set(user.id, user);
if (!this.me || user.id !== this.message.client.user.id || this.count === 0) this.count++;
if (!this.me) this.me = user.id === this.message.client.user.id;
}
_remove(user) {
if (this.partial) return;
this.users.delete(user.id);
this.users.cache.delete(user.id);
if (!this.me || user.id !== this.message.client.user.id) this.count--;
if (user.id === this.message.client.user.id) this.me = false;
if (this.count <= 0 && this.users.size === 0) {
this.message.reactions.remove(this.emoji.id || this.emoji.name);
if (this.count <= 0 && this.users.cache.size === 0) {
this.message.reactions.cache.delete(this.emoji.id || this.emoji.name);
}
}
}

View File

@@ -66,7 +66,7 @@ class Presence {
* @readonly
*/
get user() {
return this.client.users.get(this.userID) || null;
return this.client.users.cache.get(this.userID) || null;
}
/**
@@ -75,7 +75,7 @@ class Presence {
* @readonly
*/
get member() {
return this.guild.members.get(this.userID) || null;
return this.guild.members.cache.get(this.userID) || null;
}
patch(data) {

View File

@@ -74,7 +74,7 @@ class ReactionCollector extends Collector {
this.on('remove', (reaction, user) => {
this.total--;
if (!this.collected.some(r => r.users.has(user.id))) this.users.delete(user.id);
if (!this.collected.some(r => r.users.cache.has(user.id))) this.users.delete(user.id);
});
}

View File

@@ -117,7 +117,7 @@ class Role extends Base {
* @readonly
*/
get members() {
return this.guild.members.filter(m => m.roles.has(this.id));
return this.guild.members.cache.filter(m => m.roles.cache.has(this.id));
}
/**

View File

@@ -5,7 +5,7 @@ const Webhook = require('./Webhook');
const TextBasedChannel = require('./interfaces/TextBasedChannel');
const Collection = require('../util/Collection');
const DataResolver = require('../util/DataResolver');
const MessageStore = require('../stores/MessageStore');
const MessageManager = require('../managers/MessageManager');
/**
* Represents a guild text channel on Discord.
@@ -20,10 +20,10 @@ class TextChannel extends GuildChannel {
constructor(guild, data) {
super(guild, data);
/**
* A collection containing the messages sent to this channel
* @type {MessageStore<Snowflake, Message>}
* A manager of the messages sent to this channel
* @type {MessageManager}
*/
this.messages = new MessageStore(this);
this.messages = new MessageManager(this);
this._typing = new Map();
}

View File

@@ -119,8 +119,8 @@ class User extends Base {
* @readonly
*/
get lastMessage() {
const channel = this.client.channels.get(this.lastMessageChannelID);
return (channel && channel.messages.get(this.lastMessageID)) || null;
const channel = this.client.channels.cache.get(this.lastMessageChannelID);
return (channel && channel.messages.cache.get(this.lastMessageID)) || null;
}
/**
@@ -129,8 +129,8 @@ class User extends Base {
* @readonly
*/
get presence() {
for (const guild of this.client.guilds.values()) {
if (guild.presences.has(this.id)) return guild.presences.get(this.id);
for (const guild of this.client.guilds.cache.values()) {
if (guild.presences.cache.has(this.id)) return guild.presences.cache.get(this.id);
}
return new Presence(this.client, { user: { id: this.id } });
}
@@ -209,7 +209,7 @@ class User extends Base {
* @readonly
*/
get dmChannel() {
return this.client.channels.find(c => c.type === 'dm' && c.recipient.id === this.id) || null;
return this.client.channels.cache.find(c => c.type === 'dm' && c.recipient.id === this.id) || null;
}
/**

View File

@@ -34,7 +34,7 @@ class VoiceChannel extends GuildChannel {
*/
get members() {
const coll = new Collection();
for (const state of this.guild.voiceStates.values()) {
for (const state of this.guild.voiceStates.cache.values()) {
if (state.channelID === this.id && state.member) {
coll.set(state.id, state.member);
}

View File

@@ -72,7 +72,7 @@ class VoiceState extends Base {
* @readonly
*/
get member() {
return this.guild.members.get(this.id) || null;
return this.guild.members.cache.get(this.id) || null;
}
/**
@@ -81,7 +81,7 @@ class VoiceState extends Base {
* @readonly
*/
get channel() {
return this.guild.channels.get(this.channelID) || null;
return this.guild.channels.cache.get(this.channelID) || null;
}
/**

View File

@@ -70,7 +70,7 @@ class Webhook {
* The owner of the webhook
* @type {?User|Object}
*/
this.owner = this.client.users ? this.client.users.get(data.user.id) : data.user;
this.owner = this.client.users ? this.client.users.cache.get(data.user.id) : data.user;
} else {
this.owner = null;
}
@@ -154,7 +154,7 @@ class Webhook {
query: { wait: true },
auth: false,
}).then(d => {
const channel = this.client.channels ? this.client.channels.get(d.channel_id) : undefined;
const channel = this.client.channels ? this.client.channels.cache.get(d.channel_id) : undefined;
if (!channel) return d;
return channel.messages.add(d, false);
});

View File

@@ -13,10 +13,10 @@ const APIMessage = require('../APIMessage');
class TextBasedChannel {
constructor() {
/**
* A collection containing the messages sent to this channel
* @type {MessageStore<Snowflake, Message>}
* A manager of the messages sent to this channel
* @type {MessageManager}
*/
this.messages = new MessageStore(this);
this.messages = new MessageManager(this);
/**
* The ID of the last message in the channel, if one was sent
@@ -37,7 +37,7 @@ class TextBasedChannel {
* @readonly
*/
get lastMessage() {
return this.messages.get(this.lastMessageID) || null;
return this.messages.cache.get(this.lastMessageID) || null;
}
/**
@@ -350,4 +350,4 @@ class TextBasedChannel {
module.exports = TextBasedChannel;
// Fixes Circular
const MessageStore = require('../../stores/MessageStore');
const MessageManager = require('../../managers/MessageManager');

View File

@@ -0,0 +1,29 @@
'use strict';
const Collection = require('./Collection.js');
/**
* A Collection which holds a max amount of entries. The first key is deleted if the Collection has
* reached max size.
* @extends {Collection}
* @param {number} [maxSize=0] The maximum size of the Collection
* @param {Iterable} [iterable=null] Optional entries passed to the Map constructor.
*/
class LimitedCollection extends Collection {
constructor(maxSize = 0, iterable = null) {
super(iterable);
/**
* The max size of the Collection.
* @type {number}
*/
this.maxSize = maxSize;
}
set(key, value) {
if (this.maxSize === 0) return this;
if (this.size >= this.maxSize && !this.has(key)) this.delete(this.firstKey());
return super.set(key, value);
}
}
module.exports = LimitedCollection;

View File

@@ -1,7 +1,7 @@
'use strict';
/**
* Allows for the extension of built-in Discord.js structures that are instantiated by {@link DataStore DataStores}.
* Allows for the extension of built-in Discord.js structures that are instantiated by {@link BaseManager Managers}.
*/
class Structures {
constructor() {

View File

@@ -528,25 +528,25 @@ class Util {
.replace(/<@!?[0-9]+>/g, input => {
const id = input.replace(/<|!|>|@/g, '');
if (message.channel.type === 'dm') {
const user = message.client.users.get(id);
const user = message.client.users.cache.get(id);
return user ? `@${user.username}` : input;
}
const member = message.channel.guild.members.get(id);
const member = message.channel.guild.members.cache.get(id);
if (member) {
return `@${member.displayName}`;
} else {
const user = message.client.users.get(id);
const user = message.client.users.cache.get(id);
return user ? `@${user.username}` : input;
}
})
.replace(/<#[0-9]+>/g, input => {
const channel = message.client.channels.get(input.replace(/<|#|>/g, ''));
const channel = message.client.channels.cache.get(input.replace(/<|#|>/g, ''));
return channel ? `#${channel.name}` : input;
})
.replace(/<@&[0-9]+>/g, input => {
if (message.channel.type === 'dm') return input;
const role = message.guild.roles.get(input.replace(/<|@|>|&/g, ''));
const role = message.guild.roles.cache.get(input.replace(/<|@|>|&/g, ''));
return role ? `@${role.name}` : input;
});
}
@@ -571,34 +571,6 @@ class Util {
setTimeout(resolve, ms);
});
}
/**
* Adds methods from collections and maps onto the provided store
* @param {DataStore} store The store to mixin
* @param {string[]} ignored The properties to ignore
* @private
*/
/* eslint-disable func-names */
static mixin(store, ignored) {
const Collection = require('./Collection');
Object.getOwnPropertyNames(Collection.prototype)
.concat(Object.getOwnPropertyNames(Map.prototype)).forEach(prop => {
if (ignored.includes(prop)) return;
if (prop === 'size') {
Object.defineProperty(store.prototype, prop, {
get: function() {
return this._filtered[prop];
},
});
return;
}
const func = Collection.prototype[prop];
if (prop === 'constructor' || typeof func !== 'function') return;
store.prototype[prop] = function(...args) {
return func.apply(this._filtered, args);
};
});
}
}
module.exports = Util;

153
typings/index.d.ts vendored
View File

@@ -151,16 +151,16 @@ declare module 'discord.js' {
private _eval(script: string): any;
private _validateOptions(options?: ClientOptions): void;
public channels: ChannelStore;
public readonly emojis: GuildEmojiStore;
public guilds: GuildStore;
public channels: ChannelManager;
public readonly emojis: GuildEmojiManager;
public guilds: GuildManager;
public readyAt: Date | null;
public readonly readyTimestamp: number | null;
public shard: ShardClientUtil | null;
public token: string | null;
public readonly uptime: number | null;
public user: ClientUser | null;
public users: UserStore;
public users: UserManager;
public voice: ClientVoiceManager | null;
public ws: WebSocketManager;
public destroy(): void;
@@ -328,16 +328,6 @@ declare module 'discord.js' {
public setUsername(username: string): Promise<ClientUser>;
}
export class Collection<K, V> extends BaseCollection<K, V> {
public flatMap<T>(fn: (value: V, key: K, collection: this) => Collection<K, T>): Collection<K, T>;
public flatMap<T, This>(fn: (this: This, value: V, key: K, collection: this) => Collection<K, T>, thisArg: This): Collection<K, T>;
public flatMap<T>(fn: (value: V, key: K, collection: this) => Collection<K, T>, thisArg?: unknown): Collection<K, T>;
public mapValues<T>(fn: (value: V, key: K, collection: this) => T): Collection<K, T>;
public mapValues<This, T>(fn: (this: This, value: V, key: K, collection: this) => T, thisArg: This): Collection<K, T>;
public mapValues<T>(fn: (value: V, key: K, collection: this) => T, thisArg?: unknown): Collection<K, T>;
public toJSON(): object;
}
export abstract class Collector<K, V> extends EventEmitter {
constructor(client: Client, filter: CollectorFilter, options?: CollectorOptions);
private _timeout: NodeJS.Timer | null;
@@ -648,7 +638,7 @@ declare module 'discord.js' {
export class DMChannel extends TextBasedChannel(Channel) {
constructor(client: Client, data?: object);
public messages: MessageStore;
public messages: MessageManager;
public recipient: User;
public readonly partial: false;
public fetch(): Promise<DMChannel>;
@@ -680,7 +670,7 @@ declare module 'discord.js' {
public applicationID: Snowflake;
public available: boolean;
public banner: string | null;
public channels: GuildChannelStore;
public channels: GuildChannelManager;
public readonly createdAt: Date;
public readonly createdTimestamp: number;
public defaultMessageNotifications: DefaultMessageNotifications | number;
@@ -689,7 +679,7 @@ declare module 'discord.js' {
public embedChannel: GuildChannel | null;
public embedChannelID: Snowflake | null;
public embedEnabled: boolean;
public emojis: GuildEmojiStore;
public emojis: GuildEmojiManager;
public explicitContentFilter: number;
public features: GuildFeatures[];
public icon: string | null;
@@ -701,7 +691,7 @@ declare module 'discord.js' {
public maximumPresences: number | null;
public readonly me: GuildMember | null;
public memberCount: number;
public members: GuildMemberStore;
public members: GuildMemberManager;
public mfaLevel: number;
public name: string;
public readonly nameAcronym: string;
@@ -710,9 +700,9 @@ declare module 'discord.js' {
public readonly partnered: boolean;
public premiumSubscriptionCount: number | null;
public premiumTier: PremiumTier;
public presences: PresenceStore;
public presences: PresenceManager;
public region: string;
public roles: RoleStore;
public roles: RoleManager;
public readonly shard: WebSocketShard;
public shardID: number;
public splash: string | null;
@@ -723,7 +713,7 @@ declare module 'discord.js' {
public verificationLevel: number;
public readonly verified: boolean;
public readonly voice: VoiceState | null;
public readonly voiceStates: VoiceStateStore;
public readonly voiceStates: VoiceStateManager;
public readonly widgetChannel: TextChannel | null;
public widgetChannelID: Snowflake | null;
public widgetEnabled: boolean | null;
@@ -847,7 +837,7 @@ declare module 'discord.js' {
public id: Snowflake;
public managed: boolean;
public requiresColons: boolean;
public roles: GuildEmojiRoleStore;
public roles: GuildEmojiRoleManager;
public readonly url: string;
public delete(reason?: string): Promise<GuildEmoji>;
public edit(data: GuildEmojiEditData, reason?: string): Promise<GuildEmoji>;
@@ -875,7 +865,7 @@ declare module 'discord.js' {
public readonly premiumSince: Date | null;
public premiumSinceTimestamp: number | null;
public readonly presence: Presence;
public roles: GuildMemberRoleStore;
public roles: GuildMemberRoleManager;
public user: User;
public readonly voice: VoiceState;
public ban(options?: BanOptions): Promise<GuildMember>;
@@ -978,7 +968,7 @@ declare module 'discord.js' {
public readonly partial: false;
public readonly pinnable: boolean;
public pinned: boolean;
public reactions: ReactionStore;
public reactions: ReactionManager;
public system: boolean;
public tts: boolean;
public type: MessageType;
@@ -1113,7 +1103,7 @@ declare module 'discord.js' {
public me: boolean;
public message: Message;
public readonly partial: boolean;
public users: ReactionUserStore;
public users: ReactionUserManager;
public remove(): Promise<MessageReaction>;
public fetch(): Promise<MessageReaction>;
public toJSON(): object;
@@ -1397,7 +1387,7 @@ declare module 'discord.js' {
export class TextChannel extends TextBasedChannel(GuildChannel) {
constructor(guild: Guild, data?: object);
public messages: MessageStore;
public messages: MessageManager;
public nsfw: boolean;
public rateLimitPerUser: number;
public topic: string | null;
@@ -1409,7 +1399,7 @@ declare module 'discord.js' {
export class NewsChannel extends TextBasedChannel(GuildChannel) {
constructor(guild: Guild, data?: object);
public messages: MessageStore;
public messages: MessageManager;
public nsfw: boolean;
public topic: string | null;
public createWebhook(name: string, options?: { avatar?: BufferResolvable | Base64Resolvable, reason?: string }): Promise<Webhook>;
@@ -1749,64 +1739,64 @@ declare module 'discord.js' {
//#endregion
//#region Stores
//#region Collections
export class ChannelStore extends DataStore<Snowflake, Channel, typeof Channel, ChannelResolvable> {
constructor(client: Client, iterable: Iterable<any>, options?: { lru: boolean });
constructor(client: Client, options?: { lru: boolean });
public fetch(id: Snowflake, cache?: boolean): Promise<Channel>;
}
export class DataStore<K, V, VConstructor = Constructable<V>, R = any> extends Collection<K, V> {
constructor(client: Client, iterable: Iterable<any>, holds: VConstructor);
public client: Client;
public holds: VConstructor;
public add(data: any, cache?: boolean, { id, extras }?: { id: K, extras: any[] }): V;
public remove(key: K): void;
public resolve(resolvable: R): V | null;
public resolveID(resolvable: R): K | null;
// Don't worry about those bunch of ts-ignores here, this is intended https://github.com/microsoft/TypeScript/issues/1213
// @ts-ignore
public filter(fn: (value: V, key: K, collection: this) => boolean): Collection<K, V>;
// @ts-ignore
public filter<T>(fn: (this: T, value: V, key: K, collection: this) => boolean, thisArg: T): Collection<K, V>;
// @ts-ignore
public filter(fn: (value: V, key: K, collection: this) => boolean, thisArg?: unknown): Collection<K, V>;
// @ts-ignore
public partition(fn: (value: V, key: K, collection: this) => boolean): [Collection<K, V>, Collection<K, V>];
// @ts-ignore
public partition<T>(fn: (this: T, value: V, key: K, collection: this) => boolean, thisArg: T): [Collection<K, V>, Collection<K, V>];
// @ts-ignore
public partition(fn: (value: V, key: K, collection: this) => boolean, thisArg?: unknown): [Collection<K, V>, Collection<K, V>];
export class Collection<K, V> extends BaseCollection<K, V> {
public flatMap<T>(fn: (value: V, key: K, collection: this) => Collection<K, T>): Collection<K, T>;
public flatMap<T, This>(fn: (this: This, value: V, key: K, collection: this) => Collection<K, T>, thisArg: This): Collection<K, T>;
public flatMap<T>(fn: (value: V, key: K, collection: this) => Collection<K, T>, thisArg?: unknown): Collection<K, T>;
public mapValues<T>(fn: (value: V, key: K, collection: this) => T): Collection<K, T>;
public mapValues<This, T>(fn: (this: This, value: V, key: K, collection: this) => T, thisArg: This): Collection<K, T>;
public mapValues<T>(fn: (value: V, key: K, collection: this) => T, thisArg?: unknown): Collection<K, T>;
// @ts-ignore
public clone(): Collection<K, V>;
// @ts-ignore
public concat(...collections: Collection<K, V>[]): Collection<K, V>;
// @ts-ignore
public sorted(compareFunction: (firstValue: V, secondValue: V, firstKey: K, secondKey: K) => number): Collection<K, V>;
public toJSON(): object;
}
export class GuildEmojiRoleStore extends OverridableDataStore<Snowflake, Role, typeof Role, RoleResolvable> {
export class LimitedCollection<K, V> extends Collection<K, V> {
public constructor(maxSize: number, iterable: Iterable<any>);
public maxSize: number;
}
//#endregion
//#region Managers
export class ChannelManager extends BaseManager<Snowflake, Channel, ChannelResolvable> {
constructor(client: Client, iterable: Iterable<any>);
public fetch(id: Snowflake, cache?: boolean): Promise<Channel>;
}
export abstract class BaseManager<K, Holds, R> {
constructor(client: Client, iterable: Iterable<any>, holds: Constructable<Holds>, cacheType: Collection<K, Holds>);
public holds: Constructable<Holds>;
public cache: Collection<K, Holds>;
public cacheType: Collection<K, Holds>;
public readonly client: Client;
public add(data: any, cache?: boolean, { id, extras }?: { id: K, extras: any[] }): Holds;
public remove(key: K): void;
public resolve(resolvable: R): Holds | null;
public resolveID(resolvable: R): K | null;
}
export class GuildEmojiRoleManager {
constructor(emoji: GuildEmoji);
public emoji: GuildEmoji;
public guild: Guild;
public cache: Collection<Snowflake, Role>;
public add(roleOrRoles: RoleResolvable | RoleResolvable[] | Collection<Snowflake, Role>): Promise<GuildEmoji>;
public set(roles: RoleResolvable[] | Collection<Snowflake, Role>): Promise<GuildEmoji>;
public remove(roleOrRoles: RoleResolvable | RoleResolvable[] | Collection<Snowflake, Role>): Promise<GuildEmoji>;
}
export class GuildEmojiStore extends DataStore<Snowflake, GuildEmoji, typeof GuildEmoji, EmojiResolvable> {
export class GuildEmojiManager extends BaseManager<Snowflake, GuildEmoji, EmojiResolvable> {
constructor(guild: Guild, iterable?: Iterable<any>);
public guild: Guild;
public create(attachment: BufferResolvable | Base64Resolvable, name: string, options?: GuildEmojiCreateOptions): Promise<GuildEmoji>;
public resolveIdentifier(emoji: EmojiIdentifierResolvable): string | null;
}
export class GuildChannelStore extends DataStore<Snowflake, GuildChannel, typeof GuildChannel, GuildChannelResolvable> {
export class GuildChannelManager extends BaseManager<Snowflake, GuildChannel, GuildChannelResolvable> {
constructor(guild: Guild, iterable?: Iterable<any>);
public guild: Guild;
public create(name: string, options: GuildCreateChannelOptions & { type: 'voice' }): Promise<VoiceChannel>;
public create(name: string, options: GuildCreateChannelOptions & { type: 'category' }): Promise<CategoryChannel>;
public create(name: string, options?: GuildCreateChannelOptions & { type?: 'text' }): Promise<TextChannel>;
@@ -1814,78 +1804,87 @@ declare module 'discord.js' {
}
// Hacky workaround because changing the signature of an overridden method errors
class OverridableDataStore<V, K, VConstructor = Constructable<V>, R = any> extends DataStore<V, K, VConstructor, R> {
class OverridableManager<V, K, R = any> extends BaseManager<V, K, R> {
public add(data: any, cache: any): any;
public set(key: any): any;
}
export class GuildMemberRoleStore extends OverridableDataStore<Snowflake, Role, typeof Role, RoleResolvable> {
export class GuildMemberRoleManager extends OverridableManager<Snowflake, Role, RoleResolvable> {
constructor(member: GuildMember);
public readonly hoist: Role | null;
public readonly color: Role | null;
public readonly highest: Role;
public member: GuildMember;
public guild: Guild;
public add(roleOrRoles: RoleResolvable | RoleResolvable[] | Collection<Snowflake, Role>, reason?: string): Promise<GuildMember>;
public set(roles: RoleResolvable[] | Collection<Snowflake, Role>, reason?: string): Promise<GuildMember>;
public remove(roleOrRoles: RoleResolvable | RoleResolvable[] | Collection<Snowflake, Role>, reason?: string): Promise<GuildMember>;
}
export class GuildMemberStore extends DataStore<Snowflake, GuildMember, typeof GuildMember, GuildMemberResolvable> {
export class GuildMemberManager extends BaseManager<Snowflake, GuildMember, GuildMemberResolvable> {
constructor(guild: Guild, iterable?: Iterable<any>);
public guild: Guild;
public ban(user: UserResolvable, options?: BanOptions): Promise<GuildMember | User | Snowflake>;
public fetch(options: UserResolvable | FetchMemberOptions): Promise<GuildMember>;
public fetch(): Promise<GuildMemberStore>;
public fetch(): Promise<GuildMemberManager>;
public fetch(options: FetchMembersOptions): Promise<Collection<Snowflake, GuildMember>>;
public prune(options: GuildPruneMembersOptions & { dry?: false, count: false }): Promise<null>;
public prune(options?: GuildPruneMembersOptions): Promise<number>;
public unban(user: UserResolvable, reason?: string): Promise<User>;
}
export class GuildStore extends DataStore<Snowflake, Guild, typeof Guild, GuildResolvable> {
export class GuildManager extends BaseManager<Snowflake, Guild, GuildResolvable> {
constructor(client: Client, iterable?: Iterable<any>);
public create(name: string, options?: { region?: string, icon: BufferResolvable | Base64Resolvable | null }): Promise<Guild>;
}
export class MessageStore extends DataStore<Snowflake, Message, typeof Message, MessageResolvable> {
export class MessageManager extends BaseManager<Snowflake, Message, MessageResolvable> {
constructor(channel: TextChannel | DMChannel, iterable?: Iterable<any>);
public channel: TextBasedChannelFields;
public cache: LimitedCollection<Snowflake, Message>;
public fetch(message: Snowflake, cache?: boolean): Promise<Message>;
public fetch(options?: ChannelLogsQueryOptions, cache?: boolean): Promise<Collection<Snowflake, Message>>;
public fetchPinned(cache?: boolean): Promise<Collection<Snowflake, Message>>;
public remove(message: MessageResolvable, reason?: string): Promise<void>;
public delete(message: MessageResolvable, reason?: string): Promise<void>;
}
export class PresenceStore extends DataStore<Snowflake, Presence, typeof Presence, PresenceResolvable> {
export class PresenceManager extends BaseManager<Snowflake, Presence, PresenceResolvable> {
constructor(client: Client, iterable?: Iterable<any>);
}
export class ReactionStore extends DataStore<Snowflake, MessageReaction, typeof MessageReaction, MessageReactionResolvable> {
export class ReactionManager extends BaseManager<Snowflake, MessageReaction, MessageReactionResolvable> {
constructor(message: Message, iterable?: Iterable<any>);
public message: Message;
public removeAll(): Promise<Message>;
}
export class ReactionUserStore extends DataStore<Snowflake, User, typeof User, UserResolvable> {
export class ReactionUserManager extends BaseManager<Snowflake, User, UserResolvable> {
constructor(client: Client, iterable: Iterable<any> | undefined, reaction: MessageReaction);
public reaction: MessageReaction;
public fetch(options?: { limit?: number, after?: Snowflake, before?: Snowflake }): Promise<Collection<Snowflake, User>>;
public remove(user?: UserResolvable): Promise<MessageReaction>;
}
export class RoleStore extends DataStore<Snowflake, Role, typeof Role, RoleResolvable> {
export class RoleManager extends BaseManager<Snowflake, Role, RoleResolvable> {
constructor(guild: Guild, iterable?: Iterable<any>);
public readonly everyone: Role | null;
public readonly highest: Role;
public guild: Guild;
public create(options?: { data?: RoleData, reason?: string }): Promise<Role>;
public fetch(id: Snowflake, cache?: boolean): Promise<Role | null>;
public fetch(id?: Snowflake, cache?: boolean): Promise<this>;
}
export class UserStore extends DataStore<Snowflake, User, typeof User, UserResolvable> {
export class UserManager extends BaseManager<Snowflake, User, UserResolvable> {
constructor(client: Client, iterable?: Iterable<any>);
public fetch(id: Snowflake, cache?: boolean): Promise<User>;
}
export class VoiceStateStore extends DataStore<Snowflake, VoiceState, typeof VoiceState> {
export class VoiceStateManager extends BaseManager<Snowflake, VoiceState, typeof VoiceState> {
constructor(guild: Guild, iterable?: Iterable<any>);
public guild: Guild;
}
//#endregion