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 // Create an event listener for new guild members
client.on('guildMemberAdd', member => { client.on('guildMemberAdd', member => {
// Send the message to a designated channel on a server: // 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 // Do nothing if the channel wasn't found on this server
if (!channel) return; if (!channel) return;
// Send the message, mentioning the member // Send the message, mentioning the member

View File

@@ -11,10 +11,10 @@ const Webhook = require('../structures/Webhook');
const Invite = require('../structures/Invite'); const Invite = require('../structures/Invite');
const ClientApplication = require('../structures/ClientApplication'); const ClientApplication = require('../structures/ClientApplication');
const ShardClientUtil = require('../sharding/ShardClientUtil'); const ShardClientUtil = require('../sharding/ShardClientUtil');
const UserStore = require('../stores/UserStore'); const UserManager = require('../managers/UserManager');
const ChannelStore = require('../stores/ChannelStore'); const ChannelManager = require('../managers/ChannelManager');
const GuildStore = require('../stores/GuildStore'); const GuildManager = require('../managers/GuildManager');
const GuildEmojiStore = require('../stores/GuildEmojiStore'); const GuildEmojiManager = require('../managers/GuildEmojiManager');
const { Events, browser, DefaultOptions } = require('../util/Constants'); const { Events, browser, DefaultOptions } = require('../util/Constants');
const DataResolver = require('../util/DataResolver'); const DataResolver = require('../util/DataResolver');
const Structures = require('../util/Structures'); 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 * 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 - * 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 * 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 - * 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 * 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 * 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. * in the Manager without their explicit fetching or use.
* @type {ChannelStore<Snowflake, Channel>} * @type {ChannelManager}
*/ */
this.channels = new ChannelStore(this); this.channels = new ChannelManager(this);
const ClientPresence = Structures.get('ClientPresence'); 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 * All custom emojis that the client has access to, mapped by their IDs
* @type {GuildEmojiStore<Snowflake, GuildEmoji>} * @type {GuildEmojiManager}
* @readonly * @readonly
*/ */
get emojis() { get emojis() {
const emojis = new GuildEmojiStore({ client: this }); const emojis = new GuildEmojiManager({ client: this });
for (const guild of this.guilds.values()) { for (const guild of this.guilds.cache.values()) {
if (guild.available) for (const emoji of guild.emojis.values()) emojis.set(emoji.id, emoji); if (guild.available) for (const emoji of guild.emojis.cache.values()) emojis.cache.set(emoji.id, emoji);
} }
return emojis; return emojis;
} }
@@ -298,11 +298,11 @@ class Client extends BaseClient {
let channels = 0; let channels = 0;
let messages = 0; let messages = 0;
for (const channel of this.channels.values()) { for (const channel of this.channels.cache.values()) {
if (!channel.messages) continue; if (!channel.messages) continue;
channels++; channels++;
messages += channel.messages.sweep( messages += channel.messages.cache.sweep(
message => now - (message.editedTimestamp || message.createdTimestamp) > lifetimeMs message => now - (message.editedTimestamp || message.createdTimestamp) > lifetimeMs
); );
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,7 +7,7 @@ const { Events } = require('../../util/Constants');
class MessageDeleteBulkAction extends Action { class MessageDeleteBulkAction extends Action {
handle(data) { handle(data) {
const client = this.client; const client = this.client;
const channel = client.channels.get(data.channel_id); const channel = client.channels.cache.get(data.channel_id);
if (channel) { if (channel) {
const ids = data.ids; const ids = data.ids;
@@ -20,7 +20,7 @@ class MessageDeleteBulkAction extends Action {
if (message) { if (message) {
message.deleted = true; message.deleted = true;
messages.set(message.id, message); 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); const message = this.getMessage(data, channel);
if (!message) return false; if (!message) return false;
message.reactions.clear(); message.reactions.cache.clear();
this.client.emit(Events.MESSAGE_REACTION_REMOVE_ALL, message); this.client.emit(Events.MESSAGE_REACTION_REMOVE_ALL, message);
return { message }; return { message };

View File

@@ -13,7 +13,7 @@ class MessageReactionRemoveEmoji extends Action {
const reaction = this.getReaction(data, message); const reaction = this.getReaction(data, message);
if (!reaction) return false; 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. * 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 { class PresenceUpdateAction extends Action {
handle(data) { 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 && data.user.username) user = this.client.users.add(data.user);
if (!user) return; if (!user) return;
@@ -13,12 +13,12 @@ class PresenceUpdateAction extends Action {
if (!user.equals(data.user)) this.client.actions.UserUpdate.handle(data.user); 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; if (!guild) return;
let oldPresence = guild.presences.get(user.id); let oldPresence = guild.presences.cache.get(user.id);
if (oldPresence) oldPresence = oldPresence._clone(); 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') { if (!member && data.status !== 'offline') {
member = guild.members.add({ member = guild.members.add({
user, user,

View File

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

View File

@@ -7,17 +7,17 @@ const VoiceState = require('../../structures/VoiceState');
class VoiceStateUpdate extends Action { class VoiceStateUpdate extends Action {
handle(data) { handle(data) {
const client = this.client; const client = this.client;
const guild = client.guilds.get(data.guild_id); const guild = client.guilds.cache.get(data.guild_id);
if (guild) { if (guild) {
// Update the state // Update the state
const oldState = guild.voiceStates.has(data.user_id) ? const oldState = guild.voiceStates.cache.has(data.user_id) ?
guild.voiceStates.get(data.user_id)._clone() : guild.voiceStates.cache.get(data.user_id)._clone() :
new VoiceState(guild, { user_id: data.user_id }); new VoiceState(guild, { user_id: data.user_id });
const newState = guild.voiceStates.add(data); const newState = guild.voiceStates.add(data);
// Get the member // Get the member
let member = guild.members.get(data.user_id); let member = guild.members.cache.get(data.user_id);
if (member && data.member) { if (member && data.member) {
member._patch(data.member); member._patch(data.member);
} else if (data.member && data.member.user && data.member.joined_at) { } 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 { class WebhooksUpdate extends Action {
handle(data) { handle(data) {
const client = this.client; 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. * Emitted whenever a guild text channel has its webhooks changed.
* @event Client#webhookUpdate * @event Client#webhookUpdate

View File

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

View File

@@ -483,7 +483,7 @@ class VoiceConnection extends EventEmitter {
onSpeaking({ user_id, speaking }) { onSpeaking({ user_id, speaking }) {
speaking = new Speaking(speaking).freeze(); speaking = new Speaking(speaking).freeze();
const guild = this.channel.guild; 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); const old = this._speaking.get(user_id);
this._speaking.set(user_id, speaking); this._speaking.set(user_id, speaking);
/** /**

View File

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

View File

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

View File

@@ -3,7 +3,7 @@
const { Events } = require('../../../util/Constants'); const { Events } = require('../../../util/Constants');
module.exports = (client, { d: data }) => { 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); const user = client.users.add(data.user);
/** /**

View File

@@ -3,7 +3,7 @@
const { Events, Status } = require('../../../util/Constants'); const { Events, Status } = require('../../../util/Constants');
module.exports = async (client, { d: data }, shard) => { 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) {
if (!guild.available && !data.unavailable) { if (!guild.available && !data.unavailable) {
// A newly available guild // A newly available guild

View File

@@ -4,7 +4,7 @@ const { Events } = require('../../../util/Constants');
const Collection = require('../../../util/Collection'); const Collection = require('../../../util/Collection');
module.exports = (client, { d: data }) => { 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; if (!guild) return;
const members = new Collection(); const members = new Collection();

View File

@@ -3,7 +3,7 @@
const { Events, Status } = require('../../../util/Constants'); const { Events, Status } = require('../../../util/Constants');
module.exports = (client, { d: data }, shard) => { 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) { if (guild) {
guild.memberCount++; guild.memberCount++;
const member = guild.members.add(data); const member = guild.members.add(data);

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,44 +4,67 @@ const Collection = require('../util/Collection');
let Structures; let Structures;
/** /**
* Manages the creation, retrieval and deletion of a specific data model. * Manages the API methods of a data model and holds its cache.
* @extends {Collection} * @abstract
*/ */
class DataStore extends Collection { class BaseManager {
constructor(client, iterable, holds) { constructor(client, iterable, holds, cacheType = Collection, ...cacheOptions) {
super();
if (!Structures) Structures = require('../util/Structures'); 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 }); 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 = [] } = {}) { 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 && existing._patch && cache) existing._patch(data);
if (existing) return existing; if (existing) return existing;
const entry = this.holds ? new this.holds(this.client, data, ...extras) : data; 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; return entry;
} }
remove(key) { return this.delete(key); }
/** /**
* Resolves a data entry to a data Object. * Resolves a data entry to a data Object.
* @param {string|Object} idOrInstance The id or instance of something in this DataStore * @param {string|Object} idOrInstance The id or instance of something in this Manager
* @returns {?Object} An instance from this DataStore * @returns {?Object} An instance from this Manager
*/ */
resolve(idOrInstance) { resolve(idOrInstance) {
if (idOrInstance instanceof this.holds) return 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; return null;
} }
/** /**
* Resolves a data entry to a instance ID. * 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} * @returns {?Snowflake}
*/ */
resolveID(idOrInstance) { resolveID(idOrInstance) {
@@ -49,10 +72,6 @@ class DataStore extends Collection {
if (typeof idOrInstance === 'string') return idOrInstance; if (typeof idOrInstance === 'string') return idOrInstance;
return null; return null;
} }
static get [Symbol.species]() {
return Collection;
}
} }
module.exports = DataStore; module.exports = BaseManager;

View File

@@ -1,59 +1,26 @@
'use strict'; 'use strict';
const DataStore = require('./DataStore');
const Channel = require('../structures/Channel'); const Channel = require('../structures/Channel');
const BaseManager = require('./BaseManager');
const { Events } = require('../util/Constants'); const { Events } = require('../util/Constants');
const kLru = Symbol('LRU');
const lruable = ['dm'];
/** /**
* Stores channels. * A manager of channels belonging to a client
* @extends {DataStore}
*/ */
class ChannelStore extends DataStore { class ChannelManager extends BaseManager {
constructor(client, iterableOrOptions = {}, options) { constructor(client, iterable) {
if (!options && typeof iterableOrOptions[Symbol.iterator] !== 'function') { super(client, iterable, Channel);
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);
};
}
} }
get(key, peek = false) { /**
const item = super.get(key); * The cache of Channels
if (!item || !lruable.includes(item.type)) return item; * @property {Collection<Snowflake, Channel>} cache
if (!peek && this[kLru]) this[kLru].add(key); * @memberof ChannelManager
return item; * @instance
} */
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);
}
add(data, guild, cache = true) { add(data, guild, cache = true) {
const existing = this.get(data.id); const existing = this.cache.get(data.id);
if (existing) { if (existing) {
if (existing._patch && cache) existing._patch(data); if (existing._patch && cache) existing._patch(data);
if (guild) guild.channels.add(existing); if (guild) guild.channels.add(existing);
@@ -67,15 +34,15 @@ class ChannelStore extends DataStore {
return null; return null;
} }
if (cache) this.set(channel.id, channel); if (cache) this.cache.set(channel.id, channel);
return channel; return channel;
} }
remove(id) { remove(id) {
const channel = this.get(id); const channel = this.cache.get(id);
if (channel.guild) channel.guild.channels.remove(id); if (channel.guild) channel.guild.channels.cache.delete(id);
super.remove(id); this.cache.delete(id);
} }
/** /**
@@ -88,7 +55,7 @@ class ChannelStore extends DataStore {
/** /**
* Resolves a ChannelResolvable to a Channel object. * Resolves a ChannelResolvable to a Channel object.
* @method resolve * @method resolve
* @memberof ChannelStore * @memberof ChannelManager
* @instance * @instance
* @param {ChannelResolvable} channel The channel resolvable to resolve * @param {ChannelResolvable} channel The channel resolvable to resolve
* @returns {?Channel} * @returns {?Channel}
@@ -97,7 +64,7 @@ class ChannelStore extends DataStore {
/** /**
* Resolves a ChannelResolvable to a channel ID string. * Resolves a ChannelResolvable to a channel ID string.
* @method resolveID * @method resolveID
* @memberof ChannelStore * @memberof ChannelManager
* @instance * @instance
* @param {ChannelResolvable} channel The channel resolvable to resolve * @param {ChannelResolvable} channel The channel resolvable to resolve
* @returns {?Snowflake} * @returns {?Snowflake}
@@ -115,7 +82,7 @@ class ChannelStore extends DataStore {
* .catch(console.error); * .catch(console.error);
*/ */
async fetch(id, cache = true) { async fetch(id, cache = true) {
const existing = this.get(id); const existing = this.cache.get(id);
if (existing && !existing.partial) return existing; if (existing && !existing.partial) return existing;
const data = await this.client.api.channels(id).get(); 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'; 'use strict';
const { ChannelTypes } = require('../util/Constants'); const { ChannelTypes } = require('../util/Constants');
const DataStore = require('./DataStore'); const BaseManager = require('./BaseManager');
const GuildChannel = require('../structures/GuildChannel'); const GuildChannel = require('../structures/GuildChannel');
const PermissionOverwrites = require('../structures/PermissionOverwrites'); const PermissionOverwrites = require('../structures/PermissionOverwrites');
/** /**
* Stores guild channels. * Manages API methods for GuildChannels and stores their cache.
* @extends {DataStore} * @extends {BaseManager}
*/ */
class GuildChannelStore extends DataStore { class GuildChannelManager extends BaseManager {
constructor(guild, iterable) { constructor(guild, iterable) {
super(guild.client, iterable, GuildChannel); super(guild.client, iterable, GuildChannel);
/**
* The guild this Manager belongs to
* @type {Guild}
*/
this.guild = guild; this.guild = guild;
} }
/**
* The cache of this Manager
* @property {Collection<Snowflake, GuildChannel>} cache
* @memberof GuildChannelManager
* @instance
*/
add(channel) { add(channel) {
const existing = this.get(channel.id); const existing = this.cache.get(channel.id);
if (existing) return existing; if (existing) return existing;
this.set(channel.id, channel); this.cache.set(channel.id, channel);
return channel; return channel;
} }
@@ -32,7 +44,7 @@ class GuildChannelStore extends DataStore {
/** /**
* Resolves a GuildChannelResolvable to a Channel object. * Resolves a GuildChannelResolvable to a Channel object.
* @method resolve * @method resolve
* @memberof GuildChannelStore * @memberof GuildChannelManager
* @instance * @instance
* @param {GuildChannelResolvable} channel The GuildChannel resolvable to resolve * @param {GuildChannelResolvable} channel The GuildChannel resolvable to resolve
* @returns {?Channel} * @returns {?Channel}
@@ -41,7 +53,7 @@ class GuildChannelStore extends DataStore {
/** /**
* Resolves a GuildChannelResolvable to a channel ID string. * Resolves a GuildChannelResolvable to a channel ID string.
* @method resolveID * @method resolveID
* @memberof GuildChannelStore * @memberof GuildChannelManager
* @instance * @instance
* @param {GuildChannelResolvable} channel The GuildChannel resolvable to resolve * @param {GuildChannelResolvable} channel The GuildChannel resolvable to resolve
* @returns {?Snowflake} * @returns {?Snowflake}
@@ -117,4 +129,4 @@ class GuildChannelStore extends DataStore {
} }
} }
module.exports = GuildChannelStore; module.exports = GuildChannelManager;

View File

@@ -1,22 +1,33 @@
'use strict'; 'use strict';
const Collection = require('../util/Collection'); const Collection = require('../util/Collection');
const DataStore = require('./DataStore'); const BaseManager = require('./BaseManager');
const GuildEmoji = require('../structures/GuildEmoji'); const GuildEmoji = require('../structures/GuildEmoji');
const ReactionEmoji = require('../structures/ReactionEmoji'); const ReactionEmoji = require('../structures/ReactionEmoji');
const DataResolver = require('../util/DataResolver'); const DataResolver = require('../util/DataResolver');
const { TypeError } = require('../errors'); const { TypeError } = require('../errors');
/** /**
* Stores guild emojis. * Manages API methods for GuildEmojis and stores their cache.
* @extends {DataStore} * @extends {BaseManager}
*/ */
class GuildEmojiStore extends DataStore { class GuildEmojiManager extends BaseManager {
constructor(guild, iterable) { constructor(guild, iterable) {
super(guild.client, iterable, GuildEmoji); super(guild.client, iterable, GuildEmoji);
/**
* The guild this manager belongs to
* @type {Guild}
*/
this.guild = guild; this.guild = guild;
} }
/**
* The cache of GuildEmojis
* @property {Collection<Snowflake, GuildEmoji>} cache
* @memberof GuildEmojiManager
* @instance
*/
add(data, cache) { add(data, cache) {
return super.add(data, cache, { extras: [this.guild] }); 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'; 'use strict';
const Collection = require('../util/Collection'); const Collection = require('../util/Collection');
const Util = require('../util/Util');
const { TypeError } = require('../errors'); const { TypeError } = require('../errors');
/** /**
* Stores emoji roles * Manages API methods for roles belonging to emojis and stores their cache.
* @extends {Collection}
*/ */
class GuildEmojiRoleStore extends Collection { class GuildEmojiRoleManager {
constructor(emoji) { constructor(emoji) {
super(); /**
* The emoji belonging to this manager
* @type {GuildEmoji}
*/
this.emoji = emoji; this.emoji = emoji;
/**
* The guild belonging to this manager
* @type {Guild}
*/
this.guild = emoji.guild; this.guild = emoji.guild;
/**
* The client belonging to this manager
* @type {Client}
* @readonly
*/
Object.defineProperty(this, 'client', { value: emoji.client }); Object.defineProperty(this, 'client', { value: emoji.client });
} }
@@ -22,8 +32,17 @@ class GuildEmojiRoleStore extends Collection {
* @private * @private
* @readonly * @readonly
*/ */
get _filtered() { get _roles() {
return this.guild.roles.filter(role => this.emoji._roles.includes(role.id)); 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)); '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); return this.set(newRoles);
} }
@@ -60,7 +79,7 @@ class GuildEmojiRoleStore extends Collection {
'Array or Collection of Roles or Snowflakes', true)); '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); return this.set(newRoles);
} }
@@ -85,32 +104,18 @@ class GuildEmojiRoleStore extends Collection {
clone() { clone() {
const clone = new this.constructor(this.emoji); const clone = new this.constructor(this.emoji);
clone._patch(this.keyArray().slice()); clone._patch(this._roles.keyArray().slice());
return clone; return clone;
} }
/** /**
* Patches the roles for this store * Patches the roles for this manager's cache
* @param {Snowflake[]} roles The new roles * @param {Snowflake[]} roles The new roles
* @private * @private
*/ */
_patch(roles) { _patch(roles) {
this.emoji._roles = 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 = GuildEmojiRoleManager;
module.exports = GuildEmojiRoleStore;

View File

@@ -1,6 +1,6 @@
'use strict'; 'use strict';
const DataStore = require('./DataStore'); const BaseManager = require('./BaseManager');
const DataResolver = require('../util/DataResolver'); const DataResolver = require('../util/DataResolver');
const { Events } = require('../util/Constants'); const { Events } = require('../util/Constants');
const Guild = require('../structures/Guild'); const Guild = require('../structures/Guild');
@@ -9,14 +9,21 @@ const GuildMember = require('../structures/GuildMember');
const Role = require('../structures/Role'); const Role = require('../structures/Role');
/** /**
* Stores guilds. * Manages API methods for Guilds and stores their cache.
* @extends {DataStore} * @extends {BaseManager}
*/ */
class GuildStore extends DataStore { class GuildManager extends BaseManager {
constructor(client, iterable) { constructor(client, iterable) {
super(client, iterable, Guild); 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: * Data that resolves to give a Guild object. This can be:
* * A Guild object * * A Guild object
@@ -29,7 +36,7 @@ class GuildStore extends DataStore {
/** /**
* Resolves a GuildResolvable to a Guild object. * Resolves a GuildResolvable to a Guild object.
* @method resolve * @method resolve
* @memberof GuildStore * @memberof GuildManager
* @instance * @instance
* @param {GuildResolvable} guild The guild resolvable to identify * @param {GuildResolvable} guild The guild resolvable to identify
* @returns {?Guild} * @returns {?Guild}
@@ -44,7 +51,7 @@ class GuildStore extends DataStore {
/** /**
* Resolves a GuildResolvable to a Guild ID string. * Resolves a GuildResolvable to a Guild ID string.
* @method resolveID * @method resolveID
* @memberof GuildStore * @memberof GuildManager
* @instance * @instance
* @param {GuildResolvable} guild The guild resolvable to identify * @param {GuildResolvable} guild The guild resolvable to identify
* @returns {?Snowflake} * @returns {?Snowflake}
@@ -70,7 +77,7 @@ class GuildStore extends DataStore {
return new Promise((resolve, reject) => return new Promise((resolve, reject) =>
this.client.api.guilds.post({ data: { name, region, icon } }) this.client.api.guilds.post({ data: { name, region, icon } })
.then(data => { .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 => { const handleGuild = guild => {
if (guild.id === data.id) { 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'; 'use strict';
const DataStore = require('./DataStore'); const BaseManager = require('./BaseManager');
const GuildMember = require('../structures/GuildMember'); const GuildMember = require('../structures/GuildMember');
const { Events, OPCodes } = require('../util/Constants'); const { Events, OPCodes } = require('../util/Constants');
const Collection = require('../util/Collection'); const Collection = require('../util/Collection');
const { Error, TypeError } = require('../errors'); const { Error, TypeError } = require('../errors');
/** /**
* Stores guild members. * Manages API methods for GuildMembers and stores their cache.
* @extends {DataStore} * @extends {BaseManager}
*/ */
class GuildMemberStore extends DataStore { class GuildMemberManager extends BaseManager {
constructor(guild, iterable) { constructor(guild, iterable) {
super(guild.client, iterable, GuildMember); super(guild.client, iterable, GuildMember);
/**
* The guild this manager belongs to
* @type {Guild}
*/
this.guild = guild; this.guild = guild;
} }
/**
* The cache of this Manager
* @property {Collection<Snowflake, GuildMember>} cache
* @memberof GuildMemberManager
* @instance
*/
add(data, cache = true) { add(data, cache = true) {
return super.add(data, cache, { id: data.user.id, extras: [this.guild] }); 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); const memberResolvable = super.resolveID(member);
if (memberResolvable) return memberResolvable; if (memberResolvable) return memberResolvable;
const userResolvable = this.client.users.resolveID(member); 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 }) { _fetchSingle({ user, cache }) {
const existing = this.get(user); const existing = this.cache.get(user);
if (existing && !existing.partial) return Promise.resolve(existing); if (existing && !existing.partial) return Promise.resolve(existing);
return this.client.api.guilds(this.guild.id).members(user).get() return this.client.api.guilds(this.guild.id).members(user).get()
.then(data => this.add(data, cache)); .then(data => this.add(data, cache));
@@ -192,8 +203,8 @@ class GuildMemberStore extends DataStore {
_fetchMany({ query = '', limit = 0 } = {}) { _fetchMany({ query = '', limit = 0 } = {}) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (this.guild.memberCount === this.size && !query && !limit) { if (this.guild.memberCount === this.cache.size && !query && !limit) {
resolve(this); resolve(this.cache);
return; return;
} }
this.guild.shard.send({ this.guild.shard.send({
@@ -211,11 +222,11 @@ class GuildMemberStore extends DataStore {
for (const member of members.values()) { for (const member of members.values()) {
if (query || limit) fetchedMembers.set(member.id, member); 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) || ((query || limit) && members.size < 1000) ||
(limit && fetchedMembers.size >= limit)) { (limit && fetchedMembers.size >= limit)) {
this.guild.client.removeListener(Events.GUILD_MEMBERS_CHUNK, handler); 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(() => { 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'; 'use strict';
const Collection = require('../util/Collection'); const Collection = require('../util/Collection');
const Util = require('../util/Util');
const { TypeError } = require('../errors'); const { TypeError } = require('../errors');
/** /**
* Stores member roles * Manages API methods for roles of a GuildMember and stores their cache.
* @extends {Collection}
*/ */
class GuildMemberRoleStore extends Collection { class GuildMemberRoleManager {
constructor(member) { constructor(member) {
super(); /**
* The GuildMember this manager belongs to
* @type {GuildMember}
*/
this.member = member; this.member = member;
/**
* The Guild this manager belongs to
* @type {Guild}
*/
this.guild = member.guild; this.guild = member.guild;
Object.defineProperty(this, 'client', { value: member.client }); Object.defineProperty(this, 'client', { value: member.client });
} }
@@ -22,9 +27,18 @@ class GuildMemberRoleStore extends Collection {
* @private * @private
* @readonly * @readonly
*/ */
get _filtered() { get _roles() {
const everyone = this.guild.roles.everyone; 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 * @readonly
*/ */
get hoist() { get hoist() {
const hoistedRoles = this._filtered.filter(role => role.hoist); const hoistedRoles = this._roles.filter(role => role.hoist);
if (!hoistedRoles.size) return null; if (!hoistedRoles.size) return null;
return hoistedRoles.reduce((prev, role) => !prev || role.comparePositionTo(prev) > 0 ? role : prev); return hoistedRoles.reduce((prev, role) => !prev || role.comparePositionTo(prev) > 0 ? role : prev);
} }
@@ -44,7 +58,7 @@ class GuildMemberRoleStore extends Collection {
* @readonly * @readonly
*/ */
get color() { get color() {
const coloredRoles = this._filtered.filter(role => role.color); const coloredRoles = this._roles.filter(role => role.color);
if (!coloredRoles.size) return null; if (!coloredRoles.size) return null;
return coloredRoles.reduce((prev, role) => !prev || role.comparePositionTo(prev) > 0 ? role : prev); return coloredRoles.reduce((prev, role) => !prev || role.comparePositionTo(prev) > 0 ? role : prev);
} }
@@ -55,7 +69,7 @@ class GuildMemberRoleStore extends Collection {
* @readonly * @readonly
*/ */
get highest() { 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); '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); return this.set(newRoles, reason);
} else { } else {
roleOrRoles = this.guild.roles.resolve(roleOrRoles); 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 }); await this.client.api.guilds[this.guild.id].members[this.member.id].roles[roleOrRoles.id].put({ reason });
const clone = this.member._clone(); const clone = this.member._clone();
clone._roles = [...this.keys(), roleOrRoles.id]; clone._roles = [...this._roles.keys(), roleOrRoles.id];
return clone; return clone;
} }
} }
@@ -103,7 +117,7 @@ class GuildMemberRoleStore extends Collection {
'Array or Collection of Roles or Snowflakes', true); '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); return this.set(newRoles, reason);
} else { } else {
roleOrRoles = this.guild.roles.resolve(roleOrRoles); 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 }); await this.client.api.guilds[this.guild.id].members[this.member.id].roles[roleOrRoles.id].delete({ reason });
const clone = this.member._clone(); 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()]; clone._roles = [...newRoles.keys()];
return clone; return clone;
} }
@@ -134,7 +148,7 @@ class GuildMemberRoleStore extends Collection {
* @example * @example
* // Remove all the roles from a member * // Remove all the roles from a member
* guildMember.roles.set([]) * 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); * .catch(console.error);
*/ */
set(roles, reason) { set(roles, reason) {
@@ -143,23 +157,9 @@ class GuildMemberRoleStore extends Collection {
clone() { clone() {
const clone = new this.constructor(this.member); const clone = new this.constructor(this.member);
clone.member._roles = [...this.keyArray()]; clone.member._roles = [...this._roles.keyArray()];
return clone; return clone;
} }
*[Symbol.iterator]() {
yield* this._filtered.entries();
}
valueOf() {
return this._filtered;
}
static get [Symbol.species]() {
return Collection;
}
} }
Util.mixin(GuildMemberRoleStore, ['set']); module.exports = GuildMemberRoleManager;
module.exports = GuildMemberRoleStore;

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'; 'use strict';
const DataStore = require('./DataStore');
const { Presence } = require('../structures/Presence'); const { Presence } = require('../structures/Presence');
const BaseManager = require('./BaseManager');
/** /**
* Stores presences. * Manages API methods for Presences and holds their cache.
* @extends {DataStore} * @extends {BaseManager}
*/ */
class PresenceStore extends DataStore { class PresenceManager extends BaseManager {
constructor(client, iterable) { constructor(client, iterable) {
super(client, iterable, Presence); super(client, iterable, Presence);
} }
/**
* The cache of Presences
* @property {Collection<Snowflake, Presence>} cache
* @memberof PresenceManager
* @instance
*/
add(data, cache) { 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 }); 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); const presenceResolvable = super.resolveID(presence);
if (presenceResolvable) return presenceResolvable; if (presenceResolvable) return presenceResolvable;
const userResolvable = this.client.users.resolveID(presence); 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'; 'use strict';
const DataStore = require('./DataStore');
const MessageReaction = require('../structures/MessageReaction'); const MessageReaction = require('../structures/MessageReaction');
const BaseManager = require('./BaseManager');
/** /**
* Stores reactions. * Manages API methods for reactions and holds their cache.
* @extends {DataStore} * @extends {BaseManager}
*/ */
class ReactionStore extends DataStore { class ReactionManager extends BaseManager {
constructor(message, iterable) { constructor(message, iterable) {
super(message.client, iterable, MessageReaction); super(message.client, iterable, MessageReaction);
/**
* The message that this manager belongs to
* @type {Message}
*/
this.message = 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] }); 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: * Data that can be resolved to a MessageReaction object. This can be:
* * A MessageReaction * * A MessageReaction
@@ -27,7 +39,7 @@ class ReactionStore extends DataStore {
/** /**
* Resolves a MessageReactionResolvable to a MessageReaction object. * Resolves a MessageReactionResolvable to a MessageReaction object.
* @method resolve * @method resolve
* @memberof ReactionStore * @memberof ReactionManager
* @instance * @instance
* @param {MessageReactionResolvable} reaction The MessageReaction to resolve * @param {MessageReactionResolvable} reaction The MessageReaction to resolve
* @returns {?MessageReaction} * @returns {?MessageReaction}
@@ -36,7 +48,7 @@ class ReactionStore extends DataStore {
/** /**
* Resolves a MessageReactionResolvable to a MessageReaction ID string. * Resolves a MessageReactionResolvable to a MessageReaction ID string.
* @method resolveID * @method resolveID
* @memberof ReactionStore * @memberof ReactionManager
* @instance * @instance
* @param {MessageReactionResolvable} reaction The MessageReaction to resolve * @param {MessageReactionResolvable} reaction The MessageReaction to resolve
* @returns {?Snowflake} * @returns {?Snowflake}
@@ -53,18 +65,18 @@ class ReactionStore extends DataStore {
_partial(emoji) { _partial(emoji) {
const id = emoji.id || emoji.name; const id = emoji.id || emoji.name;
const existing = this.get(id); const existing = this.cache.get(id);
return !existing || existing.partial; return !existing || existing.partial;
} }
async _fetchReaction(reactionEmoji, cache) { async _fetchReaction(reactionEmoji, cache) {
const id = reactionEmoji.id || reactionEmoji.name; const id = reactionEmoji.id || reactionEmoji.name;
const existing = this.get(id); const existing = this.cache.get(id);
if (!this._partial(reactionEmoji)) return existing; if (!this._partial(reactionEmoji)) return existing;
const data = await this.client.api.channels(this.message.channel.id).messages(this.message.id).get(); 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)) { if (!data.reactions || !data.reactions.some(r => (r.emoji.id || r.emoji.name) === id)) {
reactionEmoji.reaction._patch({ count: 0 }); reactionEmoji.reaction._patch({ count: 0 });
this.message.reactions.remove(id); this.message.reactions.cache.delete(id);
return existing; return existing;
} }
for (const reaction of data.reactions) { 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'; 'use strict';
const Collection = require('../util/Collection'); const Collection = require('../util/Collection');
const DataStore = require('./DataStore'); const BaseManager = require('./BaseManager');
const { Error } = require('../errors'); const { Error } = require('../errors');
/** /**
* A data store to store User models who reacted to a MessageReaction. * Manages API methods for users who reacted to a reaction and stores their cache.
* @extends {DataStore} * @extends {BaseManager}
*/ */
class ReactionUserStore extends DataStore { class ReactionUserManager extends BaseManager {
constructor(client, iterable, reaction) { 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; 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. * 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 * @param {Object} [options] Options for fetching the users
@@ -30,7 +41,7 @@ class ReactionUserStore extends DataStore {
const users = new Collection(); const users = new Collection();
for (const rawUser of data) { for (const rawUser of data) {
const user = this.client.users.add(rawUser); const user = this.client.users.add(rawUser);
this.set(user.id, user); this.cache.set(user.id, user);
users.set(user.id, user); users.set(user.id, user);
} }
return users; return users;
@@ -52,4 +63,4 @@ class ReactionUserStore extends DataStore {
} }
} }
module.exports = ReactionUserStore; module.exports = ReactionUserManager;

View File

@@ -1,20 +1,31 @@
'use strict'; 'use strict';
const DataStore = require('./DataStore'); const BaseManager = require('./BaseManager');
const Role = require('../structures/Role'); const Role = require('../structures/Role');
const { resolveColor } = require('../util/Util'); const { resolveColor } = require('../util/Util');
const Permissions = require('../util/Permissions'); const Permissions = require('../util/Permissions');
/** /**
* Stores roles. * Manages API methods for roles and stores their cache.
* @extends {DataStore} * @extends {BaseManager}
*/ */
class RoleStore extends DataStore { class RoleManager extends BaseManager {
constructor(guild, iterable) { constructor(guild, iterable) {
super(guild.client, iterable, Role); super(guild.client, iterable, Role);
/**
* The guild belonging to this manager
* @type {Guild}
*/
this.guild = guild; this.guild = guild;
} }
/**
* The role cache of this manager
* @property {Collection<Snowflake, Role>} cache
* @memberof RoleManager
* @instance
*/
add(data, cache) { add(data, cache) {
return super.add(data, cache, { extras: [this.guild] }); 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. * 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 {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 * @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 * @example
* // Fetch all roles from the guild * // Fetch all roles from the guild
* message.guild.roles.fetch() * 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); * .catch(console.error);
* @example * @example
* // Fetch a single role * // Fetch a single role
@@ -37,14 +48,14 @@ class RoleStore extends DataStore {
*/ */
async fetch(id, cache = true) { async fetch(id, cache = true) {
if (id) { if (id) {
const existing = this.get(id); const existing = this.cache.get(id);
if (existing) return existing; if (existing) return existing;
} }
// We cannot fetch a single role, as of this commit's date, Discord API throws with 405 // 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(); const roles = await this.client.api.guilds(this.guild.id).roles.get();
for (const role of roles) this.add(role, cache); 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. * Resolves a RoleResolvable to a Role object.
* @method resolve * @method resolve
* @memberof RoleStore * @memberof RoleManager
* @instance * @instance
* @param {RoleResolvable} role The role resolvable to resolve * @param {RoleResolvable} role The role resolvable to resolve
* @returns {?Role} * @returns {?Role}
@@ -66,7 +77,7 @@ class RoleStore extends DataStore {
/** /**
* Resolves a RoleResolvable to a role ID string. * Resolves a RoleResolvable to a role ID string.
* @method resolveID * @method resolveID
* @memberof RoleStore * @memberof RoleManager
* @instance * @instance
* @param {RoleResolvable} role The role resolvable to resolve * @param {RoleResolvable} role The role resolvable to resolve
* @returns {?Snowflake} * @returns {?Snowflake}
@@ -116,17 +127,17 @@ class RoleStore extends DataStore {
* @readonly * @readonly
*/ */
get everyone() { 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} * @type {Role}
* @readonly * @readonly
*/ */
get highest() { 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'; 'use strict';
const DataStore = require('./DataStore'); const BaseManager = require('./BaseManager');
const User = require('../structures/User'); const User = require('../structures/User');
const GuildMember = require('../structures/GuildMember'); const GuildMember = require('../structures/GuildMember');
const Message = require('../structures/Message'); const Message = require('../structures/Message');
/** /**
* A data store to store User models. * Manages API methods for users and stores their cache.
* @extends {DataStore} * @extends {BaseManager}
*/ */
class UserStore extends DataStore { class UserManager extends BaseManager {
constructor(client, iterable) { constructor(client, iterable) {
super(client, iterable, User); 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: * Data that resolves to give a User object. This can be:
* * A User object * * A User object
@@ -52,11 +59,11 @@ class UserStore extends DataStore {
* @returns {Promise<User>} * @returns {Promise<User>}
*/ */
async fetch(id, cache = true) { async fetch(id, cache = true) {
const existing = this.get(id); const existing = this.cache.get(id);
if (existing && !existing.partial) return existing; if (existing && !existing.partial) return existing;
const data = await this.client.api.users(id).get(); const data = await this.client.api.users(id).get();
return this.add(data, cache); 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 * @param {string} prop Name of the client property to get, using periods for nesting
* @returns {Promise<Array<*>>} * @returns {Promise<Array<*>>}
* @example * @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`)) * .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`))
* .catch(console.error); * .catch(console.error);
* @see {@link ShardingManager#fetchClientValues} * @see {@link ShardingManager#fetchClientValues}
@@ -114,7 +114,7 @@ class ShardClientUtil {
* @param {string|Function} script JavaScript to run on each shard * @param {string|Function} script JavaScript to run on each shard
* @returns {Promise<Array<*>>} Results of the script execution * @returns {Promise<Array<*>>} Results of the script execution
* @example * @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`)) * .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`))
* .catch(console.error); * .catch(console.error);
* @see {@link ShardingManager#broadcastEval} * @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 * @param {string} prop Name of the client property to get, using periods for nesting
* @returns {Promise<Array<*>>} * @returns {Promise<Array<*>>}
* @example * @example
* manager.fetchClientValues('guilds.size') * manager.fetchClientValues('guilds.cache.size')
* .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`)) * .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`))
* .catch(console.error); * .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 * @readonly
*/ */
get children() { 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'); const DMChannel = Structures.get('DMChannel');
channel = new DMChannel(client, data); channel = new DMChannel(client, data);
} else { } else {
guild = guild || client.guilds.get(data.guild_id); guild = guild || client.guilds.cache.get(data.guild_id);
if (guild) { if (guild) {
switch (data.type) { switch (data.type) {
case ChannelTypes.TEXT: { case ChannelTypes.TEXT: {
@@ -129,7 +129,7 @@ class Channel extends Base {
break; break;
} }
} }
if (channel) guild.channels.set(channel.id, channel); if (channel) guild.channels.cache.set(channel.id, channel);
} }
} }
return channel; return channel;

View File

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

View File

@@ -82,7 +82,7 @@ class Emoji extends Base {
* @returns {string} * @returns {string}
* @example * @example
* // Send a custom emoji from a guild: * // Send a custom emoji from a guild:
* const emoji = guild.emojis.first(); * const emoji = guild.emojis.cache.first();
* msg.reply(`Hello! ${emoji}`); * msg.reply(`Hello! ${emoji}`);
* @example * @example
* // Send the emoji used in a reaction to the channel the reaction is part of * // 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 DataResolver = require('../util/DataResolver');
const Snowflake = require('../util/Snowflake'); const Snowflake = require('../util/Snowflake');
const SystemChannelFlags = require('../util/SystemChannelFlags'); const SystemChannelFlags = require('../util/SystemChannelFlags');
const GuildMemberStore = require('../stores/GuildMemberStore'); const GuildMemberManager = require('../managers/GuildMemberManager');
const RoleStore = require('../stores/RoleStore'); const RoleManager = require('../managers/RoleManager');
const GuildEmojiStore = require('../stores/GuildEmojiStore'); const GuildEmojiManager = require('../managers/GuildEmojiManager');
const GuildChannelStore = require('../stores/GuildChannelStore'); const GuildChannelManager = require('../managers/GuildChannelManager');
const PresenceStore = require('../stores/PresenceStore'); const PresenceManager = require('../managers/PresenceManager');
const VoiceStateStore = require('../stores/VoiceStateStore'); const VoiceStateManager = require('../managers/VoiceStateManager');
const Base = require('./Base'); const Base = require('./Base');
const { Error, TypeError } = require('../errors'); const { Error, TypeError } = require('../errors');
@@ -35,34 +35,34 @@ class Guild extends Base {
super(client); super(client);
/** /**
* A collection of members that are in this guild. The key is the member's ID, the value is the member * A manager of the members belonging to this guild
* @type {GuildMemberStore<Snowflake, GuildMember>} * @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 * A manager of the members belonging to this guild
* @type {GuildChannelStore<Snowflake, GuildChannel>} * @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 * A manager of the roles belonging to this guild
* @type {RoleStore<Snowflake, Role>} * @type {RoleManager}
*/ */
this.roles = new RoleStore(this); this.roles = new RoleManager(this);
/** /**
* A collection of presences in this guild * A manager of the presences belonging to this guild
* @type {PresenceStore<Snowflake, Presence>} * @type {PresenceManager}
*/ */
this.presences = new PresenceStore(this.client); this.presences = new PresenceManager(this.client);
/** /**
* A collection of voice states in this guild * A manager of the voice states of this guild
* @type {VoiceStateStore<Snowflake, VoiceState>} * @type {VoiceStateManager}
*/ */
this.voiceStates = new VoiceStateStore(this); this.voiceStates = new VoiceStateManager(this);
/** /**
* Whether the bot has been removed from the guild * Whether the bot has been removed from the guild
@@ -321,19 +321,19 @@ class Guild extends Base {
this.features = data.features || this.features || []; this.features = data.features || this.features || [];
if (data.channels) { if (data.channels) {
this.channels.clear(); this.channels.cache.clear();
for (const rawChannel of data.channels) { for (const rawChannel of data.channels) {
this.client.channels.add(rawChannel, this); this.client.channels.add(rawChannel, this);
} }
} }
if (data.roles) { if (data.roles) {
this.roles.clear(); this.roles.cache.clear();
for (const role of data.roles) this.roles.add(role); for (const role of data.roles) this.roles.add(role);
} }
if (data.members) { if (data.members) {
this.members.clear(); this.members.cache.clear();
for (const guildUser of data.members) this.members.add(guildUser); for (const guildUser of data.members) this.members.add(guildUser);
} }
@@ -352,7 +352,7 @@ class Guild extends Base {
} }
if (data.voice_states) { if (data.voice_states) {
this.voiceStates.clear(); this.voiceStates.cache.clear();
for (const voiceState of data.voice_states) { for (const voiceState of data.voice_states) {
this.voiceStates.add(voiceState); this.voiceStates.add(voiceState);
} }
@@ -360,10 +360,10 @@ class Guild extends Base {
if (!this.emojis) { if (!this.emojis) {
/** /**
* A collection of emojis that are in this guild. The key is the emoji's ID, the value is the emoji. * A manager of the emojis belonging to this guild
* @type {GuildEmojiStore<Snowflake, GuildEmoji>} * @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); if (data.emojis) for (const emoji of data.emojis) this.emojis.add(emoji);
} else if (data.emojis) { } else if (data.emojis) {
this.client.actions.GuildEmojisUpdate.handle({ this.client.actions.GuildEmojisUpdate.handle({
@@ -463,7 +463,7 @@ class Guild extends Base {
* @readonly * @readonly
*/ */
get owner() { 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) : this.members.add({ user: { id: this.ownerID } }, true) :
null); null);
} }
@@ -474,7 +474,7 @@ class Guild extends Base {
* @readonly * @readonly
*/ */
get afkChannel() { 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 * @readonly
*/ */
get systemChannel() { 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 * @readonly
*/ */
get widgetChannel() { 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 * @readonly
*/ */
get embedChannel() { 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 * @readonly
*/ */
get me() { get me() {
return this.members.get(this.client.user.id) || (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) ? return this.members.cache.get(this.client.user.id) ||
this.members.add({ user: { id: this.client.user.id } }, true) : (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) ?
null); this.members.add({ user: { id: this.client.user.id } }, true) :
null);
} }
/** /**
@@ -521,7 +522,7 @@ class Guild extends Base {
* @readonly * @readonly
*/ */
get voice() { 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() { fetchEmbed() {
return this.client.api.guilds(this.id).embed.get().then(data => ({ return this.client.api.guilds(this.id).embed.get().then(data => ({
enabled: data.enabled, 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) { addMember(user, options) {
user = this.client.users.resolveID(user); user = this.client.users.resolveID(user);
if (!user) return Promise.reject(new TypeError('INVALID_TYPE', 'user', 'UserResolvable')); 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; options.access_token = options.accessToken;
if (options.roles) { if (options.roles) {
const roles = []; const roles = [];
@@ -988,7 +989,7 @@ class Guild extends Base {
* @returns {Promise<Guild>} * @returns {Promise<Guild>}
* @example * @example
* // Edit the guild owner * // 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}`)) * .then(updated => console.log(`Updated the guild owner to ${updated.owner.displayName}`))
* .catch(console.error); * .catch(console.error);
*/ */
@@ -1203,7 +1204,7 @@ class Guild extends Base {
* @private * @private
*/ */
_sortedRoles() { _sortedRoles() {
return Util.discordSort(this.roles); return Util.discordSort(this.roles.cache);
} }
/** /**
@@ -1214,7 +1215,7 @@ class Guild extends Base {
*/ */
_sortedChannels(channel) { _sortedChannels(channel) {
const category = channel.type === ChannelTypes.CATEGORY; 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) 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) ? this.executor = guild.client.options.partials.includes(PartialTypes.USER) ?
guild.client.users.add({ id: data.user_id }) : 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. * An entry in the audit log representing a specific change.
@@ -321,7 +321,7 @@ class GuildAuditLogsEntry {
} else if (data.action_type === Actions.MESSAGE_DELETE) { } else if (data.action_type === Actions.MESSAGE_DELETE) {
this.extra = { this.extra = {
count: data.options.count, 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) { } else if (data.action_type === Actions.MESSAGE_BULK_DELETE) {
this.extra = { this.extra = {
@@ -330,11 +330,11 @@ class GuildAuditLogsEntry {
} else { } else {
switch (data.options.type) { switch (data.options.type) {
case 'member': 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 }; if (!this.extra) this.extra = { id: data.options.id };
break; break;
case 'role': 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 }; if (!this.extra) this.extra = { id: data.options.id, name: data.options.role_name };
break; break;
default: default:
@@ -357,9 +357,9 @@ class GuildAuditLogsEntry {
} else if (targetType === Targets.USER) { } else if (targetType === Targets.USER) {
this.target = guild.client.options.partials.includes(PartialTypes.USER) ? this.target = guild.client.options.partials.includes(PartialTypes.USER) ?
guild.client.users.add({ id: data.target_id }) : 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) { } 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) { } else if (targetType === Targets.WEBHOOK) {
this.target = logs.webhooks.get(data.target_id) || this.target = logs.webhooks.get(data.target_id) ||
new Webhook(guild.client, new Webhook(guild.client,
@@ -386,9 +386,9 @@ class GuildAuditLogsEntry {
} }
}); });
} else if (targetType === Targets.MESSAGE) { } 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 { } 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 * @readonly
*/ */
get parent() { 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 (!verified) member = this.guild.members.resolve(member);
if (!member) return []; if (!member) return [];
roles = roles || member.roles; roles = roles || member.roles.cache;
const roleOverwrites = []; const roleOverwrites = [];
let memberOverwrites; let memberOverwrites;
let everyoneOverwrites; let everyoneOverwrites;
@@ -149,7 +149,7 @@ class GuildChannel extends Channel {
memberPermissions(member) { memberPermissions(member) {
if (member.id === this.guild.ownerID) return new Permissions(Permissions.ALL).freeze(); 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)); const permissions = new Permissions(roles.map(role => role.permissions));
if (permissions.has(Permissions.FLAGS.ADMINISTRATOR)) return new Permissions(Permissions.ALL).freeze(); if (permissions.has(Permissions.FLAGS.ADMINISTRATOR)) return new Permissions(Permissions.ALL).freeze();
@@ -274,7 +274,7 @@ class GuildChannel extends Channel {
*/ */
get members() { get members() {
const members = new Collection(); 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)) { if (this.permissionsFor(member).has('VIEW_CHANNEL', false)) {
members.set(member.id, member); members.set(member.id, member);
} }

View File

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

View File

@@ -3,7 +3,7 @@
const TextBasedChannel = require('./interfaces/TextBasedChannel'); const TextBasedChannel = require('./interfaces/TextBasedChannel');
const Role = require('./Role'); const Role = require('./Role');
const Permissions = require('../util/Permissions'); const Permissions = require('../util/Permissions');
const GuildMemberRoleStore = require('../stores/GuildMemberRoleStore'); const GuildMemberRoleManager = require('../managers/GuildMemberRoleManager');
const Base = require('./Base'); const Base = require('./Base');
const VoiceState = require('./VoiceState'); const VoiceState = require('./VoiceState');
const { Presence } = require('./Presence'); 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 * A manager for the roles belonging to this member
* @type {GuildMemberRoleStore<Snowflake, Role>} * @type {GuildMemberRoleManager}
* @readonly * @readonly
*/ */
get roles() { get roles() {
return new GuildMemberRoleStore(this); return new GuildMemberRoleManager(this);
} }
/** /**
@@ -115,8 +115,8 @@ class GuildMember extends Base {
* @readonly * @readonly
*/ */
get lastMessage() { get lastMessage() {
const channel = this.guild.channels.get(this.lastMessageChannelID); const channel = this.guild.channels.cache.get(this.lastMessageChannelID);
return (channel && channel.messages.get(this.lastMessageID)) || null; return (channel && channel.messages.cache.get(this.lastMessageID)) || null;
} }
/** /**
@@ -125,7 +125,7 @@ class GuildMember extends Base {
* @readonly * @readonly
*/ */
get voice() { 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 * @readonly
*/ */
get presence() { 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: { user: {
id: this.id, id: this.id,
}, },
@@ -205,7 +205,7 @@ class GuildMember extends Base {
*/ */
get permissions() { get permissions() {
if (this.user.id === this.guild.ownerID) return new Permissions(Permissions.ALL).freeze(); 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 } = {}) { hasPermission(permission, { checkAdmin = true, checkOwner = true } = {}) {
if (checkOwner && this.user.id === this.guild.ownerID) return 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 * The role that this integration uses for subscribers
* @type {Role} * @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 * The user for this integration

View File

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

View File

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

View File

@@ -71,7 +71,7 @@ class MessageMentions {
} else { } else {
this.roles = new Collection(); this.roles = new Collection();
for (const mention of roles) { 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); if (role) this.roles.set(role.id, role);
} }
} }
@@ -156,7 +156,7 @@ class MessageMentions {
this._channels = new Collection(); this._channels = new Collection();
let matches; let matches;
while ((matches = this.constructor.CHANNELS_PATTERN.exec(this._content)) !== null) { 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); if (chan) this._channels.set(chan.id, chan);
} }
return this._channels; return this._channels;
@@ -175,7 +175,7 @@ class MessageMentions {
has(data, { ignoreDirect = false, ignoreRoles = false, ignoreEveryone = false } = {}) { has(data, { ignoreDirect = false, ignoreRoles = false, ignoreEveryone = false } = {}) {
if (!ignoreEveryone && this.everyone) return true; if (!ignoreEveryone && this.everyone) return true;
if (!ignoreRoles && data instanceof GuildMember) { 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) { if (!ignoreDirect) {

View File

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

View File

@@ -66,7 +66,7 @@ class Presence {
* @readonly * @readonly
*/ */
get user() { 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 * @readonly
*/ */
get member() { get member() {
return this.guild.members.get(this.userID) || null; return this.guild.members.cache.get(this.userID) || null;
} }
patch(data) { patch(data) {

View File

@@ -74,7 +74,7 @@ class ReactionCollector extends Collector {
this.on('remove', (reaction, user) => { this.on('remove', (reaction, user) => {
this.total--; 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 * @readonly
*/ */
get members() { 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 TextBasedChannel = require('./interfaces/TextBasedChannel');
const Collection = require('../util/Collection'); const Collection = require('../util/Collection');
const DataResolver = require('../util/DataResolver'); const DataResolver = require('../util/DataResolver');
const MessageStore = require('../stores/MessageStore'); const MessageManager = require('../managers/MessageManager');
/** /**
* Represents a guild text channel on Discord. * Represents a guild text channel on Discord.
@@ -20,10 +20,10 @@ class TextChannel extends GuildChannel {
constructor(guild, data) { constructor(guild, data) {
super(guild, data); super(guild, data);
/** /**
* A collection containing the messages sent to this channel * A manager of the messages sent to this channel
* @type {MessageStore<Snowflake, Message>} * @type {MessageManager}
*/ */
this.messages = new MessageStore(this); this.messages = new MessageManager(this);
this._typing = new Map(); this._typing = new Map();
} }

View File

@@ -119,8 +119,8 @@ class User extends Base {
* @readonly * @readonly
*/ */
get lastMessage() { get lastMessage() {
const channel = this.client.channels.get(this.lastMessageChannelID); const channel = this.client.channels.cache.get(this.lastMessageChannelID);
return (channel && channel.messages.get(this.lastMessageID)) || null; return (channel && channel.messages.cache.get(this.lastMessageID)) || null;
} }
/** /**
@@ -129,8 +129,8 @@ class User extends Base {
* @readonly * @readonly
*/ */
get presence() { get presence() {
for (const guild of this.client.guilds.values()) { for (const guild of this.client.guilds.cache.values()) {
if (guild.presences.has(this.id)) return guild.presences.get(this.id); if (guild.presences.cache.has(this.id)) return guild.presences.cache.get(this.id);
} }
return new Presence(this.client, { user: { id: this.id } }); return new Presence(this.client, { user: { id: this.id } });
} }
@@ -209,7 +209,7 @@ class User extends Base {
* @readonly * @readonly
*/ */
get dmChannel() { 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() { get members() {
const coll = new Collection(); 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) { if (state.channelID === this.id && state.member) {
coll.set(state.id, state.member); coll.set(state.id, state.member);
} }

View File

@@ -72,7 +72,7 @@ class VoiceState extends Base {
* @readonly * @readonly
*/ */
get member() { 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 * @readonly
*/ */
get channel() { 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 * The owner of the webhook
* @type {?User|Object} * @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 { } else {
this.owner = null; this.owner = null;
} }
@@ -154,7 +154,7 @@ class Webhook {
query: { wait: true }, query: { wait: true },
auth: false, auth: false,
}).then(d => { }).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; if (!channel) return d;
return channel.messages.add(d, false); return channel.messages.add(d, false);
}); });

View File

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

View File

@@ -528,25 +528,25 @@ class Util {
.replace(/<@!?[0-9]+>/g, input => { .replace(/<@!?[0-9]+>/g, input => {
const id = input.replace(/<|!|>|@/g, ''); const id = input.replace(/<|!|>|@/g, '');
if (message.channel.type === 'dm') { 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; return user ? `@${user.username}` : input;
} }
const member = message.channel.guild.members.get(id); const member = message.channel.guild.members.cache.get(id);
if (member) { if (member) {
return `@${member.displayName}`; return `@${member.displayName}`;
} else { } else {
const user = message.client.users.get(id); const user = message.client.users.cache.get(id);
return user ? `@${user.username}` : input; return user ? `@${user.username}` : input;
} }
}) })
.replace(/<#[0-9]+>/g, 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; return channel ? `#${channel.name}` : input;
}) })
.replace(/<@&[0-9]+>/g, input => { .replace(/<@&[0-9]+>/g, input => {
if (message.channel.type === 'dm') return 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; return role ? `@${role.name}` : input;
}); });
} }
@@ -571,34 +571,6 @@ class Util {
setTimeout(resolve, ms); 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; 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 _eval(script: string): any;
private _validateOptions(options?: ClientOptions): void; private _validateOptions(options?: ClientOptions): void;
public channels: ChannelStore; public channels: ChannelManager;
public readonly emojis: GuildEmojiStore; public readonly emojis: GuildEmojiManager;
public guilds: GuildStore; public guilds: GuildManager;
public readyAt: Date | null; public readyAt: Date | null;
public readonly readyTimestamp: number | null; public readonly readyTimestamp: number | null;
public shard: ShardClientUtil | null; public shard: ShardClientUtil | null;
public token: string | null; public token: string | null;
public readonly uptime: number | null; public readonly uptime: number | null;
public user: ClientUser | null; public user: ClientUser | null;
public users: UserStore; public users: UserManager;
public voice: ClientVoiceManager | null; public voice: ClientVoiceManager | null;
public ws: WebSocketManager; public ws: WebSocketManager;
public destroy(): void; public destroy(): void;
@@ -328,16 +328,6 @@ declare module 'discord.js' {
public setUsername(username: string): Promise<ClientUser>; 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 { export abstract class Collector<K, V> extends EventEmitter {
constructor(client: Client, filter: CollectorFilter, options?: CollectorOptions); constructor(client: Client, filter: CollectorFilter, options?: CollectorOptions);
private _timeout: NodeJS.Timer | null; private _timeout: NodeJS.Timer | null;
@@ -648,7 +638,7 @@ declare module 'discord.js' {
export class DMChannel extends TextBasedChannel(Channel) { export class DMChannel extends TextBasedChannel(Channel) {
constructor(client: Client, data?: object); constructor(client: Client, data?: object);
public messages: MessageStore; public messages: MessageManager;
public recipient: User; public recipient: User;
public readonly partial: false; public readonly partial: false;
public fetch(): Promise<DMChannel>; public fetch(): Promise<DMChannel>;
@@ -680,7 +670,7 @@ declare module 'discord.js' {
public applicationID: Snowflake; public applicationID: Snowflake;
public available: boolean; public available: boolean;
public banner: string | null; public banner: string | null;
public channels: GuildChannelStore; public channels: GuildChannelManager;
public readonly createdAt: Date; public readonly createdAt: Date;
public readonly createdTimestamp: number; public readonly createdTimestamp: number;
public defaultMessageNotifications: DefaultMessageNotifications | number; public defaultMessageNotifications: DefaultMessageNotifications | number;
@@ -689,7 +679,7 @@ declare module 'discord.js' {
public embedChannel: GuildChannel | null; public embedChannel: GuildChannel | null;
public embedChannelID: Snowflake | null; public embedChannelID: Snowflake | null;
public embedEnabled: boolean; public embedEnabled: boolean;
public emojis: GuildEmojiStore; public emojis: GuildEmojiManager;
public explicitContentFilter: number; public explicitContentFilter: number;
public features: GuildFeatures[]; public features: GuildFeatures[];
public icon: string | null; public icon: string | null;
@@ -701,7 +691,7 @@ declare module 'discord.js' {
public maximumPresences: number | null; public maximumPresences: number | null;
public readonly me: GuildMember | null; public readonly me: GuildMember | null;
public memberCount: number; public memberCount: number;
public members: GuildMemberStore; public members: GuildMemberManager;
public mfaLevel: number; public mfaLevel: number;
public name: string; public name: string;
public readonly nameAcronym: string; public readonly nameAcronym: string;
@@ -710,9 +700,9 @@ declare module 'discord.js' {
public readonly partnered: boolean; public readonly partnered: boolean;
public premiumSubscriptionCount: number | null; public premiumSubscriptionCount: number | null;
public premiumTier: PremiumTier; public premiumTier: PremiumTier;
public presences: PresenceStore; public presences: PresenceManager;
public region: string; public region: string;
public roles: RoleStore; public roles: RoleManager;
public readonly shard: WebSocketShard; public readonly shard: WebSocketShard;
public shardID: number; public shardID: number;
public splash: string | null; public splash: string | null;
@@ -723,7 +713,7 @@ declare module 'discord.js' {
public verificationLevel: number; public verificationLevel: number;
public readonly verified: boolean; public readonly verified: boolean;
public readonly voice: VoiceState | null; public readonly voice: VoiceState | null;
public readonly voiceStates: VoiceStateStore; public readonly voiceStates: VoiceStateManager;
public readonly widgetChannel: TextChannel | null; public readonly widgetChannel: TextChannel | null;
public widgetChannelID: Snowflake | null; public widgetChannelID: Snowflake | null;
public widgetEnabled: boolean | null; public widgetEnabled: boolean | null;
@@ -847,7 +837,7 @@ declare module 'discord.js' {
public id: Snowflake; public id: Snowflake;
public managed: boolean; public managed: boolean;
public requiresColons: boolean; public requiresColons: boolean;
public roles: GuildEmojiRoleStore; public roles: GuildEmojiRoleManager;
public readonly url: string; public readonly url: string;
public delete(reason?: string): Promise<GuildEmoji>; public delete(reason?: string): Promise<GuildEmoji>;
public edit(data: GuildEmojiEditData, 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 readonly premiumSince: Date | null;
public premiumSinceTimestamp: number | null; public premiumSinceTimestamp: number | null;
public readonly presence: Presence; public readonly presence: Presence;
public roles: GuildMemberRoleStore; public roles: GuildMemberRoleManager;
public user: User; public user: User;
public readonly voice: VoiceState; public readonly voice: VoiceState;
public ban(options?: BanOptions): Promise<GuildMember>; public ban(options?: BanOptions): Promise<GuildMember>;
@@ -978,7 +968,7 @@ declare module 'discord.js' {
public readonly partial: false; public readonly partial: false;
public readonly pinnable: boolean; public readonly pinnable: boolean;
public pinned: boolean; public pinned: boolean;
public reactions: ReactionStore; public reactions: ReactionManager;
public system: boolean; public system: boolean;
public tts: boolean; public tts: boolean;
public type: MessageType; public type: MessageType;
@@ -1113,7 +1103,7 @@ declare module 'discord.js' {
public me: boolean; public me: boolean;
public message: Message; public message: Message;
public readonly partial: boolean; public readonly partial: boolean;
public users: ReactionUserStore; public users: ReactionUserManager;
public remove(): Promise<MessageReaction>; public remove(): Promise<MessageReaction>;
public fetch(): Promise<MessageReaction>; public fetch(): Promise<MessageReaction>;
public toJSON(): object; public toJSON(): object;
@@ -1397,7 +1387,7 @@ declare module 'discord.js' {
export class TextChannel extends TextBasedChannel(GuildChannel) { export class TextChannel extends TextBasedChannel(GuildChannel) {
constructor(guild: Guild, data?: object); constructor(guild: Guild, data?: object);
public messages: MessageStore; public messages: MessageManager;
public nsfw: boolean; public nsfw: boolean;
public rateLimitPerUser: number; public rateLimitPerUser: number;
public topic: string | null; public topic: string | null;
@@ -1409,7 +1399,7 @@ declare module 'discord.js' {
export class NewsChannel extends TextBasedChannel(GuildChannel) { export class NewsChannel extends TextBasedChannel(GuildChannel) {
constructor(guild: Guild, data?: object); constructor(guild: Guild, data?: object);
public messages: MessageStore; public messages: MessageManager;
public nsfw: boolean; public nsfw: boolean;
public topic: string | null; public topic: string | null;
public createWebhook(name: string, options?: { avatar?: BufferResolvable | Base64Resolvable, reason?: string }): Promise<Webhook>; public createWebhook(name: string, options?: { avatar?: BufferResolvable | Base64Resolvable, reason?: string }): Promise<Webhook>;
@@ -1749,64 +1739,64 @@ declare module 'discord.js' {
//#endregion //#endregion
//#region Stores //#region Collections
export class ChannelStore extends DataStore<Snowflake, Channel, typeof Channel, ChannelResolvable> { export class Collection<K, V> extends BaseCollection<K, V> {
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>];
public flatMap<T>(fn: (value: V, key: K, collection: this) => Collection<K, T>): Collection<K, T>; 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, 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 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<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<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 mapValues<T>(fn: (value: V, key: K, collection: this) => T, thisArg?: unknown): Collection<K, T>;
// @ts-ignore public toJSON(): object;
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>;
} }
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); 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 add(roleOrRoles: RoleResolvable | RoleResolvable[] | Collection<Snowflake, Role>): Promise<GuildEmoji>;
public set(roles: 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>; 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>); constructor(guild: Guild, iterable?: Iterable<any>);
public guild: Guild;
public create(attachment: BufferResolvable | Base64Resolvable, name: string, options?: GuildEmojiCreateOptions): Promise<GuildEmoji>; public create(attachment: BufferResolvable | Base64Resolvable, name: string, options?: GuildEmojiCreateOptions): Promise<GuildEmoji>;
public resolveIdentifier(emoji: EmojiIdentifierResolvable): string | null; 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>); 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: 'voice' }): Promise<VoiceChannel>;
public create(name: string, options: GuildCreateChannelOptions & { type: 'category' }): Promise<CategoryChannel>; public create(name: string, options: GuildCreateChannelOptions & { type: 'category' }): Promise<CategoryChannel>;
public create(name: string, options?: GuildCreateChannelOptions & { type?: 'text' }): Promise<TextChannel>; 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 // 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 add(data: any, cache: any): any;
public set(key: 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); constructor(member: GuildMember);
public readonly hoist: Role | null; public readonly hoist: Role | null;
public readonly color: Role | null; public readonly color: Role | null;
public readonly highest: Role; public readonly highest: Role;
public member: GuildMember;
public guild: Guild;
public add(roleOrRoles: RoleResolvable | RoleResolvable[] | Collection<Snowflake, Role>, reason?: string): Promise<GuildMember>; public add(roleOrRoles: RoleResolvable | RoleResolvable[] | Collection<Snowflake, Role>, reason?: string): Promise<GuildMember>;
public set(roles: 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>; 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>); constructor(guild: Guild, iterable?: Iterable<any>);
public guild: Guild;
public ban(user: UserResolvable, options?: BanOptions): Promise<GuildMember | User | Snowflake>; public ban(user: UserResolvable, options?: BanOptions): Promise<GuildMember | User | Snowflake>;
public fetch(options: UserResolvable | FetchMemberOptions): Promise<GuildMember>; public fetch(options: UserResolvable | FetchMemberOptions): Promise<GuildMember>;
public fetch(): Promise<GuildMemberStore>; public fetch(): Promise<GuildMemberManager>;
public fetch(options: FetchMembersOptions): Promise<Collection<Snowflake, GuildMember>>; public fetch(options: FetchMembersOptions): Promise<Collection<Snowflake, GuildMember>>;
public prune(options: GuildPruneMembersOptions & { dry?: false, count: false }): Promise<null>; public prune(options: GuildPruneMembersOptions & { dry?: false, count: false }): Promise<null>;
public prune(options?: GuildPruneMembersOptions): Promise<number>; public prune(options?: GuildPruneMembersOptions): Promise<number>;
public unban(user: UserResolvable, reason?: string): Promise<User>; 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>); constructor(client: Client, iterable?: Iterable<any>);
public create(name: string, options?: { region?: string, icon: BufferResolvable | Base64Resolvable | null }): Promise<Guild>; 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>); 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(message: Snowflake, cache?: boolean): Promise<Message>;
public fetch(options?: ChannelLogsQueryOptions, cache?: boolean): Promise<Collection<Snowflake, Message>>; public fetch(options?: ChannelLogsQueryOptions, cache?: boolean): Promise<Collection<Snowflake, Message>>;
public fetchPinned(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>); 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>); constructor(message: Message, iterable?: Iterable<any>);
public message: Message;
public removeAll(): Promise<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); 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 fetch(options?: { limit?: number, after?: Snowflake, before?: Snowflake }): Promise<Collection<Snowflake, User>>;
public remove(user?: UserResolvable): Promise<MessageReaction>; 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>); constructor(guild: Guild, iterable?: Iterable<any>);
public readonly everyone: Role | null; public readonly everyone: Role | null;
public readonly highest: Role; public readonly highest: Role;
public guild: Guild;
public create(options?: { data?: RoleData, reason?: string }): Promise<Role>; 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<Role | null>;
public fetch(id?: Snowflake, cache?: boolean): Promise<this>; 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>); constructor(client: Client, iterable?: Iterable<any>);
public fetch(id: Snowflake, cache?: boolean): Promise<User>; 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>); constructor(guild: Guild, iterable?: Iterable<any>);
public guild: Guild;
} }
//#endregion //#endregion